This commit is contained in:
51
simhv36-1/0readme_36.txt
Normal file
51
simhv36-1/0readme_36.txt
Normal file
@@ -0,0 +1,51 @@
|
||||
Notes For V3.6-0
|
||||
|
||||
The save/restore format has been updated to improve its reliability.
|
||||
As a result, save files prior to release 3.0 are no longer supported.
|
||||
|
||||
The text documentation files are obsolete and are no longer included
|
||||
with the distribution. Up-to-date PDF documentation files are
|
||||
available on the SimH web site.
|
||||
|
||||
|
||||
1. New Features
|
||||
|
||||
1.1 3.6-0
|
||||
|
||||
1.1.1 Most magnetic tapes
|
||||
|
||||
- Added support for limiting tape capacity to a particular size in MB
|
||||
|
||||
1.1.2 IBM 7090/7094
|
||||
|
||||
- First release
|
||||
|
||||
1.1.3 VAX-11/780
|
||||
|
||||
- Added FLOAD command, loads system file from console floppy disk
|
||||
|
||||
1.1.4 VAX, VAX-11/780, and PDP-11
|
||||
|
||||
- Added card reader support (from John Dundas)
|
||||
|
||||
1.1.5 PDP-11
|
||||
|
||||
- Added instruction history
|
||||
|
||||
1.2 3.6-1
|
||||
|
||||
1.2.1 PDP-11
|
||||
|
||||
- Added RF11 support
|
||||
- Added multiple KL11/DL11 support
|
||||
- Added upper-case only mode to TTI, TTO
|
||||
|
||||
1.2.2
|
||||
|
||||
- Added binary loader (courtesy of Dave Pitt)
|
||||
|
||||
|
||||
2. Bugs Fixed
|
||||
|
||||
Please see the revision history on http://simh.trailing-edge.com or
|
||||
in the source module sim_rev.h.
|
||||
315
simhv36-1/0readme_ethernet.txt
Normal file
315
simhv36-1/0readme_ethernet.txt
Normal file
@@ -0,0 +1,315 @@
|
||||
This file contains information about the SIMH Ethernet package.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The XQ emulator is a host-independant software emulation of Digital's
|
||||
DELQA (M7516) and DEQNA (M7504) Q-bus ethernet cards for the SIMH emulator.
|
||||
|
||||
The XU emulator is a host-independant software emulation of Digital's DEUNA
|
||||
(M7792/M7793) and DELUA (M7521) Unibus ethernet cards for the SIMH emulator.
|
||||
|
||||
The XQ and XU simulators use the Sim_Ether module to execute host-specific
|
||||
packet reads and writes, since all operating systems talk to real ethernet
|
||||
cards/controllers differently. See the comments at the top of sim_ether.c
|
||||
for the list of currently supported host platforms.
|
||||
|
||||
The Sim_Ether module sets the selected ethernet card into
|
||||
promiscuous mode to gather all packets, then filters out the packets that it
|
||||
doesn't want. In Windows, packets having the same source MAC address as the
|
||||
controller are ignored for WinPCAP compatibility (see Windows notes below).
|
||||
|
||||
If your ethernet card is plugged into a switch, the promiscuous mode setting
|
||||
should not cause much of a problem, since the switch will still filter out
|
||||
most of the undesirable traffic. You will only see "excessive" traffic if you
|
||||
are on a 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://www.winpcap.org. This package for windows simulates the libpcap
|
||||
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 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 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.
|
||||
|
||||
6. Build it!
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Linux, {Free|Net|Open}BSD, OS/X, and Un*x notes:
|
||||
|
||||
----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- WARNING -----
|
||||
|
||||
Sim_Ether has been reworked to be more universal; because of this, you will
|
||||
need to get a version of libpcap that is 0.9 or greater. This can be
|
||||
downloaded from www.tcpdump.org - see the comments at the top of Sim_ether.c
|
||||
for details.
|
||||
|
||||
At the time of this release, the "Current Version" available at:
|
||||
http://www.tcpdump.org/daily/libpcap-current.tar.gz is the
|
||||
latest checked-in source code that is actually higher than the released
|
||||
0.8.3 version number. Specifically, for all platforms, it contains code that
|
||||
opens the ethernet device in Read/Write mode instead of the Read-Only mode
|
||||
that previous libpcap versions for platforms which use one of pcap-bpf.c,
|
||||
pcap-pf.c, or pcap-snit.c. This capabiligy now exists to support a newly
|
||||
provided generic packet sending capability.
|
||||
|
||||
----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- WARNING -----
|
||||
|
||||
1. For all platforms, you must run SIMH(scp) with sufficient privilege to
|
||||
allow the ethernet card can be set into promiscuous mode and to write
|
||||
packets through the driver. For most Unix/Unix-like platforms this will
|
||||
mean running as root. For systems which use bpf devices (NetBSD,
|
||||
OpenBSD, FreeBSD and OS/X) it is possible to set permissions on the bpf
|
||||
devices to allow read and write access to users other than root (For
|
||||
example: chmod 666 /dev/bpf*). Doing this, has its own security issues.
|
||||
Additional alternative methods for avoiding the 'run as root' requirement
|
||||
will be welcomed.
|
||||
|
||||
2. If you want to use TAP devices, they must be created before running SIMH.
|
||||
|
||||
Building on Linux, {Free|Net|Open}BSD, OS/X, Un*x:
|
||||
|
||||
1. Get/make/install the libpcap package for your operating system. Sources:
|
||||
All : http://www.tcpdump.org/
|
||||
Older versions of libpcap can be found, for various systems, at:
|
||||
Linux : search for your variant on http://rpmfind.net
|
||||
OS/X : Apple Developer's site?
|
||||
|
||||
NOTE: These repositories will not likely contain a version
|
||||
of libpcap greater than 0.8.1 for several years since
|
||||
other packages in these repositories don't depend on a
|
||||
later version than they currently have.
|
||||
|
||||
2. Use 'make USE_NETWORK=1'
|
||||
|
||||
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. Note: This is done by the
|
||||
build commands in descrip.mms.
|
||||
|
||||
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:
|
||||
The current descrip.mms file will build simulators capable of using
|
||||
ethernet support with them automatically. These currently are: VAX,
|
||||
PDP11, and PDP10. The descrip.mms driven builds will also build the
|
||||
pcap library and build and install the VCI execlet.
|
||||
|
||||
1. Fetch the VMS-PCAP zip file from:
|
||||
http://simh.trailing-edge.com/sources/vms-pcap.zip
|
||||
2. Unzip it into the base of the simh distribution directory.
|
||||
3. Build the simulator(s) with MMS or MMK:
|
||||
$ MMx {VAX,PDP11,PDP10, etc...}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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 and
|
||||
OpenVMS VAX 5.5-2 also.
|
||||
|
||||
|
||||
PDP11 simulator support:
|
||||
|
||||
An RT-11 v5.3 system with a freeware TCP/IP stack has been successfully run.
|
||||
Other testers have reported that RSX with DECNET and the NetBSD operating
|
||||
systems also work. RSTS/E v10.1 has preliminary support - RSTS/E boots and
|
||||
enables the XH (XQ) device - DECNET and LAT software have not been tested.
|
||||
|
||||
The XU module has been tested by a third party for basic packet functionality
|
||||
under a modified RSX11M environment. I am unable to test it in-house until
|
||||
someone can arrange to send me a disk image containing a stock RSTS/E or
|
||||
RSX11M+ system image that also contains DECNET, LAT, and/or TCP/IP software.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
How to debug problems with the ethernet subsystems:
|
||||
|
||||
PLEASE read the host-specific notes in sim_ether.c!
|
||||
|
||||
While running SCP, the following commands can be used to enable debug messages:
|
||||
|
||||
scp> SET DEBUG STDERR
|
||||
scp> SET XQ DEBUG={ETH|TRC|REG|WRN|CSR|VAR|SAN|SET|PCK}
|
||||
scp> SET XU DEBUG={ETH|TRC|REG|WRN}
|
||||
|
||||
Documentation of the functionality of these debug modifiers can be found in
|
||||
pdp11_xq.h and pdp11_xu.h. Inline debugging has replaced the previous #ifdef
|
||||
style of debugging, which required recompilation before debugging.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Things planned for future releases:
|
||||
1. PDP-11 bootstrap/bootrom
|
||||
2. Full MOP implementation
|
||||
3. DESQA support (if someone can get me the user manuals)
|
||||
4. DETQA support [DELQA-Turbo] (I have the manual)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Things which I need help with:
|
||||
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:
|
||||
david DOT hittner AT ngc DOT com
|
||||
|
||||
Thanks, and Enjoy!!
|
||||
Dave
|
||||
|
||||
|
||||
===============================================================================
|
||||
Change Log
|
||||
===============================================================================
|
||||
|
||||
19-Mar-04 Release:
|
||||
1. Genericized Sim_Ether code, reduced #ifdefs (David Hittner)
|
||||
2. Further refinement of sim_ether, qualified more platforms (Mark Pizzolato)
|
||||
3. Added XU module (David Hittner)
|
||||
4. Corrected XQ interrupt signalling for PDP11s (David Hittner)
|
||||
5. Added inline debugging support (David Hittner)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
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 Sofware 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 (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 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 (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 (David Hittner)
|
||||
2. Added PDP-11 bootrom load via CSR flags (David Hittner)
|
||||
3. Support for SPARC linux (Mark Pizzolato)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
11-Mar-03 Release:
|
||||
1. Added support for RT-11 TCP/IP
|
||||
2. Corrected interrupts (thanks to Tom Evans and Bob Supnik)
|
||||
3. Moved change log to the bottom of the readme file, cleaned up document
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
16-Jan-03 Release:
|
||||
1. Added VMScluster support (thanks to Mark Pizzolato)
|
||||
2. Verified VAX remote boot functionality (>>>B XQA0)
|
||||
3. Added major performance enhancements (thanks to Mark Pizzolato again)
|
||||
4. Changed _DEBUG tracers to XQ_DEBUG and ETH_DEBUG
|
||||
5. Added local packet processing
|
||||
6. Added system id broadcast
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
08-Nov-02 Release:
|
||||
1. Added USE_NETWORK conditional to Sim_Ether
|
||||
2. Fixed behaviour of SHOW XQ ETH if no devices exist
|
||||
3. Added OpenBSD support to Sim_Ether (courtesy of Federico Schwindt)
|
||||
4. Added ethX detection simplification (from Megan Gentry)
|
||||
|
||||
===============================================================================
|
||||
BIN
simhv36-1/BIN/pdp1
Executable file
BIN
simhv36-1/BIN/pdp1
Executable file
Binary file not shown.
BIN
simhv36-1/BIN/pdp11
Executable file
BIN
simhv36-1/BIN/pdp11
Executable file
Binary file not shown.
BIN
simhv36-1/BIN/pdp4
Executable file
BIN
simhv36-1/BIN/pdp4
Executable file
Binary file not shown.
BIN
simhv36-1/BIN/pdp7
Executable file
BIN
simhv36-1/BIN/pdp7
Executable file
Binary file not shown.
BIN
simhv36-1/BIN/pdp8
Executable file
BIN
simhv36-1/BIN/pdp8
Executable file
Binary file not shown.
BIN
simhv36-1/BIN/vax
Executable file
BIN
simhv36-1/BIN/vax
Executable file
Binary file not shown.
BIN
simhv36-1/BIN/vax730
Executable file
BIN
simhv36-1/BIN/vax730
Executable file
Binary file not shown.
BIN
simhv36-1/BIN/vax780
Executable file
BIN
simhv36-1/BIN/vax780
Executable file
Binary file not shown.
178
simhv36-1/PDP8/pdp8_clk.c
Normal file
178
simhv36-1/PDP8/pdp8_clk.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/* pdp8_clk.c: PDP-8 real-time clock simulator
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
clk real time clock
|
||||
|
||||
01-Mar-03 RMS Aded SET/SHOW CLK FREQ support
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
30-Dec-01 RMS Removed for generalized timers
|
||||
05-Sep-01 RMS Added terminal multiplexor support
|
||||
17-Jul-01 RMS Moved function prototype
|
||||
05-Mar-01 RMS Added clock calibration support
|
||||
|
||||
Note: includes the IOT's for both the PDP-8/E and PDP-8/A clocks
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
int32 clk_tps = 60; /* ticks/second */
|
||||
int32 tmxr_poll = 16000; /* term mux poll */
|
||||
|
||||
int32 clk (int32 IR, int32 AC);
|
||||
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);
|
||||
t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
/* CLK data structures
|
||||
|
||||
clk_dev CLK device descriptor
|
||||
clk_unit CLK unit descriptor
|
||||
clk_reg CLK register list
|
||||
*/
|
||||
|
||||
DIB clk_dib = { DEV_CLK, 1, { &clk } };
|
||||
|
||||
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ FLDATA (DONE, dev_done, INT_V_CLK) },
|
||||
{ FLDATA (ENABLE, int_enable, INT_V_CLK) },
|
||||
{ FLDATA (INT, int_req, INT_V_CLK) },
|
||||
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB clk_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
|
||||
&clk_set_freq, NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
|
||||
&clk_set_freq, NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
|
||||
NULL, &clk_show_freq, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE clk_dev = {
|
||||
"CLK", &clk_unit, clk_reg, clk_mod,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &clk_reset,
|
||||
NULL, NULL, NULL,
|
||||
&clk_dib, 0
|
||||
};
|
||||
|
||||
/* IOT routine
|
||||
|
||||
IOT's 6131-6133 are the PDP-8/E clock
|
||||
IOT's 6135-6137 are the PDP-8/A clock
|
||||
*/
|
||||
|
||||
int32 clk (int32 IR, int32 AC)
|
||||
{
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 1: /* CLEI */
|
||||
int_enable = int_enable | INT_CLK; /* enable clk ints */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
return AC;
|
||||
|
||||
case 2: /* CLDI */
|
||||
int_enable = int_enable & ~INT_CLK; /* disable clk ints */
|
||||
int_req = int_req & ~INT_CLK; /* update interrupts */
|
||||
return AC;
|
||||
|
||||
case 3: /* CLSC */
|
||||
if (dev_done & INT_CLK) { /* flag set? */
|
||||
dev_done = dev_done & ~INT_CLK; /* clear flag */
|
||||
int_req = int_req & ~INT_CLK; /* clear int req */
|
||||
return IOT_SKP + AC;
|
||||
}
|
||||
return AC;
|
||||
|
||||
case 5: /* CLLE */
|
||||
if (AC & 1) int_enable = int_enable | INT_CLK; /* test AC<11> */
|
||||
else int_enable = int_enable & ~INT_CLK;
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
return AC;
|
||||
|
||||
case 6: /* CLCL */
|
||||
dev_done = dev_done & ~INT_CLK; /* clear flag */
|
||||
int_req = int_req & ~INT_CLK; /* clear int req */
|
||||
return AC;
|
||||
|
||||
case 7: /* CLSK */
|
||||
return (dev_done & INT_CLK)? IOT_SKP + AC: AC;
|
||||
|
||||
default:
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat clk_svc (UNIT *uptr)
|
||||
{
|
||||
int32 t;
|
||||
|
||||
dev_done = dev_done | INT_CLK; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
|
||||
sim_activate (&clk_unit, t); /* reactivate unit */
|
||||
tmxr_poll = t; /* set mux poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat clk_reset (DEVICE *dptr)
|
||||
{
|
||||
dev_done = dev_done & ~INT_CLK; /* clear done, int */
|
||||
int_req = int_req & ~INT_CLK;
|
||||
int_enable = int_enable & ~INT_CLK; /* clear enable */
|
||||
sim_activate (&clk_unit, clk_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set frequency */
|
||||
|
||||
t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (cptr) return SCPE_ARG;
|
||||
if ((val != 50) && (val != 60)) return SCPE_IERR;
|
||||
clk_tps = val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show frequency */
|
||||
|
||||
t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
fprintf (st, (clk_tps == 50)? "50Hz": "60Hz");
|
||||
return SCPE_OK;
|
||||
}
|
||||
1534
simhv36-1/PDP8/pdp8_cpu.c
Normal file
1534
simhv36-1/PDP8/pdp8_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
197
simhv36-1/PDP8/pdp8_defs.h
Normal file
197
simhv36-1/PDP8/pdp8_defs.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/* pdp8_defs.h: PDP-8 simulator definitions
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
13-Oct-03 RMS Added TSC8-75 support
|
||||
04-Oct-02 RMS Added variable device number support
|
||||
20-Jan-02 RMS Fixed bug in TTx interrupt enable initialization
|
||||
25-Nov-01 RMS Added RL8A support
|
||||
16-Sep-01 RMS Added multiple KL support
|
||||
18-Mar-01 RMS Added DF32 support
|
||||
15-Feb-01 RMS Added DECtape support
|
||||
14-Apr-99 RMS Changed t_addr to unsigned
|
||||
19-Mar-95 RMS Added dynamic memory size
|
||||
02-May-94 RMS Added non-existent memory handling
|
||||
|
||||
The author gratefully acknowledges the help of Max Burnet, Richie Lary,
|
||||
and Bill Haygood in resolving questions about the PDP-8
|
||||
*/
|
||||
|
||||
#ifndef _PDP8_DEFS_H_
|
||||
#define _PDP8_DEFS_H_ 0
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_RSRV 1 /* must be 1 */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint */
|
||||
#define STOP_NOTSTD 4 /* non-std devno */
|
||||
#define STOP_DTOFF 5 /* DECtape off reel */
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MAXMEMSIZE 32768 /* max memory size */
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
|
||||
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
|
||||
|
||||
/* IOT subroutine return codes */
|
||||
|
||||
#define IOT_V_SKP 12 /* skip */
|
||||
#define IOT_V_REASON 13 /* reason */
|
||||
#define IOT_SKP (1 << IOT_V_SKP)
|
||||
#define IOT_REASON (1 << IOT_V_REASON)
|
||||
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
|
||||
|
||||
/* Timers */
|
||||
|
||||
#define TMR_CLK 0 /* timer 0 = clock */
|
||||
#define TMR_TTX 1 /* timer 1 = TTx */
|
||||
|
||||
/* Device information block */
|
||||
|
||||
#define DEV_MAXBLK 8 /* max dev block */
|
||||
#define DEV_MAX 64 /* total devices */
|
||||
|
||||
typedef struct {
|
||||
uint32 dev; /* base dev number */
|
||||
uint32 num; /* number of slots */
|
||||
int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat);
|
||||
} DIB;
|
||||
|
||||
/* Standard device numbers */
|
||||
|
||||
#define DEV_PTR 001 /* paper tape reader */
|
||||
#define DEV_PTP 002 /* paper tape punch */
|
||||
#define DEV_TTI 003 /* console input */
|
||||
#define DEV_TTO 004 /* console output */
|
||||
#define DEV_CLK 013 /* clock */
|
||||
#define DEV_TSC 036
|
||||
#define DEV_KJ8 040 /* extra terminals */
|
||||
#define DEV_DF 060 /* DF32 */
|
||||
#define DEV_RF 060 /* RF08 */
|
||||
#define DEV_RL 060 /* RL8A */
|
||||
#define DEV_LPT 066 /* line printer */
|
||||
#define DEV_MT 070 /* TM8E */
|
||||
#define DEV_RK 074 /* RK8E */
|
||||
#define DEV_RX 075 /* RX8E/RX28 */
|
||||
#define DEV_DTA 076 /* TC08 */
|
||||
#define DEV_TD8E 077 /* TD8E */
|
||||
|
||||
/* Interrupt flags
|
||||
|
||||
The interrupt flags consist of three groups:
|
||||
|
||||
1. Devices with individual interrupt enables. These record
|
||||
their interrupt requests in device_done and their enables
|
||||
in device_enable, and must occupy the low bit positions.
|
||||
|
||||
2. Devices without interrupt enables. These record their
|
||||
interrupt requests directly in int_req, and must occupy
|
||||
the middle bit positions.
|
||||
|
||||
3. Overhead. These exist only in int_req and must occupy the
|
||||
high bit positions.
|
||||
|
||||
Because the PDP-8 does not have priority interrupts, the order
|
||||
of devices within groups does not matter.
|
||||
|
||||
Note: all extra KL input and output interrupts must be assigned
|
||||
to contiguous bits.
|
||||
*/
|
||||
|
||||
#define INT_V_START 0 /* enable start */
|
||||
#define INT_V_LPT (INT_V_START+0) /* line printer */
|
||||
#define INT_V_PTP (INT_V_START+1) /* tape punch */
|
||||
#define INT_V_PTR (INT_V_START+2) /* tape reader */
|
||||
#define INT_V_TTO (INT_V_START+3) /* terminal */
|
||||
#define INT_V_TTI (INT_V_START+4) /* keyboard */
|
||||
#define INT_V_CLK (INT_V_START+5) /* clock */
|
||||
#define INT_V_TTO1 (INT_V_START+6) /* tto1 */
|
||||
#define INT_V_TTO2 (INT_V_START+7) /* tto2 */
|
||||
#define INT_V_TTO3 (INT_V_START+8) /* tto3 */
|
||||
#define INT_V_TTO4 (INT_V_START+9) /* tto4 */
|
||||
#define INT_V_TTI1 (INT_V_START+10) /* tti1 */
|
||||
#define INT_V_TTI2 (INT_V_START+11) /* tti2 */
|
||||
#define INT_V_TTI3 (INT_V_START+12) /* tti3 */
|
||||
#define INT_V_TTI4 (INT_V_START+13) /* tti4 */
|
||||
#define INT_V_DIRECT (INT_V_START+14) /* direct start */
|
||||
#define INT_V_RX (INT_V_DIRECT+0) /* RX8E */
|
||||
#define INT_V_RK (INT_V_DIRECT+1) /* RK8E */
|
||||
#define INT_V_RF (INT_V_DIRECT+2) /* RF08 */
|
||||
#define INT_V_DF (INT_V_DIRECT+3) /* DF32 */
|
||||
#define INT_V_MT (INT_V_DIRECT+4) /* TM8E */
|
||||
#define INT_V_DTA (INT_V_DIRECT+5) /* TC08 */
|
||||
#define INT_V_RL (INT_V_DIRECT+6) /* RL8A */
|
||||
#define INT_V_PWR (INT_V_DIRECT+7) /* power int */
|
||||
#define INT_V_UF (INT_V_DIRECT+8) /* user int */
|
||||
#define INT_V_TSC (INT_V_DIRECT+9) /* TSC8-75 int */
|
||||
#define INT_V_OVHD (INT_V_DIRECT+10) /* overhead start */
|
||||
#define INT_V_NO_ION_PENDING (INT_V_OVHD+0) /* ion pending */
|
||||
#define INT_V_NO_CIF_PENDING (INT_V_OVHD+1) /* cif pending */
|
||||
#define INT_V_ION (INT_V_OVHD+2) /* interrupts on */
|
||||
|
||||
#define INT_LPT (1 << INT_V_LPT)
|
||||
#define INT_PTP (1 << INT_V_PTP)
|
||||
#define INT_PTR (1 << INT_V_PTR)
|
||||
#define INT_TTO (1 << INT_V_TTO)
|
||||
#define INT_TTI (1 << INT_V_TTI)
|
||||
#define INT_CLK (1 << INT_V_CLK)
|
||||
#define INT_TTO1 (1 << INT_V_TTO1)
|
||||
#define INT_TTO2 (1 << INT_V_TTO2)
|
||||
#define INT_TTO3 (1 << INT_V_TTO3)
|
||||
#define INT_TTO4 (1 << INT_V_TTO4)
|
||||
#define INT_TTI1 (1 << INT_V_TTI1)
|
||||
#define INT_TTI2 (1 << INT_V_TTI2)
|
||||
#define INT_TTI3 (1 << INT_V_TTI3)
|
||||
#define INT_TTI4 (1 << INT_V_TTI4)
|
||||
#define INT_RX (1 << INT_V_RX)
|
||||
#define INT_RK (1 << INT_V_RK)
|
||||
#define INT_RF (1 << INT_V_RF)
|
||||
#define INT_DF (1 << INT_V_DF)
|
||||
#define INT_MT (1 << INT_V_MT)
|
||||
#define INT_DTA (1 << INT_V_DTA)
|
||||
#define INT_RL (1 << INT_V_RL)
|
||||
#define INT_PWR (1 << INT_V_PWR)
|
||||
#define INT_UF (1 << INT_V_UF)
|
||||
#define INT_TSC (1 << INT_V_TSC)
|
||||
#define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING)
|
||||
#define INT_NO_CIF_PENDING (1 << INT_V_NO_CIF_PENDING)
|
||||
#define INT_ION (1 << INT_V_ION)
|
||||
#define INT_DEV_ENABLE ((1 << INT_V_DIRECT) - 1) /* devices w/enables */
|
||||
#define INT_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */
|
||||
#define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \
|
||||
(INT_TTI1+INT_TTI2+INT_TTI3+INT_TTI4) | \
|
||||
(INT_TTO1+INT_TTO2+INT_TTO3+INT_TTO4)
|
||||
#define INT_PENDING (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING)
|
||||
#define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable))
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
#endif
|
||||
373
simhv36-1/PDP8/pdp8_df.c
Normal file
373
simhv36-1/PDP8/pdp8_df.c
Normal file
@@ -0,0 +1,373 @@
|
||||
/* pdp8_df.c: DF32 fixed head disk simulator
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
df DF32 fixed head disk
|
||||
|
||||
15-May-06 RMS Fixed bug in autosize attach (reported by Dave Gesswein)
|
||||
07-Jan-06 RMS Fixed unaligned register access bug (found by Doug Carman)
|
||||
04-Jan-04 RMS Changed sim_fsize calling sequence
|
||||
26-Oct-03 RMS Cleaned up buffer copy code
|
||||
26-Jul-03 RMS Fixed bug in set size routine
|
||||
14-Mar-03 RMS Fixed variable platter interaction with save/restore
|
||||
03-Mar-03 RMS Fixed autosizing
|
||||
02-Feb-03 RMS Added variable platter and autosizing support
|
||||
04-Oct-02 RMS Added DIBs, device number support
|
||||
28-Nov-01 RMS Added RL8A support
|
||||
25-Apr-01 RMS Added device enable/disable support
|
||||
|
||||
The DF32 is a head-per-track disk. It uses the three cycle data break
|
||||
facility. To minimize overhead, the entire DF32 is buffered in memory.
|
||||
|
||||
Two timing parameters are provided:
|
||||
|
||||
df_time Interword timing, must be non-zero
|
||||
df_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
|
||||
DMA occurs in a burst
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
#include <math.h>
|
||||
|
||||
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
|
||||
#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
|
||||
#define UNIT_M_PLAT 03
|
||||
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
|
||||
#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
|
||||
#define UNIT_AUTO (1 << UNIT_V_AUTO)
|
||||
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
|
||||
|
||||
/* Constants */
|
||||
|
||||
#define DF_NUMWD 2048 /* words/track */
|
||||
#define DF_NUMTR 16 /* tracks/disk */
|
||||
#define DF_DKSIZE (DF_NUMTR * DF_NUMWD) /* words/disk */
|
||||
#define DF_NUMDK 4 /* disks/controller */
|
||||
#define DF_WC 07750 /* word count */
|
||||
#define DF_MA 07751 /* mem address */
|
||||
#define DF_WMASK (DF_NUMWD - 1) /* word mask */
|
||||
|
||||
/* Parameters in the unit descriptor */
|
||||
|
||||
#define FUNC u4 /* function */
|
||||
#define DF_READ 2 /* read */
|
||||
#define DF_WRITE 4 /* write */
|
||||
|
||||
/* Status register */
|
||||
|
||||
#define DFS_PCA 04000 /* photocell status */
|
||||
#define DFS_DEX 03700 /* disk addr extension */
|
||||
#define DFS_MEX 00070 /* mem addr extension */
|
||||
#define DFS_DRL 00004 /* data late error */
|
||||
#define DFS_WLS 00002 /* write lock error */
|
||||
#define DFS_NXD 00002 /* non-existent disk */
|
||||
#define DFS_PER 00001 /* parity error */
|
||||
#define DFS_ERR (DFS_DRL | DFS_WLS | DFS_PER)
|
||||
#define DFS_V_DEX 6
|
||||
#define DFS_V_MEX 3
|
||||
|
||||
#define GET_MEX(x) (((x) & DFS_MEX) << (12 - DFS_V_MEX))
|
||||
#define GET_DEX(x) (((x) & DFS_DEX) << (12 - DFS_V_DEX))
|
||||
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
|
||||
((double) DF_NUMWD)))
|
||||
#define UPDATE_PCELL if (GET_POS (df_time) < 6) df_sta = df_sta | DFS_PCA; \
|
||||
else df_sta = df_sta & ~DFS_PCA
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, stop_inst;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 df_sta = 0; /* status register */
|
||||
int32 df_da = 0; /* disk address */
|
||||
int32 df_done = 0; /* done flag */
|
||||
int32 df_wlk = 0; /* write lock */
|
||||
int32 df_time = 10; /* inter-word time */
|
||||
int32 df_burst = 1; /* burst mode flag */
|
||||
int32 df_stopioe = 1; /* stop on error */
|
||||
|
||||
DEVICE df_dev;
|
||||
int32 df60 (int32 IR, int32 AC);
|
||||
int32 df61 (int32 IR, int32 AC);
|
||||
int32 df62 (int32 IR, int32 AC);
|
||||
t_stat df_svc (UNIT *uptr);
|
||||
t_stat pcell_svc (UNIT *uptr);
|
||||
t_stat df_reset (DEVICE *dptr);
|
||||
t_stat df_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat df_attach (UNIT *uptr, char *cptr);
|
||||
t_stat df_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
|
||||
/* DF32 data structures
|
||||
|
||||
df_dev RF device descriptor
|
||||
df_unit RF unit descriptor
|
||||
pcell_unit photocell timing unit (orphan)
|
||||
df_reg RF register list
|
||||
*/
|
||||
|
||||
DIB df_dib = { DEV_DF, 3, { &df60, &df61, &df62 } };
|
||||
|
||||
UNIT df_unit = {
|
||||
UDATA (&df_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
|
||||
DF_DKSIZE)
|
||||
};
|
||||
|
||||
REG df_reg[] = {
|
||||
{ ORDATA (STA, df_sta, 12) },
|
||||
{ ORDATA (DA, df_da, 12) },
|
||||
{ ORDATA (WC, M[DF_WC], 12), REG_FIT },
|
||||
{ ORDATA (MA, M[DF_MA], 12), REG_FIT },
|
||||
{ FLDATA (DONE, df_done, 0) },
|
||||
{ FLDATA (INT, int_req, INT_V_DF) },
|
||||
{ ORDATA (WLS, df_wlk, 8) },
|
||||
{ DRDATA (TIME, df_time, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (BURST, df_burst, 0) },
|
||||
{ FLDATA (STOP_IOE, df_stopioe, 0) },
|
||||
{ DRDATA (CAPAC, df_unit.capac, 18), REG_HRO },
|
||||
{ ORDATA (DEVNUM, df_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB df_mod[] = {
|
||||
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &df_set_size },
|
||||
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &df_set_size },
|
||||
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &df_set_size },
|
||||
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &df_set_size },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE df_dev = {
|
||||
"DF", &df_unit, df_reg, df_mod,
|
||||
1, 8, 17, 1, 8, 12,
|
||||
NULL, NULL, &df_reset,
|
||||
&df_boot, &df_attach, NULL,
|
||||
&df_dib, DEV_DISABLE
|
||||
};
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 df60 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 t;
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) { /* DCMA */
|
||||
df_da = 0; /* clear disk addr */
|
||||
df_done = 0; /* clear done */
|
||||
df_sta = df_sta & ~DFS_ERR; /* clear errors */
|
||||
int_req = int_req & ~INT_DF; /* clear int req */
|
||||
}
|
||||
if (pulse & 6) { /* DMAR, DMAW */
|
||||
df_da = df_da | AC; /* disk addr |= AC */
|
||||
df_unit.FUNC = pulse & ~1; /* save function */
|
||||
t = (df_da & DF_WMASK) - GET_POS (df_time); /* delta to new loc */
|
||||
if (t < 0) t = t + DF_NUMWD; /* wrap around? */
|
||||
sim_activate (&df_unit, t * df_time); /* schedule op */
|
||||
AC = 0; /* clear AC */
|
||||
}
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Based on the hardware implementation. DEAL and DEAC work as follows:
|
||||
|
||||
6615 pulse 1 = clear df_sta<dex,mex>
|
||||
pulse 4 = df_sta = df_sta | AC<dex,mex>
|
||||
AC = AC | old_df_sta
|
||||
6616 pulse 2 = clear AC, skip if address confirmed
|
||||
pulse 4 = df_sta = df_sta | AC<dex,mex> = 0 (nop)
|
||||
AC = AC | old_df_sta
|
||||
*/
|
||||
|
||||
int32 df61 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 old_df_sta = df_sta;
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) /* DCEA */
|
||||
df_sta = df_sta & ~(DFS_DEX | DFS_MEX); /* clear dex, mex */
|
||||
if (pulse & 2) /* DSAC */
|
||||
AC = ((df_da & DF_WMASK) == GET_POS (df_time))? IOT_SKP: 0;
|
||||
if (pulse & 4) {
|
||||
df_sta = df_sta | (AC & (DFS_DEX | DFS_MEX)); /* DEAL */
|
||||
AC = AC | old_df_sta; /* DEAC */
|
||||
}
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 df62 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) { /* DFSE */
|
||||
if ((df_sta & DFS_ERR) == 0) AC = AC | IOT_SKP;
|
||||
}
|
||||
if (pulse & 2) { /* DFSC */
|
||||
if (pulse & 4) AC = AC & ~07777; /* for DMAC */
|
||||
else if (df_done) AC = AC | IOT_SKP;
|
||||
}
|
||||
if (pulse & 4) AC = AC | df_da; /* DMAC */
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
|
||||
Note that for reads and writes, memory addresses wrap around in the
|
||||
current field. This code assumes the entire disk is buffered.
|
||||
*/
|
||||
|
||||
t_stat df_svc (UNIT *uptr)
|
||||
{
|
||||
int32 pa, t, mex;
|
||||
uint32 da;
|
||||
int16 *fbuf = uptr->filebuf;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
|
||||
df_done = 1;
|
||||
int_req = int_req | INT_DF; /* update int req */
|
||||
return IORETURN (df_stopioe, SCPE_UNATT);
|
||||
}
|
||||
|
||||
mex = GET_MEX (df_sta);
|
||||
da = GET_DEX (df_sta) | df_da; /* form disk addr */
|
||||
do {
|
||||
if (da >= uptr->capac) { /* nx disk addr? */
|
||||
df_sta = df_sta | DFS_NXD;
|
||||
break;
|
||||
}
|
||||
M[DF_WC] = (M[DF_WC] + 1) & 07777; /* incr word count */
|
||||
M[DF_MA] = (M[DF_MA] + 1) & 07777; /* incr mem addr */
|
||||
pa = mex | M[DF_MA]; /* add extension */
|
||||
if (uptr->FUNC == DF_READ) { /* read? */
|
||||
if (MEM_ADDR_OK (pa)) M[pa] = fbuf[da]; /* if !nxm, read wd */
|
||||
}
|
||||
else { /* write */
|
||||
t = (da >> 14) & 07; /* check wr lock */
|
||||
if ((df_wlk >> t) & 1) /* locked? set err */
|
||||
df_sta = df_sta | DFS_WLS;
|
||||
else { /* not locked */
|
||||
fbuf[da] = M[pa]; /* write word */
|
||||
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
|
||||
}
|
||||
}
|
||||
da = (da + 1) & 0377777; /* incr disk addr */
|
||||
} while ((M[DF_WC] != 0) && (df_burst != 0)); /* brk if wc, no brst */
|
||||
|
||||
if ((M[DF_WC] != 0) && ((df_sta & DFS_ERR) == 0)) /* more to do? */
|
||||
sim_activate (&df_unit, df_time); /* sched next */
|
||||
else {
|
||||
if (uptr->FUNC != DF_READ) da = (da - 1) & 0377777;
|
||||
df_done = 1; /* done */
|
||||
int_req = int_req | INT_DF; /* update int req */
|
||||
}
|
||||
df_sta = (df_sta & ~DFS_DEX) | ((da >> (12 - DFS_V_DEX)) & DFS_DEX);
|
||||
df_da = da & 07777; /* separate disk addr */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat df_reset (DEVICE *dptr)
|
||||
{
|
||||
df_sta = df_da = 0;
|
||||
df_done = 1;
|
||||
int_req = int_req & ~INT_DF; /* clear interrupt */
|
||||
sim_cancel (&df_unit);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define OS8_START 07750
|
||||
#define OS8_LEN (sizeof (os8_rom) / sizeof (int16))
|
||||
#define DM4_START 00200
|
||||
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16))
|
||||
|
||||
static const uint16 os8_rom[] = {
|
||||
07600, /* 7750, CLA CLL ; also word count */
|
||||
06603, /* 7751, DMAR ; also address */
|
||||
06622, /* 7752, DFSC ; done? */
|
||||
05352, /* 7753, JMP .-1 ; no */
|
||||
05752 /* 7754, JMP @.-2 ; enter boot */
|
||||
};
|
||||
|
||||
static const uint16 dm4_rom[] = {
|
||||
00200, 07600, /* 0200, CLA CLL */
|
||||
00201, 06603, /* 0201, DMAR ; read */
|
||||
00202, 06622, /* 0202, DFSC ; done? */
|
||||
00203, 05202, /* 0203, JMP .-1 ; no */
|
||||
00204, 05600, /* 0204, JMP @.-4 ; enter boot */
|
||||
07750, 07576, /* 7750, 7576 ; word count */
|
||||
07751, 07576 /* 7751, 7576 ; address */
|
||||
};
|
||||
|
||||
t_stat df_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 sim_switches, saved_PC;
|
||||
|
||||
if (sim_switches & SWMASK ('D')) {
|
||||
for (i = 0; i < DM4_LEN; i = i + 2)
|
||||
M[dm4_rom[i]] = dm4_rom[i + 1];
|
||||
saved_PC = DM4_START;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < OS8_LEN; i++)
|
||||
M[OS8_START + i] = os8_rom[i];
|
||||
saved_PC = OS8_START;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat df_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 p, sz;
|
||||
uint32 ds_bytes = DF_DKSIZE * sizeof (int16);
|
||||
|
||||
if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
|
||||
p = (sz + ds_bytes - 1) / ds_bytes;
|
||||
if (p >= DF_NUMDK) p = DF_NUMDK - 1;
|
||||
uptr->flags = (uptr->flags & ~UNIT_PLAT) |
|
||||
(p << UNIT_V_PLAT);
|
||||
}
|
||||
uptr->capac = UNIT_GETP (uptr->flags) * DF_DKSIZE;
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
|
||||
/* Change disk size */
|
||||
|
||||
t_stat df_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_GETP (val) * DF_DKSIZE;
|
||||
uptr->flags = uptr->flags & ~UNIT_AUTO;
|
||||
return SCPE_OK;
|
||||
}
|
||||
1292
simhv36-1/PDP8/pdp8_dt.c
Normal file
1292
simhv36-1/PDP8/pdp8_dt.c
Normal file
File diff suppressed because it is too large
Load Diff
181
simhv36-1/PDP8/pdp8_lp.c
Normal file
181
simhv36-1/PDP8/pdp8_lp.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/* pdp8_lp.c: PDP-8 line printer simulator
|
||||
|
||||
Copyright (c) 1993-2005, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
lpt LP8E line printer
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
04-Oct-02 RMS Added DIB, enable/disable, device number support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
int32 lpt_err = 0; /* error flag */
|
||||
int32 lpt_stopioe = 0; /* stop on error */
|
||||
|
||||
DEVICE lpt_dev;
|
||||
int32 lpt (int32 IR, int32 AC);
|
||||
t_stat lpt_svc (UNIT *uptr);
|
||||
t_stat lpt_reset (DEVICE *dptr);
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr);
|
||||
t_stat lpt_detach (UNIT *uptr);
|
||||
|
||||
/* LPT data structures
|
||||
|
||||
lpt_dev LPT device descriptor
|
||||
lpt_unit LPT unit descriptor
|
||||
lpt_reg LPT register list
|
||||
*/
|
||||
|
||||
DIB lpt_dib = { DEV_LPT, 1, { &lpt } };
|
||||
|
||||
UNIT lpt_unit = {
|
||||
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
|
||||
};
|
||||
|
||||
REG lpt_reg[] = {
|
||||
{ ORDATA (BUF, lpt_unit.buf, 8) },
|
||||
{ FLDATA (ERR, lpt_err, 0) },
|
||||
{ FLDATA (DONE, dev_done, INT_V_LPT) },
|
||||
{ FLDATA (ENABLE, int_enable, INT_V_LPT) },
|
||||
{ FLDATA (INT, int_req, INT_V_LPT) },
|
||||
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
|
||||
{ ORDATA (DEVNUM, lpt_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB lpt_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE lpt_dev = {
|
||||
"LPT", &lpt_unit, lpt_reg, lpt_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &lpt_reset,
|
||||
NULL, &lpt_attach, &lpt_detach,
|
||||
&lpt_dib, DEV_DISABLE
|
||||
};
|
||||
|
||||
/* IOT routine */
|
||||
|
||||
int32 lpt (int32 IR, int32 AC)
|
||||
{
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 1: /* PSKF */
|
||||
return (dev_done & INT_LPT)? IOT_SKP + AC: AC;
|
||||
|
||||
case 2: /* PCLF */
|
||||
dev_done = dev_done & ~INT_LPT; /* clear flag */
|
||||
int_req = int_req & ~INT_LPT; /* clear int req */
|
||||
return AC;
|
||||
|
||||
case 3: /* PSKE */
|
||||
return (lpt_err)? IOT_SKP + AC: AC;
|
||||
|
||||
case 6: /* PCLF!PSTB */
|
||||
dev_done = dev_done & ~INT_LPT; /* clear flag */
|
||||
int_req = int_req & ~INT_LPT; /* clear int req */
|
||||
|
||||
case 4: /* PSTB */
|
||||
lpt_unit.buf = AC & 0177; /* load buffer */
|
||||
if ((lpt_unit.buf == 015) || (lpt_unit.buf == 014) ||
|
||||
(lpt_unit.buf == 012)) {
|
||||
sim_activate (&lpt_unit, lpt_unit.wait);
|
||||
return AC;
|
||||
}
|
||||
return (lpt_svc (&lpt_unit) << IOT_V_REASON) + AC;
|
||||
|
||||
case 5: /* PSIE */
|
||||
int_enable = int_enable | INT_LPT; /* set enable */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
return AC;
|
||||
|
||||
case 7: /* PCIE */
|
||||
int_enable = int_enable & ~INT_LPT; /* clear enable */
|
||||
int_req = int_req & ~INT_LPT; /* clear int req */
|
||||
return AC;
|
||||
|
||||
default:
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat lpt_svc (UNIT *uptr)
|
||||
{
|
||||
dev_done = dev_done | INT_LPT; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
if ((lpt_unit.flags & UNIT_ATT) == 0) {
|
||||
lpt_err = 1;
|
||||
return IORETURN (lpt_stopioe, SCPE_UNATT);
|
||||
}
|
||||
if (putc (lpt_unit.buf, lpt_unit.fileref) == EOF) {
|
||||
perror ("LPT I/O error");
|
||||
clearerr (lpt_unit.fileref);
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
lpt_unit.pos = lpt_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat lpt_reset (DEVICE *dptr)
|
||||
{
|
||||
lpt_unit.buf = 0;
|
||||
dev_done = dev_done & ~INT_LPT; /* clear done, int */
|
||||
int_req = int_req & ~INT_LPT;
|
||||
int_enable = int_enable | INT_LPT; /* set enable */
|
||||
lpt_err = (lpt_unit.flags & UNIT_ATT) == 0;
|
||||
sim_cancel (&lpt_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat reason;
|
||||
|
||||
reason = attach_unit (uptr, cptr);
|
||||
lpt_err = (lpt_unit.flags & UNIT_ATT) == 0;
|
||||
return reason;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
|
||||
t_stat lpt_detach (UNIT *uptr)
|
||||
{
|
||||
lpt_err = 1;
|
||||
return detach_unit (uptr);
|
||||
}
|
||||
644
simhv36-1/PDP8/pdp8_mt.c
Normal file
644
simhv36-1/PDP8/pdp8_mt.c
Normal file
@@ -0,0 +1,644 @@
|
||||
/* pdp8_mt.c: PDP-8 magnetic tape simulator
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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 TM8E/TU10 magtape
|
||||
|
||||
16-Feb-06 RMS Added tape capacity checking
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
18-Mar-05 RMS Added attached test to detach routine
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
29-Mar-03 RMS Added multiformat support
|
||||
04-Mar-03 RMS Fixed bug in SKTR
|
||||
01-Mar-03 RMS Fixed interrupt handling
|
||||
Revised for magtape library
|
||||
30-Oct-02 RMS Revised BOT handling, added error record handling
|
||||
04-Oct-02 RMS Added DIBs, device number support
|
||||
30-Aug-02 RMS Revamped error handling
|
||||
28-Aug-02 RMS Added end of medium support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
22-Apr-02 RMS Added maximum record length test
|
||||
06-Jan-02 RMS Changed enable/disable support
|
||||
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
|
||||
24-Nov-01 RMS Changed UST, POS, FLG to arrays
|
||||
25-Apr-01 RMS Added device enable/disable support
|
||||
04-Oct-98 RMS V2.4 magtape format
|
||||
22-Jan-97 RMS V2.3 magtape format
|
||||
01-Jan-96 RMS Rewritten from TM8-E Maintenance Manual
|
||||
|
||||
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 "pdp8_defs.h"
|
||||
#include "sim_tape.h"
|
||||
|
||||
#define MT_NUMDR 8 /* #drives */
|
||||
#define USTAT u3 /* unit status */
|
||||
#define MT_MAXFR (1 << 16) /* max record lnt */
|
||||
#define WC_SIZE (1 << 12) /* max word count */
|
||||
#define WC_MASK (WC_SIZE - 1)
|
||||
|
||||
/* Command/unit - mt_cu */
|
||||
|
||||
#define CU_V_UNIT 9 /* unit */
|
||||
#define CU_M_UNIT 07
|
||||
#define CU_PARITY 00400 /* parity select */
|
||||
#define CU_IEE 00200 /* error int enable */
|
||||
#define CU_IED 00100 /* done int enable */
|
||||
#define CU_V_EMA 3 /* ext mem address */
|
||||
#define CU_M_EMA 07
|
||||
#define CU_EMA (CU_M_EMA << CU_V_EMA)
|
||||
#define CU_DTY 00002 /* drive type */
|
||||
#define CU_UNPAK 00001 /* 6b vs 8b mode */
|
||||
#define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT)
|
||||
#define GET_EMA(x) (((x) & CU_EMA) << (12 - CU_V_EMA))
|
||||
|
||||
/* Function - mt_fn */
|
||||
|
||||
#define FN_V_FNC 9 /* function */
|
||||
#define FN_M_FNC 07
|
||||
#define FN_UNLOAD 00
|
||||
#define FN_REWIND 01
|
||||
#define FN_READ 02
|
||||
#define FN_CMPARE 03
|
||||
#define FN_WRITE 04
|
||||
#define FN_WREOF 05
|
||||
#define FN_SPACEF 06
|
||||
#define FN_SPACER 07
|
||||
#define FN_ERASE 00400 /* erase */
|
||||
#define FN_CRC 00200 /* read CRC */
|
||||
#define FN_GO 00100 /* go */
|
||||
#define FN_INC 00040 /* incr mode */
|
||||
#define FN_RMASK 07700 /* readable bits */
|
||||
#define GET_FNC(x) (((x) >> FN_V_FNC) & FN_M_FNC)
|
||||
|
||||
/* Status - stored in mt_sta or (*) uptr->USTAT */
|
||||
|
||||
#define STA_ERR (04000 << 12) /* error */
|
||||
#define STA_REW (02000 << 12) /* *rewinding */
|
||||
#define STA_BOT (01000 << 12) /* *start of tape */
|
||||
#define STA_REM (00400 << 12) /* *offline */
|
||||
#define STA_PAR (00200 << 12) /* parity error */
|
||||
#define STA_EOF (00100 << 12) /* *end of file */
|
||||
#define STA_RLE (00040 << 12) /* rec lnt error */
|
||||
#define STA_DLT (00020 << 12) /* data late */
|
||||
#define STA_EOT (00010 << 12) /* *end of tape */
|
||||
#define STA_WLK (00004 << 12) /* *write locked */
|
||||
#define STA_CPE (00002 << 12) /* compare error */
|
||||
#define STA_ILL (00001 << 12) /* illegal */
|
||||
#define STA_9TK 00040 /* 9 track */
|
||||
/* #define STA_BAD 00020 /* bad tape?? */
|
||||
#define STA_INC 00010 /* increment error */
|
||||
#define STA_LAT 00004 /* lateral par error */
|
||||
#define STA_CRC 00002 /* CRC error */
|
||||
#define STA_LON 00001 /* long par error */
|
||||
|
||||
#define STA_CLR (FN_RMASK | 00020) /* always clear */
|
||||
#define STA_DYN (STA_REW | STA_BOT | STA_REM | STA_EOF | \
|
||||
STA_EOT | STA_WLK) /* kept in USTAT */
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, stop_inst;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 mt_cu = 0; /* command/unit */
|
||||
int32 mt_fn = 0; /* function */
|
||||
int32 mt_ca = 0; /* current address */
|
||||
int32 mt_wc = 0; /* word count */
|
||||
int32 mt_sta = 0; /* status register */
|
||||
int32 mt_db = 0; /* data buffer */
|
||||
int32 mt_done = 0; /* mag tape flag */
|
||||
int32 mt_time = 10; /* record latency */
|
||||
int32 mt_stopioe = 1; /* stop on error */
|
||||
uint8 *mtxb = NULL; /* transfer buffer */
|
||||
|
||||
DEVICE mt_dev;
|
||||
int32 mt70 (int32 IR, int32 AC);
|
||||
int32 mt71 (int32 IR, int32 AC);
|
||||
int32 mt72 (int32 IR, int32 AC);
|
||||
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);
|
||||
int32 mt_updcsta (UNIT *uptr);
|
||||
int32 mt_ixma (int32 xma);
|
||||
t_stat mt_map_err (UNIT *uptr, t_stat st);
|
||||
t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
UNIT *mt_busy (void);
|
||||
void mt_set_done (void);
|
||||
|
||||
/* 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 = { DEV_MT, 3, { &mt70, &mt71, &mt72 } };
|
||||
|
||||
UNIT mt_unit[] = {
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }
|
||||
};
|
||||
|
||||
REG mt_reg[] = {
|
||||
{ ORDATA (CMD, mt_cu, 12) },
|
||||
{ ORDATA (FNC, mt_fn, 12) },
|
||||
{ ORDATA (CA, mt_ca, 12) },
|
||||
{ ORDATA (WC, mt_wc, 12) },
|
||||
{ ORDATA (DB, mt_db, 12) },
|
||||
{ GRDATA (STA, mt_sta, 8, 12, 12) },
|
||||
{ ORDATA (STA2, mt_sta, 6) },
|
||||
{ FLDATA (DONE, mt_done, 0) },
|
||||
{ FLDATA (INT, int_req, INT_V_MT) },
|
||||
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
|
||||
{ DRDATA (TIME, mt_time, 24), PV_LEFT },
|
||||
{ URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) },
|
||||
{ URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0,
|
||||
MT_NUMDR, PV_LEFT | REG_RO) },
|
||||
{ FLDATA (DEVNUM, mt_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB mt_mod[] = {
|
||||
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", &mt_vlock },
|
||||
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &mt_vlock },
|
||||
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
|
||||
{ MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",
|
||||
&sim_tape_set_capac, &sim_tape_show_capac, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, 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
|
||||
};
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 mt70 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 f;
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 1: /* LWCR */
|
||||
mt_wc = AC; /* load word count */
|
||||
return 0;
|
||||
|
||||
case 2: /* CWCR */
|
||||
mt_wc = 0; /* clear word count */
|
||||
return AC;
|
||||
|
||||
case 3: /* LCAR */
|
||||
mt_ca = AC; /* load mem address */
|
||||
return 0;
|
||||
|
||||
case 4: /* CCAR */
|
||||
mt_ca = 0; /* clear mem address */
|
||||
return AC;
|
||||
|
||||
case 5: /* LCMR */
|
||||
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
|
||||
mt_cu = AC; /* load command reg */
|
||||
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu));
|
||||
return 0;
|
||||
|
||||
case 6: /* LFGR */
|
||||
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
|
||||
mt_fn = AC; /* load function */
|
||||
if ((mt_fn & FN_GO) == 0) { /* go set? */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return 0;
|
||||
}
|
||||
f = GET_FNC (mt_fn); /* get function */
|
||||
if (((uptr->flags & UNIT_ATT) == 0) ||
|
||||
sim_is_active (uptr) ||
|
||||
(((f == FN_WRITE) || (f == FN_WREOF)) && sim_tape_wrp (uptr))
|
||||
|| (((f == FN_SPACER) || (f == FN_REWIND)) && sim_tape_bot (uptr))) {
|
||||
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal op error */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return 0;
|
||||
}
|
||||
uptr->USTAT = uptr->USTAT & STA_WLK; /* clear status */
|
||||
if (f == FN_UNLOAD) { /* unload? */
|
||||
detach_unit (uptr); /* set offline */
|
||||
uptr->USTAT = STA_REW | STA_REM; /* rewinding, off */
|
||||
mt_set_done (); /* set done */
|
||||
}
|
||||
else if (f == FN_REWIND) { /* rewind */
|
||||
uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */
|
||||
mt_set_done (); /* set done */
|
||||
}
|
||||
else mt_done = 0; /* clear done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
sim_activate (uptr, mt_time); /* start io */
|
||||
return 0;
|
||||
|
||||
case 7: /* LDBR */
|
||||
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
|
||||
mt_db = AC; /* load buffer */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return 0;
|
||||
} /* end switch */
|
||||
|
||||
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
}
|
||||
|
||||
int32 mt71 (int32 IR, int32 AC)
|
||||
{
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = mt_dev.units + GET_UNIT (mt_cu);
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 1: /* RWCR */
|
||||
return mt_wc; /* read word count */
|
||||
|
||||
case 2: /* CLT */
|
||||
mt_reset (&mt_dev); /* reset everything */
|
||||
return AC;
|
||||
|
||||
case 3: /* RCAR */
|
||||
return mt_ca; /* read mem address */
|
||||
|
||||
case 4: /* RMSR */
|
||||
return ((mt_updcsta (uptr) >> 12) & 07777); /* read status */
|
||||
|
||||
case 5: /* RCMR */
|
||||
return mt_cu; /* read command */
|
||||
|
||||
case 6: /* RFSR */
|
||||
return (((mt_fn & FN_RMASK) | (mt_updcsta (uptr) & ~FN_RMASK))
|
||||
& 07777); /* read function */
|
||||
|
||||
case 7: /* RDBR */
|
||||
return mt_db; /* read data buffer */
|
||||
}
|
||||
|
||||
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
}
|
||||
|
||||
int32 mt72 (int32 IR, int32 AC)
|
||||
{
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 1: /* SKEF */
|
||||
return (mt_sta & STA_ERR)? IOT_SKP + AC: AC;
|
||||
|
||||
case 2: /* SKCB */
|
||||
return (!mt_busy ())? IOT_SKP + AC: AC;
|
||||
|
||||
case 3: /* SKJD */
|
||||
return mt_done? IOT_SKP + AC: AC;
|
||||
|
||||
case 4: /* SKTR */
|
||||
return (!sim_is_active (uptr) &&
|
||||
(uptr->flags & UNIT_ATT))? IOT_SKP + AC: AC;
|
||||
|
||||
case 5: /* CLF */
|
||||
if (!sim_is_active (uptr)) mt_reset (&mt_dev); /* if TUR, zap */
|
||||
else { /* just ctrl zap */
|
||||
mt_sta = 0; /* clear status */
|
||||
mt_done = 0; /* clear done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
}
|
||||
return AC;
|
||||
} /* end switch */
|
||||
|
||||
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
|
||||
If rewind done, reposition to start of tape, set status
|
||||
else, do operation, set done, interrupt
|
||||
*/
|
||||
|
||||
t_stat mt_svc (UNIT *uptr)
|
||||
{
|
||||
int32 f, i, p, u, wc, xma;
|
||||
t_mtrlnt tbc, cbc;
|
||||
t_bool passed_eot;
|
||||
uint16 c, c1, c2;
|
||||
t_stat st, r = SCPE_OK;
|
||||
|
||||
u = (int32) (uptr - mt_dev.units); /* get unit number */
|
||||
f = GET_FNC (mt_fn); /* get command */
|
||||
xma = GET_EMA (mt_cu) + mt_ca; /* get mem addr */
|
||||
wc = WC_SIZE - mt_wc; /* get wc */
|
||||
|
||||
if (uptr->USTAT & STA_REW) { /* rewind? */
|
||||
sim_tape_rewind (uptr); /* update position */
|
||||
if (uptr->flags & UNIT_ATT) /* still on line? */
|
||||
uptr->USTAT = (uptr->USTAT & STA_WLK) | STA_BOT;
|
||||
else uptr->USTAT = STA_REM;
|
||||
if (u == GET_UNIT (mt_cu)) { /* selected? */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */
|
||||
uptr->USTAT = STA_REM; /* unit off line */
|
||||
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal operation */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return IORETURN (mt_stopioe, SCPE_UNATT);
|
||||
}
|
||||
|
||||
passed_eot = sim_tape_eot (uptr); /* passed eot? */
|
||||
switch (f) { /* case on function */
|
||||
|
||||
case FN_READ: /* read */
|
||||
case FN_CMPARE: /* read/compare */
|
||||
st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */
|
||||
if (st == MTSE_RECE) mt_sta = mt_sta | STA_PAR | STA_ERR; /* rec in err? */
|
||||
else if (st != MTSE_OK) { /* other error? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
mt_sta = mt_sta | STA_RLE | STA_ERR; /* err, eof/eom, tmk */
|
||||
break;
|
||||
}
|
||||
cbc = (mt_cu & CU_UNPAK)? wc: wc * 2; /* expected bc */
|
||||
if (tbc != cbc) mt_sta = mt_sta | STA_RLE | STA_ERR; /* wrong size? */
|
||||
if (tbc < cbc) { /* record small? */
|
||||
cbc = tbc; /* use smaller */
|
||||
wc = (mt_cu & CU_UNPAK)? cbc: (cbc + 1) / 2;
|
||||
}
|
||||
for (i = p = 0; i < wc; i++) { /* copy buffer */
|
||||
xma = mt_ixma (xma); /* increment xma */
|
||||
mt_wc = (mt_wc + 1) & 07777; /* incr word cnt */
|
||||
if (mt_cu & CU_UNPAK) c = mtxb[p++];
|
||||
else {
|
||||
c1 = mtxb[p++] & 077;
|
||||
c2 = mtxb[p++] & 077;
|
||||
c = (c1 << 6) | c2;
|
||||
}
|
||||
if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
|
||||
else if ((f == FN_CMPARE) && (M[xma] != c)) {
|
||||
mt_sta = mt_sta | STA_CPE | STA_ERR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FN_WRITE: /* write */
|
||||
tbc = (mt_cu & CU_UNPAK)? wc: wc * 2;
|
||||
for (i = p = 0; i < wc; i++) { /* copy buf to tape */
|
||||
xma = mt_ixma (xma); /* incr mem addr */
|
||||
if (mt_cu & CU_UNPAK) mtxb[p++] = M[xma] & 0377;
|
||||
else {
|
||||
mtxb[p++] = (M[xma] >> 6) & 077;
|
||||
mtxb[p++] = M[xma] & 077;
|
||||
}
|
||||
}
|
||||
if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
xma = GET_EMA (mt_cu) + mt_ca; /* restore xma */
|
||||
}
|
||||
else mt_wc = 0; /* ok, clear wc */
|
||||
break;
|
||||
|
||||
case FN_WREOF:
|
||||
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
break;
|
||||
|
||||
case FN_SPACEF: /* space forward */
|
||||
do {
|
||||
mt_wc = (mt_wc + 1) & 07777; /* incr wc */
|
||||
if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
break; /* stop */
|
||||
}
|
||||
} while ((mt_wc != 0) && (passed_eot || !sim_tape_eot (uptr)));
|
||||
break;
|
||||
|
||||
case FN_SPACER: /* space reverse */
|
||||
do {
|
||||
mt_wc = (mt_wc + 1) & 07777; /* incr wc */
|
||||
if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
break; /* stop */
|
||||
}
|
||||
} while (mt_wc != 0);
|
||||
break;
|
||||
} /* end case */
|
||||
|
||||
if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */
|
||||
uptr->USTAT = uptr->USTAT | STA_EOT;
|
||||
mt_cu = (mt_cu & ~CU_EMA) | ((xma >> (12 - CU_V_EMA)) & CU_EMA);
|
||||
mt_ca = xma & 07777; /* update mem addr */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Update controller status */
|
||||
|
||||
int32 mt_updcsta (UNIT *uptr)
|
||||
{
|
||||
mt_sta = (mt_sta & ~(STA_DYN | STA_CLR)) | (uptr->USTAT & STA_DYN);
|
||||
if (((mt_sta & STA_ERR) && (mt_cu & CU_IEE)) ||
|
||||
(mt_done && (mt_cu & CU_IED))) int_req = int_req | INT_MT;
|
||||
else int_req = int_req & ~INT_MT;
|
||||
return mt_sta;
|
||||
}
|
||||
|
||||
/* Test if controller busy */
|
||||
|
||||
UNIT *mt_busy (void)
|
||||
{
|
||||
int32 u;
|
||||
UNIT *uptr;
|
||||
|
||||
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
|
||||
uptr = mt_dev.units + u;
|
||||
if (sim_is_active (uptr) && ((uptr->USTAT & STA_REW) == 0))
|
||||
return uptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Increment extended memory address */
|
||||
|
||||
int32 mt_ixma (int32 xma) /* incr extended ma */
|
||||
{
|
||||
int32 v;
|
||||
|
||||
v = ((xma + 1) & 07777) | (xma & 070000); /* wrapped incr */
|
||||
if (mt_fn & FN_INC) { /* increment mode? */
|
||||
if (xma == 077777) mt_sta = mt_sta | STA_INC | STA_ERR; /* at limit? error */
|
||||
else v = xma + 1; /* else 15b incr */
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Set done */
|
||||
|
||||
void mt_set_done (void)
|
||||
{
|
||||
mt_done = 1; /* set done */
|
||||
mt_fn = mt_fn & ~(FN_CRC | FN_GO | FN_INC); /* clear func<4:6> */
|
||||
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_sta = mt_sta | STA_ILL | STA_ERR;
|
||||
case MTSE_OK: /* no error */
|
||||
return SCPE_IERR; /* never get here! */
|
||||
|
||||
case MTSE_TMK: /* end of file */
|
||||
uptr->USTAT = uptr->USTAT | STA_EOF; /* set EOF */
|
||||
mt_sta = mt_sta | STA_ERR;
|
||||
break;
|
||||
|
||||
case MTSE_IOERR: /* IO error */
|
||||
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
|
||||
if (mt_stopioe) return SCPE_IOERR;
|
||||
break;
|
||||
|
||||
case MTSE_INVRL: /* invalid rec lnt */
|
||||
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
|
||||
return SCPE_MTRLNT;
|
||||
|
||||
case MTSE_RECE: /* record in error */
|
||||
case MTSE_EOM: /* end of medium */
|
||||
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
|
||||
break;
|
||||
|
||||
case MTSE_BOT: /* reverse into BOT */
|
||||
uptr->USTAT = uptr->USTAT | STA_BOT; /* set status */
|
||||
mt_sta = mt_sta | STA_ERR;
|
||||
break;
|
||||
|
||||
case MTSE_WRP: /* write protect */
|
||||
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal operation */
|
||||
break;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat mt_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 u;
|
||||
UNIT *uptr;
|
||||
|
||||
mt_cu = mt_fn = mt_wc = mt_ca = mt_db = mt_sta = mt_done = 0;
|
||||
int_req = int_req & ~INT_MT; /* clear interrupt */
|
||||
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
|
||||
uptr = mt_dev.units + u;
|
||||
sim_cancel (uptr); /* cancel activity */
|
||||
sim_tape_reset (uptr); /* reset tape */
|
||||
if (uptr->flags & UNIT_ATT) uptr->USTAT =
|
||||
(sim_tape_bot (uptr)? STA_BOT: 0) |
|
||||
(sim_tape_wrp (uptr)? STA_WLK: 0);
|
||||
else uptr->USTAT = STA_REM;
|
||||
}
|
||||
if (mtxb == NULL) mtxb = (uint8 *) calloc (MT_MAXFR, sizeof (uint8));
|
||||
if (mtxb == NULL) return SCPE_MEM;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat mt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
int32 u = uptr - mt_dev.units; /* get unit number */
|
||||
|
||||
r = sim_tape_attach (uptr, cptr);
|
||||
if (r != SCPE_OK) return r;
|
||||
uptr->USTAT = STA_BOT | (sim_tape_wrp (uptr)? STA_WLK: 0);
|
||||
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
|
||||
t_stat mt_detach (UNIT* uptr)
|
||||
{
|
||||
int32 u = uptr - mt_dev.units; /* get unit number */
|
||||
|
||||
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* check for attached */
|
||||
if (!sim_is_active (uptr)) uptr->USTAT = STA_REM;
|
||||
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
return sim_tape_detach (uptr);
|
||||
}
|
||||
|
||||
/* Write lock/enable routine */
|
||||
|
||||
t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 u = uptr - mt_dev.units; /* get unit number */
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr)))
|
||||
uptr->USTAT = uptr->USTAT | STA_WLK;
|
||||
else uptr->USTAT = uptr->USTAT & ~STA_WLK;
|
||||
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
288
simhv36-1/PDP8/pdp8_pt.c
Normal file
288
simhv36-1/PDP8/pdp8_pt.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/* pdp8_pt.c: PDP-8 paper tape reader/punch simulator
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
ptr,ptp PC8E paper tape reader/punch
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
04-Oct-02 RMS Added DIBs
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
30-Nov-01 RMS Added read only unit support
|
||||
30-Mar-98 RMS Added RIM loader as PTR bootstrap
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
|
||||
|
||||
int32 ptr (int32 IR, int32 AC);
|
||||
int32 ptp (int32 IR, int32 AC);
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
|
||||
|
||||
/* PTR data structures
|
||||
|
||||
ptr_dev PTR device descriptor
|
||||
ptr_unit PTR unit descriptor
|
||||
ptr_reg PTR register list
|
||||
*/
|
||||
|
||||
DIB ptr_dib = { DEV_PTR, 1, { &ptr } };
|
||||
|
||||
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 (DONE, dev_done, INT_V_PTR) },
|
||||
{ FLDATA (ENABLE, int_enable, INT_V_PTR) },
|
||||
{ FLDATA (INT, int_req, 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) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB ptr_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, ptr_reg, ptr_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
&ptr_boot, NULL, NULL,
|
||||
&ptr_dib, 0 };
|
||||
|
||||
/* PTP data structures
|
||||
|
||||
ptp_dev PTP device descriptor
|
||||
ptp_unit PTP unit descriptor
|
||||
ptp_reg PTP register list
|
||||
*/
|
||||
|
||||
DIB ptp_dib = { DEV_PTP, 1, { &ptp } };
|
||||
|
||||
UNIT ptp_unit = {
|
||||
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
|
||||
};
|
||||
|
||||
REG ptp_reg[] = {
|
||||
{ ORDATA (BUF, ptp_unit.buf, 8) },
|
||||
{ FLDATA (DONE, dev_done, INT_V_PTP) },
|
||||
{ FLDATA (ENABLE, int_enable, INT_V_PTP) },
|
||||
{ FLDATA (INT, int_req, INT_V_PTP) },
|
||||
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB ptp_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, ptp_reg, ptp_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, NULL, NULL,
|
||||
&ptp_dib, 0
|
||||
};
|
||||
|
||||
/* Paper tape reader: IOT routine */
|
||||
|
||||
int32 ptr (int32 IR, int32 AC)
|
||||
{
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 0: /* RPE */
|
||||
int_enable = int_enable | (INT_PTR+INT_PTP); /* set enable */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
return AC;
|
||||
|
||||
case 1: /* RSF */
|
||||
return (dev_done & INT_PTR)? IOT_SKP + AC: AC;
|
||||
|
||||
case 6: /* RFC!RRB */
|
||||
sim_activate (&ptr_unit, ptr_unit.wait);
|
||||
case 2: /* RRB */
|
||||
dev_done = dev_done & ~INT_PTR; /* clear flag */
|
||||
int_req = int_req & ~INT_PTR; /* clear int req */
|
||||
return (AC | ptr_unit.buf); /* or data to AC */
|
||||
|
||||
case 4: /* RFC */
|
||||
sim_activate (&ptr_unit, ptr_unit.wait);
|
||||
dev_done = dev_done & ~INT_PTR; /* clear flag */
|
||||
int_req = int_req & ~INT_PTR; /* clear int req */
|
||||
return AC;
|
||||
|
||||
default:
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat ptr_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (ptr_stopioe, SCPE_UNATT);
|
||||
if ((temp = getc (ptr_unit.fileref)) == EOF) {
|
||||
if (feof (ptr_unit.fileref)) {
|
||||
if (ptr_stopioe) printf ("PTR end of file\n");
|
||||
else return SCPE_OK;
|
||||
}
|
||||
else perror ("PTR I/O error");
|
||||
clearerr (ptr_unit.fileref);
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
dev_done = dev_done | INT_PTR; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
ptr_unit.buf = temp & 0377;
|
||||
ptr_unit.pos = ptr_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
ptr_unit.buf = 0;
|
||||
dev_done = dev_done & ~INT_PTR; /* clear done, int */
|
||||
int_req = int_req & ~INT_PTR;
|
||||
int_enable = int_enable | INT_PTR; /* set enable */
|
||||
sim_cancel (&ptr_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Paper tape punch: IOT routine */
|
||||
|
||||
int32 ptp (int32 IR, int32 AC)
|
||||
{
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 0: /* PCE */
|
||||
int_enable = int_enable & ~(INT_PTR+INT_PTP); /* clear enables */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
return AC;
|
||||
|
||||
case 1: /* PSF */
|
||||
return (dev_done & INT_PTP)? IOT_SKP + AC: AC;
|
||||
|
||||
case 2: /* PCF */
|
||||
dev_done = dev_done & ~INT_PTP; /* clear flag */
|
||||
int_req = int_req & ~INT_PTP; /* clear int req */
|
||||
return AC;
|
||||
|
||||
case 6: /* PLS */
|
||||
dev_done = dev_done & ~INT_PTP; /* clear flag */
|
||||
int_req = int_req & ~INT_PTP; /* clear int req */
|
||||
case 4: /* PPC */
|
||||
ptp_unit.buf = AC & 0377; /* load punch buf */
|
||||
sim_activate (&ptp_unit, ptp_unit.wait); /* activate unit */
|
||||
return AC;
|
||||
|
||||
default:
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat ptp_svc (UNIT *uptr)
|
||||
{
|
||||
dev_done = dev_done | INT_PTP; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (ptp_stopioe, SCPE_UNATT);
|
||||
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) {
|
||||
perror ("PTP I/O error");
|
||||
clearerr (ptp_unit.fileref);
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
ptp_unit.pos = ptp_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
ptp_unit.buf = 0;
|
||||
dev_done = dev_done & ~INT_PTP; /* clear done, int */
|
||||
int_req = int_req & ~INT_PTP;
|
||||
int_enable = int_enable | INT_PTP; /* set enable */
|
||||
sim_cancel (&ptp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define BOOT_START 07756
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const uint16 boot_rom[] = {
|
||||
06014, /* 7756, RFC */
|
||||
06011, /* 7757, LOOP, RSF */
|
||||
05357, /* JMP .-1 */
|
||||
06016, /* RFC RRB */
|
||||
07106, /* CLL RTL*/
|
||||
07006, /* RTL */
|
||||
07510, /* SPA*/
|
||||
05374, /* JMP 7774 */
|
||||
07006, /* RTL */
|
||||
06011, /* RSF */
|
||||
05367, /* JMP .-1 */
|
||||
06016, /* RFC RRB */
|
||||
07420, /* SNL */
|
||||
03776, /* DCA I 7776 */
|
||||
03376, /* 7774, DCA 7776 */
|
||||
05357, /* JMP 7757 */
|
||||
00000, /* 7776, 0 */
|
||||
05301 /* 7777, JMP 7701 */
|
||||
};
|
||||
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
extern uint16 M[];
|
||||
|
||||
if (ptr_dib.dev != DEV_PTR) return STOP_NOTSTD; /* only std devno */
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
455
simhv36-1/PDP8/pdp8_rf.c
Normal file
455
simhv36-1/PDP8/pdp8_rf.c
Normal file
@@ -0,0 +1,455 @@
|
||||
/* pdp8_rf.c: RF08 fixed head disk simulator
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
rf RF08 fixed head disk
|
||||
|
||||
15-May-06 RMS Fixed bug in autosize attach (reported by Dave Gesswein)
|
||||
07-Jan-06 RMS Fixed unaligned register access bug (found by Doug Carman)
|
||||
04-Jan-04 RMS Changed sim_fsize calling sequence
|
||||
26-Oct-03 RMS Cleaned up buffer copy code
|
||||
26-Jul-03 RMS Fixed bug in set size routine
|
||||
14-Mar-03 RMS Fixed variable platter interaction with save/restore
|
||||
03-Mar-03 RMS Fixed autosizing
|
||||
02-Feb-03 RMS Added variable platter and autosizing support
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
28-Nov-01 RMS Added RL8A support
|
||||
25-Apr-01 RMS Added device enable/disable support
|
||||
19-Mar-01 RMS Added disk monitor bootstrap, fixed IOT decoding
|
||||
15-Feb-01 RMS Fixed 3 cycle data break sequence
|
||||
14-Apr-99 RMS Changed t_addr to unsigned
|
||||
30-Mar-98 RMS Fixed bug in RF bootstrap
|
||||
|
||||
The RF08 is a head-per-track disk. It uses the three cycle data break
|
||||
facility. To minimize overhead, the entire RF08 is buffered in memory.
|
||||
|
||||
Two timing parameters are provided:
|
||||
|
||||
rf_time Interword timing, must be non-zero
|
||||
rf_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
|
||||
DMA occurs in a burst
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
#include <math.h>
|
||||
|
||||
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
|
||||
#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
|
||||
#define UNIT_M_PLAT 03
|
||||
#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
|
||||
#define UNIT_AUTO (1 << UNIT_V_AUTO)
|
||||
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
|
||||
|
||||
/* Constants */
|
||||
|
||||
#define RF_NUMWD 2048 /* words/track */
|
||||
#define RF_NUMTR 128 /* tracks/disk */
|
||||
#define RF_DKSIZE (RF_NUMTR * RF_NUMWD) /* words/disk */
|
||||
#define RF_NUMDK 4 /* disks/controller */
|
||||
#define RF_WC 07750 /* word count */
|
||||
#define RF_MA 07751 /* mem address */
|
||||
#define RF_WMASK (RF_NUMWD - 1) /* word mask */
|
||||
|
||||
/* Parameters in the unit descriptor */
|
||||
|
||||
#define FUNC u4 /* function */
|
||||
#define RF_READ 2 /* read */
|
||||
#define RF_WRITE 4 /* write */
|
||||
|
||||
/* Status register */
|
||||
|
||||
#define RFS_PCA 04000 /* photocell status */
|
||||
#define RFS_DRE 02000 /* data req enable */
|
||||
#define RFS_WLS 01000 /* write lock status */
|
||||
#define RFS_EIE 00400 /* error int enable */
|
||||
#define RFS_PIE 00200 /* photocell int enb */
|
||||
#define RFS_CIE 00100 /* done int enable */
|
||||
#define RFS_MEX 00070 /* memory extension */
|
||||
#define RFS_DRL 00004 /* data late error */
|
||||
#define RFS_NXD 00002 /* non-existent disk */
|
||||
#define RFS_PER 00001 /* parity error */
|
||||
#define RFS_ERR (RFS_WLS + RFS_DRL + RFS_NXD + RFS_PER)
|
||||
#define RFS_V_MEX 3
|
||||
|
||||
#define GET_MEX(x) (((x) & RFS_MEX) << (12 - RFS_V_MEX))
|
||||
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
|
||||
((double) RF_NUMWD)))
|
||||
#define UPDATE_PCELL if (GET_POS(rf_time) < 6) rf_sta = rf_sta | RFS_PCA; \
|
||||
else rf_sta = rf_sta & ~RFS_PCA
|
||||
#define RF_INT_UPDATE if ((rf_done && (rf_sta & RFS_CIE)) || \
|
||||
((rf_sta & RFS_ERR) && (rf_sta & RFS_EIE)) || \
|
||||
((rf_sta & RFS_PCA) && (rf_sta & RFS_PIE))) \
|
||||
int_req = int_req | INT_RF; \
|
||||
else int_req = int_req & ~INT_RF
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, stop_inst;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 rf_sta = 0; /* status register */
|
||||
int32 rf_da = 0; /* disk address */
|
||||
int32 rf_done = 0; /* done flag */
|
||||
int32 rf_wlk = 0; /* write lock */
|
||||
int32 rf_time = 10; /* inter-word time */
|
||||
int32 rf_burst = 1; /* burst mode flag */
|
||||
int32 rf_stopioe = 1; /* stop on error */
|
||||
|
||||
DEVICE rf_dev;
|
||||
int32 rf60 (int32 IR, int32 AC);
|
||||
int32 rf61 (int32 IR, int32 AC);
|
||||
int32 rf62 (int32 IR, int32 AC);
|
||||
int32 rf64 (int32 IR, int32 AC);
|
||||
t_stat rf_svc (UNIT *uptr);
|
||||
t_stat pcell_svc (UNIT *uptr);
|
||||
t_stat rf_reset (DEVICE *dptr);
|
||||
t_stat rf_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat rf_attach (UNIT *uptr, char *cptr);
|
||||
t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
|
||||
/* RF08 data structures
|
||||
|
||||
rf_dev RF device descriptor
|
||||
rf_unit RF unit descriptor
|
||||
pcell_unit photocell timing unit (orphan)
|
||||
rf_reg RF register list
|
||||
*/
|
||||
|
||||
DIB rf_dib = { DEV_RF, 5, { &rf60, &rf61, &rf62, NULL, &rf64 } };
|
||||
|
||||
UNIT rf_unit = {
|
||||
UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+
|
||||
UNIT_BUFABLE+UNIT_MUSTBUF, RF_DKSIZE)
|
||||
};
|
||||
|
||||
UNIT pcell_unit = { UDATA (&pcell_svc, 0, 0) };
|
||||
|
||||
REG rf_reg[] = {
|
||||
{ ORDATA (STA, rf_sta, 12) },
|
||||
{ ORDATA (DA, rf_da, 20) },
|
||||
{ ORDATA (WC, M[RF_WC], 12), REG_FIT },
|
||||
{ ORDATA (MA, M[RF_MA], 12), REG_FIT },
|
||||
{ FLDATA (DONE, rf_done, 0) },
|
||||
{ FLDATA (INT, int_req, INT_V_RF) },
|
||||
{ ORDATA (WLK, rf_wlk, 32) },
|
||||
{ DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (BURST, rf_burst, 0) },
|
||||
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
|
||||
{ DRDATA (CAPAC, rf_unit.capac, 21), REG_HRO },
|
||||
{ ORDATA (DEVNUM, rf_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB rf_mod[] = {
|
||||
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
|
||||
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
|
||||
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
|
||||
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
|
||||
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE rf_dev = {
|
||||
"RF", &rf_unit, rf_reg, rf_mod,
|
||||
1, 8, 20, 1, 8, 12,
|
||||
NULL, NULL, &rf_reset,
|
||||
&rf_boot, &rf_attach, NULL,
|
||||
&rf_dib, DEV_DISABLE | DEV_DIS
|
||||
};
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 rf60 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 t;
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) { /* DCMA */
|
||||
rf_da = rf_da & ~07777; /* clear DAR<8:19> */
|
||||
rf_done = 0; /* clear done */
|
||||
rf_sta = rf_sta & ~RFS_ERR; /* clear errors */
|
||||
RF_INT_UPDATE; /* update int req */
|
||||
}
|
||||
if (pulse & 6) { /* DMAR, DMAW */
|
||||
rf_da = rf_da | AC; /* DAR<8:19> |= AC */
|
||||
rf_unit.FUNC = pulse & ~1; /* save function */
|
||||
t = (rf_da & RF_WMASK) - GET_POS (rf_time); /* delta to new loc */
|
||||
if (t < 0) t = t + RF_NUMWD; /* wrap around? */
|
||||
#if 1
|
||||
printf("xxx rf_go!\n");
|
||||
sim_activate (&rf_unit, 0); /* schedule op */
|
||||
#else
|
||||
sim_activate (&rf_unit, t * rf_time); /* schedule op */
|
||||
#endif
|
||||
AC = 0; /* clear AC */
|
||||
}
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 rf61 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
|
||||
case 1: /* DCIM */
|
||||
rf_sta = rf_sta & 07007; /* clear STA<3:8> */
|
||||
int_req = int_req & ~INT_RF; /* clear int req */
|
||||
sim_cancel (&pcell_unit); /* cancel photocell */
|
||||
return AC;
|
||||
|
||||
case 2: /* DSAC */
|
||||
return ((rf_da & RF_WMASK) == GET_POS (rf_time))? IOT_SKP: 0;
|
||||
|
||||
case 5: /* DIML */
|
||||
rf_sta = (rf_sta & 07007) | (AC & 0770); /* STA<3:8> <- AC */
|
||||
if (rf_sta & RFS_PIE) /* photocell int? */
|
||||
sim_activate (&pcell_unit, (RF_NUMWD - GET_POS (rf_time)) *
|
||||
rf_time);
|
||||
else sim_cancel (&pcell_unit);
|
||||
RF_INT_UPDATE; /* update int req */
|
||||
return 0; /* clear AC */
|
||||
|
||||
case 6: /* DIMA */
|
||||
return rf_sta; /* AC <- STA<0:11> */
|
||||
}
|
||||
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 rf62 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) { /* DFSE */
|
||||
if (rf_sta & RFS_ERR) AC = AC | IOT_SKP;
|
||||
}
|
||||
if (pulse & 2) { /* DFSC */
|
||||
if (pulse & 4) AC = AC & ~07777; /* for DMAC */
|
||||
else if (rf_done) AC = AC | IOT_SKP;
|
||||
}
|
||||
if (pulse & 4) AC = AC | (rf_da & 07777); /* DMAC */
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 rf64 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
|
||||
case 1: /* DCXA */
|
||||
rf_da = rf_da & 07777; /* clear DAR<0:7> */
|
||||
#if 1
|
||||
printf("xxx rf_da %o\n", rf_da);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 3: /* DXAL */
|
||||
rf_da = rf_da & 07777; /* clear DAR<0:7> */
|
||||
case 2: /* DXAL w/o clear */
|
||||
rf_da = rf_da | ((AC & 0377) << 12); /* DAR<0:7> |= AC */
|
||||
#if 1
|
||||
printf("xxx rf_da %o\n", rf_da);
|
||||
#endif
|
||||
AC = 0; /* clear AC */
|
||||
break;
|
||||
|
||||
case 5: /* DXAC */
|
||||
AC = 0; /* clear AC */
|
||||
case 4: /* DXAC w/o clear */
|
||||
AC = AC | ((rf_da >> 12) & 0377); /* AC |= DAR<0:7> */
|
||||
break;
|
||||
|
||||
default:
|
||||
AC = (stop_inst << IOT_V_REASON) + AC;
|
||||
break;
|
||||
} /* end switch */
|
||||
|
||||
if ((uint32) rf_da >= rf_unit.capac) rf_sta = rf_sta | RFS_NXD;
|
||||
else rf_sta = rf_sta & ~RFS_NXD;
|
||||
RF_INT_UPDATE;
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
|
||||
Note that for reads and writes, memory addresses wrap around in the
|
||||
current field. This code assumes the entire disk is buffered.
|
||||
*/
|
||||
|
||||
t_stat rf_svc (UNIT *uptr)
|
||||
{
|
||||
int32 pa, t, mex;
|
||||
int16 *fbuf = uptr->filebuf;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
|
||||
rf_sta = rf_sta | RFS_NXD;
|
||||
rf_done = 1;
|
||||
RF_INT_UPDATE; /* update int req */
|
||||
return IORETURN (rf_stopioe, SCPE_UNATT);
|
||||
}
|
||||
|
||||
mex = GET_MEX (rf_sta);
|
||||
do {
|
||||
if ((uint32) rf_da >= rf_unit.capac) { /* disk overflow? */
|
||||
rf_sta = rf_sta | RFS_NXD;
|
||||
break;
|
||||
}
|
||||
M[RF_WC] = (M[RF_WC] + 1) & 07777; /* incr word count */
|
||||
M[RF_MA] = (M[RF_MA] + 1) & 07777; /* incr mem addr */
|
||||
pa = mex | M[RF_MA]; /* add extension */
|
||||
if (uptr->FUNC == RF_READ) { /* read? */
|
||||
if (MEM_ADDR_OK (pa)) /* if !nxm */
|
||||
M[pa] = fbuf[rf_da]; /* read word */
|
||||
#if 0
|
||||
printf("dma [%o] <- %o\n", pa, M[pa]);
|
||||
#endif
|
||||
}
|
||||
else { /* write */
|
||||
t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07);
|
||||
if ((rf_wlk >> t) & 1) /* write locked? */
|
||||
rf_sta = rf_sta | RFS_WLS;
|
||||
else { /* not locked */
|
||||
fbuf[rf_da] = M[pa]; /* write word */
|
||||
if (((uint32) rf_da) >= uptr->hwmark) uptr->hwmark = rf_da + 1;
|
||||
}
|
||||
}
|
||||
rf_da = (rf_da + 1) & 03777777; /* incr disk addr */
|
||||
} while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
|
||||
|
||||
if ((M[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0)) /* more to do? */
|
||||
#if 1
|
||||
sim_activate (&rf_unit, 0); /* sched next */
|
||||
#else
|
||||
sim_activate (&rf_unit, rf_time); /* sched next */
|
||||
#endif
|
||||
else {
|
||||
rf_done = 1; /* done */
|
||||
RF_INT_UPDATE; /* update int req */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Photocell unit service */
|
||||
|
||||
t_stat pcell_svc (UNIT *uptr)
|
||||
{
|
||||
rf_sta = rf_sta | RFS_PCA; /* set photocell */
|
||||
if (rf_sta & RFS_PIE) { /* int enable? */
|
||||
sim_activate (&pcell_unit, RF_NUMWD * rf_time);
|
||||
int_req = int_req | INT_RF;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat rf_reset (DEVICE *dptr)
|
||||
{
|
||||
rf_sta = rf_da = 0;
|
||||
rf_done = 1;
|
||||
int_req = int_req & ~INT_RF; /* clear interrupt */
|
||||
sim_cancel (&rf_unit);
|
||||
sim_cancel (&pcell_unit);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define OS8_START 07750
|
||||
#define OS8_LEN (sizeof (os8_rom) / sizeof (int16))
|
||||
#define DM4_START 00200
|
||||
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16))
|
||||
|
||||
static const uint16 os8_rom[] = {
|
||||
07600, /* 7750, CLA CLL ; also word count */
|
||||
06603, /* 7751, DMAR ; also address */
|
||||
06622, /* 7752, DFSC ; done? */
|
||||
05352, /* 7753, JMP .-1 ; no */
|
||||
05752 /* 7754, JMP @.-2 ; enter boot */
|
||||
};
|
||||
|
||||
static const uint16 dm4_rom[] = {
|
||||
00200, 07600, /* 0200, CLA CLL */
|
||||
00201, 06603, /* 0201, DMAR ; read */
|
||||
00202, 06622, /* 0202, DFSC ; done? */
|
||||
00203, 05202, /* 0203, JMP .-1 ; no */
|
||||
00204, 05600, /* 0204, JMP @.-4 ; enter boot */
|
||||
07750, 07576, /* 7750, 7576 ; word count */
|
||||
07751, 07576 /* 7751, 7576 ; address */
|
||||
};
|
||||
|
||||
t_stat rf_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 sim_switches, saved_PC;
|
||||
|
||||
if (rf_dib.dev != DEV_RF) return STOP_NOTSTD; /* only std devno */
|
||||
if (sim_switches & SWMASK ('D')) {
|
||||
for (i = 0; i < DM4_LEN; i = i + 2)
|
||||
M[dm4_rom[i]] = dm4_rom[i + 1];
|
||||
saved_PC = DM4_START;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < OS8_LEN; i++)
|
||||
M[OS8_START + i] = os8_rom[i];
|
||||
saved_PC = OS8_START;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat rf_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 sz, p;
|
||||
uint32 ds_bytes = RF_DKSIZE * sizeof (int16);
|
||||
|
||||
if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
|
||||
p = (sz + ds_bytes - 1) / ds_bytes;
|
||||
if (p >= RF_NUMDK) p = RF_NUMDK - 1;
|
||||
uptr->flags = (uptr->flags & ~UNIT_PLAT) |
|
||||
(p << UNIT_V_PLAT);
|
||||
}
|
||||
uptr->capac = UNIT_GETP (uptr->flags) * RF_DKSIZE;
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
|
||||
/* Change disk size */
|
||||
|
||||
t_stat rf_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_GETP (val) * RF_DKSIZE;
|
||||
uptr->flags = uptr->flags & ~UNIT_AUTO;
|
||||
return SCPE_OK;
|
||||
}
|
||||
448
simhv36-1/PDP8/pdp8_rk.c
Normal file
448
simhv36-1/PDP8/pdp8_rk.c
Normal file
@@ -0,0 +1,448 @@
|
||||
/* pdp8_rk.c: RK8E cartridge disk simulator
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
rk RK8E/RK05 cartridge disk
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
06-Jan-02 RMS Changed enable/disable support
|
||||
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
|
||||
24-Nov-01 RMS Converted FLG to array, made register names consistent
|
||||
25-Apr-01 RMS Added device enable/disable support
|
||||
29-Jun-96 RMS Added unit enable/disable support
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
/* Constants */
|
||||
|
||||
#define RK_NUMSC 16 /* sectors/surface */
|
||||
#define RK_NUMSF 2 /* surfaces/cylinder */
|
||||
#define RK_NUMCY 203 /* cylinders/drive */
|
||||
#define RK_NUMWD 256 /* words/sector */
|
||||
#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) /* words/drive */
|
||||
#define RK_NUMDR 4 /* drives/controller */
|
||||
#define RK_M_NUMDR 03
|
||||
|
||||
/* Flags in the unit flags word */
|
||||
|
||||
#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */
|
||||
#define UNIT_V_SWLK (UNIT_V_UF + 1) /* swre write lock */
|
||||
#define UNIT_HWLK (1 << UNIT_V_HWLK)
|
||||
#define UNIT_SWLK (1 << UNIT_V_SWLK)
|
||||
#define UNIT_WPRT (UNIT_HWLK|UNIT_SWLK|UNIT_RO) /* write protect */
|
||||
|
||||
/* Parameters in the unit descriptor */
|
||||
|
||||
#define CYL u3 /* current cylinder */
|
||||
#define FUNC u4 /* function */
|
||||
|
||||
/* Status register */
|
||||
|
||||
#define RKS_DONE 04000 /* transfer done */
|
||||
#define RKS_HMOV 02000 /* heads moving */
|
||||
#define RKS_SKFL 00400 /* drive seek fail */
|
||||
#define RKS_NRDY 00200 /* drive not ready */
|
||||
#define RKS_BUSY 00100 /* control busy error */
|
||||
#define RKS_TMO 00040 /* timeout error */
|
||||
#define RKS_WLK 00020 /* write lock error */
|
||||
#define RKS_CRC 00010 /* CRC error */
|
||||
#define RKS_DLT 00004 /* data late error */
|
||||
#define RKS_STAT 00002 /* drive status error */
|
||||
#define RKS_CYL 00001 /* cyl address error */
|
||||
#define RKS_ERR (RKS_BUSY+RKS_TMO+RKS_WLK+RKS_CRC+RKS_DLT+RKS_STAT+RKS_CYL)
|
||||
|
||||
/* Command register */
|
||||
|
||||
#define RKC_M_FUNC 07 /* function */
|
||||
#define RKC_READ 0
|
||||
#define RKC_RALL 1
|
||||
#define RKC_WLK 2
|
||||
#define RKC_SEEK 3
|
||||
#define RKC_WRITE 4
|
||||
#define RKC_WALL 5
|
||||
#define RKC_V_FUNC 9
|
||||
#define RKC_IE 00400 /* interrupt enable */
|
||||
#define RKC_SKDN 00200 /* set done on seek done */
|
||||
#define RKC_HALF 00100 /* 128W sector */
|
||||
#define RKC_MEX 00070 /* memory extension */
|
||||
#define RKC_V_MEX 3
|
||||
#define RKC_M_DRV 03 /* drive select */
|
||||
#define RKC_V_DRV 1
|
||||
#define RKC_CYHI 00001 /* high cylinder addr */
|
||||
|
||||
#define GET_FUNC(x) (((x) >> RKC_V_FUNC) & RKC_M_FUNC)
|
||||
#define GET_DRIVE(x) (((x) >> RKC_V_DRV) & RKC_M_DRV)
|
||||
#define GET_MEX(x) (((x) & RKC_MEX) << (12 - RKC_V_MEX))
|
||||
|
||||
/* Disk address */
|
||||
|
||||
#define RKD_V_SECT 0 /* sector */
|
||||
#define RKD_M_SECT 017
|
||||
#define RKD_V_SUR 4 /* surface */
|
||||
#define RKD_M_SUR 01
|
||||
#define RKD_V_CYL 5 /* cylinder */
|
||||
#define RKD_M_CYL 0177
|
||||
#define GET_CYL(x,y) ((((x) & RKC_CYHI) << (12-RKD_V_CYL)) | \
|
||||
(((y) >> RKD_V_CYL) & RKD_M_CYL))
|
||||
#define GET_DA(x,y) ((((x) & RKC_CYHI) << 12) | y)
|
||||
|
||||
/* Reset commands */
|
||||
|
||||
#define RKX_CLS 0 /* clear status */
|
||||
#define RKX_CLC 1 /* clear control */
|
||||
#define RKX_CLD 2 /* clear drive */
|
||||
#define RKX_CLSA 3 /* clear status alt */
|
||||
|
||||
#define RK_INT_UPDATE \
|
||||
if (((rk_sta & (RKS_DONE + RKS_ERR)) != 0) && \
|
||||
((rk_cmd & RKC_IE) != 0)) int_req = int_req | INT_RK; \
|
||||
else int_req = int_req & ~INT_RK
|
||||
#define RK_MIN 10
|
||||
#define MAX(x,y) (((x) > (y))? (x): (y))
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, stop_inst;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 rk_busy = 0; /* controller busy */
|
||||
int32 rk_sta = 0; /* status register */
|
||||
int32 rk_cmd = 0; /* command register */
|
||||
int32 rk_da = 0; /* disk address */
|
||||
int32 rk_ma = 0; /* memory address */
|
||||
int32 rk_swait = 10, rk_rwait = 10; /* seek, rotate wait */
|
||||
int32 rk_stopioe = 1; /* stop on error */
|
||||
|
||||
DEVICE rk_dev;
|
||||
int32 rk (int32 IR, int32 AC);
|
||||
t_stat rk_svc (UNIT *uptr);
|
||||
t_stat rk_reset (DEVICE *dptr);
|
||||
t_stat rk_boot (int32 unitno, DEVICE *dptr);
|
||||
void rk_go (int32 function, int32 cylinder);
|
||||
|
||||
/* RK-8E data structures
|
||||
|
||||
rk_dev RK device descriptor
|
||||
rk_unit RK unit list
|
||||
rk_reg RK register list
|
||||
rk_mod RK modifiers list
|
||||
*/
|
||||
|
||||
DIB rk_dib = { DEV_RK, 1, { &rk } };
|
||||
|
||||
UNIT rk_unit[] = {
|
||||
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, RK_SIZE) },
|
||||
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, RK_SIZE) },
|
||||
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, RK_SIZE) },
|
||||
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, RK_SIZE) }
|
||||
};
|
||||
|
||||
REG rk_reg[] = {
|
||||
{ ORDATA (RKSTA, rk_sta, 12) },
|
||||
{ ORDATA (RKCMD, rk_cmd, 12) },
|
||||
{ ORDATA (RKDA, rk_da, 12) },
|
||||
{ ORDATA (RKMA, rk_ma, 12) },
|
||||
{ FLDATA (BUSY, rk_busy, 0) },
|
||||
{ FLDATA (INT, int_req, INT_V_RK) },
|
||||
{ DRDATA (STIME, rk_swait, 24), PV_LEFT },
|
||||
{ DRDATA (RTIME, rk_rwait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, rk_stopioe, 0) },
|
||||
{ ORDATA (DEVNUM, rk_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB rk_mod[] = {
|
||||
{ UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE rk_dev = {
|
||||
"RK", rk_unit, rk_reg, rk_mod,
|
||||
RK_NUMDR, 8, 24, 1, 8, 12,
|
||||
NULL, NULL, &rk_reset,
|
||||
&rk_boot, NULL, NULL,
|
||||
&rk_dib, DEV_DISABLE
|
||||
};
|
||||
|
||||
/* IOT routine */
|
||||
|
||||
int32 rk (int32 IR, int32 AC)
|
||||
{
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 0: /* unused */
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
|
||||
case 1: /* DSKP */
|
||||
return (rk_sta & (RKS_DONE + RKS_ERR))? /* skip on done, err */
|
||||
IOT_SKP + AC: AC;
|
||||
|
||||
case 2: /* DCLR */
|
||||
rk_sta = 0; /* clear status */
|
||||
switch (AC & 03) { /* decode AC<10:11> */
|
||||
|
||||
case RKX_CLS: /* clear status */
|
||||
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
|
||||
case RKX_CLSA: /* clear status alt */
|
||||
break;
|
||||
|
||||
case RKX_CLC: /* clear control */
|
||||
rk_cmd = rk_busy = 0; /* clear registers */
|
||||
rk_ma = rk_da = 0;
|
||||
for (i = 0; i < RK_NUMDR; i++) sim_cancel (&rk_unit[i]);
|
||||
break;
|
||||
|
||||
case RKX_CLD: /* reset drive */
|
||||
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
|
||||
else rk_go (RKC_SEEK, 0); /* seek to 0 */
|
||||
break;
|
||||
} /* end switch AC */
|
||||
break;
|
||||
|
||||
case 3: /* DLAG */
|
||||
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
|
||||
else {
|
||||
rk_da = AC; /* load disk addr */
|
||||
rk_go (GET_FUNC (rk_cmd), GET_CYL (rk_cmd, rk_da));
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: /* DLCA */
|
||||
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
|
||||
else rk_ma = AC; /* load curr addr */
|
||||
break;
|
||||
|
||||
case 5: /* DRST */
|
||||
uptr = rk_dev.units + GET_DRIVE (rk_cmd); /* selected unit */
|
||||
rk_sta = rk_sta & ~(RKS_HMOV + RKS_NRDY); /* clear dynamic */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) rk_sta = rk_sta | RKS_NRDY;
|
||||
if (sim_is_active (uptr)) rk_sta = rk_sta | RKS_HMOV;
|
||||
return rk_sta;
|
||||
|
||||
case 6: /* DLDC */
|
||||
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
|
||||
else {
|
||||
rk_cmd = AC; /* load command */
|
||||
rk_sta = 0; /* clear status */
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: /* DMAN */
|
||||
break;
|
||||
} /* end case pulse */
|
||||
|
||||
RK_INT_UPDATE; /* update int req */
|
||||
return 0; /* clear AC */
|
||||
}
|
||||
|
||||
/* Initiate new function
|
||||
|
||||
Called with function, cylinder, to allow recalibrate as well as
|
||||
load and go to be processed by this routine.
|
||||
|
||||
Assumes that the controller is idle, and that updating of interrupt
|
||||
request will be done by the caller.
|
||||
*/
|
||||
|
||||
void rk_go (int32 func, int32 cyl)
|
||||
{
|
||||
int32 t;
|
||||
UNIT *uptr;
|
||||
|
||||
if (func == RKC_RALL) func = RKC_READ; /* all? use standard */
|
||||
if (func == RKC_WALL) func = RKC_WRITE;
|
||||
uptr = rk_dev.units + GET_DRIVE (rk_cmd); /* selected unit */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT;
|
||||
return;
|
||||
}
|
||||
if (sim_is_active (uptr) || (cyl >= RK_NUMCY)) { /* busy or bad cyl? */
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_STAT;
|
||||
return;
|
||||
}
|
||||
if ((func == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) {
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */
|
||||
return;
|
||||
}
|
||||
if (func == RKC_WLK) { /* write lock? */
|
||||
uptr->flags = uptr->flags | UNIT_SWLK;
|
||||
rk_sta = rk_sta | RKS_DONE;
|
||||
return;
|
||||
}
|
||||
t = abs (cyl - uptr->CYL) * rk_swait; /* seek time */
|
||||
if (func == RKC_SEEK) { /* seek? */
|
||||
sim_activate (uptr, MAX (RK_MIN, t)); /* schedule */
|
||||
rk_sta = rk_sta | RKS_DONE; /* set done */
|
||||
}
|
||||
else {
|
||||
sim_activate (uptr, t + rk_rwait); /* schedule */
|
||||
rk_busy = 1; /* set busy */
|
||||
}
|
||||
uptr->FUNC = func; /* save func */
|
||||
uptr->CYL = cyl; /* put on cylinder */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
|
||||
If seek, complete seek command
|
||||
Else complete data transfer command
|
||||
|
||||
The unit control block contains the function and cylinder address for
|
||||
the current command.
|
||||
|
||||
Note that memory addresses wrap around in the current field.
|
||||
*/
|
||||
|
||||
static uint16 fill[RK_NUMWD/2] = { 0 };
|
||||
t_stat rk_svc (UNIT *uptr)
|
||||
{
|
||||
int32 err, wc, wc1, awc, swc, pa, da;
|
||||
UNIT *seluptr;
|
||||
|
||||
if (uptr->FUNC == RKC_SEEK) { /* seek? */
|
||||
seluptr = rk_dev.units + GET_DRIVE (rk_cmd); /* see if selected */
|
||||
if ((uptr == seluptr) && ((rk_cmd & RKC_SKDN) != 0)) {
|
||||
rk_sta = rk_sta | RKS_DONE;
|
||||
RK_INT_UPDATE;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* not att? abort */
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT;
|
||||
rk_busy = 0;
|
||||
RK_INT_UPDATE;
|
||||
return IORETURN (rk_stopioe, SCPE_UNATT);
|
||||
}
|
||||
|
||||
if ((uptr->FUNC == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) {
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */
|
||||
rk_busy = 0;
|
||||
RK_INT_UPDATE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
pa = GET_MEX (rk_cmd) | rk_ma; /* phys address */
|
||||
da = GET_DA (rk_cmd, rk_da) * RK_NUMWD * sizeof (int16);/* disk address */
|
||||
swc = wc = (rk_cmd & RKC_HALF)? RK_NUMWD / 2: RK_NUMWD; /* get transfer size */
|
||||
if ((wc1 = ((rk_ma + wc) - 010000)) > 0) wc = wc - wc1; /* if wrap, limit */
|
||||
err = fseek (uptr->fileref, da, SEEK_SET); /* locate sector */
|
||||
|
||||
if ((uptr->FUNC == RKC_READ) && (err == 0) && MEM_ADDR_OK (pa)) { /* read? */
|
||||
awc = fxread (&M[pa], sizeof (int16), wc, uptr->fileref);
|
||||
for ( ; awc < wc; awc++) M[pa + awc] = 0; /* fill if eof */
|
||||
err = ferror (uptr->fileref);
|
||||
if ((wc1 > 0) && (err == 0)) { /* field wraparound? */
|
||||
pa = pa & 070000; /* wrap phys addr */
|
||||
awc = fxread (&M[pa], sizeof (int16), wc1, uptr->fileref);
|
||||
for ( ; awc < wc1; awc++) M[pa + awc] = 0; /* fill if eof */
|
||||
err = ferror (uptr->fileref);
|
||||
}
|
||||
}
|
||||
|
||||
if ((uptr->FUNC == RKC_WRITE) && (err == 0)) { /* write? */
|
||||
fxwrite (&M[pa], sizeof (int16), wc, uptr->fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
if ((wc1 > 0) && (err == 0)) { /* field wraparound? */
|
||||
pa = pa & 070000; /* wrap phys addr */
|
||||
fxwrite (&M[pa], sizeof (int16), wc1, uptr->fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
}
|
||||
if ((rk_cmd & RKC_HALF) && (err == 0)) { /* fill half sector */
|
||||
fxwrite (fill, sizeof (int16), RK_NUMWD/2, uptr->fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
}
|
||||
}
|
||||
|
||||
rk_ma = (rk_ma + swc) & 07777; /* incr mem addr reg */
|
||||
rk_sta = rk_sta | RKS_DONE; /* set done */
|
||||
rk_busy = 0;
|
||||
RK_INT_UPDATE;
|
||||
|
||||
if (err != 0) {
|
||||
perror ("RK I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat rk_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
rk_cmd = rk_ma = rk_da = rk_sta = rk_busy = 0;
|
||||
int_req = int_req & ~INT_RK; /* clear interrupt */
|
||||
for (i = 0; i < RK_NUMDR; i++) { /* stop all units */
|
||||
uptr = rk_dev.units + i;
|
||||
sim_cancel (uptr);
|
||||
uptr->flags = uptr->flags & ~UNIT_SWLK;
|
||||
uptr->CYL = uptr->FUNC = 0;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define BOOT_START 023
|
||||
#define BOOT_UNIT 032
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const uint16 boot_rom[] = {
|
||||
06007, /* 23, CAF */
|
||||
06744, /* 24, DLCA ; addr = 0 */
|
||||
01032, /* 25, TAD UNIT ; unit no */
|
||||
06746, /* 26, DLDC ; command, unit */
|
||||
06743, /* 27, DLAG ; disk addr, go */
|
||||
01032, /* 30, TAD UNIT ; unit no, for OS */
|
||||
05031, /* 31, JMP . */
|
||||
00000 /* UNIT, 0 ; in bits <9:10> */
|
||||
};
|
||||
|
||||
t_stat rk_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
if (rk_dib.dev != DEV_RK) return STOP_NOTSTD; /* only std devno */
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
M[BOOT_UNIT] = (unitno & RK_M_NUMDR) << 1;
|
||||
saved_PC = BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
679
simhv36-1/PDP8/pdp8_rl.c
Normal file
679
simhv36-1/PDP8/pdp8_rl.c
Normal file
@@ -0,0 +1,679 @@
|
||||
/* pdp8_rl.c: RL8A cartridge disk simulator
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
rl RL8A cartridge disk
|
||||
|
||||
25-Oct-05 RMS Fixed IOT 61 decode bug (found by David Gesswein)
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
04-Jan-04 RMS Changed attach routine to use sim_fsize
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
06-Jan-02 RMS Changed enable/disable support
|
||||
30-Nov-01 RMS Cloned from RL11
|
||||
|
||||
The RL8A is a four drive cartridge disk subsystem. An RL01 drive
|
||||
consists of 256 cylinders, each with 2 surfaces containing 40 sectors
|
||||
of 256 bytes. An RL02 drive has 512 cylinders.
|
||||
|
||||
The RL8A controller has several serious complications.
|
||||
- Seeking is relative to the current disk address; this requires
|
||||
keeping accurate track of the current cylinder.
|
||||
- The RL8A will not switch heads or cross cylinders during transfers.
|
||||
- The RL8A operates in 8b and 12b mode, like the RX8E; in 12b mode, it
|
||||
packs 2 12b words into 3 bytes, creating a 170 "word" sector with
|
||||
one wasted byte. Multi-sector transfers in 12b mode don't work.
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
/* Constants */
|
||||
|
||||
#define RL_NUMBY 256 /* 8b bytes/sector */
|
||||
#define RL_NUMSC 40 /* sectors/surface */
|
||||
#define RL_NUMSF 2 /* surfaces/cylinder */
|
||||
#define RL_NUMCY 256 /* cylinders/drive */
|
||||
#define RL_NUMDR 4 /* drives/controller */
|
||||
#define RL_MAXFR (1 << 12) /* max transfer */
|
||||
#define RL01_SIZE (RL_NUMCY*RL_NUMSF*RL_NUMSC*RL_NUMBY) /* words/drive */
|
||||
#define RL02_SIZE (RL01_SIZE * 2) /* words/drive */
|
||||
#define RL_BBMAP 014 /* sector for bblk map */
|
||||
#define RL_BBID 0123 /* ID for bblk map */
|
||||
|
||||
/* Flags in the unit flags word */
|
||||
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write lock */
|
||||
#define UNIT_V_RL02 (UNIT_V_UF + 1) /* RL01 vs RL02 */
|
||||
#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize enable */
|
||||
#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */
|
||||
#define UNIT_DUMMY (1u << UNIT_V_DUMMY)
|
||||
#define UNIT_WLK (1u << UNIT_V_WLK)
|
||||
#define UNIT_RL02 (1u << UNIT_V_RL02)
|
||||
#define UNIT_AUTO (1u << UNIT_V_AUTO)
|
||||
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||
|
||||
/* Parameters in the unit descriptor */
|
||||
|
||||
#define TRK u3 /* current cylinder */
|
||||
#define STAT u4 /* status */
|
||||
|
||||
/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */
|
||||
|
||||
#define RLDS_LOAD 0 /* no cartridge */
|
||||
#define RLDS_LOCK 5 /* lock on */
|
||||
#define RLDS_BHO 0000010 /* brushes home NI */
|
||||
#define RLDS_HDO 0000020 /* heads out NI */
|
||||
#define RLDS_CVO 0000040 /* cover open NI */
|
||||
#define RLDS_HD 0000100 /* head select ^ */
|
||||
#define RLDS_RL02 0000200 /* RL02 */
|
||||
#define RLDS_DSE 0000400 /* drv sel err NI */
|
||||
#define RLDS_VCK 0001000 /* vol check * */
|
||||
#define RLDS_WGE 0002000 /* wr gate err * */
|
||||
#define RLDS_SPE 0004000 /* spin err * */
|
||||
#define RLDS_STO 0010000 /* seek time out NI */
|
||||
#define RLDS_WLK 0020000 /* wr locked */
|
||||
#define RLDS_HCE 0040000 /* hd curr err NI */
|
||||
#define RLDS_WDE 0100000 /* wr data err NI */
|
||||
#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */
|
||||
#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */
|
||||
#define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \
|
||||
RLDS_VCK+RLDS_DSE) /* errors bits */
|
||||
|
||||
/* RLCSA, seek = offset/rw = address (also uptr->TRK) */
|
||||
|
||||
#define RLCSA_DIR 04000 /* direction */
|
||||
#define RLCSA_HD 02000 /* head select */
|
||||
#define RLCSA_CYL 00777 /* cyl offset */
|
||||
#define GET_CYL(x) ((x) & RLCSA_CYL)
|
||||
#define GET_TRK(x) ((((x) & RLCSA_CYL) * RL_NUMSF) + \
|
||||
(((x) & RLCSA_HD)? 1: 0))
|
||||
#define GET_DA(x) ((GET_TRK(x) * RL_NUMSC) + rlsa)
|
||||
|
||||
/* RLCSB, function/unit select */
|
||||
|
||||
#define RLCSB_V_FUNC 0 /* function */
|
||||
#define RLCSB_M_FUNC 07
|
||||
#define RLCSB_MNT 0
|
||||
#define RLCSB_CLRD 1
|
||||
#define RLCSB_GSTA 2
|
||||
#define RLCSB_SEEK 3
|
||||
#define RLCSB_RHDR 4
|
||||
#define RLCSB_WRITE 5
|
||||
#define RLCSB_READ 6
|
||||
#define RLCSB_RNOHDR 7
|
||||
#define RLCSB_V_MEX 3 /* memory extension */
|
||||
#define RLCSB_M_MEX 07
|
||||
#define RLCSB_V_DRIVE 6 /* drive */
|
||||
#define RLCSB_M_DRIVE 03
|
||||
#define RLCSB_V_IE 8 /* int enable */
|
||||
#define RLCSB_IE (1u << RLCSB_V_IE)
|
||||
#define RLCSB_8B 01000 /* 12b/8b */
|
||||
#define RCLS_MNT 02000 /* maint NI */
|
||||
#define RLCSB_RW 0001777 /* read/write */
|
||||
#define GET_FUNC(x) (((x) >> RLCSB_V_FUNC) & RLCSB_M_FUNC)
|
||||
#define GET_MEX(x) (((x) >> RLCSB_V_MEX) & RLCSB_M_MEX)
|
||||
#define GET_DRIVE(x) (((x) >> RLCSB_V_DRIVE) & RLCSB_M_DRIVE)
|
||||
|
||||
/* RLSA, disk sector */
|
||||
|
||||
#define RLSA_V_SECT 6 /* sector */
|
||||
#define RLSA_M_SECT 077
|
||||
#define GET_SECT(x) (((x) >> RLSA_V_SECT) & RLSA_M_SECT)
|
||||
|
||||
/* RLER, error register */
|
||||
|
||||
#define RLER_DRDY 00001 /* drive ready */
|
||||
#define RLER_DRE 00002 /* drive error */
|
||||
#define RLER_HDE 01000 /* header error */
|
||||
#define RLER_INCMP 02000 /* incomplete */
|
||||
#define RLER_ICRC 04000 /* CRC error */
|
||||
#define RLER_MASK 07003
|
||||
|
||||
/* RLSI, silo register, used only in read header */
|
||||
|
||||
#define RLSI_V_TRK 6 /* track */
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
uint8 *rlxb = NULL; /* xfer buffer */
|
||||
int32 rlcsa = 0; /* control/status A */
|
||||
int32 rlcsb = 0; /* control/status B */
|
||||
int32 rlma = 0; /* memory address */
|
||||
int32 rlwc = 0; /* word count */
|
||||
int32 rlsa = 0; /* sector address */
|
||||
int32 rler = 0; /* error register */
|
||||
int32 rlsi = 0, rlsi1 = 0, rlsi2 = 0; /* silo queue */
|
||||
int32 rl_lft = 0; /* silo left/right */
|
||||
int32 rl_done = 0; /* done flag */
|
||||
int32 rl_erf = 0; /* error flag */
|
||||
int32 rl_swait = 10; /* seek wait */
|
||||
int32 rl_rwait = 10; /* rotate wait */
|
||||
int32 rl_stopioe = 1; /* stop on error */
|
||||
|
||||
DEVICE rl_dev;
|
||||
int32 rl60 (int32 IR, int32 AC);
|
||||
int32 rl61 (int32 IR, int32 AC);
|
||||
t_stat rl_svc (UNIT *uptr);
|
||||
t_stat rl_reset (DEVICE *dptr);
|
||||
void rl_set_done (int32 error);
|
||||
t_stat rl_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat rl_attach (UNIT *uptr, char *cptr);
|
||||
t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
|
||||
/* RL8A data structures
|
||||
|
||||
rl_dev RL device descriptor
|
||||
rl_unit RL unit list
|
||||
rl_reg RL register list
|
||||
rl_mod RL modifier list
|
||||
*/
|
||||
|
||||
DIB rl_dib = { DEV_RL, 2, { &rl60, &rl61 } };
|
||||
|
||||
UNIT rl_unit[] = {
|
||||
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
|
||||
UNIT_ROABLE, RL01_SIZE) },
|
||||
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
|
||||
UNIT_ROABLE, RL01_SIZE) },
|
||||
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
|
||||
UNIT_ROABLE, RL01_SIZE) },
|
||||
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
|
||||
UNIT_ROABLE, RL01_SIZE) }
|
||||
};
|
||||
|
||||
REG rl_reg[] = {
|
||||
{ ORDATA (RLCSA, rlcsa, 12) },
|
||||
{ ORDATA (RLCSB, rlcsb, 12) },
|
||||
{ ORDATA (RLMA, rlma, 12) },
|
||||
{ ORDATA (RLWC, rlwc, 12) },
|
||||
{ ORDATA (RLSA, rlsa, 6) },
|
||||
{ ORDATA (RLER, rler, 12) },
|
||||
{ ORDATA (RLSI, rlsi, 16) },
|
||||
{ ORDATA (RLSI1, rlsi1, 16) },
|
||||
{ ORDATA (RLSI2, rlsi2, 16) },
|
||||
{ FLDATA (RLSIL, rl_lft, 0) },
|
||||
{ FLDATA (INT, int_req, INT_V_RL) },
|
||||
{ FLDATA (DONE, rl_done, INT_V_RL) },
|
||||
{ FLDATA (IE, rlcsb, RLCSB_V_IE) },
|
||||
{ FLDATA (ERR, rl_erf, 0) },
|
||||
{ DRDATA (STIME, rl_swait, 24), PV_LEFT },
|
||||
{ DRDATA (RTIME, rl_rwait, 24), PV_LEFT },
|
||||
{ URDATA (CAPAC, rl_unit[0].capac, 10, T_ADDR_W, 0,
|
||||
RL_NUMDR, PV_LEFT + REG_HRO) },
|
||||
{ FLDATA (STOP_IOE, rl_stopioe, 0) },
|
||||
{ ORDATA (DEVNUM, rl_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB rl_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad },
|
||||
{ (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL },
|
||||
{ (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_RL02+UNIT_ATT), 0, "RL01", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_RL02+UNIT_ATT), UNIT_RL02, "RL02", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
|
||||
{ UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
|
||||
{ (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size },
|
||||
{ (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE rl_dev = {
|
||||
"RL", rl_unit, rl_reg, rl_mod,
|
||||
RL_NUMDR, 8, 24, 1, 8, 8,
|
||||
NULL, NULL, &rl_reset,
|
||||
&rl_boot, &rl_attach, NULL,
|
||||
&rl_dib, DEV_DISABLE | DEV_DIS
|
||||
};
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 rl60 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 curr, offs, newc, maxc;
|
||||
UNIT *uptr;
|
||||
|
||||
switch (IR & 07) { /* case IR<9:11> */
|
||||
|
||||
case 0: /* RLDC */
|
||||
rl_reset (&rl_dev); /* reset device */
|
||||
break;
|
||||
|
||||
case 1: /* RLSD */
|
||||
if (rl_done) AC = IOT_SKP; /* skip if done */
|
||||
else AC = 0;
|
||||
rl_done = 0; /* clear done */
|
||||
int_req = int_req & ~INT_RL; /* clear intr */
|
||||
return AC;
|
||||
|
||||
case 2: /* RLMA */
|
||||
rlma = AC;
|
||||
break;
|
||||
|
||||
case 3: /* RLCA */
|
||||
rlcsa = AC;
|
||||
break;
|
||||
|
||||
case 4: /* RLCB */
|
||||
rlcsb = AC;
|
||||
rl_done = 0; /* clear done */
|
||||
rler = rl_erf = 0; /* clear errors */
|
||||
int_req = int_req & ~INT_RL; /* clear intr */
|
||||
rl_lft = 0; /* clear silo ptr */
|
||||
uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */
|
||||
switch (GET_FUNC (rlcsb)) { /* case on func */
|
||||
|
||||
case RLCSB_CLRD: /* clear drive */
|
||||
uptr->STAT = uptr->STAT & ~RLDS_ERR; /* clear errors */
|
||||
case RLCSB_MNT: /* mnt */
|
||||
rl_set_done (0);
|
||||
break;
|
||||
|
||||
case RLCSB_SEEK: /* seek */
|
||||
curr = GET_CYL (uptr->TRK); /* current cylinder */
|
||||
offs = GET_CYL (rlcsa); /* offset */
|
||||
if (rlcsa & RLCSA_DIR) { /* in or out? */
|
||||
newc = curr + offs; /* out */
|
||||
maxc = (uptr->flags & UNIT_RL02)?
|
||||
RL_NUMCY * 2: RL_NUMCY;
|
||||
if (newc >= maxc) newc = maxc - 1;
|
||||
}
|
||||
else {
|
||||
newc = curr - offs; /* in */
|
||||
if (newc < 0) newc = 0;
|
||||
}
|
||||
uptr->TRK = newc | (rlcsa & RLCSA_HD);
|
||||
sim_activate (uptr, rl_swait * abs (newc - curr));
|
||||
break;
|
||||
|
||||
default: /* data transfer */
|
||||
sim_activate (uptr, rl_swait); /* activate unit */
|
||||
break;
|
||||
} /* end switch func */
|
||||
break;
|
||||
|
||||
case 5: /* RLSA */
|
||||
rlsa = GET_SECT (AC);
|
||||
break;
|
||||
|
||||
case 6: /* spare */
|
||||
return 0;
|
||||
|
||||
case 7: /* RLWC */
|
||||
rlwc = AC;
|
||||
break;
|
||||
} /* end switch pulse */
|
||||
|
||||
return 0; /* clear AC */
|
||||
}
|
||||
|
||||
int32 rl61 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 dat;
|
||||
UNIT *uptr;
|
||||
|
||||
switch (IR & 07) { /* case IR<9:11> */
|
||||
|
||||
case 0: /* RRER */
|
||||
uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */
|
||||
if (!sim_is_active (uptr) && /* update drdy */
|
||||
(uptr->flags & UNIT_ATT))
|
||||
rler = rler | RLER_DRDY;
|
||||
else rler = rler & ~RLER_DRDY;
|
||||
dat = rler & RLER_MASK;
|
||||
break;
|
||||
|
||||
case 1: /* RRWC */
|
||||
dat = rlwc;
|
||||
break;
|
||||
|
||||
case 2: /* RRCA */
|
||||
dat = rlcsa;
|
||||
break;
|
||||
|
||||
case 3: /* RRCB */
|
||||
dat = rlcsb;
|
||||
break;
|
||||
|
||||
case 4: /* RRSA */
|
||||
dat = (rlsa << RLSA_V_SECT) & 07777;
|
||||
break;
|
||||
|
||||
case 5: /* RRSI */
|
||||
if (rl_lft) { /* silo left? */
|
||||
dat = (rlsi >> 8) & 0377; /* get left 8b */
|
||||
rlsi = rlsi1; /* ripple */
|
||||
rlsi1 = rlsi2;
|
||||
}
|
||||
else dat = rlsi & 0377; /* get right 8b */
|
||||
rl_lft = rl_lft ^ 1; /* change side */
|
||||
break;
|
||||
|
||||
case 6: /* spare */
|
||||
return AC;
|
||||
|
||||
case 7: /* RLSE */
|
||||
if (rl_erf) dat = IOT_SKP | AC; /* skip if err */
|
||||
else dat = AC;
|
||||
rl_erf = 0;
|
||||
break;
|
||||
} /* end switch pulse */
|
||||
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Service unit timeout
|
||||
|
||||
If seek in progress, complete seek command
|
||||
Else complete data transfer command
|
||||
|
||||
The unit control block contains the function and cylinder for
|
||||
the current command.
|
||||
*/
|
||||
|
||||
t_stat rl_svc (UNIT *uptr)
|
||||
{
|
||||
int32 err, wc, maxc;
|
||||
int32 i, j, func, da, bc, wbc;
|
||||
uint32 ma;
|
||||
|
||||
func = GET_FUNC (rlcsb); /* get function */
|
||||
if (func == RLCSB_GSTA) { /* get status? */
|
||||
rlsi = uptr->STAT |
|
||||
((uptr->TRK & RLCSA_HD)? RLDS_HD: 0) |
|
||||
((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
|
||||
if (uptr->flags & UNIT_RL02) rlsi = rlsi | RLDS_RL02;
|
||||
if (uptr->flags & UNIT_WPRT) rlsi = rlsi | RLDS_WLK;
|
||||
rlsi2 = rlsi1 = rlsi;
|
||||
rl_set_done (0); /* done */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
|
||||
uptr->STAT = uptr->STAT | RLDS_SPE; /* spin error */
|
||||
rl_set_done (RLER_INCMP); /* flag error */
|
||||
return IORETURN (rl_stopioe, SCPE_UNATT);
|
||||
}
|
||||
|
||||
if ((func == RLCSB_WRITE) && (uptr->flags & UNIT_WPRT)) {
|
||||
uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */
|
||||
rl_set_done (RLER_DRE); /* flag error */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (func == RLCSB_SEEK) { /* seek? */
|
||||
rl_set_done (0); /* done */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (func == RLCSB_RHDR) { /* read header? */
|
||||
rlsi = (GET_TRK (uptr->TRK) << RLSI_V_TRK) | rlsa;
|
||||
rlsi1 = rlsi2 = 0;
|
||||
rl_set_done (0); /* done */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (((func != RLCSB_RNOHDR) && (GET_CYL (uptr->TRK) != GET_CYL (rlcsa)))
|
||||
|| (rlsa >= RL_NUMSC)) { /* bad cyl or sector? */
|
||||
rl_set_done (RLER_HDE | RLER_INCMP); /* flag error */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
ma = (GET_MEX (rlcsb) << 12) | rlma; /* get mem addr */
|
||||
da = GET_DA (rlcsa) * RL_NUMBY; /* get disk addr */
|
||||
wc = 010000 - rlwc; /* get true wc */
|
||||
if (rlcsb & RLCSB_8B) { /* 8b mode? */
|
||||
bc = wc; /* bytes to xfr */
|
||||
maxc = (RL_NUMSC - rlsa) * RL_NUMBY; /* max transfer */
|
||||
if (bc > maxc) wc = bc = maxc; /* trk ovrun? limit */
|
||||
}
|
||||
else {
|
||||
bc = ((wc * 3) + 1) / 2; /* 12b mode */
|
||||
if (bc > RL_NUMBY) { /* > 1 sector */
|
||||
bc = RL_NUMBY; /* cap xfer */
|
||||
wc = (RL_NUMBY * 2) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
err = fseek (uptr->fileref, da, SEEK_SET);
|
||||
|
||||
if ((func >= RLCSB_READ) && (err == 0) && /* read (no hdr)? */
|
||||
MEM_ADDR_OK (ma)) { /* valid bank? */
|
||||
i = fxread (rlxb, sizeof (int8), bc, uptr->fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
for ( ; i < bc; i++) rlxb[i] = 0; /* fill buffer */
|
||||
for (i = j = 0; i < wc; i++) { /* store buffer */
|
||||
if (rlcsb & RLCSB_8B) /* 8b mode? */
|
||||
M[ma] = rlxb[i] & 0377; /* store */
|
||||
else if (i & 1) { /* odd wd 12b? */
|
||||
M[ma] = ((rlxb[j + 1] >> 4) & 017) |
|
||||
(((uint16) rlxb[j + 2]) << 4);
|
||||
j = j + 3;
|
||||
}
|
||||
else M[ma] = rlxb[j] | /* even wd 12b */
|
||||
((((uint16) rlxb[j + 1]) & 017) << 8);
|
||||
ma = (ma & 070000) + ((ma + 1) & 07777);
|
||||
} /* end for */
|
||||
} /* end if wr */
|
||||
|
||||
if ((func == RLCSB_WRITE) && (err == 0)) { /* write? */
|
||||
for (i = j = 0; i < wc; i++) { /* fetch buffer */
|
||||
if (rlcsb & RLCSB_8B) /* 8b mode? */
|
||||
rlxb[i] = M[ma] & 0377; /* fetch */
|
||||
else if (i & 1) { /* odd wd 12b? */
|
||||
rlxb[j + 1] = rlxb[j + 1] | ((M[ma] & 017) << 4);
|
||||
rlxb[j + 2] = ((M[ma] >> 4) & 0377);
|
||||
j = j + 3;
|
||||
}
|
||||
else { /* even wd 12b */
|
||||
rlxb[j] = M[ma] & 0377;
|
||||
rlxb[j + 1] = (M[ma] >> 8) & 017;
|
||||
}
|
||||
ma = (ma & 070000) + ((ma + 1) & 07777);
|
||||
} /* end for */
|
||||
wbc = (bc + (RL_NUMBY - 1)) & ~(RL_NUMBY - 1); /* clr to */
|
||||
for (i = bc; i < wbc; i++) rlxb[i] = 0; /* end of blk */
|
||||
fxwrite (rlxb, sizeof (int8), wbc, uptr->fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
} /* end write */
|
||||
|
||||
rlwc = (rlwc + wc) & 07777; /* final word count */
|
||||
if (rlwc != 0) rler = rler | RLER_INCMP; /* completed? */
|
||||
rlma = (rlma + wc) & 07777; /* final word addr */
|
||||
rlsa = rlsa + ((bc + (RL_NUMBY - 1)) / RL_NUMBY);
|
||||
rl_set_done (0);
|
||||
|
||||
if (err != 0) { /* error? */
|
||||
perror ("RL I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set done and possibly errors */
|
||||
|
||||
void rl_set_done (int32 status)
|
||||
{
|
||||
rl_done = 1;
|
||||
rler = rler | status;
|
||||
if (rler) rl_erf = 1;
|
||||
if (rlcsb & RLCSB_IE) int_req = int_req | INT_RL;
|
||||
else int_req = int_req & ~INT_RL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Device reset
|
||||
|
||||
Note that the RL8A does NOT recalibrate its drives on RESET
|
||||
*/
|
||||
|
||||
t_stat rl_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
rlcsa = rlcsb = rlsa = rler = 0;
|
||||
rlma = rlwc = 0;
|
||||
rlsi = rlsi1 = rlsi2 = 0;
|
||||
rl_lft = 0;
|
||||
rl_done = 0;
|
||||
rl_erf = 0;
|
||||
int_req = int_req & ~INT_RL;
|
||||
for (i = 0; i < RL_NUMDR; i++) {
|
||||
uptr = rl_dev.units + i;
|
||||
sim_cancel (uptr);
|
||||
uptr->STAT = 0;
|
||||
}
|
||||
if (rlxb == NULL) rlxb = (uint8 *) calloc (RL_MAXFR, sizeof (uint8));
|
||||
if (rlxb == NULL) return SCPE_MEM;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat rl_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 p;
|
||||
t_stat r;
|
||||
|
||||
uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
|
||||
r = attach_unit (uptr, cptr); /* attach unit */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
uptr->TRK = 0; /* cyl 0 */
|
||||
uptr->STAT = RLDS_VCK; /* new volume */
|
||||
if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */
|
||||
if (uptr->flags & UNIT_RO) return SCPE_OK;
|
||||
return rl_set_bad (uptr, 0, NULL, NULL);
|
||||
}
|
||||
if ((uptr->flags & UNIT_AUTO) == 0) return r; /* autosize? */
|
||||
if (p > (RL01_SIZE * sizeof (int16))) {
|
||||
uptr->flags = uptr->flags | UNIT_RL02;
|
||||
uptr->capac = RL02_SIZE;
|
||||
}
|
||||
else {
|
||||
uptr->flags = uptr->flags & ~UNIT_RL02;
|
||||
uptr->capac = RL01_SIZE;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set size routine */
|
||||
|
||||
t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||||
uptr->capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Factory bad block table creation routine
|
||||
|
||||
This routine writes the OS/8 specific bad block map in track 0, sector 014 (RL_BBMAP):
|
||||
|
||||
words 0 magic number = 0123 (RL_BBID)
|
||||
words 1-n block numbers
|
||||
:
|
||||
words n+1 end of table = 0
|
||||
|
||||
Inputs:
|
||||
uptr = pointer to unit
|
||||
val = ignored
|
||||
Outputs:
|
||||
sta = status code
|
||||
*/
|
||||
|
||||
t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 i, da = RL_BBMAP * RL_NUMBY;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
|
||||
if (uptr->flags & UNIT_RO) return SCPE_RO;
|
||||
if (!get_yn ("Create bad block table? [N]", FALSE)) return SCPE_OK;
|
||||
if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR;
|
||||
rlxb[0] = RL_BBID;
|
||||
for (i = 1; i < RL_NUMBY; i++) rlxb[i] = 0;
|
||||
fxwrite (rlxb, sizeof (uint8), RL_NUMBY, uptr->fileref);
|
||||
if (ferror (uptr->fileref)) return SCPE_IOERR;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap */
|
||||
|
||||
#define BOOT_START 1 /* start */
|
||||
#define BOOT_UNIT 02006 /* unit number */
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const uint16 boot_rom[] = {
|
||||
06600, /* BT, RLDC ; reset */
|
||||
07201, /* 02, CLA IAC ; clr drv = 1 */
|
||||
04027, /* 03, JMS GO ; do io */
|
||||
01004, /* 04, TAD 4 ; rd hdr fnc */
|
||||
04027, /* 05, JMS GO ; do io */
|
||||
06615, /* 06, RRSI ; rd hdr lo */
|
||||
07002, /* 07, BSW ; swap */
|
||||
07012, /* 10, RTR ; lo cyl to L */
|
||||
06615, /* 11, RRSI ; rd hdr hi */
|
||||
00025, /* 12, AND 25 ; mask = 377 */
|
||||
07004, /* 13, RTL ; get cyl */
|
||||
06603, /* 14, RLCA ; set addr */
|
||||
07325, /* 15, CLA STL IAC RAL ; seek = 3 */
|
||||
04027, /* 16, JMS GO ; do io */
|
||||
07332, /* 17, CLA STL RTR ; dir in = 2000 */
|
||||
06605, /* 20, RLSA ; sector */
|
||||
01026, /* 21, TAD (-200) ; one sector */
|
||||
06607, /* 22, RLWC ; word cnt */
|
||||
07327, /* 23, CLA STL IAC RTL ; read = 6*/
|
||||
04027, /* 24, JMS GO ; do io */
|
||||
00377, /* 25, JMP 377 ; start */
|
||||
07600, /* 26, -200 ; word cnt */
|
||||
00000, /* GO, 0 ; subr */
|
||||
06604, /* 30, RLCB ; load fnc */
|
||||
06601, /* 31, RLSD ; wait */
|
||||
05031, /* 32, JMP .-1 ; */
|
||||
06617, /* 33, RLSE ; error? */
|
||||
05427, /* 34, JMP I GO ; no, ok */
|
||||
05001 /* 35, JMP BT ; restart */
|
||||
};
|
||||
|
||||
|
||||
t_stat rl_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
if (unitno) return SCPE_ARG; /* only unit 0 */
|
||||
if (rl_dib.dev != DEV_RL) return STOP_NOTSTD; /* only std devno */
|
||||
rl_unit[unitno].TRK = 0;
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
730
simhv36-1/PDP8/pdp8_rx.c
Normal file
730
simhv36-1/PDP8/pdp8_rx.c
Normal file
@@ -0,0 +1,730 @@
|
||||
/* pdp8_rx.c: RX8E/RX01, RX28/RX02 floppy disk simulator
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
rx RX8E/RX01, RX28/RX02 floppy disk
|
||||
|
||||
15-May-06 RMS Fixed bug in autosize attach (reported by Dave Gesswein)
|
||||
04-Jan-04 RMS Changed sim_fsize calling sequence
|
||||
05-Nov-03 RMS Fixed bug in RX28 read status (found by Charles Dickman)
|
||||
26-Oct-03 RMS Cleaned up buffer copy code, fixed double density write
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
14-Mar-03 RMS Fixed variable size interaction with save/restore
|
||||
03-Mar-03 RMS Fixed autosizing
|
||||
08-Oct-02 RMS Added DIB, device number support
|
||||
Fixed reset to work with disabled device
|
||||
15-Sep-02 RMS Added RX28/RX02 support
|
||||
06-Jan-02 RMS Changed enable/disable support
|
||||
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
|
||||
24-Nov-01 RMS Converted FLG to array
|
||||
17-Jul-01 RMS Fixed warning from VC++ 6
|
||||
26-Apr-01 RMS Added device enable/disable support
|
||||
13-Apr-01 RMS Revised for register arrays
|
||||
14-Apr-99 RMS Changed t_addr to unsigned
|
||||
15-Aug-96 RMS Fixed bug in LCD
|
||||
|
||||
An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B.
|
||||
An RX02 diskette consists of 77 tracks, each with 26 sectors of 128B
|
||||
(single density) or 256B (double density). Tracks are numbered 0-76,
|
||||
sectors 1-26. The RX8E (RX28) can store data in 8b mode or 12b mode.
|
||||
In 8b mode, the controller reads or writes 128 bytes (128B or 256B)
|
||||
per sector. In 12b mode, it reads or writes 64 (64 or 128) 12b words
|
||||
per sector. The 12b words are bit packed into the first 96 (192) bytes
|
||||
of the sector; the last 32 (64) bytes are zeroed on writes.
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
#define RX_NUMTR 77 /* tracks/disk */
|
||||
#define RX_M_TRACK 0377
|
||||
#define RX_NUMSC 26 /* sectors/track */
|
||||
#define RX_M_SECTOR 0177 /* cf Jones!! */
|
||||
#define RX_NUMBY 128 /* bytes/sector */
|
||||
#define RX2_NUMBY 256
|
||||
#define RX_NUMWD (RX_NUMBY / 2) /* words/sector */
|
||||
#define RX2_NUMWD (RX2_NUMBY / 2)
|
||||
#define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY) /* bytes/disk */
|
||||
#define RX2_SIZE (RX_NUMTR * RX_NUMSC * RX2_NUMBY)
|
||||
#define RX_NUMDR 2 /* drives/controller */
|
||||
#define RX_M_NUMDR 01
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_V_DEN (UNIT_V_UF + 1) /* double density */
|
||||
#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */
|
||||
#define UNIT_WLK (1u << UNIT_V_WLK)
|
||||
#define UNIT_DEN (1u << UNIT_V_DEN)
|
||||
#define UNIT_AUTO (1u << UNIT_V_AUTO)
|
||||
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||
|
||||
#define IDLE 0 /* idle state */
|
||||
#define CMD8 1 /* 8b cmd, ho next */
|
||||
#define RWDS 2 /* rw, sect next */
|
||||
#define RWDT 3 /* rw, track next */
|
||||
#define RWXFR 4 /* rw, transfer */
|
||||
#define FILL 5 /* fill buffer */
|
||||
#define EMPTY 6 /* empty buffer */
|
||||
#define SDCNF 7 /* set dens, conf next */
|
||||
#define SDXFR 8 /* set dens, transfer */
|
||||
#define CMD_COMPLETE 9 /* set done next */
|
||||
#define INIT_COMPLETE 10 /* init compl next */
|
||||
|
||||
#define RXCS_V_FUNC 1 /* function */
|
||||
#define RXCS_M_FUNC 7
|
||||
#define RXCS_FILL 0 /* fill buffer */
|
||||
#define RXCS_EMPTY 1 /* empty buffer */
|
||||
#define RXCS_WRITE 2 /* write sector */
|
||||
#define RXCS_READ 3 /* read sector */
|
||||
#define RXCS_SDEN 4 /* set density (RX28) */
|
||||
#define RXCS_RXES 5 /* read status */
|
||||
#define RXCS_WRDEL 6 /* write del data */
|
||||
#define RXCS_ECODE 7 /* read error code */
|
||||
#define RXCS_DRV 0020 /* drive */
|
||||
#define RXCS_MODE 0100 /* mode */
|
||||
#define RXCS_MAINT 0200 /* maintenance */
|
||||
#define RXCS_DEN 0400 /* density (RX28) */
|
||||
#define RXCS_GETFNC(x) (((x) >> RXCS_V_FUNC) & RXCS_M_FUNC)
|
||||
|
||||
#define RXES_CRC 0001 /* CRC error NI */
|
||||
#define RXES_ID 0004 /* init done */
|
||||
#define RXES_RX02 0010 /* RX02 (RX28) */
|
||||
#define RXES_DERR 0020 /* density err (RX28) */
|
||||
#define RXES_DEN 0040 /* density (RX28) */
|
||||
#define RXES_DD 0100 /* deleted data */
|
||||
#define RXES_DRDY 0200 /* drive ready */
|
||||
|
||||
#define TRACK u3 /* current track */
|
||||
#define READ_RXDBR ((rx_csr & RXCS_MODE)? AC | (rx_dbr & 0377): rx_dbr)
|
||||
#define CALC_DA(t,s,b) (((t) * RX_NUMSC) + ((s) - 1)) * b
|
||||
|
||||
extern int32 int_req, int_enable, dev_done;
|
||||
|
||||
int32 rx_28 = 0; /* controller type */
|
||||
int32 rx_tr = 0; /* xfer ready flag */
|
||||
int32 rx_err = 0; /* error flag */
|
||||
int32 rx_csr = 0; /* control/status */
|
||||
int32 rx_dbr = 0; /* data buffer */
|
||||
int32 rx_esr = 0; /* error status */
|
||||
int32 rx_ecode = 0; /* error code */
|
||||
int32 rx_track = 0; /* desired track */
|
||||
int32 rx_sector = 0; /* desired sector */
|
||||
int32 rx_state = IDLE; /* controller state */
|
||||
int32 rx_cwait = 100; /* command time */
|
||||
int32 rx_swait = 10; /* seek, per track */
|
||||
int32 rx_xwait = 1; /* tr set time */
|
||||
int32 rx_stopioe = 0; /* stop on error */
|
||||
uint8 rx_buf[RX2_NUMBY] = { 0 }; /* sector buffer */
|
||||
int32 rx_bptr = 0; /* buffer pointer */
|
||||
|
||||
DEVICE rx_dev;
|
||||
int32 rx (int32 IR, int32 AC);
|
||||
t_stat rx_svc (UNIT *uptr);
|
||||
t_stat rx_reset (DEVICE *dptr);
|
||||
t_stat rx_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat rx_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat rx_attach (UNIT *uptr, char *cptr);
|
||||
void rx_cmd (void);
|
||||
void rx_done (int32 esr_flags, int32 new_ecode);
|
||||
t_stat rx_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat rx_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
/* RX8E data structures
|
||||
|
||||
rx_dev RX device descriptor
|
||||
rx_unit RX unit list
|
||||
rx_reg RX register list
|
||||
rx_mod RX modifier list
|
||||
*/
|
||||
|
||||
DIB rx_dib = { DEV_RX, 1, { &rx } };
|
||||
|
||||
UNIT rx_unit[] = {
|
||||
{ UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF+
|
||||
UNIT_ROABLE, RX_SIZE) },
|
||||
{ UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF+
|
||||
UNIT_ROABLE, RX_SIZE) }
|
||||
};
|
||||
|
||||
REG rx_reg[] = {
|
||||
{ ORDATA (RXCS, rx_csr, 12) },
|
||||
{ ORDATA (RXDB, rx_dbr, 12) },
|
||||
{ ORDATA (RXES, rx_esr, 12) },
|
||||
{ ORDATA (RXERR, rx_ecode, 8) },
|
||||
{ ORDATA (RXTA, rx_track, 8) },
|
||||
{ ORDATA (RXSA, rx_sector, 8) },
|
||||
{ DRDATA (STAPTR, rx_state, 4), REG_RO },
|
||||
{ DRDATA (BUFPTR, rx_bptr, 8) },
|
||||
{ FLDATA (TR, rx_tr, 0) },
|
||||
{ FLDATA (ERR, rx_err, 0) },
|
||||
{ FLDATA (DONE, dev_done, INT_V_RX) },
|
||||
{ FLDATA (ENABLE, int_enable, INT_V_RX) },
|
||||
{ FLDATA (INT, int_req, INT_V_RX) },
|
||||
{ DRDATA (CTIME, rx_cwait, 24), PV_LEFT },
|
||||
{ DRDATA (STIME, rx_swait, 24), PV_LEFT },
|
||||
{ DRDATA (XTIME, rx_xwait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, rx_stopioe, 0) },
|
||||
{ BRDATA (SBUF, rx_buf, 8, 8, RX2_NUMBY) },
|
||||
{ FLDATA (RX28, rx_28, 0), REG_HRO },
|
||||
{ URDATA (CAPAC, rx_unit[0].capac, 10, T_ADDR_W, 0,
|
||||
RX_NUMDR, REG_HRO | PV_LEFT) },
|
||||
{ ORDATA (DEVNUM, rx_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB rx_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "RX28", &rx_settype, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "RX8E", &rx_settype, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &rx_showtype, NULL },
|
||||
{ (UNIT_DEN+UNIT_ATT), UNIT_ATT, "single density", NULL, NULL },
|
||||
{ (UNIT_DEN+UNIT_ATT), (UNIT_DEN+UNIT_ATT), "double density", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_DEN+UNIT_ATT), 0, "single density", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_DEN+UNIT_ATT), UNIT_DEN, "double density", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
|
||||
{ UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
|
||||
{ (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &rx_set_size },
|
||||
{ (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &rx_set_size },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE rx_dev = {
|
||||
"RX", rx_unit, rx_reg, rx_mod,
|
||||
RX_NUMDR, 8, 20, 1, 8, 8,
|
||||
NULL, NULL, &rx_reset,
|
||||
&rx_boot, &rx_attach, NULL,
|
||||
&rx_dib, DEV_DISABLE
|
||||
};
|
||||
|
||||
/* IOT routine */
|
||||
|
||||
int32 rx (int32 IR, int32 AC)
|
||||
{
|
||||
int32 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* get drive number */
|
||||
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 0: /* unused */
|
||||
break;
|
||||
|
||||
case 1: /* LCD */
|
||||
if (rx_state != IDLE) return AC; /* ignore if busy */
|
||||
dev_done = dev_done & ~INT_RX; /* clear done, int */
|
||||
int_req = int_req & ~INT_RX;
|
||||
rx_tr = rx_err = 0; /* clear flags */
|
||||
rx_bptr = 0; /* clear buf pointer */
|
||||
if (rx_28 && (AC & RXCS_MODE)) { /* RX28 8b mode? */
|
||||
rx_dbr = rx_csr = AC & 0377; /* save 8b */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
rx_state = CMD8; /* wait for part 2 */
|
||||
}
|
||||
else {
|
||||
rx_dbr = rx_csr = AC; /* save new command */
|
||||
rx_cmd (); /* issue command */
|
||||
}
|
||||
return 0; /* clear AC */
|
||||
|
||||
case 2: /* XDR */
|
||||
switch (rx_state & 017) { /* case on state */
|
||||
|
||||
case EMPTY: /* emptying buffer */
|
||||
sim_activate (&rx_unit[drv], rx_xwait); /* sched xfer */
|
||||
return READ_RXDBR; /* return data reg */
|
||||
|
||||
case CMD8: /* waiting for cmd */
|
||||
rx_dbr = AC & 0377;
|
||||
rx_csr = (rx_csr & 0377) | ((AC & 017) << 8);
|
||||
rx_cmd ();
|
||||
break;
|
||||
|
||||
case RWDS:case RWDT:case FILL:case SDCNF: /* waiting for data */
|
||||
rx_dbr = AC; /* save data */
|
||||
sim_activate (&rx_unit[drv], rx_xwait); /* schedule */
|
||||
break;
|
||||
|
||||
default: /* default */
|
||||
return READ_RXDBR; /* return data reg */
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: /* STR */
|
||||
if (rx_tr != 0) {
|
||||
rx_tr = 0;
|
||||
return IOT_SKP + AC;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: /* SER */
|
||||
if (rx_err != 0) {
|
||||
rx_err = 0;
|
||||
return IOT_SKP + AC;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: /* SDN */
|
||||
if ((dev_done & INT_RX) != 0) {
|
||||
dev_done = dev_done & ~INT_RX;
|
||||
int_req = int_req & ~INT_RX;
|
||||
return IOT_SKP + AC;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: /* INTR */
|
||||
if (AC & 1) int_enable = int_enable | INT_RX;
|
||||
else int_enable = int_enable & ~INT_RX;
|
||||
int_req = INT_UPDATE;
|
||||
break;
|
||||
|
||||
case 7: /* INIT */
|
||||
rx_reset (&rx_dev); /* reset device */
|
||||
break;
|
||||
} /* end case pulse */
|
||||
|
||||
return AC;
|
||||
}
|
||||
|
||||
void rx_cmd (void)
|
||||
{
|
||||
int32 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* get drive number */
|
||||
|
||||
switch (RXCS_GETFNC (rx_csr)) { /* decode command */
|
||||
|
||||
case RXCS_FILL:
|
||||
rx_state = FILL; /* state = fill */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
break;
|
||||
|
||||
case RXCS_EMPTY:
|
||||
rx_state = EMPTY; /* state = empty */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
sim_activate (&rx_unit[drv], rx_xwait); /* sched xfer */
|
||||
break;
|
||||
|
||||
case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:
|
||||
rx_state = RWDS; /* state = get sector */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
break;
|
||||
|
||||
case RXCS_SDEN:
|
||||
if (rx_28) { /* RX28? */
|
||||
rx_state = SDCNF; /* state = get conf */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
break;
|
||||
} /* else fall thru */
|
||||
default:
|
||||
rx_state = CMD_COMPLETE; /* state = cmd compl */
|
||||
sim_activate (&rx_unit[drv], rx_cwait); /* sched done */
|
||||
break;
|
||||
} /* end switch func */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unit service; the action to be taken depends on the transfer state:
|
||||
|
||||
IDLE Should never get here
|
||||
RWDS Save sector, set TR, set RWDT
|
||||
RWDT Save track, set RWXFR
|
||||
RWXFR Read/write buffer
|
||||
FILL copy dbr 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 dbr, advance ptr, set tr
|
||||
CMD_COMPLETE copy requested data to dbr, finish command
|
||||
INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
|
||||
|
||||
For RWDT and CMD_COMPLETE, the input argument is the selected drive;
|
||||
otherwise, it is drive 0.
|
||||
*/
|
||||
|
||||
t_stat rx_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i, func, byptr, bps, wps;
|
||||
int8 *fbuf = uptr->filebuf;
|
||||
uint32 da;
|
||||
#define PTR12(x) (((x) + (x) + (x)) >> 1)
|
||||
|
||||
if (rx_28 && (uptr->flags & UNIT_DEN)) /* RX28 and double density? */
|
||||
bps = RX2_NUMBY; /* double bytes/sector */
|
||||
else bps = RX_NUMBY; /* RX8E, normal count */
|
||||
wps = bps / 2;
|
||||
func = RXCS_GETFNC (rx_csr); /* get function */
|
||||
switch (rx_state) { /* case on state */
|
||||
|
||||
case IDLE: /* idle */
|
||||
return SCPE_IERR;
|
||||
|
||||
case EMPTY: /* empty buffer */
|
||||
if (rx_csr & RXCS_MODE) { /* 8b xfer? */
|
||||
if (rx_bptr >= bps) { /* done? */
|
||||
rx_done (0, 0); /* set done */
|
||||
break; /* and exit */
|
||||
}
|
||||
rx_dbr = rx_buf[rx_bptr]; /* else get data */
|
||||
}
|
||||
else {
|
||||
byptr = PTR12 (rx_bptr); /* 12b xfer */
|
||||
if (rx_bptr >= wps) { /* done? */
|
||||
rx_done (0, 0); /* set done */
|
||||
break; /* and exit */
|
||||
}
|
||||
rx_dbr = (rx_bptr & 1)? /* get data */
|
||||
((rx_buf[byptr] & 017) << 8) | rx_buf[byptr + 1]:
|
||||
(rx_buf[byptr] << 4) | ((rx_buf[byptr + 1] >> 4) & 017);
|
||||
}
|
||||
rx_bptr = rx_bptr + 1;
|
||||
rx_tr = 1;
|
||||
break;
|
||||
|
||||
case FILL: /* fill buffer */
|
||||
if (rx_csr & RXCS_MODE) { /* 8b xfer? */
|
||||
rx_buf[rx_bptr] = rx_dbr; /* fill buffer */
|
||||
rx_bptr = rx_bptr + 1;
|
||||
if (rx_bptr < bps) rx_tr = 1; /* if more, set xfer */
|
||||
else rx_done (0, 0); /* else done */
|
||||
}
|
||||
else {
|
||||
byptr = PTR12 (rx_bptr); /* 12b xfer */
|
||||
if (rx_bptr & 1) { /* odd or even? */
|
||||
rx_buf[byptr] = (rx_buf[byptr] & 0360) | ((rx_dbr >> 8) & 017);
|
||||
rx_buf[byptr + 1] = rx_dbr & 0377;
|
||||
}
|
||||
else {
|
||||
rx_buf[byptr] = (rx_dbr >> 4) & 0377;
|
||||
rx_buf[byptr + 1] = (rx_dbr & 017) << 4;
|
||||
}
|
||||
rx_bptr = rx_bptr + 1;
|
||||
if (rx_bptr < wps) rx_tr = 1; /* if more, set xfer */
|
||||
else {
|
||||
for (i = PTR12 (wps); i < bps; i++)
|
||||
rx_buf[i] = 0; /* else fill sector */
|
||||
rx_done (0, 0); /* set done */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RWDS: /* wait for sector */
|
||||
rx_sector = rx_dbr & RX_M_SECTOR; /* save sector */
|
||||
rx_tr = 1; /* set xfer ready */
|
||||
rx_state = RWDT; /* advance state */
|
||||
return SCPE_OK;
|
||||
|
||||
case RWDT: /* wait for track */
|
||||
rx_track = rx_dbr & RX_M_TRACK; /* save track */
|
||||
rx_state = RWXFR;
|
||||
sim_activate (uptr, /* sched done */
|
||||
rx_swait * abs (rx_track - uptr->TRACK));
|
||||
return SCPE_OK;
|
||||
|
||||
case RWXFR: /* transfer */
|
||||
if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */
|
||||
rx_done (0, 0110); /* done, error */
|
||||
return IORETURN (rx_stopioe, SCPE_UNATT);
|
||||
}
|
||||
if (rx_track >= RX_NUMTR) { /* bad track? */
|
||||
rx_done (0, 0040); /* done, error */
|
||||
break;
|
||||
}
|
||||
uptr->TRACK = rx_track; /* now on track */
|
||||
if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */
|
||||
rx_done (0, 0070); /* done, error */
|
||||
break;
|
||||
}
|
||||
if (rx_28 && /* RX28? */
|
||||
(((uptr->flags & UNIT_DEN) != 0) ^
|
||||
((rx_csr & RXCS_DEN) != 0))) { /* densities agree? */
|
||||
rx_done (RXES_DERR, 0240); /* no, error */
|
||||
break;
|
||||
}
|
||||
da = CALC_DA (rx_track, rx_sector, bps); /* get disk address */
|
||||
if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */
|
||||
if (func == RXCS_READ) { /* read? */
|
||||
for (i = 0; i < bps; i++) rx_buf[i] = fbuf[da + i];
|
||||
}
|
||||
else { /* write */
|
||||
if (uptr->flags & UNIT_WPRT) { /* locked? */
|
||||
rx_done (0, 0100); /* done, error */
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < bps; i++) fbuf[da + i] = rx_buf[i];
|
||||
da = da + bps;
|
||||
if (da > uptr->hwmark) uptr->hwmark = da;
|
||||
}
|
||||
rx_done (0, 0); /* done */
|
||||
break;
|
||||
|
||||
case SDCNF: /* confirm set density */
|
||||
if ((rx_dbr & 0377) != 0111) { /* confirmed? */
|
||||
rx_done (0, 0250); /* no, error */
|
||||
break;
|
||||
}
|
||||
rx_state = SDXFR; /* next state */
|
||||
sim_activate (uptr, rx_cwait * 100); /* schedule operation */
|
||||
break;
|
||||
|
||||
case SDXFR: /* erase disk */
|
||||
for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0;
|
||||
uptr->hwmark = uptr->capac;
|
||||
if (rx_csr & RXCS_DEN) uptr->flags = uptr->flags | UNIT_DEN;
|
||||
else uptr->flags = uptr->flags & ~UNIT_DEN;
|
||||
rx_done (0, 0);
|
||||
break;
|
||||
|
||||
case CMD_COMPLETE: /* command complete */
|
||||
if (func == RXCS_ECODE) { /* read ecode? */
|
||||
rx_dbr = rx_ecode; /* set dbr */
|
||||
rx_done (0, -1); /* don't update */
|
||||
}
|
||||
else if (rx_28) { /* no, read sta; RX28? */
|
||||
rx_esr = rx_esr & ~RXES_DERR; /* assume dens match */
|
||||
if (((uptr->flags & UNIT_DEN) != 0) ^ /* densities mismatch? */
|
||||
((rx_csr & RXCS_DEN) != 0))
|
||||
rx_done (RXES_DERR, 0240); /* yes, error */
|
||||
else rx_done (0, 0); /* no, ok */
|
||||
}
|
||||
else rx_done (0, 0); /* RX8E status */
|
||||
break;
|
||||
|
||||
case INIT_COMPLETE: /* init complete */
|
||||
rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */
|
||||
rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */
|
||||
if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */
|
||||
rx_done (RXES_ID, 0010); /* init done, error */
|
||||
break;
|
||||
}
|
||||
da = CALC_DA (1, 1, bps); /* track 1, sector 1 */
|
||||
for (i = 0; i < bps; i++) /* read sector */
|
||||
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 */
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Command complete. Set done and put final value in interface register,
|
||||
return to IDLE state.
|
||||
*/
|
||||
|
||||
void rx_done (int32 esr_flags, int32 new_ecode)
|
||||
{
|
||||
int32 drv = (rx_csr & RXCS_DRV)? 1: 0;
|
||||
|
||||
rx_state = IDLE; /* now idle */
|
||||
dev_done = dev_done | INT_RX; /* set done */
|
||||
int_req = INT_UPDATE; /* update ints */
|
||||
rx_esr = (rx_esr | esr_flags) & ~(RXES_DRDY|RXES_RX02|RXES_DEN);
|
||||
if (rx_28) rx_esr = rx_esr | RXES_RX02; /* RX28? */
|
||||
if (rx_unit[drv].flags & UNIT_ATT) { /* update drv rdy */
|
||||
rx_esr = rx_esr | RXES_DRDY;
|
||||
if (rx_unit[drv].flags & UNIT_DEN) /* update density */
|
||||
rx_esr = rx_esr | RXES_DEN;
|
||||
}
|
||||
if (new_ecode > 0) rx_err = 1; /* test for error */
|
||||
if (new_ecode < 0) return; /* don't update? */
|
||||
rx_ecode = new_ecode; /* update ecode */
|
||||
rx_dbr = rx_esr; /* update RXDB */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine. The RX is one of the few devices that schedules
|
||||
an I/O transfer as part of its initialization */
|
||||
|
||||
t_stat rx_reset (DEVICE *dptr)
|
||||
{
|
||||
rx_dbr = rx_csr = 0; /* 12b mode, drive 0 */
|
||||
rx_esr = rx_ecode = 0; /* clear error */
|
||||
rx_tr = rx_err = 0; /* clear flags */
|
||||
rx_track = rx_sector = 0; /* clear address */
|
||||
rx_state = IDLE; /* ctrl idle */
|
||||
dev_done = dev_done & ~INT_RX; /* clear done, int */
|
||||
int_req = int_req & ~INT_RX;
|
||||
int_enable = int_enable & ~INT_RX;
|
||||
sim_cancel (&rx_unit[1]); /* cancel drive 1 */
|
||||
if (dptr->flags & DEV_DIS) sim_cancel (&rx_unit[0]); /* disabled? */
|
||||
else if (rx_unit[0].flags & UNIT_BUF) { /* attached? */
|
||||
rx_state = INIT_COMPLETE; /* yes, sched init */
|
||||
sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK));
|
||||
}
|
||||
else rx_done (rx_esr | RXES_ID, 0010); /* no, error */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat rx_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 sz;
|
||||
|
||||
if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
|
||||
if (sz > RX_SIZE) uptr->flags = uptr->flags | UNIT_DEN;
|
||||
else uptr->flags = uptr->flags & ~UNIT_DEN;
|
||||
}
|
||||
uptr->capac = (uptr->flags & UNIT_DEN)? RX2_SIZE: RX_SIZE;
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
|
||||
/* Set size routine */
|
||||
|
||||
t_stat rx_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||||
if ((rx_28 == 0) && val) return SCPE_NOFNC; /* not on RX8E */
|
||||
uptr->capac = val? RX2_SIZE: RX_SIZE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set controller type */
|
||||
|
||||
t_stat rx_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
|
||||
if (val == rx_28) return SCPE_OK;
|
||||
for (i = 0; i < RX_NUMDR; i++) {
|
||||
if (rx_unit[i].flags & UNIT_ATT) return SCPE_ALATT;
|
||||
}
|
||||
for (i = 0; i < RX_NUMDR; i++) {
|
||||
if (val) rx_unit[i].flags = rx_unit[i].flags | UNIT_DEN | UNIT_AUTO;
|
||||
else rx_unit[i].flags = rx_unit[i].flags & ~(UNIT_DEN | UNIT_AUTO);
|
||||
rx_unit[i].capac = val? RX2_SIZE: RX_SIZE;
|
||||
}
|
||||
rx_28 = val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show controller type */
|
||||
|
||||
t_stat rx_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
if (rx_28) fprintf (st, "RX28");
|
||||
else fprintf (st, "RX8E");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define BOOT_START 022
|
||||
#define BOOT_ENTRY 022
|
||||
#define BOOT_INST 060
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
#define BOOT2_START 020
|
||||
#define BOOT2_ENTRY 033
|
||||
#define BOOT2_LEN (sizeof (boot2_rom) / sizeof (int16))
|
||||
|
||||
static const uint16 boot_rom[] = {
|
||||
06755, /* 22, SDN */
|
||||
05022, /* 23, JMP .-1 */
|
||||
07126, /* 24, CLL CML RTL ; read command + */
|
||||
01060, /* 25, TAD UNIT ; unit no */
|
||||
06751, /* 26, LCD ; load read+unit */
|
||||
07201, /* 27, CLA IAC ; AC = 1 */
|
||||
04053, /* 30, JMS LOAD ; load sector */
|
||||
04053, /* 31, JMS LOAD ; load track */
|
||||
07104, /* 32, CLL RAL ; AC = 2 */
|
||||
06755, /* 33, SDN */
|
||||
05054, /* 34, JMP LOAD+1 */
|
||||
06754, /* 35, SER */
|
||||
07450, /* 36, SNA ; more to do? */
|
||||
07610, /* 37, CLA SKP ; error */
|
||||
05046, /* 40, JMP 46 ; go empty */
|
||||
07402, /* 41-45, HALT ; error */
|
||||
07402,
|
||||
07402,
|
||||
07402,
|
||||
07402,
|
||||
06751, /* 46, LCD ; load empty */
|
||||
04053, /* 47, JMS LOAD ; get data */
|
||||
03002, /* 50, DCA 2 ; store */
|
||||
02050, /* 51, ISZ 50 ; incr store */
|
||||
05047, /* 52, JMP 47 ; loop until done */
|
||||
00000, /* LOAD, 0 */
|
||||
06753, /* 54, STR */
|
||||
05033, /* 55, JMP 33 */
|
||||
06752, /* 56, XDR */
|
||||
05453, /* 57, JMP I LOAD */
|
||||
07024, /* UNIT, CML RAL ; for unit 1 */
|
||||
06030 /* 61, KCC */
|
||||
};
|
||||
|
||||
static const uint16 boot2_rom[] = {
|
||||
01061, /* READ, TAD UNIT ; next unit+den */
|
||||
01046, /* 21, TAD CON360 ; add in 360 */
|
||||
00060, /* 22, AND CON420 ; mask to 420 */
|
||||
03061, /* 23, DCA UNIT ; 400,420,0,20... */
|
||||
07327, /* 24, STL CLA IAC RTL ; AC = 6 = read */
|
||||
01061, /* 25, TAD UNIT ; +unit+den */
|
||||
06751, /* 26, LCD ; load cmd */
|
||||
07201, /* 27, CLA IAC; ; AC = 1 = trksec */
|
||||
04053, /* 30, JMS LOAD ; load trk */
|
||||
04053, /* 31, JMS LOAD ; load sec */
|
||||
07004, /* CN7004, RAL ; AC = 2 = empty */
|
||||
06755, /* START, SDN ; done? */
|
||||
05054, /* 34, JMP LOAD+1 ; check xfr */
|
||||
06754, /* 35, SER ; error? */
|
||||
07450, /* 36, SNA ; AC=0 on start */
|
||||
05020, /* 37, JMP RD ; try next den,un */
|
||||
01061, /* 40, TAD UNIT ; +unit+den */
|
||||
06751, /* 41, LCD ; load cmd */
|
||||
01061, /* 42, TAD UNIT ; set 60 for sec boot */
|
||||
00046, /* 43, AND CON360 ; only density */
|
||||
01032, /* 44, TAD CN7004 ; magic */
|
||||
03060, /* 45, DCA 60 */
|
||||
00360, /* CON360, 360 ; NOP */
|
||||
04053, /* 47, JMS LOAD ; get data */
|
||||
03002, /* 50, DCA 2 ; store */
|
||||
02050, /* 51, ISZ .-1 ; incr store */
|
||||
05047, /* 52, JMP .-3 ; loop until done */
|
||||
00000, /* LOAD, 0 */
|
||||
06753, /* 54, STR ; xfr ready? */
|
||||
05033, /* 55, JMP 33 ; no, chk done */
|
||||
06752, /* 56, XDR ; get word */
|
||||
05453, /* 57, JMP I 53 ; return */
|
||||
00420, /* CON420, 420 ; toggle */
|
||||
00020 /* UNIT, 20 ; unit+density */
|
||||
};
|
||||
|
||||
t_stat rx_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
extern uint16 M[];
|
||||
|
||||
if (rx_dib.dev != DEV_RX) return STOP_NOTSTD; /* only std devno */
|
||||
if (rx_28) {
|
||||
for (i = 0; i < BOOT2_LEN; i++) M[BOOT2_START + i] = boot2_rom[i];
|
||||
saved_PC = BOOT2_ENTRY;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
M[BOOT_INST] = unitno? 07024: 07004;
|
||||
saved_PC = BOOT_ENTRY;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
584
simhv36-1/PDP8/pdp8_sys.c
Normal file
584
simhv36-1/PDP8/pdp8_sys.c
Normal file
@@ -0,0 +1,584 @@
|
||||
/* pdp8_sys.c: PDP-8 simulator interface
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
17-Oct-03 RMS Added TSC8-75, TD8E support, DECtape off reel message
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
30-Dec-01 RMS Revised for new TTX
|
||||
26-Nov-01 RMS Added RL8A support
|
||||
17-Sep-01 RMS Removed multiconsole support
|
||||
16-Sep-01 RMS Added TSS/8 packed char support, added KL8A support
|
||||
27-May-01 RMS Added multiconsole support
|
||||
18-Mar-01 RMS Added DF32 support
|
||||
14-Mar-01 RMS Added extension detection of RIM binary tapes
|
||||
15-Feb-01 RMS Added DECtape support
|
||||
30-Oct-00 RMS Added support for examine to file
|
||||
27-Oct-98 RMS V2.4 load interface
|
||||
10-Apr-98 RMS Added RIM loader support
|
||||
17-Feb-97 RMS Fixed bug in handling of bin loader fields
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern DEVICE tsc_dev;
|
||||
extern DEVICE ptr_dev, ptp_dev;
|
||||
extern DEVICE tti_dev, tto_dev;
|
||||
extern DEVICE clk_dev, lpt_dev;
|
||||
extern DEVICE rk_dev, rl_dev;
|
||||
extern DEVICE rx_dev;
|
||||
extern DEVICE df_dev, rf_dev;
|
||||
extern DEVICE dt_dev, td_dev;
|
||||
extern DEVICE mt_dev;
|
||||
extern DEVICE ttix_dev, ttox_dev;
|
||||
extern REG cpu_reg[];
|
||||
extern uint16 M[];
|
||||
extern int32 sim_switches;
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax maximum number of words for examine/deposit
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_consoles array of pointers to consoles (if more than one)
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "PDP-8";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 4;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&tsc_dev,
|
||||
&ptr_dev,
|
||||
&ptp_dev,
|
||||
&tti_dev,
|
||||
&tto_dev,
|
||||
&ttix_dev,
|
||||
&ttox_dev,
|
||||
&clk_dev,
|
||||
&lpt_dev,
|
||||
&rk_dev,
|
||||
&rl_dev,
|
||||
&rx_dev,
|
||||
&df_dev,
|
||||
&rf_dev,
|
||||
&dt_dev,
|
||||
&td_dev,
|
||||
&mt_dev,
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unimplemented instruction",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Non-standard device number",
|
||||
"DECtape off reel"
|
||||
};
|
||||
|
||||
/* Binary loader
|
||||
|
||||
Two loader formats are supported: RIM loader (-r) and BIN (-b) loader.
|
||||
|
||||
RIM loader format consists of alternating pairs of addresses and 12-bit
|
||||
words. It can only operate in field 0 and is not checksummed.
|
||||
|
||||
BIN loader format consists of a string of 12-bit words (made up from
|
||||
7-bit characters) between leader and trailer (200). The last word on
|
||||
tape is the checksum. A word with the "link" bit set is a new origin;
|
||||
a character > 0200 indicates a change of field.
|
||||
*/
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
int32 rubout, word, low, high, csum, newf, state, i;
|
||||
uint32 origin, field;
|
||||
|
||||
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
|
||||
rubout = state = field = newf = origin = csum = 0;
|
||||
if ((sim_switches & SWMASK ('R')) || /* RIM format? */
|
||||
(match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B')))) {
|
||||
while ((i = getc (fileref)) != EOF) {
|
||||
switch (state) {
|
||||
|
||||
case 0: /* leader */
|
||||
if ((i != 0) && (i < 0200)) state = 1;
|
||||
high = i;
|
||||
break;
|
||||
|
||||
case 1: /* low byte */
|
||||
word = (high << 6) | i; /* form word */
|
||||
if (word > 07777) origin = word & 07777;
|
||||
else M[origin] = word;
|
||||
state = 2;
|
||||
break;
|
||||
|
||||
case 2: /* high byte */
|
||||
if (i >= 0200) return SCPE_OK; /* end of tape? */
|
||||
high = i; /* save high */
|
||||
state = 1;
|
||||
break;
|
||||
} /* end switch */
|
||||
} /* end while */
|
||||
} /* end if */
|
||||
|
||||
else {
|
||||
while ((i = getc (fileref)) != EOF) { /* BIN format */
|
||||
if (rubout) {
|
||||
rubout = 0;
|
||||
continue;
|
||||
}
|
||||
if (i == 0377) {
|
||||
rubout = 1;
|
||||
continue;
|
||||
}
|
||||
if (i > 0200) {
|
||||
newf = (i & 070) << 9;
|
||||
continue;
|
||||
}
|
||||
switch (state) {
|
||||
|
||||
case 0: /* leader */
|
||||
if ((i != 0) && (i != 0200)) state = 1;
|
||||
high = i; /* save as high */
|
||||
break;
|
||||
|
||||
case 1: /* low byte */
|
||||
low = i;
|
||||
state = 2;
|
||||
break;
|
||||
|
||||
case 2: /* high with test */
|
||||
word = (high << 6) | low;
|
||||
if (i == 0200) { /* end of tape? */
|
||||
if ((csum - word) & 07777) return SCPE_CSUM;
|
||||
return SCPE_OK;
|
||||
}
|
||||
csum = csum + low + high;
|
||||
if (word >= 010000) origin = word & 07777;
|
||||
else {
|
||||
if ((field | origin) >= MEMSIZE)
|
||||
return SCPE_NXM;
|
||||
M[field | origin] = word & 07777;
|
||||
origin = (origin + 1) & 07777;
|
||||
}
|
||||
field = newf;
|
||||
high = i;
|
||||
state = 1;
|
||||
break;
|
||||
} /* end switch */
|
||||
} /* end while */
|
||||
} /* end else */
|
||||
return SCPE_FMT; /* eof? error */
|
||||
}
|
||||
|
||||
/* Symbol tables */
|
||||
|
||||
#define I_V_FL 18 /* flag start */
|
||||
#define I_M_FL 07 /* flag mask */
|
||||
#define I_V_NPN 0 /* no operand */
|
||||
#define I_V_FLD 1 /* field change */
|
||||
#define I_V_MRF 2 /* mem ref */
|
||||
#define I_V_IOT 3 /* general IOT */
|
||||
#define I_V_OP1 4 /* operate 1 */
|
||||
#define I_V_OP2 5 /* operate 2 */
|
||||
#define I_V_OP3 6 /* operate 3 */
|
||||
#define I_NPN (I_V_NPN << I_V_FL)
|
||||
#define I_FLD (I_V_FLD << I_V_FL)
|
||||
#define I_MRF (I_V_MRF << I_V_FL)
|
||||
#define I_IOT (I_V_IOT << I_V_FL)
|
||||
#define I_OP1 (I_V_OP1 << I_V_FL)
|
||||
#define I_OP2 (I_V_OP2 << I_V_FL)
|
||||
#define I_OP3 (I_V_OP3 << I_V_FL)
|
||||
|
||||
static const int32 masks[] = {
|
||||
07777, 07707, 07000, 07000,
|
||||
07416, 07571, 017457
|
||||
};
|
||||
|
||||
static const char *opcode[] = {
|
||||
"SKON", "ION", "IOF", "SRQ",
|
||||
"GTF", "RTF", "SGT", "CAF",
|
||||
"RPE", "RSF", "RRB", "RFC", "RFC RRB",
|
||||
"PCE", "PSF", "PCF", "PPC", "PLS",
|
||||
"KCF", "KSF", "KCC", "KRS", "KIE", "KRB",
|
||||
"TLF", "TSF", "TCF", "TPC", "SPI", "TLS",
|
||||
"SBE", "SPL", "CAL",
|
||||
"CLEI", "CLDI", "CLSC", "CLLE", "CLCL", "CLSK",
|
||||
"CINT", "RDF", "RIF", "RIB",
|
||||
"RMF", "SINT", "CUF", "SUF",
|
||||
"ADCL", "ADLM", "ADST", "ADRB",
|
||||
"ADSK", "ADSE", "ADLE", "ADRS",
|
||||
"DCMA", "DMAR", "DMAW",
|
||||
"DCIM", "DSAC", "DIML", "DIMA",
|
||||
"DCEA", "DEAL", "DEAC",
|
||||
"DFSE", "DFSC", "DISK", "DMAC",
|
||||
"DCXA", "DXAL", "DXAC",
|
||||
"PSKF", "PCLF", "PSKE",
|
||||
"PSTB", "PSIE", "PCLF PSTB", "PCIE",
|
||||
"LWCR", "CWCR", "LCAR",
|
||||
"CCAR", "LCMR", "LFGR", "LDBR",
|
||||
"RWCR", "CLT", "RCAR",
|
||||
"RMSR", "RCMR", "RFSR", "RDBR",
|
||||
"SKEF", "SKCB", "SKJD", "SKTR", "CLF",
|
||||
"DSKP", "DCLR", "DLAG",
|
||||
"DLCA", "DRST", "DLDC", "DMAN",
|
||||
"LCD", "XDR", "STR",
|
||||
"SER", "SDN", "INTR", "INIT",
|
||||
"DTRA", "DTCA", "DTXA", "DTLA",
|
||||
"DTSF", "DTRB", "DTLB",
|
||||
"RLDC", "RLSD", "RLMA", "RLCA",
|
||||
"RLCB", "RLSA", "RLWC",
|
||||
"RRER", "RRWC", "RRCA", "RRCB",
|
||||
"RRSA", "RRSI", "RLSE",
|
||||
"ETDS", "ESKP", "ECTF", "ECDF",
|
||||
"ERTB", "ESME", "ERIOT", "ETEN",
|
||||
|
||||
"CDF", "CIF", "CIF CDF",
|
||||
"AND", "TAD", "ISZ", "DCA", "JMS", "JMP", "IOT",
|
||||
"NOP", "NOP2", "NOP3", "SWAB", "SWBA",
|
||||
"STL", "GLK", "STA", "LAS", "CIA",
|
||||
"BSW", "RAL", "RTL", "RAR", "RTR", "RAL RAR", "RTL RTR",
|
||||
"SKP", "SNL", "SZL",
|
||||
"SZA", "SNA", "SZA SNL", "SNA SZL",
|
||||
"SMA", "SPA", "SMA SNL", "SPA SZL",
|
||||
"SMA SZA", "SPA SNA", "SMA SZA SNL", "SPA SNA SZL",
|
||||
"SCL", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",
|
||||
"SCA", "SCA SCL", "SCA MUY", "SCA DVI",
|
||||
"SCA NMI", "SCA SHL", "SCA ASR", "SCA LSR",
|
||||
"ACS", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",
|
||||
"SCA", "DAD", "DST", "SWBA",
|
||||
"DPSZ", "DPIC", "DCIM", "SAM",
|
||||
"CLA", "CLL", "CMA", "CML", "IAC", /* encode only */
|
||||
"CLA", "OAS", "HLT",
|
||||
"CLA", "MQA", "MQL",
|
||||
NULL, NULL, NULL, NULL, /* decode only */
|
||||
NULL
|
||||
};
|
||||
|
||||
static const int32 opc_val[] = {
|
||||
06000+I_NPN, 06001+I_NPN, 06002+I_NPN, 06003+I_NPN,
|
||||
06004+I_NPN, 06005+I_NPN, 06006+I_NPN, 06007+I_NPN,
|
||||
06010+I_NPN, 06011+I_NPN, 06012+I_NPN, 06014+I_NPN, 06016+I_NPN,
|
||||
06020+I_NPN, 06021+I_NPN, 06022+I_NPN, 06024+I_NPN, 06026+I_NPN,
|
||||
06030+I_NPN, 06031+I_NPN, 06032+I_NPN, 06034+I_NPN, 06035+I_NPN, 06036+I_NPN,
|
||||
06040+I_NPN, 06041+I_NPN, 06042+I_NPN, 06044+I_NPN, 06045+I_NPN, 06046+I_NPN,
|
||||
06101+I_NPN, 06102+I_NPN, 06103+I_NPN,
|
||||
06131+I_NPN, 06132+I_NPN, 06133+I_NPN, 06135+I_NPN, 06136+I_NPN, 06137+I_NPN,
|
||||
06204+I_NPN, 06214+I_NPN, 06224+I_NPN, 06234+I_NPN,
|
||||
06244+I_NPN, 06254+I_NPN, 06264+I_NPN, 06274+I_NPN,
|
||||
06530+I_NPN, 06531+I_NPN, 06532+I_NPN, 06533+I_NPN,
|
||||
06534+I_NPN, 06535+I_NPN, 06536+I_NPN, 06537+I_NPN,
|
||||
06601+I_NPN, 06603+I_NPN, 06605+I_NPN,
|
||||
06611+I_NPN, 06612+I_NPN, 06615+I_NPN, 06616+I_NPN,
|
||||
06611+I_NPN, 06615+I_NPN, 06616+I_NPN,
|
||||
06621+I_NPN, 06622+I_NPN, 06623+I_NPN, 06626+I_NPN,
|
||||
06641+I_NPN, 06643+I_NPN, 06645+I_NPN,
|
||||
06661+I_NPN, 06662+I_NPN, 06663+I_NPN,
|
||||
06664+I_NPN, 06665+I_NPN, 06666+I_NPN, 06667+I_NPN,
|
||||
06701+I_NPN, 06702+I_NPN, 06703+I_NPN,
|
||||
06704+I_NPN, 06705+I_NPN, 06706+I_NPN, 06707+I_NPN,
|
||||
06711+I_NPN, 06712+I_NPN, 06713+I_NPN,
|
||||
06714+I_NPN, 06715+I_NPN, 06716+I_NPN, 06717+I_NPN,
|
||||
06721+I_NPN, 06722+I_NPN, 06723+I_NPN, 06724+I_NPN, 06725+I_NPN,
|
||||
06741+I_NPN, 06742+I_NPN, 06743+I_NPN,
|
||||
06744+I_NPN, 06745+I_NPN, 06746+I_NPN, 06747+I_NPN,
|
||||
06751+I_NPN, 06752+I_NPN, 06753+I_NPN,
|
||||
06754+I_NPN, 06755+I_NPN, 06756+I_NPN, 06757+I_NPN,
|
||||
06761+I_NPN, 06762+I_NPN, 06764+I_NPN, 06766+I_NPN,
|
||||
06771+I_NPN, 06772+I_NPN, 06774+I_NPN,
|
||||
06600+I_NPN, 06601+I_NPN, 06602+I_NPN, 06603+I_NPN,
|
||||
06604+I_NPN, 06605+I_NPN, 06607+I_NPN,
|
||||
06610+I_NPN, 06611+I_NPN, 06612+I_NPN, 06613+I_NPN,
|
||||
06614+I_NPN, 06615+I_NPN, 06617+I_NPN,
|
||||
06360+I_NPN, 06361+I_NPN, 06362+I_NPN, 06363+I_NPN,
|
||||
06364+I_NPN, 06365+I_NPN, 06366+I_NPN, 06367+I_NPN,
|
||||
|
||||
06201+I_FLD, 06202+I_FLD, 06203+I_FLD,
|
||||
00000+I_MRF, 01000+I_MRF, 02000+I_MRF, 03000+I_MRF,
|
||||
04000+I_MRF, 05000+I_MRF, 06000+I_IOT,
|
||||
07000+I_NPN, 07400+I_NPN, 07401+I_NPN, 07431+I_NPN, 07447+I_NPN,
|
||||
07120+I_NPN, 07204+I_NPN, 07240+I_NPN, 07604+I_NPN, 07041+I_NPN,
|
||||
07002+I_OP1, 07004+I_OP1, 07006+I_OP1,
|
||||
07010+I_OP1, 07012+I_OP1, 07014+I_OP1, 07016+I_OP1,
|
||||
07410+I_OP2, 07420+I_OP2, 07430+I_OP2,
|
||||
07440+I_OP2, 07450+I_OP2, 07460+I_OP2, 07470+I_OP2,
|
||||
07500+I_OP2, 07510+I_OP2, 07520+I_OP2, 07530+I_OP2,
|
||||
07540+I_OP2, 07550+I_OP2, 07560+I_OP2, 07570+I_OP2,
|
||||
07403+I_OP3, 07405+I_OP3, 07407+I_OP3,
|
||||
07411+I_OP3, 07413+I_OP3, 07415+I_OP3, 07417+I_OP3,
|
||||
07441+I_OP3, 07443+I_OP3, 07445+I_OP3, 07447+I_OP3,
|
||||
07451+I_OP3, 07453+I_OP3, 07455+I_OP3, 07457+I_OP3,
|
||||
017403+I_OP3, 017405+I_OP3, 0174017+I_OP3,
|
||||
017411+I_OP3, 017413+I_OP3, 017415+I_OP3, 017417+I_OP3,
|
||||
017441+I_OP3, 017443+I_OP3, 017445+I_OP3, 017447+I_OP3,
|
||||
017451+I_OP3, 017453+I_OP3, 017455+I_OP3, 017457+I_OP3,
|
||||
07200+I_OP1, 07100+I_OP1, 07040+I_OP1, 07020+I_OP1, 07001+I_OP1,
|
||||
07600+I_OP2, 07404+I_OP2, 07402+I_OP2,
|
||||
07601+I_OP3, 07501+I_OP3, 07421+I_OP3,
|
||||
07000+I_OP1, 07400+I_OP2, 07401+I_OP3, 017401+I_OP3,
|
||||
-1
|
||||
};
|
||||
|
||||
/* Operate decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
inst = mask bits
|
||||
class = instruction class code
|
||||
sp = space needed?
|
||||
Outputs:
|
||||
status = space needed
|
||||
*/
|
||||
|
||||
int32 fprint_opr (FILE *of, int32 inst, int32 class, int32 sp)
|
||||
{
|
||||
int32 i, j;
|
||||
|
||||
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
|
||||
if ((j == class) && (opc_val[i] & inst)) { /* same class? */
|
||||
inst = inst & ~opc_val[i]; /* mask bit set? */
|
||||
fprintf (of, (sp? " %s": "%s"), opcode[i]);
|
||||
sp = 1;
|
||||
}
|
||||
}
|
||||
return sp;
|
||||
}
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to data
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = status code
|
||||
*/
|
||||
|
||||
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
|
||||
#define SIXTOASC(x) (((x) >= 040)? (x): (x) + 0100)
|
||||
#define TSSTOASC(x) ((x) + 040)
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 cflag, i, j, sp, inst, disp;
|
||||
extern int32 emode;
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
inst = val[0];
|
||||
if (sw & SWMASK ('A')) { /* ASCII? */
|
||||
if (inst > 0377) return SCPE_ARG;
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK;
|
||||
}
|
||||
if (sw & SWMASK ('C')) { /* characters? */
|
||||
fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077));
|
||||
fprintf (of, "%c", SIXTOASC (inst & 077));
|
||||
return SCPE_OK;
|
||||
}
|
||||
if (sw & SWMASK ('T')) { /* TSS8 packed? */
|
||||
fprintf (of, "%c", TSSTOASC ((inst >> 6) & 077));
|
||||
fprintf (of, "%c", TSSTOASC (inst & 077));
|
||||
return SCPE_OK;
|
||||
}
|
||||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||||
|
||||
/* Instruction decode */
|
||||
|
||||
inst = val[0] | ((emode & 1) << 12); /* include EAE mode */
|
||||
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] & 017777) == (inst & masks[j])) { /* match? */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
|
||||
case I_V_NPN: /* no operands */
|
||||
fprintf (of, "%s", opcode[i]); /* opcode */
|
||||
break;
|
||||
|
||||
case I_V_FLD: /* field change */
|
||||
fprintf (of, "%s %-o", opcode[i], (inst >> 3) & 07);
|
||||
break;
|
||||
|
||||
case I_V_MRF: /* mem ref */
|
||||
disp = inst & 0177; /* displacement */
|
||||
fprintf (of, "%s%s", opcode[i], ((inst & 00400)? " I ": " "));
|
||||
if (inst & 0200) { /* current page? */
|
||||
if (cflag) fprintf (of, "%-o", (addr & 07600) | disp);
|
||||
else fprintf (of, "C %-o", disp);
|
||||
}
|
||||
else fprintf (of, "%-o", disp); /* page zero */
|
||||
break;
|
||||
|
||||
case I_V_IOT: /* IOT */
|
||||
fprintf (of, "%s %-o", opcode[i], inst & 0777);
|
||||
break;
|
||||
|
||||
case I_V_OP1: /* operate group 1 */
|
||||
sp = fprint_opr (of, inst & 0361, j, 0);
|
||||
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
|
||||
break;
|
||||
|
||||
case I_V_OP2: /* operate group 2 */
|
||||
if (opcode[i]) fprintf (of, "%s", opcode[i]); /* skips */
|
||||
fprint_opr (of, inst & 0206, j, opcode[i] != NULL);
|
||||
break;
|
||||
|
||||
case I_V_OP3: /* operate group 3 */
|
||||
sp = fprint_opr (of, inst & 0320, j, 0);
|
||||
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
|
||||
break;
|
||||
} /* end case */
|
||||
|
||||
return SCPE_OK;
|
||||
} /* end if */
|
||||
} /* end for */
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 cflag, d, i, j, k;
|
||||
t_stat r;
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||||
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (t_value) cptr[0] | 0200;
|
||||
return SCPE_OK;
|
||||
}
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (((t_value) cptr[0] & 077) << 6) |
|
||||
((t_value) cptr[1] & 077);
|
||||
return SCPE_OK;
|
||||
}
|
||||
if ((sw & SWMASK ('T')) || ((*cptr == '"') && cptr++)) { /* TSS8 string? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (((t_value) (cptr[0] - 040) & 077) << 6) |
|
||||
((t_value) (cptr[1] - 040) & 077);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Instruction parse */
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
|
||||
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
if (opcode[i] == NULL) return SCPE_ARG;
|
||||
val[0] = opc_val[i] & 07777; /* get value */
|
||||
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
|
||||
case I_V_IOT: /* IOT */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get dev+pulse */
|
||||
d = get_uint (gbuf, 8, 0777, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | d;
|
||||
break;
|
||||
|
||||
case I_V_FLD: /* field */
|
||||
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
|
||||
cptr = get_glyph (cptr, gbuf, 0)) {
|
||||
for (i = 0; (opcode[i] != NULL) &&
|
||||
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
if (opcode[i] != NULL) {
|
||||
k = (opc_val[i] >> I_V_FL) & I_M_FL;
|
||||
if (k != j) return SCPE_ARG;
|
||||
val[0] = val[0] | (opc_val[i] & 07777);
|
||||
}
|
||||
else {
|
||||
d = get_uint (gbuf, 8, 07, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | (d << 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case I_V_MRF: /* mem ref */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
|
||||
if (strcmp (gbuf, "I") == 0) { /* indirect? */
|
||||
val[0] = val[0] | 0400;
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
}
|
||||
if ((k = (strcmp (gbuf, "C") == 0)) || (strcmp (gbuf, "Z") == 0)) {
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
d = get_uint (gbuf, 8, 0177, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | d | (k? 0200: 0);
|
||||
}
|
||||
else {
|
||||
d = get_uint (gbuf, 8, 07777, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
if (d <= 0177) val[0] = val[0] | d;
|
||||
else if (cflag && (((addr ^ d) & 07600) == 0))
|
||||
val[0] = val[0] | (d & 0177) | 0200;
|
||||
else return SCPE_ARG;
|
||||
}
|
||||
break;
|
||||
|
||||
case I_V_NPN: case I_V_OP1: case I_V_OP2: case I_V_OP3: /* operates */
|
||||
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
|
||||
cptr = get_glyph (cptr, gbuf, 0)) {
|
||||
for (i = 0; (opcode[i] != NULL) &&
|
||||
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
k = opc_val[i] & 07777;
|
||||
if ((opcode[i] == NULL) || (((k ^ val[0]) & 07000) != 0))
|
||||
return SCPE_ARG;
|
||||
val[0] = val[0] | k;
|
||||
}
|
||||
break;
|
||||
} /* end case */
|
||||
|
||||
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
913
simhv36-1/PDP8/pdp8_td.c
Normal file
913
simhv36-1/PDP8/pdp8_td.c
Normal file
@@ -0,0 +1,913 @@
|
||||
/* pdp8_td.c: PDP-8 simple DECtape controller (TD8E) simulator
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This module was inspired by Gerold Pauler's TD8E simulator for Doug Jones'
|
||||
PDP8 simulator but tracks the hardware implementation more closely.
|
||||
|
||||
td TD8E/TU56 DECtape
|
||||
|
||||
23-Jun-06 RMS Fixed switch conflict in ATTACH
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR
|
||||
|
||||
PDP-8 DECtapes are represented in memory by fixed length buffer of 12b words.
|
||||
Three file formats are supported:
|
||||
|
||||
18b/36b 256 words per block [256 x 18b]
|
||||
16b 256 words per block [256 x 16b]
|
||||
12b 129 words per block [129 x 12b]
|
||||
|
||||
When a 16b or 18/36b DECtape file is read in, it is converted to 12b 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 (as
|
||||
taken from the TD8E formatter) is:
|
||||
|
||||
reverse end zone 8192 reverse end zone codes ~ 10 feet
|
||||
reverse buffer 200 interblock codes
|
||||
block 0
|
||||
:
|
||||
block n
|
||||
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
|
||||
standard block length of 256 words; the PDP-8 uses a standard block length
|
||||
of 86 words (x 18b = 129 words x 12b).
|
||||
|
||||
Because a DECtape file only contains data, the simulator cannot support
|
||||
write timing and mark track and can only do a limited implementation
|
||||
of non-data words. Read assumes that the tape has been conventionally
|
||||
written forward:
|
||||
|
||||
header word 0 0
|
||||
header word 1 block number (for forward reads)
|
||||
header words 2,3 0
|
||||
header word 4 checksum (for reverse reads)
|
||||
:
|
||||
trailer word 4 checksum (for forward reads)
|
||||
trailer words 3,2 0
|
||||
trailer word 1 block number (for reverse reads)
|
||||
trailer word 0 0
|
||||
|
||||
Write modifies only the data words and dumps the non-data words in the
|
||||
bit bucket.
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
#define DT_NUMDR 2 /* #drives */
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */
|
||||
#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define UNIT_8FMT (1 << UNIT_V_8FMT)
|
||||
#define UNIT_11FMT (1 << UNIT_V_11FMT)
|
||||
#define STATE u3 /* unit state */
|
||||
#define LASTT u4 /* last time update */
|
||||
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||
|
||||
/* System independent DECtape constants */
|
||||
|
||||
#define DT_LPERMC 6 /* lines per mark track */
|
||||
#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */
|
||||
#define DT_BFLIN (200 * DT_LPERMC) /* end zone buffer */
|
||||
#define DT_HTLIN (5 * DT_LPERMC) /* lines per hdr/trlr */
|
||||
|
||||
/* 16b, 18b, 36b DECtape constants */
|
||||
|
||||
#define D18_WSIZE 6 /* word sizein lines */
|
||||
#define D18_BSIZE 384 /* block size in 12b */
|
||||
#define D18_TSIZE 578 /* tape size */
|
||||
#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN)
|
||||
#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE))
|
||||
#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */
|
||||
|
||||
#define D18_NBSIZE ((D18_BSIZE * D8_WSIZE) / D18_WSIZE)
|
||||
#define D18_FILSIZ (D18_NBSIZE * D18_TSIZE * sizeof (int32))
|
||||
#define D11_FILSIZ (D18_NBSIZE * D18_TSIZE * sizeof (int16))
|
||||
|
||||
/* 12b DECtape constants */
|
||||
|
||||
#define D8_WSIZE 4 /* word size in lines */
|
||||
#define D8_BSIZE 129 /* block size in 12b */
|
||||
#define D8_TSIZE 1474 /* tape size */
|
||||
#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN)
|
||||
#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE))
|
||||
#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */
|
||||
#define D8_FILSIZ (D8_CAPAC * sizeof (int16))
|
||||
|
||||
/* This controller */
|
||||
|
||||
#define DT_CAPAC D8_CAPAC /* default */
|
||||
#define DT_WSIZE D8_WSIZE
|
||||
|
||||
/* Calculated constants, per unit */
|
||||
|
||||
#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE)
|
||||
#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE)
|
||||
#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB)
|
||||
#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ)
|
||||
#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC)
|
||||
|
||||
#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u))
|
||||
#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u))
|
||||
|
||||
/* Command register */
|
||||
|
||||
#define TDC_UNIT 04000 /* unit select */
|
||||
#define TDC_FWDRV 02000 /* fwd/rev */
|
||||
#define TDC_STPGO 01000 /* stop/go */
|
||||
#define TDC_RW 00400 /* read/write */
|
||||
#define TDC_MASK 07400 /* implemented */
|
||||
#define TDC_GETUNIT(x) (((x) & TDC_UNIT)? 1: 0)
|
||||
|
||||
/* Status register */
|
||||
|
||||
#define TDS_WLO 00200 /* write lock */
|
||||
#define TDS_TME 00100 /* timing/sel err */
|
||||
|
||||
/* Mark track register and codes */
|
||||
|
||||
#define MTK_MASK 077
|
||||
#define MTK_REV_END 055 /* rev end zone */
|
||||
#define MTK_INTER 025 /* interblock */
|
||||
#define MTK_FWD_BLK 026 /* fwd block */
|
||||
#define MTK_REV_GRD 032 /* reverse guard */
|
||||
#define MTK_FWD_PRE 010 /* lock, etc */
|
||||
#define MTK_DATA 070 /* data */
|
||||
#define MTK_REV_PRE 073 /* lock, etc */
|
||||
#define MTK_FWD_GRD 051 /* fwd guard */
|
||||
#define MTK_REV_BLK 045 /* rev block */
|
||||
#define MTK_FWD_END 022 /* fwd end zone */
|
||||
|
||||
/* DECtape state */
|
||||
|
||||
#define STA_STOP 0 /* stopped */
|
||||
#define STA_DEC 2 /* decelerating */
|
||||
#define STA_ACC 4 /* accelerating */
|
||||
#define STA_UTS 6 /* up to speed */
|
||||
#define STA_DIR 1 /* fwd/rev */
|
||||
|
||||
#define ABS(x) (((x) < 0)? (-(x)): (x))
|
||||
#define MTK_BIT(c,p) (((c) >> (DT_LPERMC - 1 - ((p) % DT_LPERMC))) & 1)
|
||||
|
||||
/* State and declarations */
|
||||
|
||||
int32 td_cmd = 0; /* command */
|
||||
int32 td_dat = 0; /* data */
|
||||
int32 td_mtk = 0; /* mark track */
|
||||
int32 td_slf = 0; /* single line flag */
|
||||
int32 td_qlf = 0; /* quad line flag */
|
||||
int32 td_tme = 0; /* timing error flag */
|
||||
int32 td_csum = 0; /* save check sum */
|
||||
int32 td_qlctr = 0; /* quad line ctr */
|
||||
int32 td_ltime = 20; /* interline time */
|
||||
int32 td_dctime = 40000; /* decel time */
|
||||
int32 td_stopoffr = 0;
|
||||
static uint8 tdb_mtk[DT_NUMDR][D18_LPERB]; /* mark track bits */
|
||||
|
||||
DEVICE td_dev;
|
||||
int32 td77 (int32 IR, int32 AC);
|
||||
t_stat td_svc (UNIT *uptr);
|
||||
t_stat td_reset (DEVICE *dptr);
|
||||
t_stat td_attach (UNIT *uptr, char *cptr);
|
||||
t_stat td_detach (UNIT *uptr);
|
||||
t_stat td_boot (int32 unitno, DEVICE *dptr);
|
||||
t_bool td_newsa (int32 newf);
|
||||
t_bool td_setpos (UNIT *uptr);
|
||||
int32 td_header (UNIT *uptr, int32 blk, int32 line);
|
||||
int32 td_trailer (UNIT *uptr, int32 blk, int32 line);
|
||||
int32 td_read (UNIT *uptr, int32 blk, int32 line);
|
||||
void td_write (UNIT *uptr, int32 blk, int32 line, int32 datb);
|
||||
int32 td_set_mtk (int32 code, int32 u, int32 k);
|
||||
t_stat td_show_pos (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 sim_switches;
|
||||
extern int32 sim_is_running;
|
||||
|
||||
/* TD data structures
|
||||
|
||||
td_dev DT device descriptor
|
||||
td_unit DT unit list
|
||||
td_reg DT register list
|
||||
td_mod DT modifier list
|
||||
*/
|
||||
|
||||
DIB td_dib = { DEV_TD8E, 1, { &td77 } };
|
||||
|
||||
UNIT td_unit[] = {
|
||||
{ UDATA (&td_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
|
||||
UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
|
||||
{ UDATA (&td_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
|
||||
UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }
|
||||
};
|
||||
|
||||
REG td_reg[] = {
|
||||
{ GRDATA (TDCMD, td_cmd, 8, 4, 8) },
|
||||
{ ORDATA (TDDAT, td_dat, 12) },
|
||||
{ ORDATA (TDMTK, td_mtk, 6) },
|
||||
{ FLDATA (TDSLF, td_slf, 0) },
|
||||
{ FLDATA (TDQLF, td_qlf, 0) },
|
||||
{ FLDATA (TDTME, td_tme, 0) },
|
||||
{ ORDATA (TDQL, td_qlctr, 2) },
|
||||
{ ORDATA (TDCSUM, td_csum, 6), REG_RO },
|
||||
{ DRDATA (LTIME, td_ltime, 31), REG_NZ | PV_LEFT },
|
||||
{ DRDATA (DCTIME, td_dctime, 31), REG_NZ | PV_LEFT },
|
||||
{ URDATA (POS, td_unit[0].pos, 10, T_ADDR_W, 0,
|
||||
DT_NUMDR, PV_LEFT | REG_RO) },
|
||||
{ URDATA (STATT, td_unit[0].STATE, 8, 18, 0,
|
||||
DT_NUMDR, REG_RO) },
|
||||
{ URDATA (LASTT, td_unit[0].LASTT, 10, 32, 0,
|
||||
DT_NUMDR, REG_HRO) },
|
||||
{ FLDATA (STOP_OFFR, td_stopoffr, 0) },
|
||||
{ ORDATA (DEVNUM, td_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB td_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL },
|
||||
{ UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL },
|
||||
{ UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "POSITION", NULL, NULL, &td_show_pos },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE td_dev = {
|
||||
"TD", td_unit, td_reg, td_mod,
|
||||
DT_NUMDR, 8, 24, 1, 8, 12,
|
||||
NULL, NULL, &td_reset,
|
||||
&td_boot, &td_attach, &td_detach,
|
||||
&td_dib, DEV_DISABLE | DEV_DIS
|
||||
};
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 td77 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
int32 u = TDC_GETUNIT (td_cmd); /* get unit */
|
||||
int32 diff, t;
|
||||
|
||||
switch (pulse) {
|
||||
|
||||
case 01: /* SDSS */
|
||||
if (td_slf) return AC | IOT_SKP;
|
||||
break;
|
||||
|
||||
case 02: /* SDST */
|
||||
if (td_tme) return AC | IOT_SKP;
|
||||
break;
|
||||
|
||||
case 03: /* SDSQ */
|
||||
if (td_qlf) return AC | IOT_SKP;
|
||||
break;
|
||||
|
||||
case 04: /* SDLC */
|
||||
td_tme = 0; /* clear tim err */
|
||||
diff = (td_cmd ^ AC) & TDC_MASK; /* cmd changes */
|
||||
td_cmd = AC & TDC_MASK; /* update cmd */
|
||||
if ((diff != 0) && (diff != TDC_RW)) { /* signif change? */
|
||||
if (td_newsa (td_cmd)) /* new command */
|
||||
return AC | (IORETURN (td_stopoffr, STOP_DTOFF) << IOT_V_REASON);
|
||||
}
|
||||
break;
|
||||
|
||||
case 05: /* SDLD */
|
||||
td_slf = 0; /* clear flags */
|
||||
td_qlf = 0;
|
||||
td_qlctr = 0;
|
||||
td_dat = AC; /* load data reg */
|
||||
break;
|
||||
|
||||
case 06: /* SDRC */
|
||||
td_slf = 0; /* clear flags */
|
||||
td_qlf = 0;
|
||||
td_qlctr = 0;
|
||||
t = td_cmd | td_mtk; /* form status */
|
||||
if (td_tme || !(td_unit[u].flags & UNIT_ATT)) /* tim/sel err? */
|
||||
t = t | TDS_TME;
|
||||
if (td_unit[u].flags & UNIT_WPRT) /* write locked? */
|
||||
t = t | TDS_WLO;
|
||||
return t; /* return status */
|
||||
|
||||
case 07: /* SDRD */
|
||||
td_slf = 0; /* clear flags */
|
||||
td_qlf = 0;
|
||||
td_qlctr = 0;
|
||||
return td_dat; /* return data */
|
||||
}
|
||||
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Command register change (start/stop, forward/reverse, new unit)
|
||||
|
||||
1. If change in motion, stop to start
|
||||
- schedule up to speed
|
||||
- set function as next state
|
||||
2. If change in motion, start to stop, or change in direction
|
||||
- schedule stop
|
||||
*/
|
||||
|
||||
t_bool td_newsa (int32 newf)
|
||||
{
|
||||
int32 prev_mving, new_mving, prev_dir, new_dir;
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = td_dev.units + TDC_GETUNIT (newf); /* new unit */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return FALSE; /* new unit attached? */
|
||||
|
||||
new_mving = ((newf & TDC_STPGO) != 0); /* new moving? */
|
||||
prev_mving = (uptr->STATE != STA_STOP); /* previous moving? */
|
||||
new_dir = ((newf & TDC_FWDRV) != 0); /* new dir? */
|
||||
prev_dir = ((uptr->STATE & STA_DIR) != 0); /* previous dir? */
|
||||
|
||||
td_mtk = 0; /* mark trk reg cleared */
|
||||
|
||||
if (!prev_mving && !new_mving) return FALSE; /* stop from stop? */
|
||||
|
||||
if (new_mving && !prev_mving) { /* start from stop? */
|
||||
if (td_setpos (uptr)) return TRUE; /* update pos */
|
||||
sim_cancel (uptr); /* stop current */
|
||||
sim_activate (uptr, td_dctime - (td_dctime >> 2)); /* sched accel */
|
||||
uptr->STATE = STA_ACC | new_dir; /* set status */
|
||||
td_slf = td_qlf = td_qlctr = 0; /* clear state */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((prev_mving && !new_mving) || /* stop from moving? */
|
||||
(prev_dir != new_dir)) { /* dir chg while moving? */
|
||||
if (uptr->STATE >= STA_ACC) { /* not stopping? */
|
||||
if (td_setpos (uptr)) return TRUE; /* update pos */
|
||||
sim_cancel (uptr); /* stop current */
|
||||
sim_activate (uptr, td_dctime); /* schedule decel */
|
||||
uptr->STATE = STA_DEC | prev_dir; /* set status */
|
||||
td_slf = td_qlf = td_qlctr = 0; /* clear state */
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Update DECtape position
|
||||
|
||||
DECtape motion is modeled as a constant velocity, with linear
|
||||
acceleration and deceleration. The motion equations are as follows:
|
||||
|
||||
t = time since operation started
|
||||
tmax = time for operation (accel, decel only)
|
||||
v = at speed velocity in lines (= 1/td_ltime)
|
||||
|
||||
Then:
|
||||
at speed dist = t * v
|
||||
accel dist = (t^2 * v) / (2 * tmax)
|
||||
decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax)
|
||||
|
||||
This routine uses the relative (integer) time, rather than the absolute
|
||||
(floating point) time, to allow save and restore of the start times.
|
||||
*/
|
||||
|
||||
t_bool td_setpos (UNIT *uptr)
|
||||
{
|
||||
uint32 new_time, ut, ulin, udelt;
|
||||
int32 delta;
|
||||
|
||||
new_time = sim_grtime (); /* current time */
|
||||
ut = new_time - uptr->LASTT; /* elapsed time */
|
||||
if (ut == 0) return FALSE; /* no time gone? exit */
|
||||
uptr->LASTT = new_time; /* update last time */
|
||||
switch (uptr->STATE & ~STA_DIR) { /* case on motion */
|
||||
|
||||
case STA_STOP: /* stop */
|
||||
delta = 0;
|
||||
break;
|
||||
|
||||
case STA_DEC: /* slowing */
|
||||
ulin = ut / (uint32) td_ltime;
|
||||
udelt = td_dctime / td_ltime;
|
||||
delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
|
||||
break;
|
||||
|
||||
case STA_ACC: /* accelerating */
|
||||
ulin = ut / (uint32) td_ltime;
|
||||
udelt = (td_dctime - (td_dctime >> 2)) / td_ltime;
|
||||
delta = (ulin * ulin) / (2 * udelt);
|
||||
break;
|
||||
|
||||
case STA_UTS: /* at speed */
|
||||
delta = ut / (uint32) td_ltime;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uptr->STATE & STA_DIR) uptr->pos = uptr->pos - delta; /* update pos */
|
||||
else uptr->pos = uptr->pos + delta;
|
||||
if (((int32) uptr->pos < 0) ||
|
||||
((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) {
|
||||
detach_unit (uptr); /* off reel */
|
||||
sim_cancel (uptr); /* no timing pulses */
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Unit service - unit is either changing speed, or it is up to speed */
|
||||
|
||||
t_stat td_svc (UNIT *uptr)
|
||||
{
|
||||
int32 mot = uptr->STATE & ~STA_DIR;
|
||||
int32 dir = uptr->STATE & STA_DIR;
|
||||
int32 unum = uptr - td_dev.units;
|
||||
int32 su = TDC_GETUNIT (td_cmd);
|
||||
int32 mtkb, datb;
|
||||
|
||||
/* Motion cases
|
||||
|
||||
Decelerating - if go, next state must be accel as specified by td_cmd
|
||||
Accelerating - next state must be up to speed, fall through
|
||||
Up to speed - process line */
|
||||
|
||||
if (mot == STA_STOP) return SCPE_OK; /* stopped? done */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
|
||||
uptr->STATE = uptr->pos = 0; /* also done */
|
||||
return SCPE_UNATT;
|
||||
}
|
||||
|
||||
switch (mot) { /* case on motion */
|
||||
|
||||
case STA_DEC: /* deceleration */
|
||||
if (td_setpos (uptr)) /* upd pos; off reel? */
|
||||
return IORETURN (td_stopoffr, STOP_DTOFF);
|
||||
if ((unum != su) || !(td_cmd & TDC_STPGO)) /* not sel or stop? */
|
||||
uptr->STATE = 0; /* stop */
|
||||
else { /* selected and go */
|
||||
uptr->STATE = STA_ACC | /* accelerating */
|
||||
((td_cmd & TDC_FWDRV)? STA_DIR: 0); /* in new dir */
|
||||
sim_activate (uptr, td_dctime - (td_dctime >> 2));
|
||||
}
|
||||
return SCPE_OK;
|
||||
|
||||
case STA_ACC: /* accelerating */
|
||||
if (td_setpos (uptr)) /* upd pos; off reel? */
|
||||
return IORETURN (td_stopoffr, STOP_DTOFF);
|
||||
uptr->STATE = STA_UTS | dir; /* set up to speed */
|
||||
break;
|
||||
|
||||
case STA_UTS: /* up to speed */
|
||||
if (dir) uptr->pos = uptr->pos - 1; /* adjust position */
|
||||
else uptr->pos = uptr->pos + 1;
|
||||
uptr->LASTT = sim_grtime (); /* save time */
|
||||
if (((int32) uptr->pos < 0) || /* off reel? */
|
||||
(uptr->pos >= (((uint32) DTU_FWDEZ (uptr)) + DT_EZLIN))) {
|
||||
detach_unit (uptr);
|
||||
return IORETURN (td_stopoffr, STOP_DTOFF);
|
||||
}
|
||||
break; /* check function */
|
||||
}
|
||||
|
||||
/* At speed - process the current line
|
||||
|
||||
Once the TD8E is running at speed, it operates line by line. If reading,
|
||||
the current mark track bit is shifted into the mark track register, and
|
||||
the current data nibble (3b) is shifted into the data register. If
|
||||
writing, the current mark track bit is shifted into the mark track
|
||||
register, the top nibble from the data register is written to tape, and
|
||||
the data register is shifted up. The complexity here comes from
|
||||
synthesizing the mark track, based on tape position, and the header data. */
|
||||
|
||||
sim_activate (uptr, td_ltime); /* sched next line */
|
||||
if (unum != su) return SCPE_OK; /* not sel? done */
|
||||
td_slf = 1; /* set single */
|
||||
td_qlctr = (td_qlctr + 1) % DT_WSIZE; /* count words */
|
||||
if (td_qlctr == 0) { /* lines mod 4? */
|
||||
if (td_qlf) { /* quad line set? */
|
||||
td_tme = 1; /* timing error */
|
||||
td_cmd = td_cmd & ~TDC_RW; /* clear write */
|
||||
}
|
||||
else td_qlf = 1; /* no, set quad */
|
||||
}
|
||||
|
||||
datb = 0; /* assume no data */
|
||||
if (uptr->pos < (DT_EZLIN - DT_BFLIN)) /* rev end zone? */
|
||||
mtkb = MTK_BIT (MTK_REV_END, uptr->pos);
|
||||
else if (uptr->pos < DT_EZLIN) /* rev buffer? */
|
||||
mtkb = MTK_BIT (MTK_INTER, uptr->pos);
|
||||
else if (uptr->pos < ((uint32) DTU_FWDEZ (uptr))) { /* data zone? */
|
||||
int32 blkno = DT_LIN2BL (uptr->pos, uptr); /* block # */
|
||||
int32 lineno = DT_LIN2OF (uptr->pos, uptr); /* line # within block */
|
||||
if (lineno < DT_HTLIN) { /* header? */
|
||||
if ((td_cmd & TDC_RW) == 0) /* read? */
|
||||
datb = td_header (uptr, blkno, lineno); /* get nibble */
|
||||
}
|
||||
else if (lineno < (DTU_LPERB (uptr) - DT_HTLIN)) { /* data? */
|
||||
if (td_cmd & TDC_RW) /* write? */
|
||||
td_write (uptr, blkno, /* write data nibble */
|
||||
lineno - DT_HTLIN, /* data rel line num */
|
||||
(td_dat >> 9) & 07);
|
||||
else datb = td_read (uptr, blkno, /* no, read */
|
||||
lineno - DT_HTLIN);
|
||||
}
|
||||
else if ((td_cmd & TDC_RW) == 0) /* trailer; read? */
|
||||
datb = td_trailer (uptr, blkno, lineno - /* get trlr nibble */
|
||||
(DTU_LPERB (uptr) - DT_HTLIN));
|
||||
mtkb = tdb_mtk[unum][lineno];
|
||||
}
|
||||
else if (uptr->pos < (((uint32) DTU_FWDEZ (uptr)) + DT_BFLIN))
|
||||
mtkb = MTK_BIT (MTK_INTER, uptr->pos); /* fwd buffer? */
|
||||
else mtkb = MTK_BIT (MTK_FWD_END, uptr->pos); /* fwd end zone */
|
||||
|
||||
if (dir) { /* reverse? */
|
||||
mtkb = mtkb ^ 01; /* complement mark bit, */
|
||||
datb = datb ^ 07; /* data bits */
|
||||
}
|
||||
td_mtk = ((td_mtk << 1) | mtkb) & MTK_MASK; /* shift mark reg */
|
||||
td_dat = ((td_dat << 3) | datb) & 07777; /* shift data reg */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Header read - reads out 18b words in 3b increments
|
||||
|
||||
word lines contents
|
||||
0 0-5 0
|
||||
1 6-11 block number
|
||||
2 12-17 0
|
||||
3 18-23 0
|
||||
4 24-29 reverse checksum (0777777)
|
||||
*/
|
||||
|
||||
int32 td_header (UNIT *uptr, int32 blk, int32 line)
|
||||
{
|
||||
int32 nibp;
|
||||
|
||||
switch (line) {
|
||||
|
||||
case 8: case 9: case 10: case 11: /* block num */
|
||||
nibp = 3 * (DT_LPERMC - 1 - (line % DT_LPERMC));
|
||||
return (blk >> nibp) & 07;
|
||||
|
||||
case 24: case 25: case 26: case 27: case 28: case 29: /* rev csum */
|
||||
return 07; /* 777777 */
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Trailer read - reads out 18b words in 3b increments
|
||||
Checksum is stored to avoid double calculation
|
||||
|
||||
word lines contents
|
||||
0 0-5 forward checksum (lines 0-1, rest 0)
|
||||
1 6-11 0
|
||||
2 12-17 0
|
||||
3 18-23 reverse block mark
|
||||
4 24-29 0
|
||||
|
||||
Note that the reverse block mark (when read forward) appears
|
||||
as the complement obverse (3b nibbles swapped end for end and
|
||||
complemented).
|
||||
*/
|
||||
|
||||
int32 td_trailer (UNIT *uptr, int32 blk, int32 line)
|
||||
{
|
||||
int32 nibp, i, ba;
|
||||
int16 *fbuf= (int16 *) uptr->filebuf;
|
||||
|
||||
switch (line) {
|
||||
|
||||
case 0:
|
||||
td_csum = 07777; /* init csum */
|
||||
ba = blk * DTU_BSIZE (uptr);
|
||||
for (i = 0; i < DTU_BSIZE (uptr); i++) /* loop thru buf */
|
||||
td_csum = (td_csum ^ ~fbuf[ba + i]) & 07777;
|
||||
td_csum = ((td_csum >> 6) ^ td_csum) & 077;
|
||||
return (td_csum >> 3) & 07;
|
||||
|
||||
case 1:
|
||||
return (td_csum & 07);
|
||||
|
||||
case 18: case 19: case 20: case 21:
|
||||
nibp = 3 * (line % DT_LPERMC);
|
||||
return ((blk >> nibp) & 07) ^ 07;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Data read - convert block number/data line # to offset in data array */
|
||||
|
||||
int32 td_read (UNIT *uptr, int32 blk, int32 line)
|
||||
{
|
||||
int16 *fbuf = (int16 *) uptr->filebuf; /* buffer */
|
||||
uint32 ba = blk * DTU_BSIZE (uptr); /* block base */
|
||||
int32 nibp = 3 * (DT_WSIZE - 1 - (line % DT_WSIZE)); /* nibble pos */
|
||||
|
||||
ba = ba + (line / DT_WSIZE); /* block addr */
|
||||
return (fbuf[ba] >> nibp) & 07; /* get data nibble */
|
||||
}
|
||||
|
||||
/* Data write - convert block number/data line # to offset in data array */
|
||||
|
||||
void td_write (UNIT *uptr, int32 blk, int32 line, int32 dat)
|
||||
{
|
||||
int16 *fbuf = (int16 *) uptr->filebuf; /* buffer */
|
||||
uint32 ba = blk * DTU_BSIZE (uptr); /* block base */
|
||||
int32 nibp = 3 * (DT_WSIZE - 1 - (line % DT_WSIZE)); /* nibble pos */
|
||||
|
||||
ba = ba + (line / DT_WSIZE); /* block addr */
|
||||
fbuf[ba] = (fbuf[ba] & ~(07 << nibp)) | (dat << nibp); /* upd data nibble */
|
||||
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; /* upd length */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat td_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */
|
||||
uptr = td_dev.units + i;
|
||||
if (sim_is_running) { /* CAF? */
|
||||
if (uptr->STATE >= STA_ACC) { /* accel or uts? */
|
||||
if (td_setpos (uptr)) continue; /* update pos */
|
||||
sim_cancel (uptr);
|
||||
sim_activate (uptr, td_dctime); /* sched decel */
|
||||
uptr->STATE = STA_DEC | (uptr->STATE & STA_DIR);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sim_cancel (uptr); /* sim reset */
|
||||
uptr->STATE = 0;
|
||||
uptr->LASTT = sim_grtime ();
|
||||
}
|
||||
}
|
||||
td_slf = td_qlf = td_qlctr = 0; /* clear state */
|
||||
td_cmd = td_dat = td_mtk = 0;
|
||||
td_csum = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine - OS/8 only
|
||||
|
||||
1) Read reverse until reverse end zone (mark track is complement obverse
|
||||
2) Read forward until mark track code 031. This is a composite code from
|
||||
the last 4b of the forward block number and the first two bits of the
|
||||
reverse guard (01 -0110 01- 1010). There are 16 lines before the first
|
||||
data word.
|
||||
3) Store data words from 7354 to end of page. This includes header and
|
||||
trailer words.
|
||||
4) Continue at location 7400.
|
||||
*/
|
||||
|
||||
#define BOOT_START 07300
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const uint16 boot_rom[] = {
|
||||
01312, /* ST, TAD L4MT ;=2000, reverse */
|
||||
04312, /* JMS L4MT ; rev lk for 022 */
|
||||
04312, /* JMS L4MT ; fwd lk for 031 */
|
||||
06773, /* DAT, SDSQ ; wait for 12b */
|
||||
05303, /* JMP .-1 */
|
||||
06777, /* SDRD ; read word */
|
||||
03726, /* DCA I BUF ; store */
|
||||
02326, /* ISZ BUF ; incr ptr */
|
||||
05303, /* JMP DAT ; if not 0, cont */
|
||||
05732, /* JMP I SCB ; jump to boot */
|
||||
02000, /* L4MT,2000 ; overwritten */
|
||||
01300, /* TAD ST ; =1312, go */
|
||||
06774, /* SDLC ; new command */
|
||||
06771, /* MTK, SDSS ; wait for mark */
|
||||
05315, /* JMP .-1 */
|
||||
06776, /* SDRC ; get mark code */
|
||||
00331, /* AND K77 ; mask to 6b */
|
||||
01327, /* CMP, TAD MCD ; got target code? */
|
||||
07640, /* SZA CLA ; skip if yes */
|
||||
05315, /* JMP MTK ; wait for mark */
|
||||
02321, /* ISZ CMP ; next target */
|
||||
05712, /* JMP I L4MT ; exit */
|
||||
07354, /* BUF, 7354 ; loading point */
|
||||
07756, /* MCD, -22 ; target 1 */
|
||||
07747, /* -31 ; target 2 */
|
||||
00077, /* 77 ; mask */
|
||||
07400 /* SCB, 7400 ; secondary boot */
|
||||
};
|
||||
|
||||
t_stat td_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
if (unitno) return SCPE_ARG; /* only unit 0 */
|
||||
if (td_dib.dev != DEV_TD8E) return STOP_NOTSTD; /* only std devno */
|
||||
td_unit[unitno].pos = DT_EZLIN;
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine
|
||||
|
||||
Determine 12b, 16b, or 18b/36b format
|
||||
Allocate buffer
|
||||
If 16b or 18b, read 16b or 18b format and convert to 12b in buffer
|
||||
If 12b, read data into buffer
|
||||
Set up mark track bit array
|
||||
*/
|
||||
|
||||
t_stat td_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 pdp18b[D18_NBSIZE];
|
||||
uint16 pdp11b[D18_NBSIZE], *fbuf;
|
||||
int32 i, k, mtkpb;
|
||||
int32 u = uptr - td_dev.units;
|
||||
t_stat r;
|
||||
uint32 ba, sz;
|
||||
|
||||
r = attach_unit (uptr, cptr); /* attach */
|
||||
if (r != SCPE_OK) return r; /* fail? */
|
||||
if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */
|
||||
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
|
||||
if (sim_switches & SWMASK ('F')) /* att 18b? */
|
||||
uptr->flags = uptr->flags & ~UNIT_8FMT;
|
||||
else if (sim_switches & SWMASK ('S')) /* att 16b? */
|
||||
uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
|
||||
else if (!(sim_switches & SWMASK ('A')) && /* autosize? */
|
||||
(sz = sim_fsize (uptr->fileref))) {
|
||||
if (sz == D11_FILSIZ)
|
||||
uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
|
||||
else if (sz > D8_FILSIZ)
|
||||
uptr->flags = uptr->flags & ~UNIT_8FMT;
|
||||
}
|
||||
}
|
||||
uptr->capac = DTU_CAPAC (uptr); /* set capacity */
|
||||
uptr->filebuf = calloc (uptr->capac, sizeof (int16));
|
||||
if (uptr->filebuf == NULL) { /* can't alloc? */
|
||||
detach_unit (uptr);
|
||||
return SCPE_MEM;
|
||||
}
|
||||
fbuf = (uint16 *) uptr->filebuf; /* file buffer */
|
||||
printf ("%s%d: ", sim_dname (&td_dev), u);
|
||||
if (uptr->flags & UNIT_8FMT) printf ("12b format");
|
||||
else if (uptr->flags & UNIT_11FMT) printf ("16b format");
|
||||
else printf ("18b/36b format");
|
||||
printf (", buffering file in memory\n");
|
||||
if (uptr->flags & UNIT_8FMT) /* 12b? */
|
||||
uptr->hwmark = fxread (uptr->filebuf, sizeof (uint16),
|
||||
uptr->capac, uptr->fileref);
|
||||
else { /* 16b/18b */
|
||||
for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
|
||||
if (uptr->flags & UNIT_11FMT) {
|
||||
k = fxread (pdp11b, sizeof (uint16), D18_NBSIZE, uptr->fileref);
|
||||
for (i = 0; i < k; i++) pdp18b[i] = pdp11b[i];
|
||||
}
|
||||
else k = fxread (pdp18b, sizeof (uint32), D18_NBSIZE, uptr->fileref);
|
||||
if (k == 0) break;
|
||||
for ( ; k < D18_NBSIZE; k++) pdp18b[k] = 0;
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) { /* loop thru blk */
|
||||
fbuf[ba] = (pdp18b[k] >> 6) & 07777;
|
||||
fbuf[ba + 1] = ((pdp18b[k] & 077) << 6) |
|
||||
((pdp18b[k + 1] >> 12) & 077);
|
||||
fbuf[ba + 2] = pdp18b[k + 1] & 07777;
|
||||
ba = ba + 3;
|
||||
} /* end blk loop */
|
||||
} /* end file loop */
|
||||
uptr->hwmark = ba;
|
||||
} /* end else */
|
||||
uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */
|
||||
uptr->pos = DT_EZLIN; /* beyond leader */
|
||||
uptr->LASTT = sim_grtime (); /* last pos update */
|
||||
uptr->STATE = STA_STOP; /* stopped */
|
||||
|
||||
mtkpb = (DTU_BSIZE (uptr) * DT_WSIZE) / DT_LPERMC; /* mtk codes per blk */
|
||||
k = td_set_mtk (MTK_INTER, u, 0); /* fill mark track */
|
||||
k = td_set_mtk (MTK_FWD_BLK, u, k); /* bit array */
|
||||
k = td_set_mtk (MTK_REV_GRD, u, k);
|
||||
for (i = 0; i < 4; i++) k = td_set_mtk (MTK_FWD_PRE, u, k);
|
||||
for (i = 0; i < (mtkpb - 4); i++) k = td_set_mtk (MTK_DATA, u, k);
|
||||
for (i = 0; i < 4; i++) k = td_set_mtk (MTK_REV_PRE, u, k);
|
||||
k = td_set_mtk (MTK_FWD_GRD, u, k);
|
||||
k = td_set_mtk (MTK_REV_BLK, u, k);
|
||||
k = td_set_mtk (MTK_INTER, u, k);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Detach routine
|
||||
|
||||
If 12b, write buffer to file
|
||||
If 16b or 18b, convert 12b buffer to 16b or 18b and write to file
|
||||
Deallocate buffer
|
||||
*/
|
||||
|
||||
t_stat td_detach (UNIT* uptr)
|
||||
{
|
||||
uint32 pdp18b[D18_NBSIZE];
|
||||
uint16 pdp11b[D18_NBSIZE], *fbuf;
|
||||
int32 i, k;
|
||||
int32 u = uptr - td_dev.units;
|
||||
uint32 ba;
|
||||
|
||||
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;
|
||||
fbuf = (uint16 *) uptr->filebuf; /* file buffer */
|
||||
if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) { /* any data? */
|
||||
printf ("%s%d: writing buffer to file\n", sim_dname (&td_dev), u);
|
||||
rewind (uptr->fileref); /* start of file */
|
||||
if (uptr->flags & UNIT_8FMT) /* PDP8? */
|
||||
fxwrite (uptr->filebuf, sizeof (uint16), /* write file */
|
||||
uptr->hwmark, uptr->fileref);
|
||||
else { /* 16b/18b */
|
||||
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru buf */
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) {
|
||||
pdp18b[k] = ((uint32) (fbuf[ba] & 07777) << 6) |
|
||||
((uint32) (fbuf[ba + 1] >> 6) & 077);
|
||||
pdp18b[k + 1] = ((uint32) (fbuf[ba + 1] & 077) << 12) |
|
||||
((uint32) (fbuf[ba + 2] & 07777));
|
||||
ba = ba + 3;
|
||||
} /* end loop blk */
|
||||
if (uptr->flags & UNIT_11FMT) { /* 16b? */
|
||||
for (i = 0; i < D18_NBSIZE; i++) pdp11b[i] = pdp18b[i];
|
||||
fxwrite (pdp11b, sizeof (uint16),
|
||||
D18_NBSIZE, uptr->fileref);
|
||||
}
|
||||
else fxwrite (pdp18b, sizeof (uint32),
|
||||
D18_NBSIZE, uptr->fileref);
|
||||
} /* end loop buf */
|
||||
} /* end else */
|
||||
if (ferror (uptr->fileref)) perror ("I/O error");
|
||||
} /* end if hwmark */
|
||||
free (uptr->filebuf); /* release buf */
|
||||
uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */
|
||||
uptr->filebuf = NULL; /* clear buf ptr */
|
||||
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; /* default fmt */
|
||||
uptr->capac = DT_CAPAC; /* default size */
|
||||
uptr->pos = uptr->STATE = 0;
|
||||
sim_cancel (uptr); /* no more pulses */
|
||||
return detach_unit (uptr);
|
||||
}
|
||||
|
||||
/* Set mark track code into bit array */
|
||||
|
||||
int32 td_set_mtk (int32 code, int32 u, int32 k)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 5; i >= 0; i--) tdb_mtk[u][k++] = (code >> i) & 1;
|
||||
return k;
|
||||
}
|
||||
|
||||
/* Show position */
|
||||
|
||||
t_stat td_show_pos (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
|
||||
if (uptr->pos < DT_EZLIN) /* rev end zone? */
|
||||
fprintf (st, "Reverse end zone\n");
|
||||
else if (uptr->pos < ((uint32) DTU_FWDEZ (uptr))) { /* data zone? */
|
||||
int32 blkno = DT_LIN2BL (uptr->pos, uptr); /* block # */
|
||||
int32 lineno = DT_LIN2OF (uptr->pos, uptr); /* line # within block */
|
||||
fprintf (st, "Block %d, line %d, ", blkno, lineno);
|
||||
if (lineno < DT_HTLIN) /* header? */
|
||||
fprintf (st, "header cell %d, nibble %d\n",
|
||||
lineno / DT_LPERMC, lineno % DT_LPERMC);
|
||||
else if (lineno < (DTU_LPERB (uptr) - DT_HTLIN)) /* data? */
|
||||
fprintf (st, "data word %d, nibble %d\n",
|
||||
(lineno - DT_HTLIN) / DT_WSIZE, (lineno - DT_HTLIN) % DT_WSIZE);
|
||||
else fprintf (st, "trailer cell %d, nibble %d\n",
|
||||
(lineno - (DTU_LPERB (uptr) - DT_HTLIN)) / DT_LPERMC,
|
||||
(lineno - (DTU_LPERB (uptr) - DT_HTLIN)) % DT_LPERMC);
|
||||
}
|
||||
else fprintf (st, "Forward end zone\n"); /* fwd end zone */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
158
simhv36-1/PDP8/pdp8_tsc.c
Normal file
158
simhv36-1/PDP8/pdp8_tsc.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/* pdp8_tsc.c: PDP-8 ETOS timesharing option board (TSC8-75)
|
||||
|
||||
Copyright (c) 2003-2005, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This module is based on Bernhard Baehr's PDP-8/E simulator
|
||||
|
||||
PDP-8/E Simulator Source Code
|
||||
|
||||
Copyright ) 2001-2003 Bernhard Baehr
|
||||
|
||||
TSC8iots.c - IOTs for the TSC8-75 Board plugin
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
tsc TSC8-75 option board
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
extern int32 int_req;
|
||||
extern int32 SF;
|
||||
extern int32 tsc_ir; /* "ERIOT" */
|
||||
extern int32 tsc_pc; /* "ERTB" */
|
||||
extern int32 tsc_cdf; /* "ECDF" */
|
||||
extern int32 tsc_enb; /* enable */
|
||||
|
||||
#define UNIT_V_SN699 (UNIT_V_UF + 0) /* SN 699 or above */
|
||||
#define UNIT_SN699 (1 << UNIT_V_SN699)
|
||||
|
||||
DEVICE tsc_dev;
|
||||
int32 tsc (int32 IR, int32 AC);
|
||||
t_stat tsc_reset (DEVICE *dptr);
|
||||
|
||||
/* TSC data structures
|
||||
|
||||
tsc_dev TSC device descriptor
|
||||
tsc_unit TSC unit descriptor
|
||||
tsc_reg TSC register list
|
||||
*/
|
||||
|
||||
DIB tsc_dib = { DEV_TSC, 1, { &tsc } };
|
||||
|
||||
UNIT tsc_unit = { UDATA (NULL, UNIT_SN699, 0) };
|
||||
|
||||
REG tsc_reg[] = {
|
||||
{ ORDATA (IR, tsc_ir, 12) },
|
||||
{ ORDATA (PC, tsc_pc, 12) },
|
||||
{ FLDATA (CDF, tsc_cdf, 0) },
|
||||
{ FLDATA (ENB, tsc_enb, 0) },
|
||||
{ FLDATA (INT, int_req, INT_V_TSC) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB tsc_mod[] = {
|
||||
{ UNIT_SN699, UNIT_SN699, "ESME", "ESME", NULL },
|
||||
{ UNIT_SN699, 0, "no ESME", "NOESME", NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE tsc_dev = {
|
||||
"TSC", &tsc_unit, tsc_reg, tsc_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tsc_reset,
|
||||
NULL, NULL, NULL,
|
||||
&tsc_dib, DEV_DISABLE | DEV_DIS
|
||||
};
|
||||
|
||||
/* IOT routine */
|
||||
|
||||
int32 tsc (int32 IR, int32 AC)
|
||||
{
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 0: /* ETDS */
|
||||
tsc_enb = 0; /* disable int req */
|
||||
int_req = int_req & ~INT_TSC; /* clear flag */
|
||||
break;
|
||||
|
||||
case 1: /* ESKP */
|
||||
return (int_req & INT_TSC)? IOT_SKP + AC: AC; /* skip on int req */
|
||||
|
||||
case 2: /* ECTF */
|
||||
int_req = int_req & ~INT_TSC; /* clear int req */
|
||||
break;
|
||||
|
||||
case 3: /* ECDF */
|
||||
AC = AC | ((tsc_ir >> 3) & 07); /* read "ERIOT"<6:8> */
|
||||
if (tsc_cdf) AC = AC | IOT_SKP; /* if cdf, skip */
|
||||
tsc_cdf = 0;
|
||||
break;
|
||||
|
||||
case 4: /* ERTB */
|
||||
return tsc_pc;
|
||||
|
||||
case 5: /* ESME */
|
||||
if (tsc_unit.flags & UNIT_SN699) { /* enabled? */
|
||||
if (tsc_cdf && ((tsc_ir & 070) >> 3) == (SF & 07)) {
|
||||
AC = AC | IOT_SKP;
|
||||
tsc_cdf = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: /* ERIOT */
|
||||
return tsc_ir;
|
||||
|
||||
case 7: /* ETEN */
|
||||
tsc_enb = 1;
|
||||
break;
|
||||
} /* end switch */
|
||||
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat tsc_reset (DEVICE *dptr)
|
||||
{
|
||||
tsc_ir = 0;
|
||||
tsc_pc = 0;
|
||||
tsc_cdf = 0;
|
||||
tsc_enb = 0;
|
||||
int_req = int_req & ~INT_TSC;
|
||||
return SCPE_OK;
|
||||
}
|
||||
415
simhv36-1/PDP8/pdp8_tt.c
Normal file
415
simhv36-1/PDP8/pdp8_tt.c
Normal file
@@ -0,0 +1,415 @@
|
||||
/* pdp8_tt.c: PDP-8 console terminal simulator
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
tti,tto KL8E terminal input/output
|
||||
|
||||
22-Nov-05 RMS Revised for new terminal processing routines
|
||||
28-May-04 RMS Removed SET TTI CTRL-C
|
||||
29-Dec-03 RMS Added console output backpressure support
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
02-Mar-02 RMS Added SET TTI CTRL-C
|
||||
22-Dec-02 RMS Added break support
|
||||
01-Nov-02 RMS Added 7B/8B support
|
||||
04-Oct-02 RMS Added DIBs, device number support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
int32 tti (int32 IR, int32 AC);
|
||||
int32 tto (int32 IR, int32 AC);
|
||||
t_stat tti_svc (UNIT *uptr);
|
||||
t_stat tto_svc (UNIT *uptr);
|
||||
t_stat tti_reset (DEVICE *dptr);
|
||||
t_stat tto_reset (DEVICE *dptr);
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
|
||||
/* TTI data structures
|
||||
|
||||
tti_dev TTI device descriptor
|
||||
tti_unit TTI unit descriptor
|
||||
tti_reg TTI register list
|
||||
tti_mod TTI modifiers list
|
||||
*/
|
||||
|
||||
DIB tti_dib = { DEV_TTI, 1, { &tti } };
|
||||
|
||||
#undef KBD_POLL_WAIT
|
||||
#define KBD_POLL_WAIT 10
|
||||
|
||||
UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_KSR, 0), KBD_POLL_WAIT };
|
||||
|
||||
REG tti_reg[] = {
|
||||
{ ORDATA (BUF, tti_unit.buf, 8) },
|
||||
{ FLDATA (DONE, dev_done, INT_V_TTI) },
|
||||
{ FLDATA (ENABLE, int_enable, INT_V_TTI) },
|
||||
{ FLDATA (INT, int_req, INT_V_TTI) },
|
||||
{ DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB tti_mod[] = {
|
||||
{ TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_7P, "7b", NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE tti_dev = {
|
||||
"TTI", &tti_unit, tti_reg, tti_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tti_reset,
|
||||
NULL, NULL, NULL,
|
||||
&tti_dib, 0
|
||||
};
|
||||
|
||||
/* TTO data structures
|
||||
|
||||
tto_dev TTO device descriptor
|
||||
tto_unit TTO unit descriptor
|
||||
tto_reg TTO register list
|
||||
*/
|
||||
|
||||
DIB tto_dib = { DEV_TTO, 1, { &tto } };
|
||||
|
||||
#undef SERIAL_OUT_WAIT
|
||||
#define SERIAL_OUT_WAIT 0
|
||||
|
||||
UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG tto_reg[] = {
|
||||
{ ORDATA (BUF, tto_unit.buf, 8) },
|
||||
{ FLDATA (DONE, dev_done, INT_V_TTO) },
|
||||
{ FLDATA (ENABLE, int_enable, INT_V_TTO) },
|
||||
{ FLDATA (INT, int_req, INT_V_TTO) },
|
||||
{ DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB tto_mod[] = {
|
||||
{ TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
|
||||
{ TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE tto_dev = {
|
||||
"TTO", &tto_unit, tto_reg, tto_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tto_reset,
|
||||
NULL, NULL, NULL,
|
||||
&tto_dib, 0
|
||||
};
|
||||
|
||||
#define FAKE_INPUT
|
||||
#ifdef FAKE_INPUT
|
||||
int tt_input_index;
|
||||
char tt_input[] = "START\r01:01:85\r10:10\r\r\r";
|
||||
int tt_input_count = sizeof(tt_input)-1;
|
||||
#endif
|
||||
|
||||
/* Terminal input: IOT routine */
|
||||
|
||||
int32 tti (int32 IR, int32 AC)
|
||||
{
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 0: /* KCF */
|
||||
dev_done = dev_done & ~INT_TTI; /* clear flag */
|
||||
int_req = int_req & ~INT_TTI;
|
||||
return AC;
|
||||
|
||||
case 1: /* KSF */
|
||||
#ifdef FAKE_INPUT
|
||||
if (tt_input_index == 0 &&
|
||||
(dev_done & INT_TTI) == 0)
|
||||
{
|
||||
void tt_set_event(void);
|
||||
tt_set_event();
|
||||
}
|
||||
#endif
|
||||
return (dev_done & INT_TTI)? IOT_SKP + AC: AC;
|
||||
|
||||
case 2: /* KCC */
|
||||
dev_done = dev_done & ~INT_TTI; /* clear flag */
|
||||
int_req = int_req & ~INT_TTI;
|
||||
#ifdef FAKE_INPUT
|
||||
{
|
||||
void tt_set_event(void);
|
||||
tt_set_event();
|
||||
}
|
||||
#endif
|
||||
return 0; /* clear AC */
|
||||
|
||||
case 4: /* KRS */
|
||||
#ifdef FAKE_INPUT
|
||||
printf("xxx rx input %o (%d/%d)\n",
|
||||
tti_unit.buf, tt_input_index, tt_input_count);
|
||||
#endif
|
||||
return (AC | tti_unit.buf); /* return buffer */
|
||||
|
||||
case 5: /* KIE */
|
||||
if (AC & 1) int_enable = int_enable | (INT_TTI+INT_TTO);
|
||||
else int_enable = int_enable & ~(INT_TTI+INT_TTO);
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
return AC;
|
||||
|
||||
case 6: /* KRB */
|
||||
dev_done = dev_done & ~INT_TTI; /* clear flag */
|
||||
int_req = int_req & ~INT_TTI;
|
||||
#ifdef FAKE_INPUT
|
||||
{
|
||||
void tt_set_event(void);
|
||||
tt_set_event();
|
||||
}
|
||||
printf("xxx rx input %o (%d/%d)\n",
|
||||
tti_unit.buf, tt_input_index, tt_input_count);
|
||||
#endif
|
||||
return (tti_unit.buf); /* return buffer */
|
||||
|
||||
default:
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat tti_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c;
|
||||
|
||||
#ifdef FAKE_INPUT
|
||||
return SCPE_OK;
|
||||
#endif
|
||||
|
||||
sim_activate (uptr, uptr->wait); /* continue poll */
|
||||
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
|
||||
if (c & SCPE_BREAK) uptr->buf = 0; /* break? */
|
||||
else uptr->buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR);
|
||||
uptr->pos = uptr->pos + 1;
|
||||
dev_done = dev_done | INT_TTI; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat tti_reset (DEVICE *dptr)
|
||||
{
|
||||
tti_unit.buf = 0;
|
||||
dev_done = dev_done & ~INT_TTI; /* clear done, int */
|
||||
int_req = int_req & ~INT_TTI;
|
||||
int_enable = int_enable | INT_TTI; /* set enable */
|
||||
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
#ifdef FAKE_INPUT
|
||||
char tt_buf[1024];
|
||||
int tt_buf_count;
|
||||
|
||||
int tt_flag;
|
||||
int tt_data;
|
||||
int tt_countdown;
|
||||
int tt_event;
|
||||
|
||||
void tt_set_event(void)
|
||||
{
|
||||
tt_event = 1;
|
||||
}
|
||||
|
||||
void tt_service(void)
|
||||
{
|
||||
if (tt_input_index < tt_input_count &&
|
||||
(dev_done & INT_TTI) == 0 && tt_event)
|
||||
{
|
||||
tti_unit.buf = tt_input[tt_input_index++];
|
||||
tti_unit.pos++;
|
||||
dev_done |= INT_TTI;
|
||||
int_req = INT_UPDATE;
|
||||
tt_event = 0;
|
||||
}
|
||||
|
||||
if (tt_countdown > 0) {
|
||||
tt_countdown--;
|
||||
if (tt_countdown == 0) {
|
||||
int i;
|
||||
|
||||
printf("xxx tx_data %o\n", tt_data);
|
||||
|
||||
tt_flag = 1;
|
||||
|
||||
dev_done |= INT_TTO;
|
||||
int_req = INT_UPDATE;
|
||||
|
||||
tt_buf[tt_buf_count++] = tt_data;
|
||||
printf("xxx output: ");
|
||||
for (i = 0; i < tt_buf_count; i++) {
|
||||
char ch = tt_buf[i] & 0177;
|
||||
switch (ch) {
|
||||
case '\n': printf("\\n"); break;
|
||||
case '\r': printf("\\r"); break;
|
||||
default: printf("%c", ch & 0177); break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
if (tt_flag && int_enable) {
|
||||
printf("tt_flag set; set int\n");
|
||||
dev_done |= INT_TTO;
|
||||
int_req = INT_UPDATE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void check_output(int c);
|
||||
|
||||
void tt_output(int c)
|
||||
{
|
||||
check_output(c & 0x7f);
|
||||
tt_data = c & 0xff;
|
||||
tt_countdown = 98/*100*/;
|
||||
tt_flag = 0;
|
||||
}
|
||||
#else
|
||||
void tt_service(void) {}
|
||||
#endif
|
||||
|
||||
/* Terminal output: IOT routine */
|
||||
|
||||
int32 tto (int32 IR, int32 AC)
|
||||
{
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
|
||||
case 0: /* TLF */
|
||||
dev_done = dev_done | INT_TTO; /* set flag */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
return AC;
|
||||
|
||||
case 1: /* TSF */
|
||||
return (dev_done & INT_TTO)? IOT_SKP + AC: AC;
|
||||
|
||||
case 2: /* TCF */
|
||||
dev_done = dev_done & ~INT_TTO; /* clear flag */
|
||||
int_req = int_req & ~INT_TTO; /* clear int req */
|
||||
return AC;
|
||||
|
||||
case 5: /* SPI */
|
||||
return (int_req & (INT_TTI+INT_TTO))? IOT_SKP + AC: AC;
|
||||
|
||||
case 6: /* TLS */
|
||||
dev_done = dev_done & ~INT_TTO; /* clear flag */
|
||||
int_req = int_req & ~INT_TTO; /* clear int req */
|
||||
case 4: /* TPC */
|
||||
#ifdef FAKE_INPUT
|
||||
tt_output(AC);
|
||||
#else
|
||||
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
|
||||
#endif
|
||||
tto_unit.buf = AC; /* load buffer */
|
||||
return AC;
|
||||
|
||||
default:
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
#ifdef FAKE_INPUT
|
||||
static int state;
|
||||
extern int need_stop;
|
||||
|
||||
void check_output(int c)
|
||||
{
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (c == '\r')
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
state = c == '\n' ? 2 : 0;
|
||||
break;
|
||||
case 2:
|
||||
if (c == '.') {
|
||||
need_stop = 1;
|
||||
}
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
t_stat tto_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c;
|
||||
t_stat r;
|
||||
|
||||
c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags));
|
||||
if (c >= 0) {
|
||||
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output char; error? */
|
||||
sim_activate (uptr, uptr->wait); /* try again */
|
||||
return ((r == SCPE_STALL)? SCPE_OK: r); /* if !stall, report */
|
||||
}
|
||||
}
|
||||
#ifdef FAKE_INPUT
|
||||
check_output(c);
|
||||
#endif
|
||||
dev_done = dev_done | INT_TTO; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
uptr->pos = uptr->pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat tto_reset (DEVICE *dptr)
|
||||
{
|
||||
tto_unit.buf = 0;
|
||||
dev_done = dev_done & ~INT_TTO; /* clear done, int */
|
||||
int_req = int_req & ~INT_TTO;
|
||||
int_enable = int_enable | INT_TTO; /* set enable */
|
||||
sim_cancel (&tto_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
tti_unit.flags = (tti_unit.flags & ~TT_MODE) | val;
|
||||
tto_unit.flags = (tto_unit.flags & ~TT_MODE) | val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
423
simhv36-1/PDP8/pdp8_ttx.c
Normal file
423
simhv36-1/PDP8/pdp8_ttx.c
Normal file
@@ -0,0 +1,423 @@
|
||||
/* pdp8_ttx.c: PDP-8 additional terminals simulator
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
ttix,ttox PT08/KL8JA terminal input/output
|
||||
|
||||
06-Jul-06 RMS Fixed bug in DETACH routine
|
||||
22-Nov-05 RMS Revised for new terminal processing routines
|
||||
29-Jun-05 RMS Added SET TTOXn DISCONNECT
|
||||
Fixed bug in SET LOG/NOLOG
|
||||
21-Jun-05 RMS Fixed bug in SHOW CONN/STATS
|
||||
05-Jan-04 RMS Revised for tmxr library changes
|
||||
09-May-03 RMS Added network device flag
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
22-Dec-02 RMS Added break support
|
||||
02-Nov-02 RMS Added 7B/8B support
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
22-Aug-02 RMS Updated for changes to sim_tmxr.c
|
||||
06-Jan-02 RMS Added device enable/disable support
|
||||
30-Dec-01 RMS Complete rebuild
|
||||
30-Nov-01 RMS Added extended SET/SHOW support
|
||||
|
||||
This module implements four individual serial interfaces similar in function
|
||||
to the console. These interfaces are mapped to Telnet based connections as
|
||||
though they were the four lines of a terminal multiplexor. The connection
|
||||
polling mechanism is superimposed onto the keyboard of the first interface.
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
#include "sim_sock.h"
|
||||
#include "sim_tmxr.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define TTX_LINES 4
|
||||
#define TTX_MASK (TTX_LINES - 1)
|
||||
|
||||
#define TTX_GETLN(x) (((x) >> 4) & TTX_MASK)
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */
|
||||
uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */
|
||||
int32 ttx_tps = 100; /* polls per second */
|
||||
TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */
|
||||
TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */
|
||||
|
||||
DEVICE ttix_dev, ttox_dev;
|
||||
int32 ttix (int32 IR, int32 AC);
|
||||
int32 ttox (int32 IR, int32 AC);
|
||||
t_stat ttix_svc (UNIT *uptr);
|
||||
t_stat ttix_reset (DEVICE *dptr);
|
||||
t_stat ttox_svc (UNIT *uptr);
|
||||
t_stat ttox_reset (DEVICE *dptr);
|
||||
t_stat ttx_attach (UNIT *uptr, char *cptr);
|
||||
t_stat ttx_detach (UNIT *uptr);
|
||||
t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
void ttx_enbdis (int32 dis);
|
||||
|
||||
/* TTIx data structures
|
||||
|
||||
ttix_dev TTIx device descriptor
|
||||
ttix_unit TTIx unit descriptor
|
||||
ttix_reg TTIx register list
|
||||
ttix_mod TTIx modifiers list
|
||||
*/
|
||||
|
||||
DIB ttix_dib = { DEV_KJ8, 8,
|
||||
{ &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox } };
|
||||
|
||||
UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT };
|
||||
|
||||
REG ttix_reg[] = {
|
||||
{ BRDATA (BUF, ttix_buf, 8, 8, TTX_LINES) },
|
||||
{ GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTI1) },
|
||||
{ GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTI1) },
|
||||
{ GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTI1) },
|
||||
{ DRDATA (TIME, ttix_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (TPS, ttx_tps, 10), REG_NZ + PV_LEFT },
|
||||
{ ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB ttix_mod[] = {
|
||||
{ UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &ttx_summ },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
|
||||
&tmxr_dscln, NULL, &ttx_desc },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||
NULL, &ttx_show, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
|
||||
NULL, &ttx_show, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE ttix_dev = {
|
||||
"TTIX", &ttix_unit, ttix_reg, ttix_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
&tmxr_ex, &tmxr_dep, &ttix_reset,
|
||||
NULL, &ttx_attach, &ttx_detach,
|
||||
&ttix_dib, DEV_NET | DEV_DISABLE
|
||||
};
|
||||
|
||||
/* TTOx data structures
|
||||
|
||||
ttox_dev TTOx device descriptor
|
||||
ttox_unit TTOx unit descriptor
|
||||
ttox_reg TTOx register list
|
||||
*/
|
||||
|
||||
UNIT ttox_unit[] = {
|
||||
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
|
||||
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
|
||||
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
|
||||
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }
|
||||
};
|
||||
|
||||
REG ttox_reg[] = {
|
||||
{ BRDATA (BUF, ttox_buf, 8, 8, TTX_LINES) },
|
||||
{ GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTO1) },
|
||||
{ GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTO1) },
|
||||
{ GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTO1) },
|
||||
{ URDATA (TIME, ttox_unit[0].wait, 10, 24, 0,
|
||||
TTX_LINES, PV_LEFT) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB ttox_mod[] = {
|
||||
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
|
||||
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
|
||||
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
|
||||
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
|
||||
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
|
||||
&tmxr_dscln, NULL, &ttx_desc },
|
||||
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
|
||||
&tmxr_set_log, &tmxr_show_log, &ttx_desc },
|
||||
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
|
||||
&tmxr_set_nolog, NULL, &ttx_desc },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE ttox_dev = {
|
||||
"TTOX", ttox_unit, ttox_reg, ttox_mod,
|
||||
4, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ttox_reset,
|
||||
NULL, NULL, NULL,
|
||||
NULL, DEV_DISABLE
|
||||
};
|
||||
|
||||
/* Terminal input: IOT routine */
|
||||
|
||||
int32 ttix (int32 inst, int32 AC)
|
||||
{
|
||||
int32 pulse = inst & 07; /* IOT pulse */
|
||||
int32 ln = TTX_GETLN (inst); /* line # */
|
||||
int32 itti = (INT_TTI1 << ln); /* rx intr */
|
||||
int32 itto = (INT_TTO1 << ln); /* tx intr */
|
||||
|
||||
switch (pulse) { /* case IR<9:11> */
|
||||
|
||||
case 0: /* KCF */
|
||||
dev_done = dev_done & ~itti; /* clear flag */
|
||||
int_req = int_req & ~itti;
|
||||
break;
|
||||
|
||||
case 1: /* KSF */
|
||||
return (dev_done & itti)? IOT_SKP + AC: AC;
|
||||
|
||||
case 2: /* KCC */
|
||||
dev_done = dev_done & ~itti; /* clear flag */
|
||||
int_req = int_req & ~itti;
|
||||
return 0; /* clear AC */
|
||||
|
||||
case 4: /* KRS */
|
||||
return (AC | ttix_buf[ln]); /* return buf */
|
||||
|
||||
case 5: /* KIE */
|
||||
if (AC & 1) int_enable = int_enable | (itti + itto);
|
||||
else int_enable = int_enable & ~(itti + itto);
|
||||
int_req = INT_UPDATE; /* update intr */
|
||||
break;
|
||||
|
||||
case 6: /* KRB */
|
||||
dev_done = dev_done & ~itti; /* clear flag */
|
||||
int_req = int_req & ~itti;
|
||||
return ttix_buf[ln]; /* return buf */
|
||||
|
||||
default:
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
} /* end switch */
|
||||
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat ttix_svc (UNIT *uptr)
|
||||
{
|
||||
int32 ln, c, temp;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
|
||||
temp = sim_rtcn_calb (ttx_tps, TMR_TTX); /* calibrate */
|
||||
sim_activate (uptr, temp); /* continue poll */
|
||||
ln = tmxr_poll_conn (&ttx_desc); /* look for connect */
|
||||
if (ln >= 0) ttx_ldsc[ln].rcve = 1; /* got one? rcv enb*/
|
||||
tmxr_poll_rx (&ttx_desc); /* poll for input */
|
||||
for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */
|
||||
if (ttx_ldsc[ln].conn) { /* connected? */
|
||||
if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */
|
||||
if (temp & SCPE_BREAK) c = 0; /* break? */
|
||||
else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags));
|
||||
ttix_buf[ln] = c;
|
||||
dev_done = dev_done | (INT_TTI1 << ln);
|
||||
int_req = INT_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ttix_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 t, ln, itto;
|
||||
|
||||
ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
|
||||
if (ttix_unit.flags & UNIT_ATT) { /* if attached, */
|
||||
if (!sim_is_active (&ttix_unit)) {
|
||||
t = sim_rtcn_init (ttix_unit.wait, TMR_TTX);
|
||||
sim_activate (&ttix_unit, t); /* activate */
|
||||
}
|
||||
}
|
||||
else sim_cancel (&ttix_unit); /* else stop */
|
||||
for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */
|
||||
ttix_buf[ln] = 0; /* clear buf, */
|
||||
itto = (INT_TTI1 << ln); /* interrupt */
|
||||
dev_done = dev_done & ~itto; /* clr done, int */
|
||||
int_req = int_req & ~itto;
|
||||
int_enable = int_enable | itto; /* set enable */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Terminal output: IOT routine */
|
||||
|
||||
int32 ttox (int32 inst, int32 AC)
|
||||
{
|
||||
int32 pulse = inst & 07; /* pulse */
|
||||
int32 ln = TTX_GETLN (inst); /* line # */
|
||||
int32 itti = (INT_TTI1 << ln); /* rx intr */
|
||||
int32 itto = (INT_TTO1 << ln); /* tx intr */
|
||||
|
||||
switch (pulse) { /* case IR<9:11> */
|
||||
|
||||
case 0: /* TLF */
|
||||
dev_done = dev_done | itto; /* set flag */
|
||||
int_req = INT_UPDATE; /* update intr */
|
||||
break;
|
||||
|
||||
case 1: /* TSF */
|
||||
return (dev_done & itto)? IOT_SKP + AC: AC;
|
||||
|
||||
case 2: /* TCF */
|
||||
dev_done = dev_done & ~itto; /* clear flag */
|
||||
int_req = int_req & ~itto; /* clear intr */
|
||||
break;
|
||||
|
||||
case 5: /* SPI */
|
||||
return (int_req & (itti | itto))? IOT_SKP + AC: AC;
|
||||
|
||||
case 6: /* TLS */
|
||||
dev_done = dev_done & ~itto; /* clear flag */
|
||||
int_req = int_req & ~itto; /* clear int req */
|
||||
case 4: /* TPC */
|
||||
sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */
|
||||
ttox_buf[ln] = AC & 0377; /* load buffer */
|
||||
break;
|
||||
|
||||
default:
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
} /* end switch */
|
||||
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat ttox_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c, ln = uptr - ttox_unit; /* line # */
|
||||
|
||||
if (ttx_ldsc[ln].conn) { /* connected? */
|
||||
if (ttx_ldsc[ln].xmte) { /* tx enabled? */
|
||||
TMLN *lp = &ttx_ldsc[ln]; /* get line */
|
||||
c = sim_tt_outcvt (ttox_buf[ln], TT_GET_MODE (ttox_unit[ln].flags));
|
||||
if (c >= 0) tmxr_putc_ln (lp, c); /* output char */
|
||||
tmxr_poll_tx (&ttx_desc); /* poll xmt */
|
||||
}
|
||||
else {
|
||||
tmxr_poll_tx (&ttx_desc); /* poll xmt */
|
||||
sim_activate (uptr, ttox_unit[ln].wait); /* wait */
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
dev_done = dev_done | (INT_TTO1 << ln); /* set done */
|
||||
int_req = INT_UPDATE; /* update intr */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ttox_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 ln, itto;
|
||||
|
||||
ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
|
||||
for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */
|
||||
ttox_buf[ln] = 0; /* clear buf */
|
||||
itto = (INT_TTO1 << ln); /* interrupt */
|
||||
dev_done = dev_done & ~itto; /* clr done, int */
|
||||
int_req = int_req & ~itto;
|
||||
int_enable = int_enable | itto; /* set enable */
|
||||
sim_cancel (&ttox_unit[ln]); /* deactivate */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach master unit */
|
||||
|
||||
t_stat ttx_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
int32 t;
|
||||
t_stat r;
|
||||
|
||||
r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */
|
||||
if (r != SCPE_OK) return r; /* error */
|
||||
t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init calib */
|
||||
sim_activate (uptr, t); /* start poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Detach master unit */
|
||||
|
||||
t_stat ttx_detach (UNIT *uptr)
|
||||
{
|
||||
int32 i;
|
||||
t_stat r;
|
||||
|
||||
r = tmxr_detach (&ttx_desc, uptr); /* detach */
|
||||
for (i = 0; i < TTX_LINES; i++) /* all lines, */
|
||||
ttx_ldsc[i].rcve = 0; /* disable rcv */
|
||||
sim_cancel (uptr); /* stop poll */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Show summary processor */
|
||||
|
||||
t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
int32 i, t;
|
||||
|
||||
for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0);
|
||||
if (t == 1) fprintf (st, "1 connection");
|
||||
else fprintf (st, "%d connections", t);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* SHOW CONN/STAT processor */
|
||||
|
||||
t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
int32 i, t;
|
||||
|
||||
for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0);
|
||||
if (t) {
|
||||
for (i = 0; i < TTX_LINES; i++) {
|
||||
if (ttx_ldsc[i].conn) {
|
||||
if (val) tmxr_fconns (st, &ttx_ldsc[i], i);
|
||||
else tmxr_fstats (st, &ttx_ldsc[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else fprintf (st, "all disconnected\n");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Enable/disable device */
|
||||
|
||||
void ttx_enbdis (int32 dis)
|
||||
{
|
||||
if (dis) {
|
||||
ttix_dev.flags = ttox_dev.flags | DEV_DIS;
|
||||
ttox_dev.flags = ttox_dev.flags | DEV_DIS;
|
||||
}
|
||||
else {
|
||||
ttix_dev.flags = ttix_dev.flags & ~DEV_DIS;
|
||||
ttox_dev.flags = ttox_dev.flags & ~DEV_DIS;
|
||||
}
|
||||
return;
|
||||
}
|
||||
14
simhv36-1/build_mingw.bat
Normal file
14
simhv36-1/build_mingw.bat
Normal file
@@ -0,0 +1,14 @@
|
||||
@echo off
|
||||
rem Compile all of SIMH using MINGW make and gcc environment
|
||||
rem Individual simulator sources are in .\simulator_name
|
||||
rem Individual simulator executables are to .\bin
|
||||
rem
|
||||
rem If needed, define the path for the MINGW bin directory.
|
||||
rem (this should already be set if MINGW was installed correctly)
|
||||
rem
|
||||
gcc -v 1>NUL 2>NUL
|
||||
if ERRORLEVEL 1 path C:\MinGW\bin;%path%
|
||||
if not exist BIN mkdir BIN
|
||||
gcc -v 1>NUL 2>NUL
|
||||
if ERRORLEVEL 1 echo "MinGW Environment Unavailable"
|
||||
mingw32-make WIN32=1 -f makefile %1 %2 %3 %4
|
||||
15
simhv36-1/build_mingw_ether.bat
Normal file
15
simhv36-1/build_mingw_ether.bat
Normal file
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
rem 12-Nov-02 rms Ethernet support
|
||||
rem Compile all of SIMH using MINGW make and gcc environment
|
||||
rem Individual simulator sources are in .\simulator_name
|
||||
rem Individual simulator executables are to .\bin
|
||||
rem
|
||||
rem If needed, define the path for the MINGW bin directory.
|
||||
rem (this should already be set if MINGW was installed correctly)
|
||||
rem
|
||||
gcc -v 1>NUL 2>NUL
|
||||
if ERRORLEVEL 1 path C:\MinGW\bin;%path%
|
||||
if not exist BIN mkdir BIN
|
||||
gcc -v 1>NUL 2>NUL
|
||||
if ERRORLEVEL 1 echo "MinGW Environment Unavailable"
|
||||
mingw32-make WIN32=1 USE_NETWORK=1 -f makefile %1 %2 %3 %4
|
||||
1171
simhv36-1/descrip.mms
Normal file
1171
simhv36-1/descrip.mms
Normal file
File diff suppressed because it is too large
Load Diff
408
simhv36-1/makefile
Normal file
408
simhv36-1/makefile
Normal file
@@ -0,0 +1,408 @@
|
||||
# CC Command
|
||||
#
|
||||
# Note: -O2 is sometimes broken in GCC when setjump/longjump is being
|
||||
# used. Try -O2 only with released simulators.
|
||||
#
|
||||
ifeq ($(WIN32),)
|
||||
#Unix Environments
|
||||
ifeq ($(OSTYPE),solaris)
|
||||
OS_CCDEFS = -lsocket -lnsl -lpthread -D_GNU_SOURCE
|
||||
else
|
||||
OS_CCDEFS = -D_GNU_SOURCE
|
||||
endif
|
||||
CC = gcc -std=c99 -O2 -U__STRICT_ANSI__ -g -lm $(OS_CCDEFS) -I .
|
||||
ifeq ($(USE_NETWORK),)
|
||||
else
|
||||
NETWORK_OPT = -DUSE_NETWORK -isystem /usr/local/include /usr/local/lib/libpcap.a
|
||||
endif
|
||||
else
|
||||
#Win32 Environments
|
||||
LDFLAGS = -lm -lwsock32
|
||||
CC = gcc -std=c99 -U__STRICT_ANSI__ -O0 -I.
|
||||
EXE = .exe
|
||||
ifeq ($(USE_NETWORK),)
|
||||
else
|
||||
NETWORK_OPT = -DUSE_NETWORK -lwpcap -lpacket
|
||||
endif
|
||||
endif
|
||||
|
||||
#brad
|
||||
NETWORK_OPT = -DUSE_NETWORK -lpcap
|
||||
|
||||
#
|
||||
# Common Libraries
|
||||
#
|
||||
BIN = BIN/
|
||||
SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \
|
||||
sim_tmxr.c sim_ether.c sim_tape.c
|
||||
|
||||
|
||||
#
|
||||
# Emulator source files and compile time options
|
||||
#
|
||||
PDP1D = PDP1/
|
||||
PDP1 = ${PDP1D}pdp1_lp.c ${PDP1D}pdp1_cpu.c ${PDP1D}pdp1_stddev.c \
|
||||
${PDP1D}pdp1_sys.c ${PDP1D}pdp1_dt.c ${PDP1D}pdp1_drm.c
|
||||
PDP1_OPT = -I ${PDP1D}
|
||||
|
||||
|
||||
NOVAD = NOVA/
|
||||
NOVA = ${NOVAD}nova_sys.c ${NOVAD}nova_cpu.c ${NOVAD}nova_dkp.c \
|
||||
${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c ${NOVAD}nova_mta.c \
|
||||
${NOVAD}nova_plt.c ${NOVAD}nova_pt.c ${NOVAD}nova_clk.c \
|
||||
${NOVAD}nova_tt.c ${NOVAD}nova_tt1.c ${NOVAD}nova_qty.c
|
||||
NOVA_OPT = -I ${NOVAD}
|
||||
|
||||
|
||||
|
||||
ECLIPSE = ${NOVAD}eclipse_cpu.c ${NOVAD}eclipse_tt.c ${NOVAD}nova_sys.c \
|
||||
${NOVAD}nova_dkp.c ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c \
|
||||
${NOVAD}nova_mta.c ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c \
|
||||
${NOVAD}nova_clk.c ${NOVAD}nova_tt1.c ${NOVAD}nova_qty.c
|
||||
ECLIPSE_OPT = -I ${NOVAD} -DECLIPSE -DUSE_INT64
|
||||
|
||||
|
||||
|
||||
PDP18BD = PDP18B/
|
||||
PDP18B = ${PDP18BD}pdp18b_dt.c ${PDP18BD}pdp18b_drm.c ${PDP18BD}pdp18b_cpu.c \
|
||||
${PDP18BD}pdp18b_lp.c ${PDP18BD}pdp18b_mt.c ${PDP18BD}pdp18b_rf.c \
|
||||
${PDP18BD}pdp18b_rp.c ${PDP18BD}pdp18b_stddev.c ${PDP18BD}pdp18b_sys.c \
|
||||
${PDP18BD}pdp18b_rb.c ${PDP18BD}pdp18b_tt1.c ${PDP18BD}pdp18b_fpp.c
|
||||
PDP4_OPT = -DPDP4 -I ${PDP18BD}
|
||||
PDP7_OPT = -DPDP7 -I ${PDP18BD}
|
||||
PDP9_OPT = -DPDP9 -I ${PDP18BD}
|
||||
PDP15_OPT = -DPDP15 -I ${PDP18BD}
|
||||
|
||||
|
||||
|
||||
PDP11D = PDP11/
|
||||
PDP11 = ${PDP11D}pdp11_fp.c ${PDP11D}pdp11_cpu.c ${PDP11D}pdp11_dz.c \
|
||||
${PDP11D}pdp11_cis.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_rk.c \
|
||||
${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rp.c ${PDP11D}pdp11_rx.c \
|
||||
${PDP11D}pdp11_stddev.c ${PDP11D}pdp11_sys.c ${PDP11D}pdp11_tc.c \
|
||||
${PDP11D}pdp11_tm.c ${PDP11D}pdp11_ts.c ${PDP11D}pdp11_io.c \
|
||||
${PDP11D}pdp11_rq.c ${PDP11D}pdp11_tq.c ${PDP11D}pdp11_pclk.c \
|
||||
${PDP11D}pdp11_ry.c ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_hk.c \
|
||||
${PDP11D}pdp11_xq.c ${PDP11D}pdp11_xu.c ${PDP11D}pdp11_vh.c \
|
||||
${PDP11D}pdp11_rh.c ${PDP11D}pdp11_tu.c ${PDP11D}pdp11_cpumod.c \
|
||||
${PDP11D}pdp11_cr.c ${PDP11D}pdp11_rf.c ${PDP11D}pdp11_dl.c \
|
||||
${PDP11D}pdp11_ke.c
|
||||
PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT}
|
||||
|
||||
|
||||
|
||||
VAXD = VAX/
|
||||
VAX = ${VAXD}vax_cpu.c ${VAXD}vax_cpu1.c ${VAXD}vax_fpa.c ${VAXD}vax_io.c \
|
||||
${VAXD}vax_cis.c ${VAXD}vax_octa.c ${VAXD}vax_cmode.c \
|
||||
${VAXD}vax_mmu.c ${VAXD}vax_stddev.c ${VAXD}vax_sysdev.c \
|
||||
${VAXD}vax_sys.c ${VAXD}vax_syscm.c ${VAXD}vax_syslist.c \
|
||||
${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \
|
||||
${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_tq.c \
|
||||
${PDP11D}pdp11_xq.c ${PDP11D}pdp11_ry.c \
|
||||
${PDP11D}pdp11_vh.c ${PDP11D}pdp11_cr.c
|
||||
VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT}
|
||||
|
||||
|
||||
|
||||
VAX780 = ${VAXD}vax_cpu.c ${VAXD}vax_cpu1.c ${VAXD}vax_fpa.c \
|
||||
${VAXD}vax_cis.c ${VAXD}vax_octa.c ${VAXD}vax_cmode.c \
|
||||
${VAXD}vax_mmu.c ${VAXD}vax_sys.c ${VAXD}vax_syscm.c \
|
||||
${VAXD}vax780_stddev.c ${VAXD}vax780_sbi.c \
|
||||
${VAXD}vax780_mem.c ${VAXD}vax780_uba.c ${VAXD}vax780_mba.c \
|
||||
${VAXD}vax780_fload.c ${VAXD}vax780_syslist.c \
|
||||
${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \
|
||||
${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_tq.c \
|
||||
${PDP11D}pdp11_xu.c ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_cr.c \
|
||||
${PDP11D}pdp11_rp.c ${PDP11D}pdp11_tu.c ${PDP11D}pdp11_hk.c
|
||||
VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT}
|
||||
|
||||
VAX730 = ${VAXD}vax_cpu.c ${VAXD}vax_cpu1.c ${VAXD}vax_fpa.c \
|
||||
${VAXD}vax_cis.c ${VAXD}vax_octa.c ${VAXD}vax_cmode.c \
|
||||
${VAXD}vax_mmu.c ${VAXD}vax_sys.c ${VAXD}vax_syscm.c \
|
||||
${VAXD}vax780_stddev.c ${VAXD}vax730_bus.c \
|
||||
${VAXD}vax730_mem.c ${VAXD}vax780_uba.c \
|
||||
${VAXD}vax730_syslist.c \
|
||||
${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \
|
||||
${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_tq.c \
|
||||
${PDP11D}pdp11_xu.c ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_cr.c \
|
||||
${PDP11D}pdp11_hk.c
|
||||
VAX730_OPT = -DVM_VAX -DVAX_730 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT}
|
||||
|
||||
|
||||
|
||||
PDP10D = PDP10/
|
||||
PDP10 = ${PDP10D}pdp10_fe.c ${PDP11D}pdp11_dz.c ${PDP10D}pdp10_cpu.c \
|
||||
${PDP10D}pdp10_ksio.c ${PDP10D}pdp10_lp20.c ${PDP10D}pdp10_mdfp.c \
|
||||
${PDP10D}pdp10_pag.c ${PDP10D}pdp10_rp.c ${PDP10D}pdp10_sys.c \
|
||||
${PDP10D}pdp10_tim.c ${PDP10D}pdp10_tu.c ${PDP10D}pdp10_xtnd.c \
|
||||
${PDP11D}pdp11_pt.c ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_xu.c
|
||||
PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} -I ${VAXD} ${NETWORK_OPT}
|
||||
|
||||
|
||||
|
||||
PDP8D = PDP8/
|
||||
PDP8 = ${PDP8D}pdp8_cpu.c ${PDP8D}pdp8_clk.c ${PDP8D}pdp8_df.c \
|
||||
${PDP8D}pdp8_dt.c ${PDP8D}pdp8_lp.c ${PDP8D}pdp8_mt.c \
|
||||
${PDP8D}pdp8_pt.c ${PDP8D}pdp8_rf.c ${PDP8D}pdp8_rk.c \
|
||||
${PDP8D}pdp8_rx.c ${PDP8D}pdp8_sys.c ${PDP8D}pdp8_tt.c \
|
||||
${PDP8D}pdp8_ttx.c ${PDP8D}pdp8_rl.c ${PDP8D}pdp8_tsc.c \
|
||||
${PDP8D}pdp8_td.c
|
||||
PDP8_OPT = -I ${PDP8D}
|
||||
|
||||
|
||||
|
||||
H316D = H316/
|
||||
H316 = ${H316D}h316_stddev.c ${H316D}h316_lp.c ${H316D}h316_cpu.c \
|
||||
${H316D}h316_sys.c ${H316D}h316_mt.c ${H316D}h316_fhd.c \
|
||||
${H316D}h316_dp.c
|
||||
H316_OPT = -I ${H316D}
|
||||
|
||||
|
||||
|
||||
HP2100D = HP2100/
|
||||
HP2100 = ${HP2100D}hp2100_stddev.c ${HP2100D}hp2100_dp.c ${HP2100D}hp2100_dq.c \
|
||||
${HP2100D}hp2100_dr.c ${HP2100D}hp2100_lps.c ${HP2100D}hp2100_ms.c \
|
||||
${HP2100D}hp2100_mt.c ${HP2100D}hp2100_mux.c ${HP2100D}hp2100_cpu.c \
|
||||
${HP2100D}hp2100_fp.c ${HP2100D}hp2100_sys.c ${HP2100D}hp2100_lpt.c \
|
||||
${HP2100D}hp2100_ipl.c ${HP2100D}hp2100_ds.c ${HP2100D}hp2100_cpu1.c \
|
||||
${HP2100D}hp2100_fp1.c
|
||||
HP2100_OPT = -DHAVE_INT64 -I ${HP2100D}
|
||||
|
||||
|
||||
|
||||
I1401D = I1401/
|
||||
I1401 = ${I1401D}i1401_lp.c ${I1401D}i1401_cpu.c ${I1401D}i1401_iq.c \
|
||||
${I1401D}i1401_cd.c ${I1401D}i1401_mt.c ${I1401D}i1401_dp.c \
|
||||
${I1401D}i1401_sys.c
|
||||
I1401_OPT = -I ${I1401D}
|
||||
|
||||
|
||||
|
||||
I1620D = I1620/
|
||||
I1620 = ${I1620D}i1620_cd.c ${I1620D}i1620_dp.c ${I1620D}i1620_pt.c \
|
||||
${I1620D}i1620_tty.c ${I1620D}i1620_cpu.c ${I1620D}i1620_lp.c \
|
||||
${I1620D}i1620_fp.c ${I1620D}i1620_sys.c
|
||||
I1620_OPT = -I ${I1620D}
|
||||
|
||||
|
||||
|
||||
I7094D = I7094/
|
||||
I7094 = ${I7094D}i7094_cpu.c ${I7094D}i7094_cpu1.c ${I7094D}i7094_io.c \
|
||||
${I7094D}i7094_cd.c ${I7094D}i7094_clk.c ${I7094D}i7094_com.c \
|
||||
${I7094D}i7094_drm.c ${I7094D}i7094_dsk.c ${I7094D}i7094_sys.c \
|
||||
${I7094D}i7094_lp.c ${I7094D}i7094_mt.c ${I7094D}i7094_binloader.c
|
||||
I7094_OPT = -DUSE_INT64 -I ${I7094D}
|
||||
|
||||
|
||||
|
||||
IBM1130D = Ibm1130/
|
||||
IBM1130 = ${IBM1130D}ibm1130_cpu.c ${IBM1130D}ibm1130_cr.c \
|
||||
${IBM1130D}ibm1130_disk.c ${IBM1130D}ibm1130_stddev.c \
|
||||
${IBM1130D}ibm1130_sys.c ${IBM1130D}ibm1130_gdu.c \
|
||||
${IBM1130D}ibm1130_gui.c ${IBM1130D}ibm1130_prt.c \
|
||||
${IBM1130D}ibm1130_fmt.c ${IBM1130D}ibm1130_ptrp.c
|
||||
IBM1130_OPT = -I ${IBM1130D}
|
||||
|
||||
|
||||
|
||||
ID16D = Interdata/
|
||||
ID16 = ${ID16D}id16_cpu.c ${ID16D}id16_sys.c ${ID16D}id_dp.c \
|
||||
${ID16D}id_fd.c ${ID16D}id_fp.c ${ID16D}id_idc.c ${ID16D}id_io.c \
|
||||
${ID16D}id_lp.c ${ID16D}id_mt.c ${ID16D}id_pas.c ${ID16D}id_pt.c \
|
||||
${ID16D}id_tt.c ${ID16D}id_uvc.c ${ID16D}id16_dboot.c ${ID16D}id_ttp.c
|
||||
ID16_OPT = -I ${ID16D}
|
||||
|
||||
|
||||
|
||||
ID32D = Interdata/
|
||||
ID32 = ${ID32D}id32_cpu.c ${ID32D}id32_sys.c ${ID32D}id_dp.c \
|
||||
${ID32D}id_fd.c ${ID32D}id_fp.c ${ID32D}id_idc.c ${ID32D}id_io.c \
|
||||
${ID32D}id_lp.c ${ID32D}id_mt.c ${ID32D}id_pas.c ${ID32D}id_pt.c \
|
||||
${ID32D}id_tt.c ${ID32D}id_uvc.c ${ID32D}id32_dboot.c ${ID32D}id_ttp.c
|
||||
ID32_OPT = -I ${ID32D}
|
||||
|
||||
|
||||
|
||||
S3D = S3/
|
||||
S3 = ${S3D}s3_cd.c ${S3D}s3_cpu.c ${S3D}s3_disk.c ${S3D}s3_lp.c \
|
||||
${S3D}s3_pkb.c ${S3D}s3_sys.c
|
||||
S3_OPT = -I ${S3D}
|
||||
|
||||
|
||||
|
||||
ALTAIRD = ALTAIR/
|
||||
ALTAIR = ${ALTAIRD}altair_sio.c ${ALTAIRD}altair_cpu.c ${ALTAIRD}altair_dsk.c \
|
||||
${ALTAIRD}altair_sys.c
|
||||
ALTAIR_OPT = -I ${ALTAIRD}
|
||||
|
||||
|
||||
|
||||
ALTAIRZ80D = AltairZ80/
|
||||
ALTAIRZ80 = ${ALTAIRZ80D}altairz80_cpu.c ${ALTAIRZ80D}altairz80_dsk.c \
|
||||
${ALTAIRZ80D}altairz80_sio.c ${ALTAIRZ80D}altairz80_sys.c \
|
||||
${ALTAIRZ80D}altairz80_hdsk.c
|
||||
ALTAIRZ80_OPT = -I ${ALTAIRZ80D}
|
||||
|
||||
|
||||
|
||||
GRID = GRI/
|
||||
GRI = ${GRID}gri_cpu.c ${GRID}gri_stddev.c ${GRID}gri_sys.c
|
||||
GRI_OPT = -I ${GRID}
|
||||
|
||||
|
||||
|
||||
LGPD = LGP/
|
||||
LGP = ${LGPD}lgp_cpu.c ${LGPD}lgp_stddev.c ${LGPD}lgp_sys.c
|
||||
LGP_OPT = -I ${LGPD}
|
||||
|
||||
|
||||
|
||||
SDSD = SDS/
|
||||
SDS = ${SDSD}sds_cpu.c ${SDSD}sds_drm.c ${SDSD}sds_dsk.c ${SDSD}sds_io.c \
|
||||
${SDSD}sds_lp.c ${SDSD}sds_mt.c ${SDSD}sds_mux.c ${SDSD}sds_rad.c \
|
||||
${SDSD}sds_stddev.c ${SDSD}sds_sys.c
|
||||
SDS_OPT = -I ${SDSD}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Build everything
|
||||
#
|
||||
ALL = ${BIN}pdp1${EXE} ${BIN}pdp4${EXE} ${BIN}pdp7${EXE} ${BIN}pdp8${EXE} \
|
||||
${BIN}pdp9${EXE} ${BIN}pdp15${EXE} ${BIN}pdp11${EXE} ${BIN}pdp10${EXE} \
|
||||
${BIN}vax${EXE} ${BIN}vax780${EXE} ${BIN}nova${EXE} ${BIN}eclipse${EXE} \
|
||||
${BIN}hp2100${EXE} ${BIN}i1401${EXE} ${BIN}i1620${EXE} ${BIN}s3${EXE} \
|
||||
${BIN}altair${EXE} ${BIN}altairz80${EXE} ${BIN}gri${EXE} \
|
||||
${BIN}i1620${EXE} ${BIN}i7094${EXE} ${BIN}ibm1130${EXE} ${BIN}id16${EXE} \
|
||||
${BIN}id32${EXE} ${BIN}sds${EXE} ${BIN}lgp${EXE} ${BIN}h316${EXE}
|
||||
|
||||
all : ${ALL}
|
||||
|
||||
clean :
|
||||
ifeq ($(WIN32),)
|
||||
${RM} ${ALL}
|
||||
else
|
||||
if exist BIN\*.exe del /q BIN\*.exe
|
||||
endif
|
||||
#
|
||||
# Individual builds
|
||||
#
|
||||
${BIN}pdp1${EXE} : ${PDP1} ${SIM}
|
||||
${CC} ${PDP1} ${SIM} ${PDP1_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}pdp4${EXE} : ${PDP18B} ${SIM}
|
||||
${CC} ${PDP18B} ${SIM} ${PDP4_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}pdp7${EXE} : ${PDP18B} ${SIM}
|
||||
${CC} ${PDP18B} ${SIM} ${PDP7_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}pdp8${EXE} : ${PDP8} ${SIM}
|
||||
${CC} ${PDP8} ${SIM} ${PDP8_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}pdp9${EXE} : ${PDP18B} ${SIM}
|
||||
${CC} ${PDP18B} ${SIM} ${PDP9_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}pdp15${EXE} : ${PDP18B} ${SIM}
|
||||
${CC} ${PDP18B} ${SIM} ${PDP15_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}pdp10${EXE} : ${PDP10} ${SIM}
|
||||
${CC} ${PDP10} ${SIM} ${PDP10_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}pdp11${EXE} : ${PDP11} ${SIM}
|
||||
${CC} ${PDP11} ${SIM} ${PDP11_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}vax${EXE} : ${VAX} ${SIM}
|
||||
${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}vax780${EXE} : ${VAX780} ${SIM}
|
||||
${CC} ${VAX780} ${SIM} ${VAX780_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
${BIN}vax730${EXE} : ${VAX730} ${SIM} VAX/vax730_defs.h
|
||||
${CC} ${VAX730} ${SIM} ${VAX730_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}nova${EXE} : ${NOVA} ${SIM}
|
||||
${CC} ${NOVA} ${SIM} ${NOVA_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}eclipse${EXE} : ${ECLIPSE} ${SIM}
|
||||
${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}h316${EXE} : ${H316} ${SIM}
|
||||
${CC} ${H316} ${SIM} ${H316_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}hp2100${EXE} : ${HP2100} ${SIM}
|
||||
${CC} ${HP2100} ${SIM} ${HP2100_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}i1401${EXE} : ${I1401} ${SIM}
|
||||
${CC} ${I1401} ${SIM} ${I1401_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}i1620${EXE} : ${I1620} ${SIM}
|
||||
${CC} ${I1620} ${SIM} ${I1620_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}i7094${EXE} : ${I7094} ${SIM}
|
||||
${CC} ${I7094} ${SIM} ${I7094_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
|
||||
${BIN}ibm1130${EXE} : ${IBM1130}
|
||||
${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}s3${EXE} : ${S3} ${SIM}
|
||||
${CC} ${S3} ${SIM} ${S3_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}altair${EXE} : ${ALTAIR} ${SIM}
|
||||
${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}altairz80${EXE} : ${ALTAIRZ80} ${SIM}
|
||||
${CC} ${ALTAIRZ80} ${SIM} ${ALTAIRZ80_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}gri${EXE} : ${GRI} ${SIM}
|
||||
${CC} ${GRI} ${SIM} ${GRI_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}lgp${EXE} : ${LGP} ${SIM}
|
||||
${CC} ${LGP} ${SIM} ${LGP_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}id16${EXE} : ${ID16} ${SIM}
|
||||
${CC} ${ID16} ${SIM} ${ID16_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}id32${EXE} : ${ID32} ${SIM}
|
||||
${CC} ${ID32} ${SIM} ${ID32_OPT} -o $@ ${LDFLAGS}
|
||||
|
||||
|
||||
${BIN}sds${EXE} : ${SDS} ${SIM}
|
||||
${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ ${LDFLAGS}
|
||||
4314
simhv36-1/scp.c
Normal file
4314
simhv36-1/scp.c
Normal file
File diff suppressed because it is too large
Load Diff
119
simhv36-1/scp.h
Normal file
119
simhv36-1/scp.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* scp.h: simulator control program headers
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
14-Jul-06 RMS Added sim_activate_abs
|
||||
06-Jan-06 RMS Added fprint_stopped_gen
|
||||
Changed arg type in sim_brk_test
|
||||
07-Feb-05 RMS Added ASSERT command
|
||||
09-Sep-04 RMS Added reset_all_p
|
||||
14-Feb-04 RMS Added debug prototypes (from Dave Hittner)
|
||||
02-Jan-04 RMS Split out from SCP
|
||||
*/
|
||||
|
||||
#ifndef _SIM_SCP_H_
|
||||
#define _SIM_SCP_H_ 0
|
||||
|
||||
/* run_cmd parameters */
|
||||
|
||||
#define RU_RUN 0 /* run */
|
||||
#define RU_GO 1 /* go */
|
||||
#define RU_STEP 2 /* step */
|
||||
#define RU_CONT 3 /* continue */
|
||||
#define RU_BOOT 4 /* boot */
|
||||
|
||||
/* get_sim_opt parameters */
|
||||
|
||||
#define CMD_OPT_SW 001 /* switches */
|
||||
#define CMD_OPT_OF 002 /* output file */
|
||||
#define CMD_OPT_SCH 004 /* search */
|
||||
#define CMD_OPT_DFT 010 /* defaults */
|
||||
|
||||
/* Command processors */
|
||||
|
||||
t_stat reset_cmd (int32 flag, char *ptr);
|
||||
t_stat exdep_cmd (int32 flag, char *ptr);
|
||||
t_stat eval_cmd (int32 flag, char *ptr);
|
||||
t_stat load_cmd (int32 flag, char *ptr);
|
||||
t_stat run_cmd (int32 flag, char *ptr);
|
||||
t_stat attach_cmd (int32 flag, char *ptr);
|
||||
t_stat detach_cmd (int32 flag, char *ptr);
|
||||
t_stat assign_cmd (int32 flag, char *ptr);
|
||||
t_stat deassign_cmd (int32 flag, char *ptr);
|
||||
t_stat save_cmd (int32 flag, char *ptr);
|
||||
t_stat restore_cmd (int32 flag, char *ptr);
|
||||
t_stat exit_cmd (int32 flag, char *ptr);
|
||||
t_stat set_cmd (int32 flag, char *ptr);
|
||||
t_stat show_cmd (int32 flag, char *ptr);
|
||||
t_stat brk_cmd (int32 flag, char *ptr);
|
||||
t_stat do_cmd (int32 flag, char *ptr);
|
||||
t_stat assert_cmd (int32 flag, char *ptr);
|
||||
t_stat help_cmd (int32 flag, char *ptr);
|
||||
t_stat spawn_cmd (int32 flag, char *ptr);
|
||||
t_stat echo_cmd (int32 flag, char *ptr);
|
||||
|
||||
/* Utility routines */
|
||||
|
||||
t_stat sim_process_event (void);
|
||||
t_stat sim_activate (UNIT *uptr, int32 interval);
|
||||
t_stat sim_activate_abs (UNIT *uptr, int32 interval);
|
||||
t_stat sim_cancel (UNIT *uptr);
|
||||
int32 sim_is_active (UNIT *uptr);
|
||||
double sim_gtime (void);
|
||||
uint32 sim_grtime (void);
|
||||
int32 sim_qcount (void);
|
||||
t_stat attach_unit (UNIT *uptr, char *cptr);
|
||||
t_stat detach_unit (UNIT *uptr);
|
||||
t_stat reset_all (uint32 start_device);
|
||||
t_stat reset_all_p (uint32 start_device);
|
||||
char *sim_dname (DEVICE *dptr);
|
||||
t_stat get_yn (char *ques, t_stat deflt);
|
||||
char *get_sim_opt (int32 opt, char *cptr, t_stat *st);
|
||||
char *get_glyph (char *iptr, char *optr, char mchar);
|
||||
char *get_glyph_nc (char *iptr, char *optr, char mchar);
|
||||
t_value get_uint (char *cptr, uint32 radix, t_value max, t_stat *status);
|
||||
char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi,
|
||||
uint32 rdx, t_addr max, char term);
|
||||
t_stat get_ipaddr (char *cptr, uint32 *ipa, uint32 *ipp);
|
||||
t_value strtotv (char *cptr, char **endptr, uint32 radix);
|
||||
t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt);
|
||||
CTAB *find_cmd (char *gbuf);
|
||||
DEVICE *find_dev (char *ptr);
|
||||
DEVICE *find_unit (char *ptr, UNIT **uptr);
|
||||
DEVICE *find_dev_from_unit (UNIT *uptr);
|
||||
REG *find_reg (char *ptr, char **optr, DEVICE *dptr);
|
||||
CTAB *find_ctab (CTAB *tab, char *gbuf);
|
||||
C1TAB *find_c1tab (C1TAB *tab, char *gbuf);
|
||||
SHTAB *find_shtab (SHTAB *tab, char *gbuf);
|
||||
BRKTAB *sim_brk_fnd (t_addr loc);
|
||||
uint32 sim_brk_test (t_addr bloc, uint32 btyp);
|
||||
void sim_brk_clrspc (uint32 spc);
|
||||
char *match_ext (char *fnam, char *ext);
|
||||
t_stat sim_cancel_step (void);
|
||||
void sim_debug_u16 (uint32 dbits, DEVICE* dptr, const char* const* bitdefs,
|
||||
uint16 before, uint16 after, int terminate);
|
||||
void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...);
|
||||
void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr);
|
||||
|
||||
#endif
|
||||
1092
simhv36-1/sim_console.c
Normal file
1092
simhv36-1/sim_console.c
Normal file
File diff suppressed because it is too large
Load Diff
81
simhv36-1/sim_console.h
Normal file
81
simhv36-1/sim_console.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* sim_console.h: simulator console I/O library headers
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
22-Jun-06 RMS Implemented SET/SHOW PCHAR
|
||||
22-Nov-05 RMS Added central input/output conversion support
|
||||
05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy
|
||||
28-May-04 RMS Added SET/SHOW CONSOLE
|
||||
02-Jan-04 RMS Removed timer routines, added Telnet console routines
|
||||
*/
|
||||
|
||||
#ifndef _SIM_CONSOLE_H_
|
||||
#define _SIM_CONSOLE_H_ 0
|
||||
|
||||
#define TTUF_V_MODE (UNIT_V_UF + 0)
|
||||
#define TTUF_W_MODE 2
|
||||
#define TTUF_MODE_7B 0
|
||||
#define TTUF_MODE_8B 1
|
||||
#define TTUF_MODE_UC 2
|
||||
#define TTUF_MODE_7P 3
|
||||
#define TTUF_KSR (1u << TTUF_W_MODE)
|
||||
#define TTUF_M_MODE ((1u << TTUF_W_MODE) - 1)
|
||||
#define TTUF_V_UF (TTUF_V_MODE + TTUF_W_MODE)
|
||||
#define TT_MODE (TTUF_M_MODE << TTUF_V_MODE)
|
||||
#define TT_MODE_7B (TTUF_MODE_7B << TTUF_V_MODE)
|
||||
#define TT_MODE_8B (TTUF_MODE_8B << TTUF_V_MODE)
|
||||
#define TT_MODE_UC (TTUF_MODE_UC << TTUF_V_MODE)
|
||||
#define TT_MODE_7P (TTUF_MODE_7P << TTUF_V_MODE)
|
||||
#define TT_MODE_KSR (TT_MODE_UC)
|
||||
#define TT_GET_MODE(x) (((x) >> TTUF_V_MODE) & TTUF_M_MODE)
|
||||
|
||||
t_stat sim_set_console (int32 flag, char *cptr);
|
||||
t_stat sim_set_kmap (int32 flag, char *cptr);
|
||||
t_stat sim_set_telnet (int32 flag, char *cptr);
|
||||
t_stat sim_set_notelnet (int32 flag, char *cptr);
|
||||
t_stat sim_set_logon (int32 flag, char *cptr);
|
||||
t_stat sim_set_logoff (int32 flag, char *cptr);
|
||||
t_stat sim_set_debon (int32 flag, char *cptr);
|
||||
t_stat sim_set_deboff (int32 flag, char *cptr);
|
||||
t_stat sim_set_pchar (int32 flag, char *cptr);
|
||||
t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||
t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||
t_stat sim_show_telnet (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||
t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||
t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||
t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||
t_stat sim_check_console (int32 sec);
|
||||
t_stat sim_poll_kbd (void);
|
||||
t_stat sim_putchar (int32 c);
|
||||
t_stat sim_putchar_s (int32 c);
|
||||
t_stat sim_ttinit (void);
|
||||
t_stat sim_ttrun (void);
|
||||
t_stat sim_ttcmd (void);
|
||||
t_stat sim_ttclose (void);
|
||||
t_stat sim_os_poll_kbd (void);
|
||||
t_stat sim_os_putchar (int32 out);
|
||||
int32 sim_tt_inpcvt (int32 c, uint32 mode);
|
||||
int32 sim_tt_outcvt (int32 c, uint32 mode);
|
||||
|
||||
#endif
|
||||
514
simhv36-1/sim_defs.h
Normal file
514
simhv36-1/sim_defs.h
Normal file
@@ -0,0 +1,514 @@
|
||||
/* sim_defs.h: simulator definitions
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
13-Jul-06 RMS Guarantee CBUFSIZE is at least 256
|
||||
07-Jan-06 RMS Added support for breakpoint spaces
|
||||
Added REG_FIT flag
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
11-Mar-05 RMS Moved 64b data type definitions outside USE_INT64
|
||||
07-Feb-05 RMS Added assertion fail stop
|
||||
05-Nov-04 RMS Added support for SHOW opt=val
|
||||
20-Oct-04 RMS Converted all base types to typedefs
|
||||
21-Sep-04 RMS Added switch to flag stop message printout
|
||||
06-Feb-04 RMS Moved device and unit user flags fields (V3.2)
|
||||
RMS Added REG_VMAD
|
||||
29-Dec-03 RMS Added output stall status
|
||||
15-Jun-03 RMS Added register flag REG_VMIO
|
||||
23-Apr-03 RMS Revised for 32b/64b t_addr
|
||||
14-Mar-03 RMS Lengthened default serial output wait
|
||||
31-Mar-03 RMS Added u5, u6 fields
|
||||
18-Mar-03 RMS Added logical name support
|
||||
Moved magtape definitions to sim_tape.h
|
||||
Moved breakpoint definitions from scp.c
|
||||
03-Mar-03 RMS Added sim_fsize
|
||||
08-Feb-03 RMS Changed sim_os_sleep to void, added match_ext
|
||||
05-Jan-03 RMS Added hidden switch definitions, device dyn memory support,
|
||||
parameters for function pointers, case sensitive SET support
|
||||
22-Dec-02 RMS Added break flag
|
||||
08-Oct-02 RMS Increased simulator error code space
|
||||
Added Telnet errors
|
||||
Added end of medium support
|
||||
Added help messages to CTAB
|
||||
Added flag and context fields to DEVICE
|
||||
Added restore flag masks
|
||||
Revised 64b definitions
|
||||
02-May-02 RMS Removed log status codes
|
||||
22-Apr-02 RMS Added magtape record length error
|
||||
30-Dec-01 RMS Generalized timer package, added circular arrays
|
||||
07-Dec-01 RMS Added breakpoint package
|
||||
01-Dec-01 RMS Added read-only unit support, extended SET/SHOW features,
|
||||
improved error messages
|
||||
24-Nov-01 RMS Added unit-based registers
|
||||
27-Sep-01 RMS Added queue count prototype
|
||||
17-Sep-01 RMS Removed multiple console support
|
||||
07-Sep-01 RMS Removed conditional externs on function prototypes
|
||||
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
|
||||
17-Jul-01 RMS Added additional function prototypes
|
||||
27-May-01 RMS Added multiple console support
|
||||
15-May-01 RMS Increased string buffer size
|
||||
25-Feb-01 RMS Revisions for V2.6
|
||||
15-Oct-00 RMS Editorial revisions for V2.5
|
||||
11-Jul-99 RMS Added unsigned int data types
|
||||
14-Apr-99 RMS Converted t_addr to unsigned
|
||||
04-Oct-98 RMS Additional definitions for V2.4
|
||||
|
||||
The interface between the simulator control package (SCP) and the
|
||||
simulator consists of the following routines and data structures
|
||||
|
||||
sim_name simulator name string
|
||||
sim_devices[] array of pointers to simulated devices
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_interval simulator interval to next event
|
||||
sim_stop_messages[] array of pointers to stop messages
|
||||
sim_instr() instruction execution routine
|
||||
sim_load() binary loader routine
|
||||
sim_emax maximum number of words in an instruction
|
||||
|
||||
In addition, the simulator must supply routines to print and parse
|
||||
architecture specific formats
|
||||
|
||||
print_sym print symbolic output
|
||||
parse_sym parse symbolic input
|
||||
*/
|
||||
|
||||
#ifndef _SIM_DEFS_H_
|
||||
#define _SIM_DEFS_H_ 0
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* Length specific integer declarations */
|
||||
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed int int32;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef int t_stat; /* status */
|
||||
typedef int t_bool; /* boolean */
|
||||
|
||||
/* 64b integers */
|
||||
|
||||
#if defined (__GNUC__) /* GCC */
|
||||
typedef signed long long t_int64;
|
||||
typedef unsigned long long t_uint64;
|
||||
#elif defined (_WIN32) /* Windows */
|
||||
typedef signed __int64 t_int64;
|
||||
typedef unsigned __int64 t_uint64;
|
||||
#elif defined (__ALPHA) && defined (VMS) /* Alpha VMS */
|
||||
typedef signed __int64 t_int64;
|
||||
typedef unsigned __int64 t_uint64;
|
||||
#elif defined (__ALPHA) && defined (__unix__) /* Alpha UNIX */
|
||||
typedef signed long t_int64;
|
||||
typedef unsigned long t_uint64;
|
||||
#else /* default */
|
||||
#define t_int64 signed long long
|
||||
#define t_uint64 unsigned long long
|
||||
#endif /* end 64b */
|
||||
|
||||
#if defined (USE_INT64) /* 64b data */
|
||||
typedef t_int64 t_svalue; /* signed value */
|
||||
typedef t_uint64 t_value; /* value */
|
||||
#else /* 32b data */
|
||||
typedef int32 t_svalue;
|
||||
typedef uint32 t_value;
|
||||
#endif /* end 64b data */
|
||||
|
||||
#if defined (USE_INT64) && defined (USE_ADDR64) /* 64b address */
|
||||
typedef t_uint64 t_addr;
|
||||
#define T_ADDR_W 64
|
||||
#else /* 32b address */
|
||||
typedef uint32 t_addr;
|
||||
#define T_ADDR_W 32
|
||||
#endif /* end 64b address */
|
||||
|
||||
/* System independent definitions */
|
||||
|
||||
#define FLIP_SIZE (1 << 16) /* flip buf size */
|
||||
#if !defined (PATH_MAX) /* usually in limits */
|
||||
#define PATH_MAX 512
|
||||
#endif
|
||||
#if (PATH_MAX >= 128)
|
||||
#define CBUFSIZE (128 + PATH_MAX) /* string buf size */
|
||||
#else
|
||||
#define CBUFSIZE 256
|
||||
#endif
|
||||
|
||||
/* Breakpoint spaces definitions */
|
||||
|
||||
#define SIM_BKPT_N_SPC 64 /* max number spaces */
|
||||
#define SIM_BKPT_V_SPC 26 /* location in arg */
|
||||
|
||||
/* Extended switch definitions (bits >= 26) */
|
||||
|
||||
#define SIM_SW_HIDE (1u << 26) /* enable hiding */
|
||||
#define SIM_SW_REST (1u << 27) /* attach/restore */
|
||||
#define SIM_SW_REG (1u << 28) /* register value */
|
||||
#define SIM_SW_STOP (1u << 29) /* stop message */
|
||||
|
||||
/* Simulator status codes
|
||||
|
||||
0 ok
|
||||
1 - (SCPE_BASE - 1) simulator specific
|
||||
SCPE_BASE - n general
|
||||
*/
|
||||
|
||||
#define SCPE_OK 0 /* normal return */
|
||||
#define SCPE_BASE 64 /* base for messages */
|
||||
#define SCPE_NXM (SCPE_BASE + 0) /* nxm */
|
||||
#define SCPE_UNATT (SCPE_BASE + 1) /* no file */
|
||||
#define SCPE_IOERR (SCPE_BASE + 2) /* I/O error */
|
||||
#define SCPE_CSUM (SCPE_BASE + 3) /* loader cksum */
|
||||
#define SCPE_FMT (SCPE_BASE + 4) /* loader format */
|
||||
#define SCPE_NOATT (SCPE_BASE + 5) /* not attachable */
|
||||
#define SCPE_OPENERR (SCPE_BASE + 6) /* open error */
|
||||
#define SCPE_MEM (SCPE_BASE + 7) /* alloc error */
|
||||
#define SCPE_ARG (SCPE_BASE + 8) /* argument error */
|
||||
#define SCPE_STEP (SCPE_BASE + 9) /* step expired */
|
||||
#define SCPE_UNK (SCPE_BASE + 10) /* unknown command */
|
||||
#define SCPE_RO (SCPE_BASE + 11) /* read only */
|
||||
#define SCPE_INCOMP (SCPE_BASE + 12) /* incomplete */
|
||||
#define SCPE_STOP (SCPE_BASE + 13) /* sim stopped */
|
||||
#define SCPE_EXIT (SCPE_BASE + 14) /* sim exit */
|
||||
#define SCPE_TTIERR (SCPE_BASE + 15) /* console tti err */
|
||||
#define SCPE_TTOERR (SCPE_BASE + 16) /* console tto err */
|
||||
#define SCPE_EOF (SCPE_BASE + 17) /* end of file */
|
||||
#define SCPE_REL (SCPE_BASE + 18) /* relocation error */
|
||||
#define SCPE_NOPARAM (SCPE_BASE + 19) /* no parameters */
|
||||
#define SCPE_ALATT (SCPE_BASE + 20) /* already attached */
|
||||
#define SCPE_TIMER (SCPE_BASE + 21) /* hwre timer err */
|
||||
#define SCPE_SIGERR (SCPE_BASE + 22) /* signal err */
|
||||
#define SCPE_TTYERR (SCPE_BASE + 23) /* tty setup err */
|
||||
#define SCPE_SUB (SCPE_BASE + 24) /* subscript err */
|
||||
#define SCPE_NOFNC (SCPE_BASE + 25) /* func not imp */
|
||||
#define SCPE_UDIS (SCPE_BASE + 26) /* unit disabled */
|
||||
#define SCPE_NORO (SCPE_BASE + 27) /* rd only not ok */
|
||||
#define SCPE_INVSW (SCPE_BASE + 28) /* invalid switch */
|
||||
#define SCPE_MISVAL (SCPE_BASE + 29) /* missing value */
|
||||
#define SCPE_2FARG (SCPE_BASE + 30) /* too few arguments */
|
||||
#define SCPE_2MARG (SCPE_BASE + 31) /* too many arguments */
|
||||
#define SCPE_NXDEV (SCPE_BASE + 32) /* nx device */
|
||||
#define SCPE_NXUN (SCPE_BASE + 33) /* nx unit */
|
||||
#define SCPE_NXREG (SCPE_BASE + 34) /* nx register */
|
||||
#define SCPE_NXPAR (SCPE_BASE + 35) /* nx parameter */
|
||||
#define SCPE_NEST (SCPE_BASE + 36) /* nested DO */
|
||||
#define SCPE_IERR (SCPE_BASE + 37) /* internal error */
|
||||
#define SCPE_MTRLNT (SCPE_BASE + 38) /* tape rec lnt error */
|
||||
#define SCPE_LOST (SCPE_BASE + 39) /* Telnet conn lost */
|
||||
#define SCPE_TTMO (SCPE_BASE + 40) /* Telnet conn timeout */
|
||||
#define SCPE_STALL (SCPE_BASE + 41) /* Telnet conn stall */
|
||||
#define SCPE_AFAIL (SCPE_BASE + 42) /* assert failed */
|
||||
#define SCPE_KFLAG 0010000 /* tti data flag */
|
||||
#define SCPE_BREAK 0020000 /* tti break flag */
|
||||
|
||||
/* Print value format codes */
|
||||
|
||||
#define PV_RZRO 0 /* right, zero fill */
|
||||
#define PV_RSPC 1 /* right, space fill */
|
||||
#define PV_LEFT 2 /* left justify */
|
||||
|
||||
/* Default timing parameters */
|
||||
|
||||
#define KBD_POLL_WAIT 5000 /* keyboard poll */
|
||||
#define SERIAL_IN_WAIT 100 /* serial in time */
|
||||
#define SERIAL_OUT_WAIT 100 /* serial output */
|
||||
#define NOQUEUE_WAIT 10000 /* min check time */
|
||||
|
||||
/* Convert switch letter to bit mask */
|
||||
|
||||
#define SWMASK(x) (1u << (((int) (x)) - ((int) 'A')))
|
||||
|
||||
/* String match */
|
||||
|
||||
#define MATCH_CMD(ptr,cmd) strncmp ((ptr), (cmd), strlen (ptr))
|
||||
|
||||
/* Device data structure */
|
||||
|
||||
struct sim_device {
|
||||
char *name; /* name */
|
||||
struct sim_unit *units; /* units */
|
||||
struct sim_reg *registers; /* registers */
|
||||
struct sim_mtab *modifiers; /* modifiers */
|
||||
uint32 numunits; /* #units */
|
||||
uint32 aradix; /* address radix */
|
||||
uint32 awidth; /* address width */
|
||||
uint32 aincr; /* addr increment */
|
||||
uint32 dradix; /* data radix */
|
||||
uint32 dwidth; /* data width */
|
||||
t_stat (*examine)(t_value *v, t_addr a, struct sim_unit *up,
|
||||
int32 sw); /* examine routine */
|
||||
t_stat (*deposit)(t_value v, t_addr a, struct sim_unit *up,
|
||||
int32 sw); /* deposit routine */
|
||||
t_stat (*reset)(struct sim_device *dp);/* reset routine */
|
||||
t_stat (*boot)(int32 u, struct sim_device *dp);
|
||||
/* boot routine */
|
||||
t_stat (*attach)(struct sim_unit *up, char *cp);
|
||||
/* attach routine */
|
||||
t_stat (*detach)(struct sim_unit *up); /* detach routine */
|
||||
void *ctxt; /* context */
|
||||
uint32 flags; /* flags */
|
||||
uint32 dctrl; /* debug control */
|
||||
struct sim_debtab *debflags; /* debug flags */
|
||||
t_stat (*msize)(struct sim_unit *up, int32 v, char *cp, void *dp);
|
||||
/* mem size routine */
|
||||
char *lname; /* logical name */
|
||||
};
|
||||
|
||||
/* Device flags */
|
||||
|
||||
#define DEV_V_DIS 0 /* dev disabled */
|
||||
#define DEV_V_DISABLE 1 /* dev disable-able */
|
||||
#define DEV_V_DYNM 2 /* mem size dynamic */
|
||||
#define DEV_V_NET 3 /* network attach */
|
||||
#define DEV_V_DEBUG 4 /* debug capability */
|
||||
#define DEV_V_RAW 5 /* raw supported */
|
||||
#define DEV_V_RAWONLY 6 /* only raw supported */
|
||||
#define DEV_V_UF_31 12 /* user flags, V3.1 */
|
||||
#define DEV_V_UF 16 /* user flags */
|
||||
#define DEV_V_RSV 31 /* reserved */
|
||||
|
||||
#define DEV_DIS (1 << DEV_V_DIS)
|
||||
#define DEV_DISABLE (1 << DEV_V_DISABLE)
|
||||
#define DEV_DYNM (1 << DEV_V_DYNM)
|
||||
#define DEV_NET (1 << DEV_V_NET)
|
||||
#define DEV_DEBUG (1 << DEV_V_DEBUG)
|
||||
#define DEV_RAW (1 << DEV_V_RAW)
|
||||
#define DEV_RAWONLY (1 << DEV_V_RAWONLY)
|
||||
|
||||
#define DEV_UFMASK_31 (((1u << DEV_V_RSV) - 1) & ~((1u << DEV_V_UF_31) - 1))
|
||||
#define DEV_UFMASK (((1u << DEV_V_RSV) - 1) & ~((1u << DEV_V_UF) - 1))
|
||||
#define DEV_RFLAGS (DEV_UFMASK|DEV_DIS) /* restored flags */
|
||||
|
||||
/* Unit data structure
|
||||
|
||||
Parts of the unit structure are device specific, that is, they are
|
||||
not referenced by the simulator control package and can be freely
|
||||
used by device simulators. Fields starting with 'buf', and flags
|
||||
starting with 'UF', are device specific. The definitions given here
|
||||
are for a typical sequential device.
|
||||
*/
|
||||
|
||||
struct sim_unit {
|
||||
struct sim_unit *next; /* next active */
|
||||
t_stat (*action)(struct sim_unit *up); /* action routine */
|
||||
char *filename; /* open file name */
|
||||
FILE *fileref; /* file reference */
|
||||
void *filebuf; /* memory buffer */
|
||||
uint32 hwmark; /* high water mark */
|
||||
int32 time; /* time out */
|
||||
uint32 flags; /* flags */
|
||||
t_addr capac; /* capacity */
|
||||
t_addr pos; /* file position */
|
||||
int32 buf; /* buffer */
|
||||
int32 wait; /* wait */
|
||||
int32 u3; /* device specific */
|
||||
int32 u4; /* device specific */
|
||||
int32 u5; /* device specific */
|
||||
int32 u6; /* device specific */
|
||||
};
|
||||
|
||||
/* Unit flags */
|
||||
|
||||
#define UNIT_V_UF_31 12 /* dev spec, V3.1 */
|
||||
#define UNIT_V_UF 16 /* device specific */
|
||||
#define UNIT_V_RSV 31 /* reserved!! */
|
||||
|
||||
#define UNIT_ATTABLE 000001 /* attachable */
|
||||
#define UNIT_RO 000002 /* read only */
|
||||
#define UNIT_FIX 000004 /* fixed capacity */
|
||||
#define UNIT_SEQ 000010 /* sequential */
|
||||
#define UNIT_ATT 000020 /* attached */
|
||||
#define UNIT_BINK 000040 /* K = power of 2 */
|
||||
#define UNIT_BUFABLE 000100 /* bufferable */
|
||||
#define UNIT_MUSTBUF 000200 /* must buffer */
|
||||
#define UNIT_BUF 000400 /* buffered */
|
||||
#define UNIT_ROABLE 001000 /* read only ok */
|
||||
#define UNIT_DISABLE 002000 /* disable-able */
|
||||
#define UNIT_DIS 004000 /* disabled */
|
||||
#define UNIT_RAW 010000 /* raw mode */
|
||||
|
||||
#define UNIT_UFMASK_31 (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF_31) - 1))
|
||||
#define UNIT_UFMASK (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1))
|
||||
#define UNIT_RFLAGS (UNIT_UFMASK|UNIT_DIS) /* restored flags */
|
||||
|
||||
/* Register data structure */
|
||||
|
||||
struct sim_reg {
|
||||
char *name; /* name */
|
||||
void *loc; /* location */
|
||||
uint32 radix; /* radix */
|
||||
uint32 width; /* width */
|
||||
uint32 offset; /* starting bit */
|
||||
uint32 depth; /* save depth */
|
||||
uint32 flags; /* flags */
|
||||
uint32 qptr; /* circ q ptr */
|
||||
};
|
||||
|
||||
#define REG_FMT 00003 /* see PV_x */
|
||||
#define REG_RO 00004 /* read only */
|
||||
#define REG_HIDDEN 00010 /* hidden */
|
||||
#define REG_NZ 00020 /* must be non-zero */
|
||||
#define REG_UNIT 00040 /* in unit struct */
|
||||
#define REG_CIRC 00100 /* circular array */
|
||||
#define REG_VMIO 00200 /* use VM data print/parse */
|
||||
#define REG_VMAD 00400 /* use VM addr print/parse */
|
||||
#define REG_FIT 01000 /* fit access to size */
|
||||
#define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */
|
||||
|
||||
/* Command tables, base and alternate formats */
|
||||
|
||||
struct sim_ctab {
|
||||
char *name; /* name */
|
||||
t_stat (*action)(int32 flag, char *cptr);
|
||||
/* action routine */
|
||||
int32 arg; /* argument */
|
||||
char *help; /* help string */
|
||||
};
|
||||
|
||||
struct sim_c1tab {
|
||||
char *name; /* name */
|
||||
t_stat (*action)(struct sim_device *dptr, struct sim_unit *uptr,
|
||||
int32 flag, char *cptr); /* action routine */
|
||||
int32 arg; /* argument */
|
||||
char *help; /* help string */
|
||||
};
|
||||
|
||||
struct sim_shtab {
|
||||
char *name; /* name */
|
||||
t_stat (*action)(FILE *st, struct sim_device *dptr,
|
||||
struct sim_unit *uptr, int32 flag, char *cptr);
|
||||
int32 arg; /* argument */
|
||||
char *help; /* help string */
|
||||
};
|
||||
|
||||
/* Modifier table - only extended entries have disp, reg, or flags */
|
||||
|
||||
struct sim_mtab {
|
||||
uint32 mask; /* mask */
|
||||
uint32 match; /* match */
|
||||
char *pstring; /* print string */
|
||||
char *mstring; /* match string */
|
||||
t_stat (*valid)(struct sim_unit *up, int32 v, char *cp, void *dp);
|
||||
/* validation routine */
|
||||
t_stat (*disp)(FILE *st, struct sim_unit *up, int32 v, void *dp);
|
||||
/* display routine */
|
||||
void *desc; /* value descriptor */
|
||||
/* REG * if MTAB_VAL */
|
||||
/* int * if not */
|
||||
};
|
||||
|
||||
#define MTAB_XTD (1u << UNIT_V_RSV) /* ext entry flag */
|
||||
#define MTAB_VDV 001 /* valid for dev */
|
||||
#define MTAB_VUN 002 /* valid for unit */
|
||||
#define MTAB_VAL 004 /* takes a value */
|
||||
#define MTAB_NMO 010 /* only if named */
|
||||
#define MTAB_NC 020 /* no UC conversion */
|
||||
#define MTAB_SHP 040 /* show takes parameter */
|
||||
|
||||
/* Search table */
|
||||
|
||||
struct sim_schtab {
|
||||
int32 logic; /* logical operator */
|
||||
int32 boolop; /* boolean operator */
|
||||
t_value mask; /* mask for logical */
|
||||
t_value comp; /* comparison for boolean */
|
||||
};
|
||||
|
||||
/* Breakpoint table */
|
||||
|
||||
struct sim_brktab {
|
||||
t_addr addr; /* address */
|
||||
int32 typ; /* mask of types */
|
||||
int32 cnt; /* proceed count */
|
||||
char *act; /* action string */
|
||||
};
|
||||
|
||||
/* Debug table */
|
||||
|
||||
struct sim_debtab {
|
||||
char *name; /* control name */
|
||||
uint32 mask; /* control bit */
|
||||
};
|
||||
|
||||
#define DEBUG_PRS(d) (sim_deb && d.dctrl)
|
||||
#define DEBUG_PRD(d) (sim_deb && d->dctrl)
|
||||
#define DEBUG_PRI(d,m) (sim_deb && (d.dctrl & (m)))
|
||||
|
||||
/* The following macros define structure contents */
|
||||
|
||||
#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,0
|
||||
|
||||
#if defined (__STDC__) || defined (_WIN32)
|
||||
#define ORDATA(nm,loc,wd) #nm, &(loc), 8, (wd), 0, 1
|
||||
#define DRDATA(nm,loc,wd) #nm, &(loc), 10, (wd), 0, 1
|
||||
#define HRDATA(nm,loc,wd) #nm, &(loc), 16, (wd), 0, 1
|
||||
#define FLDATA(nm,loc,pos) #nm, &(loc), 2, 1, (pos), 1
|
||||
#define GRDATA(nm,loc,rdx,wd,pos) #nm, &(loc), (rdx), (wd), (pos), 1
|
||||
#define BRDATA(nm,loc,rdx,wd,dep) #nm, (loc), (rdx), (wd), 0, (dep)
|
||||
#define URDATA(nm,loc,rdx,wd,off,dep,fl) \
|
||||
#nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT)
|
||||
#else
|
||||
#define ORDATA(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1
|
||||
#define DRDATA(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1
|
||||
#define HRDATA(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1
|
||||
#define FLDATA(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1
|
||||
#define GRDATA(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1
|
||||
#define BRDATA(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep)
|
||||
#define URDATA(nm,loc,rdx,wd,off,dep,fl) \
|
||||
"nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT)
|
||||
#endif
|
||||
|
||||
/* Typedefs for principal structures */
|
||||
|
||||
typedef struct sim_device DEVICE;
|
||||
typedef struct sim_unit UNIT;
|
||||
typedef struct sim_reg REG;
|
||||
typedef struct sim_ctab CTAB;
|
||||
typedef struct sim_c1tab C1TAB;
|
||||
typedef struct sim_shtab SHTAB;
|
||||
typedef struct sim_mtab MTAB;
|
||||
typedef struct sim_schtab SCHTAB;
|
||||
typedef struct sim_brktab BRKTAB;
|
||||
typedef struct sim_debtab DEBTAB;
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
#include "scp.h"
|
||||
#include "sim_console.h"
|
||||
#include "sim_timer.h"
|
||||
#include "sim_fio.h"
|
||||
|
||||
#endif
|
||||
1273
simhv36-1/sim_ether.c
Normal file
1273
simhv36-1/sim_ether.c
Normal file
File diff suppressed because it is too large
Load Diff
212
simhv36-1/sim_ether.h
Normal file
212
simhv36-1/sim_ether.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/* sim_ether.h: OS-dependent network information
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2002-2005, David T. Hittner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of the author shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from the author.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Modification history:
|
||||
|
||||
30-Nov-05 DTH Added CRC length to packet and more field comments
|
||||
04-Feb-04 DTH Added debugging information
|
||||
14-Jan-04 MP Generalized BSD support issues
|
||||
05-Jan-04 DTH Added eth_mac_scan
|
||||
26-Dec-03 DTH Added ethernet show and queue functions from pdp11_xq
|
||||
23-Dec-03 DTH Added status to packet
|
||||
01-Dec-03 DTH Added reflections, tweaked decnet fix items
|
||||
25-Nov-03 DTH Verified DECNET_FIX, reversed ifdef to mainstream code
|
||||
14-Nov-03 DTH Added #ifdef DECNET_FIX for problematic duplicate detection code
|
||||
07-Jun-03 MP Added WIN32 support for DECNET duplicate address detection.
|
||||
05-Jun-03 DTH Added used to struct eth_packet
|
||||
01-Feb-03 MP Changed some uint8 strings to char* to reflect usage
|
||||
22-Oct-02 DTH Added all_multicast and promiscuous support
|
||||
21-Oct-02 DTH Corrected copyright again
|
||||
16-Oct-02 DTH Fixed copyright
|
||||
08-Oct-02 DTH Integrated with 2.10-0p4, added variable vector and copyrights
|
||||
03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11
|
||||
15-Aug-02 DTH Started XQ simulation
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _SIM_ETHER_H
|
||||
#define _SIM_ETHER_H
|
||||
|
||||
#include "sim_defs.h"
|
||||
|
||||
/* make common BSD code a bit easier to read in this file */
|
||||
/* OS/X seems to define and compile using one of these BSD types */
|
||||
#if defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__)
|
||||
#define xBSD 1
|
||||
#endif
|
||||
#if !defined(__FreeBSD__) && !defined(_WIN32) && !defined(VMS)
|
||||
#define USE_SETNONBLOCK 1
|
||||
#endif
|
||||
|
||||
#if defined(__sun__) && defined(__i386__)
|
||||
#define USE_READER_THREAD 1
|
||||
#endif
|
||||
|
||||
/* make common winpcap code a bit easier to read in this file */
|
||||
#if defined(_WIN32) || defined(VMS)
|
||||
#define PCAP_READ_TIMEOUT -1
|
||||
#else
|
||||
#define PCAP_READ_TIMEOUT 1
|
||||
#endif
|
||||
|
||||
/* set related values to have correct relationships */
|
||||
#if defined (USE_READER_THREAD)
|
||||
#if defined (USE_SETNONBLOCK)
|
||||
#undef USE_SETNONBLOCK
|
||||
#endif
|
||||
#undef PCAP_READ_TIMEOUT
|
||||
#define PCAP_READ_TIMEOUT 15
|
||||
#if !defined (xBSD) && !defined(_WIN32) && !defined(VMS)
|
||||
#define MUST_DO_SELECT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
USE_BPF is defined to let this code leverage the libpcap/OS kernel provided
|
||||
BPF packet filtering. This generally will enhance performance. It may not
|
||||
be available in some environments and/or it may not work correctly, so
|
||||
undefining this will still provide working code here.
|
||||
*/
|
||||
#define USE_BPF 1
|
||||
|
||||
#if defined (USE_READER_THREAD)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
/* structure declarations */
|
||||
|
||||
#define ETH_PROMISC 1 /* promiscuous mode = true */
|
||||
#define ETH_TIMEOUT -1 /* read timeout in milliseconds (immediate) */
|
||||
#define ETH_FILTER_MAX 20 /* maximum address filters */
|
||||
#define ETH_DEV_NAME_MAX 256 /* maximum device name size */
|
||||
#define ETH_DEV_DESC_MAX 256 /* maximum device description size */
|
||||
#define ETH_MIN_PACKET 60 /* minimum ethernet packet size */
|
||||
#define ETH_MAX_PACKET 1514 /* maximum ethernet packet size */
|
||||
#define ETH_MAX_DEVICE 10 /* maximum ethernet devices */
|
||||
#define ETH_CRC_SIZE 4 /* ethernet CRC size */
|
||||
#define ETH_FRAME_SIZE 1518 /* ethernet maximum frame size */
|
||||
|
||||
#define DECNET_SELF_FRAME(dnet_mac, msg) \
|
||||
((memcmp(dnet_mac, msg , 6) == 0) && \
|
||||
(memcmp(dnet_mac, msg+6, 6) == 0))
|
||||
|
||||
struct eth_packet {
|
||||
uint8 msg[ETH_FRAME_SIZE]; /* ethernet frame (message) */
|
||||
int len; /* packet length without CRC */
|
||||
int used; /* bytes processed (used in packet chaining) */
|
||||
int status; /* transmit/receive status */
|
||||
int crc_len; /* packet length with CRC */
|
||||
};
|
||||
|
||||
struct eth_item {
|
||||
int type; /* receive (0=setup, 1=loopback, 2=normal) */
|
||||
struct eth_packet packet;
|
||||
};
|
||||
|
||||
struct eth_queue {
|
||||
int max;
|
||||
int count;
|
||||
int head;
|
||||
int tail;
|
||||
int loss;
|
||||
int high;
|
||||
struct eth_item* item;
|
||||
};
|
||||
|
||||
struct eth_list {
|
||||
int num;
|
||||
char name[ETH_DEV_NAME_MAX];
|
||||
char desc[ETH_DEV_DESC_MAX];
|
||||
};
|
||||
|
||||
typedef int ETH_BOOL;
|
||||
typedef unsigned char ETH_MAC[6];
|
||||
typedef struct eth_packet ETH_PACK;
|
||||
typedef void (*ETH_PCALLBACK)(int status);
|
||||
typedef struct eth_list ETH_LIST;
|
||||
typedef struct eth_queue ETH_QUE;
|
||||
typedef struct eth_item ETH_ITEM;
|
||||
|
||||
struct eth_device {
|
||||
char* name; /* name of ethernet device */
|
||||
void* handle; /* handle of implementation-specific device */
|
||||
ETH_PCALLBACK read_callback; /* read callback function */
|
||||
ETH_PCALLBACK write_callback; /* write callback function */
|
||||
ETH_PACK* read_packet; /* read packet */
|
||||
ETH_PACK* write_packet; /* write packet */
|
||||
ETH_MAC filter_address[ETH_FILTER_MAX]; /* filtering addresses */
|
||||
int addr_count; /* count of filtering addresses */
|
||||
ETH_BOOL promiscuous; /* promiscuous mode flag */
|
||||
ETH_BOOL all_multicast; /* receive all multicast messages */
|
||||
int32 decnet_self_sent; /* loopback packets sent but not seen */
|
||||
ETH_MAC decnet_addr; /* decnet address of interface */
|
||||
DEVICE* dptr; /* device ethernet is attached to */
|
||||
uint32 dbit; /* debugging bit */
|
||||
int reflections; /* packet reflections on interface */
|
||||
int need_crc; /* device needs CRC (Cyclic Redundancy Check) */
|
||||
#if defined (USE_READER_THREAD)
|
||||
ETH_QUE read_queue;
|
||||
pthread_mutex_t lock;
|
||||
pthread_t reader_thread; /* Reader Thread Id */
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct eth_device ETH_DEV;
|
||||
|
||||
/* prototype declarations*/
|
||||
|
||||
t_stat eth_open (ETH_DEV* dev, char* name, /* open ethernet interface */
|
||||
DEVICE* dptr, uint32 dbit);
|
||||
t_stat eth_close (ETH_DEV* dev); /* close ethernet interface */
|
||||
t_stat eth_write (ETH_DEV* dev, ETH_PACK* packet, /* write sychronous packet; */
|
||||
ETH_PCALLBACK routine); /* callback when done */
|
||||
t_stat eth_read (ETH_DEV* dev, ETH_PACK* packet, /* read single packet; */
|
||||
ETH_PCALLBACK routine); /* callback when done*/
|
||||
t_stat eth_filter (ETH_DEV* dev, int addr_count, /* set filter on incoming packets */
|
||||
ETH_MAC* addresses,
|
||||
ETH_BOOL all_multicast,
|
||||
ETH_BOOL promiscuous);
|
||||
int eth_devices (int max, ETH_LIST* dev); /* get ethernet devices on host */
|
||||
void eth_setcrc (ETH_DEV* dev, int need_crc); /* enable/disable CRC mode */
|
||||
|
||||
void eth_packet_trace (ETH_DEV* dev, const uint8 *msg, int len, char* txt); /* trace ethernet packet */
|
||||
t_stat eth_show (FILE* st, UNIT* uptr, /* show ethernet devices */
|
||||
int32 val, void* desc);
|
||||
|
||||
void eth_mac_fmt (ETH_MAC* add, char* buffer); /* format ethernet mac address */
|
||||
t_stat eth_mac_scan (ETH_MAC* mac, char* strmac); /* scan string for mac, put in mac */
|
||||
|
||||
t_stat ethq_init (ETH_QUE* que, int max); /* initialize FIFO queue */
|
||||
void ethq_clear (ETH_QUE* que); /* clear FIFO queue */
|
||||
void ethq_remove (ETH_QUE* que); /* remove item from FIFO queue */
|
||||
void ethq_insert (ETH_QUE* que, int32 type, /* insert item into FIFO queue */
|
||||
ETH_PACK* packet, int32 status);
|
||||
|
||||
|
||||
#endif /* _SIM_ETHER_H */
|
||||
320
simhv36-1/sim_fio.c
Normal file
320
simhv36-1/sim_fio.c
Normal file
@@ -0,0 +1,320 @@
|
||||
/* sim_fio.c: simulator file I/O library
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman)
|
||||
15-May-06 RMS Added sim_fsize_name
|
||||
21-Apr-06 RMS Added FreeBSD large file support (from Mark Martinec)
|
||||
19-Nov-05 RMS Added OS/X large file support (from Peter Schorn)
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
17-Jul-04 RMS Fixed bug in optimized sim_fread (reported by Scott Bailey)
|
||||
26-May-04 RMS Optimized sim_fread (suggested by John Dundas)
|
||||
02-Jan-04 RMS Split out from SCP
|
||||
|
||||
This library includes:
|
||||
|
||||
sim_finit - initialize package
|
||||
sim_fopen - open file
|
||||
sim_fread - endian independent read (formerly fxread)
|
||||
sim_write - endian independent write (formerly fxwrite)
|
||||
sim_fseek - extended (>32b) seek (formerly fseek_ext)
|
||||
sim_fsize - get file size
|
||||
|
||||
sim_fopen and sim_fseek are OS-dependent. The other routines are not.
|
||||
sim_fsize is always a 32b routine (it is used only with small capacity random
|
||||
access devices like fixed head disks and DECtapes).
|
||||
*/
|
||||
|
||||
#include "sim_defs.h"
|
||||
|
||||
static unsigned char sim_flip[FLIP_SIZE];
|
||||
int32 sim_end = 1; /* 1 = little */
|
||||
|
||||
/* OS-independent, endian independent binary I/O package
|
||||
|
||||
For consistency, all binary data read and written by the simulator
|
||||
is stored in little endian data order. That is, in a multi-byte
|
||||
data item, the bytes are written out right to left, low order byte
|
||||
to high order byte. On a big endian host, data is read and written
|
||||
from high byte to low byte. Consequently, data written on a little
|
||||
endian system must be byte reversed to be usable on a big endian
|
||||
system, and vice versa.
|
||||
|
||||
These routines are analogs of the standard C runtime routines
|
||||
fread and fwrite. If the host is little endian, or the data items
|
||||
are size char, then the calls are passed directly to fread or
|
||||
fwrite. Otherwise, these routines perform the necessary byte swaps.
|
||||
Sim_fread swaps in place, sim_fwrite uses an intermediate buffer.
|
||||
*/
|
||||
|
||||
int32 sim_finit (void)
|
||||
{
|
||||
union {int32 i; char c[sizeof (int32)]; } end_test;
|
||||
|
||||
end_test.i = 1; /* test endian-ness */
|
||||
sim_end = end_test.c[0];
|
||||
return sim_end;
|
||||
}
|
||||
|
||||
size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr)
|
||||
{
|
||||
size_t c, j;
|
||||
int32 k;
|
||||
unsigned char by, *sptr, *dptr;
|
||||
|
||||
if ((size == 0) || (count == 0)) return 0; /* check arguments */
|
||||
c = fread (bptr, size, count, fptr); /* read buffer */
|
||||
if (sim_end || (size == sizeof (char)) || (c == 0)) /* le, byte, or err? */
|
||||
return c; /* done */
|
||||
for (j = 0, dptr = sptr = (unsigned char *) bptr; j < c; j++) { /* loop on items */
|
||||
for (k = size - 1; k >= (((int32) size + 1) / 2); k--) {
|
||||
by = *sptr; /* swap end-for-end */
|
||||
*sptr++ = *(dptr + k);
|
||||
*(dptr + k) = by;
|
||||
}
|
||||
sptr = dptr = dptr + size; /* next item */
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr)
|
||||
{
|
||||
size_t c, j, nelem, nbuf, lcnt, total;
|
||||
int32 i, k;
|
||||
unsigned char *sptr, *dptr;
|
||||
|
||||
if ((size == 0) || (count == 0)) return 0; /* check arguments */
|
||||
if (sim_end || (size == sizeof (char))) /* le or byte? */
|
||||
return fwrite (bptr, size, count, fptr); /* done */
|
||||
nelem = FLIP_SIZE / size; /* elements in buffer */
|
||||
nbuf = count / nelem; /* number buffers */
|
||||
lcnt = count % nelem; /* count in last buf */
|
||||
if (lcnt) nbuf = nbuf + 1;
|
||||
else lcnt = nelem;
|
||||
total = 0;
|
||||
sptr = (unsigned char *) bptr; /* init input ptr */
|
||||
for (i = nbuf; i > 0; i--) { /* loop on buffers */
|
||||
c = (i == 1)? lcnt: nelem;
|
||||
for (j = 0, dptr = sim_flip; j < c; j++) { /* loop on items */
|
||||
for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++;
|
||||
dptr = dptr + size;
|
||||
}
|
||||
c = fwrite (sim_flip, size, c, fptr);
|
||||
if (c == 0) return total;
|
||||
total = total + c;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Get file size */
|
||||
|
||||
uint32 sim_fsize_name (char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
uint32 sz;
|
||||
|
||||
if ((fp = sim_fopen (fname, "rb")) == NULL) return 0;
|
||||
sz = sim_fsize (fp);
|
||||
fclose (fp);
|
||||
return sz;
|
||||
}
|
||||
|
||||
uint32 sim_fsize (FILE *fp)
|
||||
{
|
||||
uint32 pos, sz;
|
||||
|
||||
if (fp == NULL) return 0;
|
||||
pos = ftell (fp);
|
||||
fseek (fp, 0, SEEK_END);
|
||||
sz = ftell (fp);
|
||||
fseek (fp, pos, SEEK_SET);
|
||||
return sz;
|
||||
}
|
||||
|
||||
/* OS-dependent routines */
|
||||
|
||||
/* Optimized file open */
|
||||
|
||||
FILE *sim_fopen (const char *file, const char *mode)
|
||||
{
|
||||
#if defined (VMS)
|
||||
return fopen (file, mode, "ALQ=32", "DEQ=4096",
|
||||
"MBF=6", "MBC=127", "FOP=cbt,tef", "ROP=rah,wbh", "CTX=stm");
|
||||
#elif defined (USE_INT64) && defined (USE_ADDR64) && defined (__linux)
|
||||
return fopen64 (file, mode);
|
||||
#else
|
||||
return fopen (file, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Long seek */
|
||||
|
||||
#if defined (USE_INT64) && defined (USE_ADDR64)
|
||||
|
||||
/* Alpha VMS */
|
||||
|
||||
#if defined (__ALPHA) && defined (VMS) /* Alpha VMS */
|
||||
#define _SIM_IO_FSEEK_EXT_ 1
|
||||
|
||||
static t_int64 fpos_t_to_int64 (fpos_t *pos)
|
||||
{
|
||||
unsigned short *w = (unsigned short *) pos; /* endian dep! */
|
||||
t_int64 result;
|
||||
|
||||
result = w[1];
|
||||
result <<= 16;
|
||||
result += w[0];
|
||||
result <<= 9;
|
||||
result += w[2];
|
||||
return result;
|
||||
}
|
||||
|
||||
static void int64_to_fpos_t (t_int64 ipos, fpos_t *pos, size_t mbc)
|
||||
{
|
||||
unsigned short *w = (unsigned short *) pos;
|
||||
int bufsize = mbc << 9;
|
||||
|
||||
w[3] = 0;
|
||||
w[2] = (unsigned short) (ipos % bufsize);
|
||||
ipos -= w[2];
|
||||
ipos >>= 9;
|
||||
w[0] = (unsigned short) ipos;
|
||||
ipos >>= 16;
|
||||
w[1] = (unsigned short) ipos;
|
||||
if ((w[2] == 0) && (w[0] || w[1])) {
|
||||
w[2] = bufsize;
|
||||
w[0] -= mbc;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int sim_fseek (FILE *st, t_addr offset, int whence)
|
||||
{
|
||||
t_addr fileaddr;
|
||||
fpos_t filepos;
|
||||
|
||||
switch (whence) {
|
||||
|
||||
case SEEK_SET:
|
||||
fileaddr = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
if (fgetpos (st, &filepos)) return (-1);
|
||||
fileaddr = fpos_t_to_int64 (&filepos);
|
||||
fileaddr = fileaddr + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int64_to_fpos_t (fileaddr, &filepos, 127);
|
||||
return fsetpos (st, &filepos);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Alpha UNIX - natively 64b */
|
||||
|
||||
#if defined (__ALPHA) && defined (__unix__) /* Alpha UNIX */
|
||||
#define _SIM_IO_FSEEK_EXT_ 1
|
||||
|
||||
int sim_fseek (FILE *st, t_addr offset, int whence)
|
||||
{
|
||||
return fseek (st, offset, whence);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Windows */
|
||||
|
||||
#if defined (_WIN32)
|
||||
#define _SIM_IO_FSEEK_EXT_ 1
|
||||
|
||||
int sim_fseek (FILE *st, t_addr offset, int whence)
|
||||
{
|
||||
fpos_t fileaddr;
|
||||
|
||||
switch (whence) {
|
||||
|
||||
case SEEK_SET:
|
||||
fileaddr = offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
if (fgetpos (st, &fileaddr)) return (-1);
|
||||
fileaddr = fileaddr + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return fsetpos (st, &fileaddr);
|
||||
}
|
||||
|
||||
#endif /* end Windows */
|
||||
|
||||
/* Linux */
|
||||
|
||||
#if defined (__linux)
|
||||
#define _SIM_IO_FSEEK_EXT_ 1
|
||||
|
||||
int sim_fseek (FILE *st, t_addr xpos, int origin)
|
||||
{
|
||||
return fseeko64 (st, xpos, origin);
|
||||
}
|
||||
|
||||
#endif /* end Linux with LFS */
|
||||
|
||||
/* Apple OS/X */
|
||||
|
||||
#if defined (__APPLE__) || defined (__FreeBSD__)
|
||||
#define _SIM_IO_FSEEK_EXT_ 1
|
||||
|
||||
int sim_fseek (FILE *st, t_addr xpos, int origin)
|
||||
{
|
||||
return fseeko (st, xpos, origin);
|
||||
}
|
||||
|
||||
#endif /* end Apple OS/X */
|
||||
|
||||
#endif /* end 64b seek defs */
|
||||
|
||||
/* Default: no OS-specific routine has been defined */
|
||||
|
||||
#if !defined (_SIM_IO_FSEEK_EXT_)
|
||||
#define _SIM_IO_FSEEK_EXT_ 0
|
||||
|
||||
int sim_fseek (FILE *st, t_addr xpos, int origin)
|
||||
{
|
||||
return fseek (st, (int32) xpos, origin);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uint32 sim_taddr_64 = _SIM_IO_FSEEK_EXT_;
|
||||
46
simhv36-1/sim_fio.h
Normal file
46
simhv36-1/sim_fio.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* sim_fio.h: simulator file I/O library headers
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
15-May-06 RMS Added sim_fsize_name
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
02-Jan-04 RMS Split out from SCP
|
||||
*/
|
||||
|
||||
#ifndef _SIM_FIO_H_
|
||||
#define _SIM_FIO_H_ 0
|
||||
|
||||
#define FLIP_SIZE (1 << 16) /* flip buf size */
|
||||
#define fxread(a,b,c,d) sim_fread (a, b, c, d)
|
||||
#define fxwrite(a,b,c,d) sim_fwrite (a, b, c, d)
|
||||
|
||||
int32 sim_finit (void);
|
||||
FILE *sim_fopen (const char *file, const char *mode);
|
||||
int sim_fseek (FILE *st, t_addr offset, int whence);
|
||||
size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr);
|
||||
size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr);
|
||||
uint32 sim_fsize (FILE *fptr);
|
||||
uint32 sim_fsize_name (char *fname);
|
||||
|
||||
#endif
|
||||
1744
simhv36-1/sim_rev.h
Normal file
1744
simhv36-1/sim_rev.h
Normal file
File diff suppressed because it is too large
Load Diff
314
simhv36-1/sim_sock.c
Normal file
314
simhv36-1/sim_sock.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/* sim_sock.c: OS-dependent socket routines
|
||||
|
||||
Copyright (c) 2001-2005, 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.
|
||||
|
||||
19-Nov-05 RMS Added conditional for OpenBSD (from Federico G. Schwindt)
|
||||
16-Aug-05 RMS Fixed spurious SIGPIPE signal error in Unix
|
||||
14-Apr-05 RMS Added WSAEINPROGRESS test (from Tim Riker)
|
||||
09-Jan-04 RMS Fixed typing problem in Alpha Unix (found by Tim Chapman)
|
||||
17-Apr-03 RMS Fixed non-implemented version of sim_close_sock
|
||||
(found by Mark Pizzolato)
|
||||
17-Dec-02 RMS Added sim_connect_socket, sim_create_socket
|
||||
08-Oct-02 RMS Revised for .NET compatibility
|
||||
22-Aug-02 RMS Changed calling sequence for sim_accept_conn
|
||||
22-May-02 RMS Added OS2 EMX support from Holger Veit
|
||||
06-Feb-02 RMS Added VMS support from Robert Alan Byer
|
||||
16-Sep-01 RMS Added Macintosh support from Peter Schorn
|
||||
02-Sep-01 RMS Fixed UNIX bugs found by Mirian Lennox and Tom Markson
|
||||
*/
|
||||
|
||||
#include "sim_defs.h"
|
||||
#include "sim_sock.h"
|
||||
#include <signal.h>
|
||||
|
||||
/* OS dependent routines
|
||||
|
||||
sim_master_sock create master socket
|
||||
sim_accept_conn accept connection
|
||||
sim_read_sock read from socket
|
||||
sim_write_sock write from socket
|
||||
sim_close_sock close socket
|
||||
sim_setnonblock set socket non-blocking
|
||||
sim_msg_sock send message to socket
|
||||
*/
|
||||
|
||||
int32 sim_sock_cnt = 0;
|
||||
|
||||
/* First, all the non-implemented versions */
|
||||
|
||||
#if defined (__OS2__) && !defined (__EMX__)
|
||||
|
||||
SOCKET sim_master_sock (int32 port)
|
||||
{
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
SOCKET sim_connect_sock (int32 ip, int32 port)
|
||||
{
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr)
|
||||
{
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sim_close_sock (SOCKET sock, t_bool master)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SOCKET sim_setnonblock (SOCKET sock)
|
||||
{
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
#else /* endif unimpl */
|
||||
|
||||
/* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */
|
||||
|
||||
SOCKET sim_err_sock (SOCKET s, char *emsg, int32 flg)
|
||||
{
|
||||
int32 err = WSAGetLastError ();
|
||||
|
||||
printf ("Sockets: %s error %d\n", emsg, err);
|
||||
sim_close_sock (s, flg);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
SOCKET sim_create_sock (void)
|
||||
{
|
||||
SOCKET newsock;
|
||||
int32 err;
|
||||
|
||||
#if defined (_WIN32)
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
wVersionRequested = MAKEWORD (1, 1);
|
||||
|
||||
if (sim_sock_cnt == 0) {
|
||||
err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */
|
||||
if (err != 0) {
|
||||
printf ("Winsock: startup error %d\n", err);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
sim_sock_cnt = sim_sock_cnt + 1;
|
||||
#endif /* endif Win32 */
|
||||
#if defined (SIGPIPE)
|
||||
signal (SIGPIPE, SIG_IGN); /* no pipe signals */
|
||||
#endif
|
||||
|
||||
newsock = socket (AF_INET, SOCK_STREAM, 0); /* create socket */
|
||||
if (newsock == INVALID_SOCKET) { /* socket error? */
|
||||
err = WSAGetLastError ();
|
||||
printf ("Sockets: socket error %d\n", err);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
return newsock;
|
||||
}
|
||||
|
||||
SOCKET sim_master_sock (int32 port)
|
||||
{
|
||||
SOCKET newsock;
|
||||
struct sockaddr_in name;
|
||||
int32 sta;
|
||||
|
||||
newsock = sim_create_sock (); /* create socket */
|
||||
if (newsock == INVALID_SOCKET) return newsock; /* socket error? */
|
||||
|
||||
name.sin_family = AF_INET; /* name socket */
|
||||
name.sin_port = htons ((unsigned short) port); /* insert port */
|
||||
name.sin_addr.s_addr = htonl (INADDR_ANY); /* insert addr */
|
||||
|
||||
sta = bind (newsock, (struct sockaddr *) &name, sizeof (name));
|
||||
if (sta == SOCKET_ERROR) /* bind error? */
|
||||
return sim_err_sock (newsock, "bind", 1);
|
||||
sta = sim_setnonblock (newsock); /* set nonblocking */
|
||||
if (sta == SOCKET_ERROR) /* fcntl error? */
|
||||
return sim_err_sock (newsock, "fcntl", 1);
|
||||
sta = listen (newsock, 1); /* listen on socket */
|
||||
if (sta == SOCKET_ERROR) /* listen error? */
|
||||
return sim_err_sock (newsock, "listen", 1);
|
||||
return newsock; /* got it! */
|
||||
}
|
||||
|
||||
SOCKET sim_connect_sock (int32 ip, int32 port)
|
||||
{
|
||||
SOCKET newsock;
|
||||
struct sockaddr_in name;
|
||||
int32 sta;
|
||||
|
||||
newsock = sim_create_sock (); /* create socket */
|
||||
if (newsock == INVALID_SOCKET) return newsock; /* socket error? */
|
||||
|
||||
name.sin_family = AF_INET; /* name socket */
|
||||
name.sin_port = htons ((unsigned short) port); /* insert port */
|
||||
name.sin_addr.s_addr = htonl (ip); /* insert addr */
|
||||
|
||||
sta = sim_setnonblock (newsock); /* set nonblocking */
|
||||
if (sta == SOCKET_ERROR) /* fcntl error? */
|
||||
return sim_err_sock (newsock, "fcntl", 1);
|
||||
sta = connect (newsock, (struct sockaddr *) &name, sizeof (name));
|
||||
if ((sta == SOCKET_ERROR) &&
|
||||
(WSAGetLastError () != WSAEWOULDBLOCK) &&
|
||||
(WSAGetLastError () != WSAEINPROGRESS))
|
||||
return sim_err_sock (newsock, "connect", 1);
|
||||
|
||||
return newsock; /* got it! */
|
||||
}
|
||||
|
||||
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr)
|
||||
{
|
||||
int32 sta, err;
|
||||
#if defined (macintosh) || defined (__linux) || \
|
||||
defined (__APPLE__) || defined (__OpenBSD__)
|
||||
socklen_t size;
|
||||
#elif defined (_WIN32) || defined (__EMX__) ||\
|
||||
(defined (__ALPHA) && defined (__unix__))
|
||||
int size;
|
||||
#else
|
||||
size_t size;
|
||||
#endif
|
||||
SOCKET newsock;
|
||||
struct sockaddr_in clientname;
|
||||
|
||||
if (master == 0) return INVALID_SOCKET; /* not attached? */
|
||||
size = sizeof (clientname);
|
||||
newsock = accept (master, (struct sockaddr *) &clientname, &size);
|
||||
if (newsock == INVALID_SOCKET) { /* error? */
|
||||
err = WSAGetLastError ();
|
||||
if (err != WSAEWOULDBLOCK)
|
||||
printf ("Sockets: accept error %d\n", err);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
if (ipaddr != NULL) *ipaddr = ntohl (clientname.sin_addr.s_addr);
|
||||
|
||||
sta = sim_setnonblock (newsock); /* set nonblocking */
|
||||
if (sta == SOCKET_ERROR) /* fcntl error? */
|
||||
return sim_err_sock (newsock, "fcntl", 0);
|
||||
return newsock;
|
||||
}
|
||||
|
||||
int32 sim_check_conn (SOCKET sock, t_bool rd)
|
||||
{
|
||||
fd_set rw_set, er_set;
|
||||
fd_set *rw_p = &rw_set;
|
||||
fd_set *er_p = &er_set;
|
||||
struct timeval tz;
|
||||
|
||||
timerclear (&tz);
|
||||
FD_ZERO (rw_p);
|
||||
FD_ZERO (er_p);
|
||||
FD_SET (sock, rw_p);
|
||||
FD_SET (sock, er_p);
|
||||
if (rd) select ((int) sock + 1, rw_p, NULL, er_p, &tz);
|
||||
else select ((int) sock + 1, NULL, rw_p, er_p, &tz);
|
||||
if (FD_ISSET (sock, rw_p)) return 1;
|
||||
if (FD_ISSET (sock, er_p)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes)
|
||||
{
|
||||
int32 rbytes, err;
|
||||
|
||||
rbytes = recv (sock, buf, nbytes, 0);
|
||||
if (rbytes == 0) return -1; /* disconnect */
|
||||
if (rbytes == SOCKET_ERROR) {
|
||||
err = WSAGetLastError ();
|
||||
if (err == WSAEWOULDBLOCK) return 0; /* no data */
|
||||
printf ("Sockets: read error %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
return rbytes;
|
||||
}
|
||||
|
||||
int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes)
|
||||
{
|
||||
return send (sock, msg, nbytes, 0);
|
||||
}
|
||||
|
||||
void sim_close_sock (SOCKET sock, t_bool master)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
closesocket (sock);
|
||||
if (master) {
|
||||
sim_sock_cnt = sim_sock_cnt - 1;
|
||||
if (sim_sock_cnt <= 0) {
|
||||
WSACleanup ();
|
||||
sim_sock_cnt = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
close (sock);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined (_WIN32) /* Windows */
|
||||
SOCKET sim_setnonblock (SOCKET sock)
|
||||
{
|
||||
unsigned long non_block = 1;
|
||||
|
||||
return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */
|
||||
}
|
||||
|
||||
#elif defined (VMS) /* VMS */
|
||||
SOCKET sim_setnonblock (SOCKET sock)
|
||||
{
|
||||
int non_block = 1;
|
||||
|
||||
return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */
|
||||
}
|
||||
|
||||
#else /* Mac, Unix, OS/2 */
|
||||
int32 sim_setnonblock (SOCKET sock)
|
||||
{
|
||||
int32 fl, sta;
|
||||
|
||||
fl = fcntl (sock, F_GETFL,0); /* get flags */
|
||||
if (fl == -1) return SOCKET_ERROR;
|
||||
sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */
|
||||
if (sta == -1) return SOCKET_ERROR;
|
||||
#if !defined (macintosh) && !defined (__EMX__) /* Unix only */
|
||||
sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */
|
||||
if (sta == -1) return SOCKET_ERROR;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* endif !Win32 && !VMS */
|
||||
|
||||
#endif /* end else !implemented */
|
||||
86
simhv36-1/sim_sock.h
Normal file
86
simhv36-1/sim_sock.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* sim_sock.h: OS-dependent socket routines header file
|
||||
|
||||
Copyright (c) 2001-2005, 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.
|
||||
|
||||
14-Apr-05 RMS Added WSAEINPROGRESS (from Tim Riker)
|
||||
20-Aug-04 HV Added missing definition for OS/2 (from Holger Veit)
|
||||
22-Oct-03 MP Changed WIN32 winsock include to use winsock2.h to
|
||||
avoid a conflict if sim_sock.h and sim_ether.h get
|
||||
included by the same module.
|
||||
20-Mar-03 RMS Added missing timerclear definition for VMS (from
|
||||
Robert Alan Byer)
|
||||
15-Feb-03 RMS Added time.h for EMX (from Holger Veit)
|
||||
17-Dec-02 RMS Added sim_connect_sock
|
||||
08-Oct-02 RMS Revised for .NET compatibility
|
||||
20-Aug-02 RMS Changed calling sequence for sim_accept_conn
|
||||
30-Apr-02 RMS Changed VMS stropts include to ioctl
|
||||
06-Feb-02 RMS Added VMS support from Robert Alan Byer
|
||||
16-Sep-01 RMS Added Macintosh support from Peter Schorn
|
||||
*/
|
||||
|
||||
#ifndef _SIM_SOCK_H_
|
||||
#define _SIM_SOCK_H_ 0
|
||||
|
||||
#if defined (_WIN32) /* Windows */
|
||||
#undef INT_PTR /* hack, hack */
|
||||
#include <winsock2.h>
|
||||
|
||||
#elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */
|
||||
#define WSAGetLastError() errno /* Windows macros */
|
||||
#define SOCKET int32
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define WSAEINPROGRESS EINPROGRESS
|
||||
#define INVALID_SOCKET -1
|
||||
#define SOCKET_ERROR -1
|
||||
#include <sys/types.h> /* for fcntl, getpid */
|
||||
#include <sys/socket.h> /* for sockets */
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h> /* for sockaddr_in */
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h> /* for EMX */
|
||||
#endif
|
||||
|
||||
#if defined (VMS) /* VMS unique */
|
||||
#include <ioctl.h> /* for ioctl */
|
||||
#if !defined (timerclear)
|
||||
#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__EMX__) /* OS/2 unique */
|
||||
#if !defined (timerclear)
|
||||
#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SOCKET sim_master_sock (int32 port);
|
||||
SOCKET sim_connect_sock (int32 ip, int32 port);
|
||||
SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr);
|
||||
int32 sim_check_conn (SOCKET sock, t_bool rd);
|
||||
int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes);
|
||||
int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes);
|
||||
void sim_close_sock (SOCKET sock, t_bool master);
|
||||
SOCKET sim_setnonblock (SOCKET sock);
|
||||
|
||||
#endif
|
||||
675
simhv36-1/sim_tape.c
Normal file
675
simhv36-1/sim_tape.c
Normal file
@@ -0,0 +1,675 @@
|
||||
/* sim_tape.c: simulator tape support library
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
Ultimately, this will be a place to hide processing of various tape formats,
|
||||
as well as OS-specific direct hardware access.
|
||||
|
||||
14-Feb-06 RMS Added variable tape capacity
|
||||
23-Jan-06 JDB Fixed odd-byte-write problem in sim_tape_wrrecf
|
||||
17-Dec-05 RMS Added write support for Paul Pierce 7b format
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
02-May-05 RMS Added support for Pierce 7b format
|
||||
28-Jul-04 RMS Fixed bug in writing error records (found by Dave Bryan)
|
||||
RMS Fixed incorrect error codes (found by Dave Bryan)
|
||||
05-Jan-04 RMS Revised for file I/O library
|
||||
25-Apr-03 RMS Added extended file support
|
||||
28-Mar-03 RMS Added E11 and TPC format support
|
||||
|
||||
Public routines:
|
||||
|
||||
sim_tape_attach attach tape unit
|
||||
sim_tape_detach detach tape unit
|
||||
sim_tape_rdrecf read tape record forward
|
||||
sim_tape_rdrecr read tape record reverse
|
||||
sim_tape_wrrecf write tape record forward
|
||||
sim_tape_sprecf space tape record forward
|
||||
sim_tape_sprecr space tape record reverse
|
||||
sim_tape_wrtmk write tape mark
|
||||
sim_tape_wreom erase remainder of tape
|
||||
sim_tape_rewind rewind
|
||||
sim_tape_reset reset unit
|
||||
sim_tape_bot TRUE if at beginning of tape
|
||||
sim_tape_eot TRUE if at or beyond end of tape
|
||||
sim_tape_wrp TRUE if write protected
|
||||
sim_tape_set_fmt set tape format
|
||||
sim_tape_show_fmt show tape format
|
||||
sim_tape_set_capac set tape capacity
|
||||
sim_tape_show_capac show tape capacity
|
||||
*/
|
||||
|
||||
#include "sim_defs.h"
|
||||
#include "sim_tape.h"
|
||||
|
||||
struct sim_tape_fmt {
|
||||
char *name; /* name */
|
||||
int32 uflags; /* unit flags */
|
||||
t_addr bot; /* bot test */
|
||||
};
|
||||
|
||||
static struct sim_tape_fmt fmts[MTUF_N_FMT] = {
|
||||
{ "SIMH", 0, sizeof (t_mtrlnt) - 1 },
|
||||
{ "E11", 0, sizeof (t_mtrlnt) - 1 },
|
||||
{ "TPC", UNIT_RO, sizeof (t_tpclnt) - 1 },
|
||||
{ "P7B", 0, 0 },
|
||||
/* { "TPF", UNIT_RO, 0 }, */
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
extern int32 sim_switches;
|
||||
|
||||
t_stat sim_tape_ioerr (UNIT *uptr);
|
||||
t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat);
|
||||
uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map);
|
||||
t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map);
|
||||
|
||||
/* Attach tape unit */
|
||||
|
||||
t_stat sim_tape_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 objc;
|
||||
char gbuf[CBUFSIZE];
|
||||
t_stat r;
|
||||
|
||||
if (sim_switches & SWMASK ('F')) { /* format spec? */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get spec */
|
||||
if (*cptr == 0) return SCPE_2FARG; /* must be more */
|
||||
if (sim_tape_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK)
|
||||
return SCPE_ARG;
|
||||
}
|
||||
r = attach_unit (uptr, cptr); /* attach unit */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
switch (MT_GET_FMT (uptr)) { /* case on format */
|
||||
|
||||
case MTUF_F_TPC: /* TPC */
|
||||
objc = sim_tape_tpc_map (uptr, NULL); /* get # objects */
|
||||
if (objc == 0) { /* tape empty? */
|
||||
sim_tape_detach (uptr);
|
||||
return SCPE_FMT; /* yes, complain */
|
||||
}
|
||||
uptr->filebuf = calloc (objc + 1, sizeof (t_addr));
|
||||
if (uptr->filebuf == NULL) { /* map allocated? */
|
||||
sim_tape_detach (uptr);
|
||||
return SCPE_MEM; /* no, complain */
|
||||
}
|
||||
uptr->hwmark = objc + 1; /* save map size */
|
||||
sim_tape_tpc_map (uptr, (t_addr *) uptr->filebuf); /* fill map */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sim_tape_rewind (uptr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Detach tape unit */
|
||||
|
||||
t_stat sim_tape_detach (UNIT *uptr)
|
||||
{
|
||||
uint32 f = MT_GET_FMT (uptr);
|
||||
t_stat r;
|
||||
|
||||
r = detach_unit (uptr); /* detach unit */
|
||||
if (r != SCPE_OK) return r;
|
||||
switch (f) { /* case on format */
|
||||
|
||||
case MTUF_F_TPC: /* TPC */
|
||||
if (uptr->filebuf) free (uptr->filebuf); /* free map */
|
||||
uptr->filebuf = NULL;
|
||||
uptr->hwmark = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sim_tape_rewind (uptr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Read record length forward (internal routine)
|
||||
|
||||
Inputs:
|
||||
uptr = pointer to tape unit
|
||||
bc = pointer to returned record length
|
||||
Outputs:
|
||||
status = operation status
|
||||
|
||||
exit condition position
|
||||
|
||||
unit unattached unchanged
|
||||
read error unchanged, PNU set
|
||||
end of file/medium unchanged, PNU set
|
||||
tape mark updated
|
||||
data record updated, sim_fread will read record forward
|
||||
*/
|
||||
|
||||
t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc)
|
||||
{
|
||||
uint8 c;
|
||||
t_bool all_eof;
|
||||
uint32 f = MT_GET_FMT (uptr);
|
||||
t_mtrlnt sbc;
|
||||
t_tpclnt tpcbc;
|
||||
|
||||
MT_CLR_PNU (uptr);
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */
|
||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */
|
||||
switch (f) { /* switch on fmt */
|
||||
|
||||
case MTUF_F_STD: case MTUF_F_E11:
|
||||
sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */
|
||||
sbc = MTR_L (*bc); /* save rec lnt */
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
return sim_tape_ioerr (uptr);
|
||||
}
|
||||
if (feof (uptr->fileref) || (*bc == MTR_EOM)) { /* eof or eom? */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
return MTSE_EOM;
|
||||
}
|
||||
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over rec lnt */
|
||||
if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */
|
||||
uptr->pos = uptr->pos + sizeof (t_mtrlnt) + /* spc over record */
|
||||
((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc);
|
||||
break;
|
||||
|
||||
case MTUF_F_TPC:
|
||||
sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
|
||||
*bc = tpcbc; /* save rec lnt */
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
return sim_tape_ioerr (uptr);
|
||||
}
|
||||
if (feof (uptr->fileref)) { /* eof? */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
return MTSE_EOM;
|
||||
}
|
||||
uptr->pos = uptr->pos + sizeof (t_tpclnt); /* spc over reclnt */
|
||||
if (tpcbc == TPC_TMK) return MTSE_TMK; /* tape mark? */
|
||||
uptr->pos = uptr->pos + ((tpcbc + 1) & ~1); /* spc over record */
|
||||
break;
|
||||
|
||||
case MTUF_F_P7B:
|
||||
for (sbc = 0, all_eof = 1; ; sbc++) { /* loop thru record */
|
||||
sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
return sim_tape_ioerr (uptr);
|
||||
}
|
||||
if (feof (uptr->fileref)) { /* eof? */
|
||||
if (sbc == 0) return MTSE_EOM; /* no data? eom */
|
||||
break; /* treat like eor */
|
||||
}
|
||||
if ((sbc != 0) && (c & P7B_SOR)) break; /* next record? */
|
||||
if ((c & P7B_DPAR) != P7B_EOF) all_eof = 0;
|
||||
}
|
||||
*bc = sbc; /* save rec lnt */
|
||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
|
||||
uptr->pos = uptr->pos + sbc; /* spc over record */
|
||||
if (all_eof) return MTSE_TMK; /* tape mark? */
|
||||
break;
|
||||
|
||||
default:
|
||||
return MTSE_FMT;
|
||||
}
|
||||
|
||||
return MTSE_OK;
|
||||
}
|
||||
|
||||
/* Read record length reverse (internal routine)
|
||||
|
||||
Inputs:
|
||||
uptr = pointer to tape unit
|
||||
bc = pointer to returned record length
|
||||
Outputs:
|
||||
status = operation status
|
||||
|
||||
exit condition position
|
||||
|
||||
unit unattached unchanged
|
||||
beginning of tape unchanged
|
||||
read error unchanged
|
||||
end of file unchanged
|
||||
end of medium updated
|
||||
tape mark updated
|
||||
data record updated, sim_fread will read record forward
|
||||
*/
|
||||
|
||||
t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc)
|
||||
{
|
||||
uint8 c;
|
||||
t_bool all_eof;
|
||||
uint32 f = MT_GET_FMT (uptr);
|
||||
t_addr ppos;
|
||||
t_mtrlnt sbc;
|
||||
t_tpclnt tpcbc;
|
||||
|
||||
MT_CLR_PNU (uptr);
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */
|
||||
if (sim_tape_bot (uptr)) return MTSE_BOT; /* at BOT? */
|
||||
switch (f) { /* switch on fmt */
|
||||
|
||||
case MTUF_F_STD: case MTUF_F_E11:
|
||||
sim_fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET);
|
||||
sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */
|
||||
sbc = MTR_L (*bc);
|
||||
if (ferror (uptr->fileref)) /* error? */
|
||||
return sim_tape_ioerr (uptr);
|
||||
if (feof (uptr->fileref)) return MTSE_EOM; /* eof? */
|
||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over rec lnt */
|
||||
if (*bc == MTR_EOM) return MTSE_EOM; /* eom? */
|
||||
if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */
|
||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt) - /* spc over record */
|
||||
((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc);
|
||||
sim_fseek (uptr->fileref, uptr->pos + sizeof (t_mtrlnt), SEEK_SET);
|
||||
break;
|
||||
|
||||
case MTUF_F_TPC:
|
||||
ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf); /* find prev rec */
|
||||
sim_fseek (uptr->fileref, ppos, SEEK_SET); /* position */
|
||||
sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
|
||||
*bc = tpcbc; /* save rec lnt */
|
||||
if (ferror (uptr->fileref)) /* error? */
|
||||
return sim_tape_ioerr (uptr);
|
||||
if (feof (uptr->fileref)) return MTSE_EOM; /* eof? */
|
||||
uptr->pos = ppos; /* spc over record */
|
||||
if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */
|
||||
sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET);
|
||||
break;
|
||||
|
||||
case MTUF_F_P7B:
|
||||
for (sbc = 1, all_eof = 1; (t_addr) sbc <= uptr->pos ; sbc++) {
|
||||
sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET);
|
||||
sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
|
||||
if (ferror (uptr->fileref)) /* error? */
|
||||
return sim_tape_ioerr (uptr);
|
||||
if (feof (uptr->fileref)) return MTSE_EOM; /* eof? */
|
||||
if ((c & P7B_DPAR) != P7B_EOF) all_eof = 0;
|
||||
if (c & P7B_SOR) break; /* start of record? */
|
||||
}
|
||||
uptr->pos = uptr->pos - sbc; /* update position */
|
||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
|
||||
if (all_eof) return MTSE_TMK; /* tape mark? */
|
||||
break;
|
||||
|
||||
default:
|
||||
return MTSE_FMT;
|
||||
}
|
||||
|
||||
return MTSE_OK;
|
||||
}
|
||||
|
||||
/* Read record forward
|
||||
|
||||
Inputs:
|
||||
uptr = pointer to tape unit
|
||||
buf = pointer to buffer
|
||||
bc = pointer to returned record length
|
||||
max = maximum record size
|
||||
Outputs:
|
||||
status = operation status
|
||||
|
||||
exit condition position
|
||||
|
||||
unit unattached unchanged
|
||||
read error unchanged, PNU set
|
||||
end of file/medium unchanged, PNU set
|
||||
invalid record unchanged, PNU set
|
||||
tape mark updated
|
||||
data record updated
|
||||
data record error updated
|
||||
*/
|
||||
|
||||
t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
|
||||
{
|
||||
uint32 f = MT_GET_FMT (uptr);
|
||||
t_mtrlnt i, tbc, rbc;
|
||||
t_addr opos;
|
||||
t_stat st;
|
||||
|
||||
opos = uptr->pos; /* old position */
|
||||
if (st = sim_tape_rdlntf (uptr, &tbc)) return st; /* read rec lnt */
|
||||
*bc = rbc = MTR_L (tbc); /* strip error flag */
|
||||
if (rbc > max) { /* rec out of range? */
|
||||
MT_SET_PNU (uptr);
|
||||
uptr->pos = opos;
|
||||
return MTSE_INVRL;
|
||||
}
|
||||
i = sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr);
|
||||
uptr->pos = opos;
|
||||
return sim_tape_ioerr (uptr);
|
||||
}
|
||||
for ( ; i < rbc; i++) buf[i] = 0; /* fill with 0's */
|
||||
if (f == MTUF_F_P7B) buf[0] = buf[0] & P7B_DPAR; /* p7b? strip SOR */
|
||||
return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
|
||||
}
|
||||
|
||||
/* Read record reverse
|
||||
|
||||
Inputs:
|
||||
uptr = pointer to tape unit
|
||||
buf = pointer to buffer
|
||||
bc = pointer to returned record length
|
||||
max = maximum record size
|
||||
Outputs:
|
||||
status = operation status
|
||||
|
||||
exit condition position
|
||||
|
||||
unit unattached unchanged
|
||||
read error unchanged
|
||||
end of file unchanged
|
||||
end of medium updated
|
||||
invalid record unchanged
|
||||
tape mark updated
|
||||
data record updated
|
||||
data record error updated
|
||||
*/
|
||||
|
||||
t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
|
||||
{
|
||||
uint32 f = MT_GET_FMT (uptr);
|
||||
t_mtrlnt i, rbc, tbc;
|
||||
t_stat st;
|
||||
|
||||
if (st = sim_tape_rdlntr (uptr, &tbc)) return st; /* read rec lnt */
|
||||
*bc = rbc = MTR_L (tbc); /* strip error flag */
|
||||
if (rbc > max) return MTSE_INVRL; /* rec out of range? */
|
||||
i = sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */
|
||||
if (ferror (uptr->fileref)) /* error? */
|
||||
return sim_tape_ioerr (uptr);
|
||||
for ( ; i < rbc; i++) buf[i] = 0; /* fill with 0's */
|
||||
if (f == MTUF_F_P7B) buf[0] = buf[0] & P7B_DPAR; /* p7b? strip SOR */
|
||||
return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
|
||||
}
|
||||
|
||||
/* Write record forward
|
||||
|
||||
Inputs:
|
||||
uptr = pointer to tape unit
|
||||
buf = pointer to buffer
|
||||
bc = record length
|
||||
Outputs:
|
||||
status = operation status
|
||||
|
||||
exit condition position
|
||||
|
||||
unit unattached unchanged
|
||||
write protect unchanged
|
||||
write error unchanged, PNU set
|
||||
data record updated
|
||||
*/
|
||||
|
||||
t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc)
|
||||
{
|
||||
uint32 f = MT_GET_FMT (uptr);
|
||||
t_mtrlnt sbc;
|
||||
|
||||
MT_CLR_PNU (uptr);
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */
|
||||
if (sim_tape_wrp (uptr)) return MTSE_WRP; /* write prot? */
|
||||
sbc = MTR_L (bc);
|
||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */
|
||||
switch (f) { /* case on format */
|
||||
|
||||
case MTUF_F_STD: /* standard */
|
||||
sbc = MTR_L ((bc + 1) & ~1); /* pad odd length */
|
||||
case MTUF_F_E11: /* E11 */
|
||||
sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
|
||||
sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
|
||||
sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr);
|
||||
return sim_tape_ioerr (uptr);
|
||||
}
|
||||
uptr->pos = uptr->pos + sbc + (2 * sizeof (t_mtrlnt)); /* move tape */
|
||||
break;
|
||||
|
||||
case MTUF_F_P7B: /* Pierce 7B */
|
||||
buf[0] = buf[0] | P7B_SOR; /* mark start of rec */
|
||||
sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
|
||||
sim_fwrite (buf, sizeof (uint8), 1, uptr->fileref); /* delimit rec */
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr);
|
||||
return sim_tape_ioerr (uptr);
|
||||
}
|
||||
uptr->pos = uptr->pos + sbc; /* move tape */
|
||||
break;
|
||||
}
|
||||
|
||||
return MTSE_OK;
|
||||
}
|
||||
|
||||
/* Write metadata forward (internal routine) */
|
||||
|
||||
t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat)
|
||||
{
|
||||
MT_CLR_PNU (uptr);
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */
|
||||
if (sim_tape_wrp (uptr)) return MTSE_WRP; /* write prot? */
|
||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */
|
||||
sim_fwrite (&dat, sizeof (t_mtrlnt), 1, uptr->fileref);
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr);
|
||||
return sim_tape_ioerr (uptr);
|
||||
}
|
||||
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* move tape */
|
||||
return MTSE_OK;
|
||||
}
|
||||
|
||||
/* Write tape mark */
|
||||
|
||||
t_stat sim_tape_wrtmk (UNIT *uptr)
|
||||
{
|
||||
if (MT_GET_FMT (uptr) == MTUF_F_P7B) { /* P7B? */
|
||||
uint8 buf = P7B_EOF; /* eof mark */
|
||||
return sim_tape_wrrecf (uptr, &buf, 1); /* write char */
|
||||
}
|
||||
return sim_tape_wrdata (uptr, MTR_TMK);
|
||||
}
|
||||
|
||||
/* Write end of medium */
|
||||
|
||||
t_stat sim_tape_wreom (UNIT *uptr)
|
||||
{
|
||||
if (MT_GET_FMT (uptr) == MTUF_F_P7B) return MTSE_FMT; /* cant do P7B */
|
||||
return sim_tape_wrdata (uptr, MTR_EOM);
|
||||
}
|
||||
|
||||
/* Space record forward */
|
||||
|
||||
t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc)
|
||||
{
|
||||
t_stat st;
|
||||
|
||||
st = sim_tape_rdlntf (uptr, bc); /* get record length */
|
||||
*bc = MTR_L (*bc);
|
||||
return st;
|
||||
}
|
||||
|
||||
/* Space record reverse */
|
||||
|
||||
t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc)
|
||||
{
|
||||
t_stat st;
|
||||
|
||||
if (MT_TST_PNU (uptr)) {
|
||||
MT_CLR_PNU (uptr);
|
||||
*bc = 0;
|
||||
return MTSE_OK;
|
||||
}
|
||||
st = sim_tape_rdlntr (uptr, bc); /* get record length */
|
||||
*bc = MTR_L (*bc);
|
||||
return st;
|
||||
}
|
||||
|
||||
/* Rewind tape */
|
||||
|
||||
t_stat sim_tape_rewind (UNIT *uptr)
|
||||
{
|
||||
uptr->pos = 0;
|
||||
MT_CLR_PNU (uptr);
|
||||
return MTSE_OK;
|
||||
}
|
||||
|
||||
/* Reset tape */
|
||||
|
||||
t_stat sim_tape_reset (UNIT *uptr)
|
||||
{
|
||||
MT_CLR_PNU (uptr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Test for BOT */
|
||||
|
||||
t_bool sim_tape_bot (UNIT *uptr)
|
||||
{
|
||||
uint32 f = MT_GET_FMT (uptr);
|
||||
|
||||
return (uptr->pos <= fmts[f].bot)? TRUE: FALSE;
|
||||
}
|
||||
|
||||
/* Test for end of tape */
|
||||
|
||||
t_bool sim_tape_eot (UNIT *uptr)
|
||||
{
|
||||
return (uptr->capac && (uptr->pos >= uptr->capac))? TRUE: FALSE;
|
||||
}
|
||||
|
||||
/* Test for write protect */
|
||||
|
||||
t_bool sim_tape_wrp (UNIT *uptr)
|
||||
{
|
||||
return (uptr->flags & MTUF_WRP)? TRUE: FALSE;
|
||||
}
|
||||
|
||||
/* Process I/O error */
|
||||
|
||||
t_stat sim_tape_ioerr (UNIT *uptr)
|
||||
{
|
||||
perror ("Magtape library I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
return MTSE_IOERR;
|
||||
}
|
||||
|
||||
/* Set tape format */
|
||||
|
||||
t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 f;
|
||||
|
||||
if (uptr == NULL) return SCPE_IERR;
|
||||
if (cptr == NULL) return SCPE_ARG;
|
||||
for (f = 0; f < MTUF_N_FMT; f++) {
|
||||
if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) {
|
||||
uptr->flags = (uptr->flags & ~MTUF_FMT) |
|
||||
(f << MTUF_V_FMT) | fmts[f].uflags;
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Show tape format */
|
||||
|
||||
t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
int32 f = MT_GET_FMT (uptr);
|
||||
|
||||
if (fmts[f].name) fprintf (st, "%s format", fmts[f].name);
|
||||
else fprintf (st, "invalid format");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Map a TPC format tape image */
|
||||
|
||||
uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map)
|
||||
{
|
||||
t_addr tpos;
|
||||
t_tpclnt bc;
|
||||
uint32 i, objc;
|
||||
|
||||
if ((uptr == NULL) || (uptr->fileref == NULL)) return 0;
|
||||
for (objc = 0, tpos = 0;; ) {
|
||||
sim_fseek (uptr->fileref, tpos, SEEK_SET);
|
||||
i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref);
|
||||
if (i == 0) break;
|
||||
if (map) map[objc] = tpos;
|
||||
objc++;
|
||||
tpos = tpos + ((bc + 1) & ~1) + sizeof (t_tpclnt);
|
||||
}
|
||||
if (map) map[objc] = tpos;
|
||||
return objc;
|
||||
}
|
||||
|
||||
/* Find the preceding record in a TPC file */
|
||||
|
||||
t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map)
|
||||
{
|
||||
uint32 lo, hi, p;
|
||||
|
||||
|
||||
if (map == NULL) return 0;
|
||||
lo = 0;
|
||||
hi = uptr->hwmark - 1;
|
||||
do {
|
||||
p = (lo + hi) >> 1;
|
||||
if (uptr->pos == map[p])
|
||||
return ((p == 0)? map[p]: map[p - 1]);
|
||||
else if (uptr->pos < map[p]) hi = p - 1;
|
||||
else lo = p + 1;
|
||||
}
|
||||
while (lo <= hi);
|
||||
return ((p == 0)? map[p]: map[p - 1]);
|
||||
}
|
||||
|
||||
/* Set tape capacity */
|
||||
|
||||
t_stat sim_tape_set_capac (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
extern uint32 sim_taddr_64;
|
||||
t_addr cap;
|
||||
t_stat r;
|
||||
|
||||
if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG;
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||||
cap = (t_addr) get_uint (cptr, 10, sim_taddr_64? 2000000: 2000, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
uptr->capac = cap * ((t_addr) 1000000);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show tape capacity */
|
||||
|
||||
t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
if (uptr->capac) fprintf (st, "capacity=%dMB", (uint32) (uptr->capac / ((t_addr) 1000000)));
|
||||
else fprintf (st, "unlimited capacity");
|
||||
return SCPE_OK;
|
||||
}
|
||||
122
simhv36-1/sim_tape.h
Normal file
122
simhv36-1/sim_tape.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* sim_tape.h: simulator tape support library definitions
|
||||
|
||||
Copyright (c) 1993-2006, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
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.
|
||||
|
||||
14-Feb-06 RMS Added variable tape capacity
|
||||
17-Dec-05 RMS Added write support for Paul Pierce 7b format
|
||||
02-May-05 RMS Added support for Paul Pierce 7b format
|
||||
*/
|
||||
|
||||
#ifndef _SIM_TAPE_H_
|
||||
#define _SIM_TAPE_H_ 0
|
||||
|
||||
/* SIMH/E11 tape format */
|
||||
|
||||
typedef uint32 t_mtrlnt; /* magtape rec lnt */
|
||||
|
||||
#define MTR_TMK 0x00000000 /* tape mark */
|
||||
#define MTR_EOM 0xFFFFFFFF /* end of medium */
|
||||
#define MTR_ERF 0x80000000 /* error flag */
|
||||
#define MTR_F(x) ((x) & MTR_ERF) /* record error flg */
|
||||
#define MTR_L(x) ((x) & ~MTR_ERF) /* record length */
|
||||
|
||||
/* TPC tape format */
|
||||
|
||||
typedef uint16 t_tpclnt; /* magtape rec lnt */
|
||||
|
||||
/* P7B tape format */
|
||||
|
||||
#define P7B_SOR 0x80 /* start of record */
|
||||
#define P7B_PAR 0x40 /* parity */
|
||||
#define P7B_DATA 0x3F /* data */
|
||||
#define P7B_DPAR (P7B_PAR|P7B_DATA) /* data and parity */
|
||||
#define P7B_EOF 0x0F /* eof character */
|
||||
|
||||
#define TPC_TMK 0x0000 /* tape mark */
|
||||
|
||||
/* Unit flags */
|
||||
|
||||
#define MTUF_V_PNU (UNIT_V_UF + 0) /* position not upd */
|
||||
#define MTUF_V_WLK (UNIT_V_UF + 1) /* write locked */
|
||||
#define MTUF_V_FMT (UNIT_V_UF + 2) /* tape file format */
|
||||
#define MTUF_W_FMT 3 /* 3b of formats */
|
||||
#define MTUF_N_FMT (1u << MTUF_W_FMT) /* number of formats */
|
||||
#define MTUF_M_FMT ((1u << MTUF_W_FMT) - 1)
|
||||
#define MTUF_F_STD 0 /* SIMH format */
|
||||
#define MTUF_F_E11 1 /* E11 format */
|
||||
#define MTUF_F_TPC 2 /* TPC format */
|
||||
#define MTUF_F_P7B 3 /* P7B format */
|
||||
#define MUTF_F_TDF 4 /* TDF format */
|
||||
#define MTUF_V_UF (MTUF_V_FMT + MTUF_W_FMT)
|
||||
#define MTUF_PNU (1u << MTUF_V_PNU)
|
||||
#define MTUF_WLK (1u << MTUF_V_WLK)
|
||||
#define MTUF_FMT (MTUF_M_FMT << MTUF_V_FMT)
|
||||
#define MTUF_WRP (MTUF_WLK | UNIT_RO)
|
||||
|
||||
#define MT_F_STD (MTUF_F_STD << MTUF_V_FMT)
|
||||
#define MT_F_E11 (MTUF_F_E11 << MTUF_V_FMT)
|
||||
#define MT_F_TPC (MTUF_F_TPC << MTUF_V_FMT)
|
||||
#define MT_F_P7B (MTUF_F_P7B << MTUF_V_FMT)
|
||||
#define MT_F_TDF (MTUF_F_TDF << MTUF_V_FMT)
|
||||
|
||||
#define MT_SET_PNU(u) (u)->flags = (u)->flags | MTUF_PNU
|
||||
#define MT_CLR_PNU(u) (u)->flags = (u)->flags & ~MTUF_PNU
|
||||
#define MT_TST_PNU(u) ((u)->flags & MTUF_PNU)
|
||||
#define MT_GET_FMT(u) (((u)->flags >> MTUF_V_FMT) & MTUF_M_FMT)
|
||||
|
||||
/* Return status codes */
|
||||
|
||||
#define MTSE_OK 0 /* no error */
|
||||
#define MTSE_TMK 1 /* tape mark */
|
||||
#define MTSE_UNATT 2 /* unattached */
|
||||
#define MTSE_IOERR 3 /* IO error */
|
||||
#define MTSE_INVRL 4 /* invalid rec lnt */
|
||||
#define MTSE_FMT 5 /* invalid format */
|
||||
#define MTSE_BOT 6 /* beginning of tape */
|
||||
#define MTSE_EOM 7 /* end of medium */
|
||||
#define MTSE_RECE 8 /* error in record */
|
||||
#define MTSE_WRP 9 /* write protected */
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
t_stat sim_tape_attach (UNIT *uptr, char *cptr);
|
||||
t_stat sim_tape_detach (UNIT *uptr);
|
||||
t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max);
|
||||
t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max);
|
||||
t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc);
|
||||
t_stat sim_tape_wrtmk (UNIT *uptr);
|
||||
t_stat sim_tape_wreom (UNIT *uptr);
|
||||
t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc);
|
||||
t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc);
|
||||
t_stat sim_tape_rewind (UNIT *uptr);
|
||||
t_stat sim_tape_reset (UNIT *uptr);
|
||||
t_bool sim_tape_bot (UNIT *uptr);
|
||||
t_bool sim_tape_wrp (UNIT *uptr);
|
||||
t_bool sim_tape_eot (UNIT *uptr);
|
||||
t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
t_stat sim_tape_set_capac (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
#endif
|
||||
251
simhv36-1/sim_timer.c
Normal file
251
simhv36-1/sim_timer.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/* sim_timer.c: simulator timer library
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
21-Aug-05 RMS Added sim_rtcn_init_all
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
02-Jan-04 RMS Split out from SCP
|
||||
|
||||
This library includes the following routines:
|
||||
|
||||
sim_rtc_init - initialize calibration
|
||||
sim_rtc_calb - calibrate clock
|
||||
sim_os_msec - return elapsed time in msec
|
||||
sim_os_sleep - sleep specified number of seconds
|
||||
|
||||
The calibration routines are OS-independent; the _os_ routines are not
|
||||
*/
|
||||
|
||||
#include "sim_defs.h"
|
||||
|
||||
/* OS-dependent timer and clock routines */
|
||||
|
||||
/* VMS */
|
||||
|
||||
#if defined (VMS)
|
||||
|
||||
#if defined(__VAX)
|
||||
#define sys$gettim SYS$GETTIM
|
||||
#endif
|
||||
|
||||
#include <starlet.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const t_bool rtc_avail = TRUE;
|
||||
|
||||
uint32 sim_os_msec ()
|
||||
{
|
||||
uint32 quo, htod, tod[2];
|
||||
int32 i;
|
||||
|
||||
sys$gettim (tod); /* time 0.1usec */
|
||||
|
||||
/* To convert to msec, must divide a 64b quantity by 10000. This is actually done
|
||||
by dividing the 96b quantity 0'time by 10000, producing 64b of quotient, the
|
||||
high 32b of which are discarded. This can probably be done by a clever multiply...
|
||||
*/
|
||||
|
||||
quo = htod = 0;
|
||||
for (i = 0; i < 64; i++) { /* 64b quo */
|
||||
htod = (htod << 1) | ((tod[1] >> 31) & 1); /* shift divd */
|
||||
tod[1] = (tod[1] << 1) | ((tod[0] >> 31) & 1);
|
||||
tod[0] = tod[0] << 1;
|
||||
quo = quo << 1; /* shift quo */
|
||||
if (htod >= 10000) { /* divd work? */
|
||||
htod = htod - 10000; /* subtract */
|
||||
quo = quo | 1; /* set quo bit */
|
||||
}
|
||||
}
|
||||
return quo;
|
||||
}
|
||||
|
||||
void sim_os_sleep (unsigned int sec)
|
||||
{
|
||||
sleep (sec);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Win32 routines */
|
||||
|
||||
#elif defined (_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
const t_bool rtc_avail = TRUE;
|
||||
|
||||
uint32 sim_os_msec ()
|
||||
{
|
||||
return GetTickCount ();
|
||||
}
|
||||
|
||||
void sim_os_sleep (unsigned int sec)
|
||||
{
|
||||
Sleep (sec * 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
/* OS/2 routines, from Bruce Ray */
|
||||
|
||||
#elif defined (__OS2__)
|
||||
|
||||
const t_bool rtc_avail = FALSE;
|
||||
|
||||
uint32 sim_os_msec ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sim_os_sleep (unsigned int sec)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Metrowerks CodeWarrior Macintosh routines, from Ben Supnik */
|
||||
|
||||
#elif defined (__MWERKS__) && defined (macintosh)
|
||||
|
||||
#include <Timer.h>
|
||||
#include <Mactypes.h>
|
||||
#include <sioux.h>
|
||||
#include <unistd.h>
|
||||
#include <siouxglobals.h>
|
||||
|
||||
const t_bool rtc_avail = TRUE;
|
||||
|
||||
uint32 sim_os_msec (void)
|
||||
{
|
||||
unsigned long long micros;
|
||||
UnsignedWide macMicros;
|
||||
unsigned long millis;
|
||||
|
||||
Microseconds (&macMicros);
|
||||
micros = *((unsigned long long *) &macMicros);
|
||||
millis = micros / 1000LL;
|
||||
return (uint32) millis;
|
||||
}
|
||||
|
||||
void sim_os_sleep (unsigned int sec)
|
||||
{
|
||||
sleep (sec);
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* UNIX routines */
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const t_bool rtc_avail = TRUE;
|
||||
|
||||
uint32 sim_os_msec ()
|
||||
{
|
||||
struct timeval cur;
|
||||
struct timezone foo;
|
||||
uint32 msec;
|
||||
|
||||
gettimeofday (&cur, &foo);
|
||||
msec = (((uint32) cur.tv_sec) * 1000) + (((uint32) cur.tv_usec) / 1000);
|
||||
return msec;
|
||||
}
|
||||
|
||||
void sim_os_sleep (unsigned int sec)
|
||||
{
|
||||
sleep (sec);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* OS independent clock calibration package */
|
||||
|
||||
static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */
|
||||
static uint32 rtc_rtime[SIM_NTIMERS] = { 0 }; /* real time */
|
||||
static uint32 rtc_vtime[SIM_NTIMERS] = { 0 }; /* virtual time */
|
||||
static uint32 rtc_nxintv[SIM_NTIMERS] = { 0 }; /* next interval */
|
||||
static int32 rtc_based[SIM_NTIMERS] = { 0 }; /* base delay */
|
||||
static int32 rtc_currd[SIM_NTIMERS] = { 0 }; /* current delay */
|
||||
static int32 rtc_initd[SIM_NTIMERS] = { 0 }; /* initial delay */
|
||||
|
||||
int32 sim_rtcn_init (int32 time, int32 tmr)
|
||||
{
|
||||
if (time == 0) time = 1;
|
||||
if ((tmr < 0) || (tmr >= SIM_NTIMERS)) return time;
|
||||
rtc_rtime[tmr] = sim_os_msec ();
|
||||
rtc_vtime[tmr] = rtc_rtime[tmr];
|
||||
rtc_nxintv[tmr] = 1000;
|
||||
rtc_ticks[tmr] = 0;
|
||||
rtc_based[tmr] = time;
|
||||
rtc_currd[tmr] = time;
|
||||
rtc_initd[tmr] = time;
|
||||
return time;
|
||||
}
|
||||
|
||||
int32 sim_rtcn_calb (int32 ticksper, int32 tmr)
|
||||
{
|
||||
uint32 new_rtime, delta_rtime;
|
||||
int32 delta_vtime;
|
||||
|
||||
if ((tmr < 0) || (tmr >= SIM_NTIMERS)) return 10000;
|
||||
rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */
|
||||
if (rtc_ticks[tmr] < ticksper) return rtc_currd[tmr]; /* 1 sec yet? */
|
||||
rtc_ticks[tmr] = 0; /* reset ticks */
|
||||
if (!rtc_avail) return rtc_currd[tmr]; /* no timer? */
|
||||
new_rtime = sim_os_msec (); /* wall time */
|
||||
if (new_rtime < rtc_rtime[tmr]) { /* time running backwards? */
|
||||
rtc_rtime[tmr] = new_rtime; /* reset wall time */
|
||||
return rtc_currd[tmr]; /* can't calibrate */
|
||||
}
|
||||
delta_rtime = new_rtime - rtc_rtime[tmr]; /* elapsed wtime */
|
||||
rtc_rtime[tmr] = new_rtime; /* adv wall time */
|
||||
rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */
|
||||
if (delta_rtime > 30000) /* gap too big? */
|
||||
return rtc_initd[tmr]; /* can't calibr */
|
||||
if (delta_rtime == 0) /* gap too small? */
|
||||
rtc_based[tmr] = rtc_based[tmr] * ticksper; /* slew wide */
|
||||
else rtc_based[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) /
|
||||
((double) delta_rtime)); /* new base rate */
|
||||
delta_vtime = rtc_vtime[tmr] - rtc_rtime[tmr]; /* gap */
|
||||
if (delta_vtime > SIM_TMAX) delta_vtime = SIM_TMAX; /* limit gap */
|
||||
else if (delta_vtime < -SIM_TMAX) delta_vtime = -SIM_TMAX;
|
||||
rtc_nxintv[tmr] = 1000 + delta_vtime; /* next wtime */
|
||||
rtc_currd[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) /
|
||||
1000.0); /* next delay */
|
||||
if (rtc_based[tmr] <= 0) rtc_based[tmr] = 1; /* never negative or zero! */
|
||||
if (rtc_currd[tmr] <= 0) rtc_currd[tmr] = 1; /* never negative or zero! */
|
||||
return rtc_currd[tmr];
|
||||
}
|
||||
|
||||
/* Prior interfaces - default to timer 0 */
|
||||
|
||||
int32 sim_rtc_init (int32 time)
|
||||
{
|
||||
return sim_rtcn_init (time, 0);
|
||||
}
|
||||
|
||||
int32 sim_rtc_calb (int32 ticksper)
|
||||
{
|
||||
return sim_rtcn_calb (ticksper, 0);
|
||||
}
|
||||
42
simhv36-1/sim_timer.h
Normal file
42
simhv36-1/sim_timer.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* sim_timer.h: simulator timer library headers
|
||||
|
||||
Copyright (c) 1993-2005, 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.
|
||||
|
||||
02-Jan-04 RMS Split out from SCP
|
||||
*/
|
||||
|
||||
#ifndef _SIM_TIMER_H_
|
||||
#define _SIM_TIMER_H_ 0
|
||||
|
||||
#define SIM_NTIMERS 8 /* # timers */
|
||||
#define SIM_TMAX 500 /* max timer makeup */
|
||||
|
||||
int32 sim_rtcn_init (int32 time, int32 tmr);
|
||||
int32 sim_rtcn_calb (int32 ticksper, int32 tmr);
|
||||
int32 sim_rtc_init (int32 time);
|
||||
int32 sim_rtc_calb (int32 ticksper);
|
||||
uint32 sim_os_msec (void);
|
||||
void sim_os_sleep (unsigned int sec);
|
||||
|
||||
#endif
|
||||
665
simhv36-1/sim_tmxr.c
Normal file
665
simhv36-1/sim_tmxr.c
Normal file
@@ -0,0 +1,665 @@
|
||||
/* sim_tmxr.c: Telnet terminal multiplexor library
|
||||
|
||||
Copyright (c) 2001-2005, 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.
|
||||
|
||||
Based on the original DZ11 simulator by Thord Nilson, as updated by
|
||||
Arthur Krewat.
|
||||
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
29-Jun-05 RMS Extended tmxr_dscln to support unit array devices
|
||||
Fixed bug in SET LOG/NOLOG
|
||||
04-Jan-04 RMS Changed TMXR ldsc to be pointer to linedesc array
|
||||
Added tmxr_linemsg, circular output pointers, logging
|
||||
(from Mark Pizzolato)
|
||||
29-Dec-03 RMS Added output stall support
|
||||
01-Nov-03 RMS Cleaned up attach routine
|
||||
09-Mar-03 RMS Fixed bug in SHOW CONN
|
||||
22-Dec-02 RMS Fixed bugs in IAC+IAC receive and transmit sequences
|
||||
Added support for received break (all from by Mark Pizzolato)
|
||||
Fixed bug in attach
|
||||
31-Oct-02 RMS Fixed bug in 8b (binary) support
|
||||
22-Aug-02 RMS Added tmxr_open_master, tmxr_close_master
|
||||
30-Dec-01 RMS Added tmxr_fstats, tmxr_dscln, renamed tmxr_fstatus
|
||||
03-Dec-01 RMS Changed tmxr_fconns for extended SET/SHOW
|
||||
20-Oct-01 RMS Fixed bugs in read logic (found by Thord Nilson).
|
||||
Added tmxr_rqln, tmxr_tqln
|
||||
|
||||
This library includes:
|
||||
|
||||
tmxr_poll_conn - poll for connection
|
||||
tmxr_reset_ln - reset line
|
||||
tmxr_getc_ln - get character for line
|
||||
tmxr_poll_rx - poll receive
|
||||
tmxr_putc_ln - put character for line
|
||||
tmxr_poll_tx - poll transmit
|
||||
tmxr_open_master - open master connection
|
||||
tmxr_close_master - close master connection
|
||||
tmxr_attach - attach terminal multiplexor
|
||||
tmxr_detach - detach terminal multiplexor
|
||||
tmxr_ex - (null) examine
|
||||
tmxr_dep - (null) deposit
|
||||
tmxr_msg - send message to socket
|
||||
tmxr_linemsg - send message to line
|
||||
tmxr_fconns - output connection status
|
||||
tmxr_fstats - output connection statistics
|
||||
tmxr_dscln - disconnect line (SET routine)
|
||||
tmxr_rqln - number of available characters for line
|
||||
tmxr_tqln - number of buffered characters for line
|
||||
|
||||
All routines are OS-independent.
|
||||
*/
|
||||
|
||||
#include "sim_defs.h"
|
||||
#include "sim_sock.h"
|
||||
#include "sim_tmxr.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/* Telnet protocol constants - negatives are for init'ing signed char data */
|
||||
|
||||
#define TN_IAC -1 /* protocol delim */
|
||||
#define TN_DONT -2 /* dont */
|
||||
#define TN_DO -3 /* do */
|
||||
#define TN_WONT -4 /* wont */
|
||||
#define TN_WILL -5 /* will */
|
||||
#define TN_BRK -13 /* break */
|
||||
#define TN_BIN 0 /* bin */
|
||||
#define TN_ECHO 1 /* echo */
|
||||
#define TN_SGA 3 /* sga */
|
||||
#define TN_LINE 34 /* line mode */
|
||||
#define TN_CR 015 /* carriage return */
|
||||
|
||||
/* Telnet line states */
|
||||
|
||||
#define TNS_NORM 000 /* normal */
|
||||
#define TNS_IAC 001 /* IAC seen */
|
||||
#define TNS_WILL 002 /* WILL seen */
|
||||
#define TNS_WONT 003 /* WONT seen */
|
||||
#define TNS_SKIP 004 /* skip next */
|
||||
|
||||
void tmxr_rmvrc (TMLN *lp, int32 p);
|
||||
int32 tmxr_send_buffered_data (TMLN *lp);
|
||||
TMLN *tmxr_find_ldsc (UNIT *uptr, int32 val, TMXR *mp);
|
||||
|
||||
extern int32 sim_switches;
|
||||
extern char sim_name[];
|
||||
extern FILE *sim_log;
|
||||
extern uint32 sim_os_msec (void);
|
||||
|
||||
/* Poll for new connection
|
||||
|
||||
Called from unit service routine to test for new connection
|
||||
|
||||
Inputs:
|
||||
*mp = pointer to terminal multiplexor descriptor
|
||||
Outputs:
|
||||
line number activated, -1 if none
|
||||
*/
|
||||
|
||||
int32 tmxr_poll_conn (TMXR *mp)
|
||||
{
|
||||
SOCKET newsock;
|
||||
TMLN *lp;
|
||||
int32 i;
|
||||
uint32 ipaddr;
|
||||
static char mantra[] = {
|
||||
TN_IAC, TN_WILL, TN_LINE,
|
||||
TN_IAC, TN_WILL, TN_SGA,
|
||||
TN_IAC, TN_WILL, TN_ECHO,
|
||||
TN_IAC, TN_WILL, TN_BIN,
|
||||
TN_IAC, TN_DO, TN_BIN
|
||||
};
|
||||
|
||||
newsock = sim_accept_conn (mp->master, &ipaddr); /* poll connect */
|
||||
if (newsock != INVALID_SOCKET) { /* got a live one? */
|
||||
for (i = 0; i < mp->lines; i++) { /* find avail line */
|
||||
lp = mp->ldsc + i; /* ptr to ln desc */
|
||||
if (lp->conn == 0) break; /* available? */
|
||||
}
|
||||
if (i >= mp->lines) { /* all busy? */
|
||||
tmxr_msg (newsock, "All connections busy\r\n");
|
||||
sim_close_sock (newsock, 0);
|
||||
}
|
||||
else {
|
||||
lp = mp->ldsc + i; /* get line desc */
|
||||
lp->conn = newsock; /* record connection */
|
||||
lp->ipad = ipaddr; /* ip address */
|
||||
lp->cnms = sim_os_msec (); /* time of conn */
|
||||
lp->rxbpr = lp->rxbpi = 0; /* init buf pointers */
|
||||
lp->txbpr = lp->txbpi = 0;
|
||||
lp->rxcnt = lp->txcnt = 0; /* init counters */
|
||||
lp->tsta = 0; /* init telnet state */
|
||||
lp->xmte = 1; /* enable transmit */
|
||||
lp->dstb = 0; /* default bin mode */
|
||||
sim_write_sock (newsock, mantra, 15);
|
||||
tmxr_linemsg (lp, "\n\r\nConnected to the ");
|
||||
tmxr_linemsg (lp, sim_name);
|
||||
tmxr_linemsg (lp, " simulator\r\n\n");
|
||||
tmxr_poll_tx (mp); /* flush output */
|
||||
return i;
|
||||
}
|
||||
} /* end if newsock */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reset line */
|
||||
|
||||
void tmxr_reset_ln (TMLN *lp)
|
||||
{
|
||||
if (lp->txlog) fflush (lp->txlog); /* dump log */
|
||||
tmxr_send_buffered_data (lp); /* send buffered data */
|
||||
sim_close_sock (lp->conn, 0); /* reset conn */
|
||||
lp->conn = lp->tsta = 0; /* reset state */
|
||||
lp->rxbpr = lp->rxbpi = 0;
|
||||
lp->txbpr = lp->txbpi = 0;
|
||||
lp->xmte = 1;
|
||||
lp->dstb = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get character from specific line
|
||||
|
||||
Inputs:
|
||||
*lp = pointer to terminal line descriptor
|
||||
Output:
|
||||
valid + char, 0 if line
|
||||
*/
|
||||
|
||||
int32 tmxr_getc_ln (TMLN *lp)
|
||||
{
|
||||
int32 j, val = 0;
|
||||
uint32 tmp;
|
||||
|
||||
if (lp->conn && lp->rcve) { /* conn & enb? */
|
||||
j = lp->rxbpi - lp->rxbpr; /* # input chrs */
|
||||
if (j) { /* any? */
|
||||
tmp = lp->rxb[lp->rxbpr]; /* get char */
|
||||
val = TMXR_VALID | (tmp & 0377); /* valid + chr */
|
||||
if (lp->rbr[lp->rxbpr]) val = val | SCPE_BREAK; /* break? */
|
||||
lp->rxbpr = lp->rxbpr + 1; /* adv pointer */
|
||||
}
|
||||
} /* end if conn */
|
||||
if (lp->rxbpi == lp->rxbpr) /* empty? zero ptrs */
|
||||
lp->rxbpi = lp->rxbpr = 0;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Poll for input
|
||||
|
||||
Inputs:
|
||||
*mp = pointer to terminal multiplexor descriptor
|
||||
Outputs: none
|
||||
*/
|
||||
|
||||
void tmxr_poll_rx (TMXR *mp)
|
||||
{
|
||||
int32 i, nbytes, j;
|
||||
TMLN *lp;
|
||||
|
||||
for (i = 0; i < mp->lines; i++) { /* loop thru lines */
|
||||
lp = mp->ldsc + i; /* get line desc */
|
||||
if (!lp->conn || !lp->rcve) continue; /* skip if !conn */
|
||||
|
||||
nbytes = 0;
|
||||
if (lp->rxbpi == 0) /* need input? */
|
||||
nbytes = sim_read_sock (lp->conn, /* yes, read */
|
||||
&(lp->rxb[lp->rxbpi]), /* leave spc for */
|
||||
TMXR_MAXBUF - TMXR_GUARD); /* Telnet cruft */
|
||||
else if (lp->tsta) /* in Telnet seq? */
|
||||
nbytes = sim_read_sock (lp->conn, /* yes, read to end */
|
||||
&(lp->rxb[lp->rxbpi]),
|
||||
TMXR_MAXBUF - lp->rxbpi);
|
||||
if (nbytes < 0) tmxr_reset_ln (lp); /* closed? reset ln */
|
||||
else if (nbytes > 0) { /* if data rcvd */
|
||||
j = lp->rxbpi; /* start of data */
|
||||
memset (&lp->rbr[j], 0, nbytes); /* clear status */
|
||||
lp->rxbpi = lp->rxbpi + nbytes; /* adv pointers */
|
||||
lp->rxcnt = lp->rxcnt + nbytes;
|
||||
|
||||
/* Examine new data, remove TELNET cruft before making input available */
|
||||
|
||||
for (; j < lp->rxbpi; ) { /* loop thru char */
|
||||
signed char tmp = lp->rxb[j]; /* get char */
|
||||
switch (lp->tsta) { /* case tlnt state */
|
||||
|
||||
case TNS_NORM: /* normal */
|
||||
if (tmp == TN_IAC) { /* IAC? */
|
||||
lp->tsta = TNS_IAC; /* change state */
|
||||
tmxr_rmvrc (lp, j); /* remove char */
|
||||
break;
|
||||
}
|
||||
if ((tmp == TN_CR) && lp->dstb) /* CR, no bin */
|
||||
lp->tsta = TNS_SKIP; /* skip next */
|
||||
j = j + 1; /* advance j */
|
||||
break;
|
||||
|
||||
case TNS_IAC: /* IAC prev */
|
||||
if ((tmp == TN_IAC) & !lp->dstb) { /* IAC + IAC, bin? */
|
||||
lp->tsta = TNS_NORM; /* treat as normal */
|
||||
j = j + 1; /* advance j */
|
||||
break; /* keep IAC */
|
||||
}
|
||||
if (tmp == TN_BRK) { /* IAC + BRK? */
|
||||
lp->tsta = TNS_NORM; /* treat as normal */
|
||||
lp->rxb[j] = 0; /* char is null */
|
||||
lp->rbr[j] = 1; /* flag break */
|
||||
j = j + 1; /* advance j */
|
||||
break;
|
||||
}
|
||||
if (tmp == TN_WILL) /* IAC + WILL? */
|
||||
lp->tsta = TNS_WILL;
|
||||
else if (tmp == TN_WONT) /* IAC + WONT? */
|
||||
lp->tsta = TNS_WONT;
|
||||
else lp->tsta = TNS_SKIP; /* IAC + other */
|
||||
tmxr_rmvrc (lp, j); /* remove char */
|
||||
break;
|
||||
|
||||
case TNS_WILL: case TNS_WONT: /* IAC+WILL/WONT prev */
|
||||
if (tmp == TN_BIN) { /* BIN? */
|
||||
if (lp->tsta == TNS_WILL) lp->dstb = 0;
|
||||
else lp->dstb = 1;
|
||||
}
|
||||
|
||||
case TNS_SKIP: default: /* skip char */
|
||||
lp->tsta = TNS_NORM; /* next normal */
|
||||
tmxr_rmvrc (lp, j); /* remove char */
|
||||
break;
|
||||
} /* end case state */
|
||||
} /* end for char */
|
||||
} /* end else nbytes */
|
||||
} /* end for lines */
|
||||
for (i = 0; i < mp->lines; i++) { /* loop thru lines */
|
||||
lp = mp->ldsc + i; /* get line desc */
|
||||
if (lp->rxbpi == lp->rxbpr) /* if buf empty, */
|
||||
lp->rxbpi = lp->rxbpr = 0; /* reset pointers */
|
||||
} /* end for */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Return count of available characters for line */
|
||||
|
||||
int32 tmxr_rqln (TMLN *lp)
|
||||
{
|
||||
return (lp->rxbpi - lp->rxbpr);
|
||||
}
|
||||
|
||||
/* Remove character p (and matching status) from line l input buffer */
|
||||
|
||||
void tmxr_rmvrc (TMLN *lp, int32 p)
|
||||
{
|
||||
for ( ; p < lp->rxbpi; p++) {
|
||||
lp->rxb[p] = lp->rxb[p + 1];
|
||||
lp->rbr[p] = lp->rbr[p + 1];
|
||||
}
|
||||
lp->rxbpi = lp->rxbpi - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store character in line buffer
|
||||
|
||||
Inputs:
|
||||
*lp = pointer to line descriptor
|
||||
chr = characters
|
||||
Outputs:
|
||||
status = ok, connection lost, or stall
|
||||
*/
|
||||
|
||||
t_stat tmxr_putc_ln (TMLN *lp, int32 chr)
|
||||
{
|
||||
if (lp->txlog) fputc (chr, lp->txlog); /* log if available */
|
||||
if (lp->conn == 0) return SCPE_LOST; /* no conn? lost */
|
||||
if (tmxr_tqln (lp) < (TMXR_MAXBUF - 1)) { /* room for char (+ IAC)? */
|
||||
lp->txb[lp->txbpi] = (char) chr; /* buffer char */
|
||||
lp->txbpi = lp->txbpi + 1; /* adv pointer */
|
||||
if (lp->txbpi >= TMXR_MAXBUF) lp->txbpi = 0; /* wrap? */
|
||||
if ((char) chr == TN_IAC) { /* IAC? */
|
||||
lp->txb[lp->txbpi] = (char) chr; /* IAC + IAC */
|
||||
lp->txbpi = lp->txbpi + 1; /* adv pointer */
|
||||
if (lp->txbpi >= TMXR_MAXBUF) lp->txbpi = 0; /* wrap? */
|
||||
}
|
||||
if (tmxr_tqln (lp) > (TMXR_MAXBUF - TMXR_GUARD)) /* near full? */
|
||||
lp->xmte = 0; /* disable line */
|
||||
return SCPE_OK; /* char sent */
|
||||
}
|
||||
lp->xmte = 0; /* no room, dsbl line */
|
||||
return SCPE_STALL; /* char not sent */
|
||||
}
|
||||
|
||||
/* Poll for output
|
||||
|
||||
Inputs:
|
||||
*mp = pointer to terminal multiplexor descriptor
|
||||
Outputs:
|
||||
none
|
||||
*/
|
||||
|
||||
void tmxr_poll_tx (TMXR *mp)
|
||||
{
|
||||
int32 i, nbytes;
|
||||
TMLN *lp;
|
||||
|
||||
for (i = 0; i < mp->lines; i++) { /* loop thru lines */
|
||||
lp = mp->ldsc + i; /* get line desc */
|
||||
if (lp->conn == 0) continue; /* skip if !conn */
|
||||
nbytes = tmxr_send_buffered_data (lp); /* buffered bytes */
|
||||
if (nbytes == 0) lp->xmte = 1; /* buf empty? enab line */
|
||||
} /* end for */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send buffered data across network
|
||||
|
||||
Inputs:
|
||||
*lp = pointer to line descriptor
|
||||
Outputs:
|
||||
returns number of bytes still buffered
|
||||
*/
|
||||
|
||||
int32 tmxr_send_buffered_data (TMLN *lp)
|
||||
{
|
||||
int32 nbytes, sbytes;
|
||||
|
||||
nbytes = tmxr_tqln(lp); /* avail bytes */
|
||||
if (nbytes) { /* >0? write */
|
||||
if (lp->txbpr < lp->txbpi) /* no wrap? */
|
||||
sbytes = sim_write_sock (lp->conn, /* write all data */
|
||||
&(lp->txb[lp->txbpr]), nbytes);
|
||||
else sbytes = sim_write_sock (lp->conn, /* write to end buf */
|
||||
&(lp->txb[lp->txbpr]), TMXR_MAXBUF - lp->txbpr);
|
||||
if (sbytes != SOCKET_ERROR) { /* ok? */
|
||||
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */
|
||||
if (lp->txbpr >= TMXR_MAXBUF) lp->txbpr = 0; /* wrap? */
|
||||
lp->txcnt = lp->txcnt + sbytes; /* update counts */
|
||||
nbytes = nbytes - sbytes;
|
||||
}
|
||||
if (nbytes && (lp->txbpr == 0)) { /* more data and wrap? */
|
||||
sbytes = sim_write_sock (lp->conn, lp->txb, nbytes);
|
||||
if (sbytes != SOCKET_ERROR) { /* ok */
|
||||
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */
|
||||
if (lp->txbpr >= TMXR_MAXBUF) lp->txbpr = 0;/* wrap? */
|
||||
lp->txcnt = lp->txcnt + sbytes; /* update counts */
|
||||
nbytes = nbytes - sbytes;
|
||||
}
|
||||
}
|
||||
} /* end if nbytes */
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
/* Return count of buffered characters for line */
|
||||
|
||||
int32 tmxr_tqln (TMLN *lp)
|
||||
{
|
||||
return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? TMXR_MAXBUF: 0));
|
||||
}
|
||||
|
||||
/* Open master socket */
|
||||
|
||||
t_stat tmxr_open_master (TMXR *mp, char *cptr)
|
||||
{
|
||||
int32 i, port;
|
||||
SOCKET sock;
|
||||
TMLN *lp;
|
||||
t_stat r;
|
||||
|
||||
port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */
|
||||
if ((r != SCPE_OK) || (port == 0)) return SCPE_ARG;
|
||||
sock = sim_master_sock (port); /* make master socket */
|
||||
if (sock == INVALID_SOCKET) return SCPE_OPENERR; /* open error */
|
||||
printf ("Listening on port %d (socket %d)\n", port, sock);
|
||||
if (sim_log) fprintf (sim_log,
|
||||
"Listening on port %d (socket %d)\n", port, sock);
|
||||
mp->port = port; /* save port */
|
||||
mp->master = sock; /* save master socket */
|
||||
for (i = 0; i < mp->lines; i++) { /* initialize lines */
|
||||
lp = mp->ldsc + i;
|
||||
lp->conn = lp->tsta = 0;
|
||||
lp->rxbpi = lp->rxbpr = 0;
|
||||
lp->txbpi = lp->txbpr = 0;
|
||||
lp->rxcnt = lp->txcnt = 0;
|
||||
lp->xmte = 1;
|
||||
lp->dstb = 0;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach unit to master socket */
|
||||
|
||||
t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr)
|
||||
{
|
||||
char* tptr;
|
||||
t_stat r;
|
||||
|
||||
tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */
|
||||
if (tptr == NULL) return SCPE_MEM; /* no more mem? */
|
||||
r = tmxr_open_master (mp, cptr); /* open master socket */
|
||||
if (r != SCPE_OK) { /* error? */
|
||||
free (tptr); /* release buf */
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
strcpy (tptr, cptr); /* copy port */
|
||||
uptr->filename = tptr; /* save */
|
||||
uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Close master socket */
|
||||
|
||||
t_stat tmxr_close_master (TMXR *mp)
|
||||
{
|
||||
int32 i;
|
||||
TMLN *lp;
|
||||
|
||||
for (i = 0; i < mp->lines; i++) { /* loop thru conn */
|
||||
lp = mp->ldsc + i;
|
||||
if (lp->conn) {
|
||||
tmxr_linemsg (lp, "\r\nDisconnected from the ");
|
||||
tmxr_linemsg (lp, sim_name);
|
||||
tmxr_linemsg (lp, " simulator\r\n\n");
|
||||
tmxr_reset_ln (lp);
|
||||
} /* end if conn */
|
||||
} /* end for */
|
||||
sim_close_sock (mp->master, 1); /* close master socket */
|
||||
mp->master = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Detach unit from master socket */
|
||||
|
||||
t_stat tmxr_detach (TMXR *mp, UNIT *uptr)
|
||||
{
|
||||
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
|
||||
tmxr_close_master (mp); /* close master socket */
|
||||
free (uptr->filename); /* free port string */
|
||||
uptr->filename = NULL;
|
||||
uptr->flags = uptr->flags & ~UNIT_ATT; /* not attached */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Stub examine and deposit */
|
||||
|
||||
t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
return SCPE_NOFNC;
|
||||
}
|
||||
|
||||
t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
return SCPE_NOFNC;
|
||||
}
|
||||
|
||||
/* Output message to socket or line descriptor */
|
||||
|
||||
void tmxr_msg (SOCKET sock, char *msg)
|
||||
{
|
||||
if (sock) sim_write_sock (sock, msg, strlen (msg));
|
||||
return;
|
||||
}
|
||||
|
||||
void tmxr_linemsg (TMLN *lp, char *msg)
|
||||
{
|
||||
int32 len;
|
||||
|
||||
for (len = strlen (msg); len > 0; --len)
|
||||
tmxr_putc_ln (lp, *msg++);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print connections - used only in named SHOW command */
|
||||
|
||||
void tmxr_fconns (FILE *st, TMLN *lp, int32 ln)
|
||||
{
|
||||
if (ln >= 0) fprintf (st, "line %d: ", ln);
|
||||
if (lp->conn) {
|
||||
int32 o1, o2, o3, o4, hr, mn, sc;
|
||||
uint32 ctime;
|
||||
|
||||
o1 = (lp->ipad >> 24) & 0xFF;
|
||||
o2 = (lp->ipad >> 16) & 0xFF;
|
||||
o3 = (lp->ipad >> 8) & 0xFF;
|
||||
o4 = (lp->ipad) & 0xFF;
|
||||
ctime = (sim_os_msec () - lp->cnms) / 1000;
|
||||
hr = ctime / 3600;
|
||||
mn = (ctime / 60) % 60;
|
||||
sc = ctime % 60;
|
||||
fprintf (st, "IP address %d.%d.%d.%d", o1, o2, o3, o4);
|
||||
if (ctime) fprintf (st, ", connected %02d:%02d:%02d\n", hr, mn, sc);
|
||||
}
|
||||
else fprintf (st, "line disconnected\n");
|
||||
if (lp->txlog) fprintf (st, "Logging to %s\n", lp->txlogname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print statistics - used only in named SHOW command */
|
||||
|
||||
void tmxr_fstats (FILE *st, TMLN *lp, int32 ln)
|
||||
{
|
||||
static const char *enab = "on";
|
||||
static const char *dsab = "off";
|
||||
|
||||
if (ln >= 0) fprintf (st, "line %d: ", ln);
|
||||
if (lp->conn) {
|
||||
fprintf (st, "input (%s) queued/total = %d/%d, ",
|
||||
(lp->rcve? enab: dsab),
|
||||
lp->rxbpi - lp->rxbpr, lp->rxcnt);
|
||||
fprintf (st, "output (%s) queued/total = %d/%d\n",
|
||||
(lp->xmte? enab: dsab),
|
||||
lp->txbpi - lp->txbpr, lp->txcnt);
|
||||
}
|
||||
else fprintf (st, "line disconnected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disconnect line */
|
||||
|
||||
t_stat tmxr_dscln (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
TMXR *mp = (TMXR *) desc;
|
||||
TMLN *lp;
|
||||
int32 ln;
|
||||
t_stat r;
|
||||
|
||||
if (mp == NULL) return SCPE_IERR;
|
||||
if (val) { /* = n form */
|
||||
if (cptr == NULL) return SCPE_ARG;
|
||||
ln = (int32) get_uint (cptr, 10, mp->lines - 1, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
lp = mp->ldsc + ln;
|
||||
}
|
||||
else {
|
||||
lp = tmxr_find_ldsc (uptr, 0, mp);
|
||||
if (lp == NULL) return SCPE_IERR;
|
||||
}
|
||||
if (lp->conn) {
|
||||
tmxr_linemsg (lp, "\r\nOperator disconnected line\r\n\n");
|
||||
tmxr_reset_ln (lp);
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Enable logging for line */
|
||||
|
||||
t_stat tmxr_set_log (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
TMXR *mp = (TMXR *) desc;
|
||||
TMLN *lp;
|
||||
|
||||
if (cptr == NULL) return SCPE_2FARG; /* no file name? */
|
||||
lp = tmxr_find_ldsc (uptr, val, mp); /* find line desc */
|
||||
if (lp == NULL) return SCPE_IERR;
|
||||
if (lp->txlog) tmxr_set_nolog (NULL, val, NULL, desc); /* close existing log */
|
||||
lp->txlogname = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc namebuf */
|
||||
if (lp->txlogname == NULL) return SCPE_MEM; /* can't? */
|
||||
strncpy (lp->txlogname, cptr, CBUFSIZE); /* save file name */
|
||||
lp->txlog = fopen (cptr, "ab"); /* open log */
|
||||
if (lp->txlog == NULL) { /* error? */
|
||||
free (lp->txlogname); /* free buffer */
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Disable logging for line */
|
||||
|
||||
t_stat tmxr_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
TMXR *mp = (TMXR *) desc;
|
||||
TMLN *lp;
|
||||
|
||||
if (cptr) return SCPE_2MARG; /* no arguments */
|
||||
lp = tmxr_find_ldsc (uptr, val, mp); /* find line desc */
|
||||
if (lp == NULL) return SCPE_IERR;
|
||||
if (lp->txlog) { /* logging? */
|
||||
fclose (lp->txlog); /* close log */
|
||||
free (lp->txlogname); /* free namebuf */
|
||||
lp->txlog = NULL;
|
||||
lp->txlogname = NULL;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show logging status for line */
|
||||
|
||||
t_stat tmxr_show_log (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
TMXR *mp = (TMXR *) desc;
|
||||
TMLN *lp;
|
||||
|
||||
lp = tmxr_find_ldsc (uptr, val, mp); /* find line desc */
|
||||
if (lp == NULL) return SCPE_IERR;
|
||||
if (lp->txlog) fprintf (st, "logging to %s", lp->txlogname);
|
||||
else fprintf (st, "no logging");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Find line descriptor */
|
||||
|
||||
TMLN *tmxr_find_ldsc (UNIT *uptr, int32 val, TMXR *mp)
|
||||
{
|
||||
if (uptr) { /* called from SET? */
|
||||
DEVICE *dptr = find_dev_from_unit (uptr); /* find device */
|
||||
if (dptr == NULL) return NULL; /* what?? */
|
||||
val = (int32) (uptr - dptr->units); /* implicit line # */
|
||||
}
|
||||
if ((val < 0) || (val >= mp->lines)) return NULL; /* invalid line? */
|
||||
return mp->ldsc + val; /* line descriptor */
|
||||
}
|
||||
103
simhv36-1/sim_tmxr.h
Normal file
103
simhv36-1/sim_tmxr.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* sim_tmxr.h: terminal multiplexor definitions
|
||||
|
||||
Copyright (c) 2001-2005, 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.
|
||||
|
||||
Based on the original DZ11 simulator by Thord Nilson, as updated by
|
||||
Arthur Krewat.
|
||||
|
||||
04-Jan-04 RMS Changed TMXR ldsc to be pointer to linedesc array
|
||||
Added tmxr_linemsg, logging (from Mark Pizzolato)
|
||||
29-Dec-03 RMS Added output stall support, increased buffer size
|
||||
22-Dec-02 RMS Added break support (from Mark Pizzolato)
|
||||
20-Aug-02 RMS Added tmxr_open_master, tmxr_close_master, tmxr.port
|
||||
30-Dec-01 RMS Renamed tmxr_fstatus, added tmxr_fstats
|
||||
20-Oct-01 RMS Removed tmxr_getchar, formalized buffer guard,
|
||||
added tmxr_rqln, tmxr_tqln
|
||||
*/
|
||||
|
||||
#ifndef _SIM_TMXR_H_
|
||||
#define _SIM_TMXR_H_ 0
|
||||
|
||||
#define TMXR_V_VALID 15
|
||||
#define TMXR_VALID (1 << TMXR_V_VALID)
|
||||
#define TMXR_MAXBUF 256 /* buffer size */
|
||||
#define TMXR_GUARD 12 /* buffer guard */
|
||||
|
||||
struct tmln {
|
||||
SOCKET conn; /* line conn */
|
||||
uint32 ipad; /* IP address */
|
||||
uint32 cnms; /* conn time */
|
||||
int32 tsta; /* Telnet state */
|
||||
int32 rcve; /* rcv enable */
|
||||
int32 xmte; /* xmt enable */
|
||||
int32 dstb; /* disable Tlnt bin */
|
||||
int32 rxbpr; /* rcv buf remove */
|
||||
int32 rxbpi; /* rcv buf insert */
|
||||
int32 rxcnt; /* rcv count */
|
||||
int32 txbpr; /* xmt buf remove */
|
||||
int32 txbpi; /* xmt buf insert */
|
||||
int32 txcnt; /* xmt count */
|
||||
FILE *txlog; /* xmt log file */
|
||||
char *txlogname; /* xmt log file name */
|
||||
char rxb[TMXR_MAXBUF]; /* rcv buffer */
|
||||
char rbr[TMXR_MAXBUF]; /* rcv break */
|
||||
char txb[TMXR_MAXBUF]; /* xmt buffer */
|
||||
};
|
||||
|
||||
typedef struct tmln TMLN;
|
||||
|
||||
struct tmxr {
|
||||
int32 lines; /* # lines */
|
||||
int32 port; /* listening port */
|
||||
SOCKET master; /* master socket */
|
||||
TMLN *ldsc; /* line descriptors */
|
||||
};
|
||||
|
||||
typedef struct tmxr TMXR;
|
||||
|
||||
int32 tmxr_poll_conn (TMXR *mp);
|
||||
void tmxr_reset_ln (TMLN *lp);
|
||||
int32 tmxr_getc_ln (TMLN *lp);
|
||||
void tmxr_poll_rx (TMXR *mp);
|
||||
t_stat tmxr_putc_ln (TMLN *lp, int32 chr);
|
||||
void tmxr_poll_tx (TMXR *mp);
|
||||
t_stat tmxr_open_master (TMXR *mp, char *cptr);
|
||||
t_stat tmxr_close_master (TMXR *mp);
|
||||
t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr);
|
||||
t_stat tmxr_detach (TMXR *mp, UNIT *uptr);
|
||||
t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
void tmxr_msg (SOCKET sock, char *msg);
|
||||
void tmxr_linemsg (TMLN *lp, char *msg);
|
||||
void tmxr_fconns (FILE *st, TMLN *lp, int32 ln);
|
||||
void tmxr_fstats (FILE *st, TMLN *lp, int32 ln);
|
||||
t_stat tmxr_set_log (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat tmxr_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat tmxr_show_log (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
t_stat tmxr_dscln (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
int32 tmxr_rqln (TMLN *lp);
|
||||
int32 tmxr_tqln (TMLN *lp);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user