1
0
mirror of synced 2026-04-08 22:21:15 +00:00
This commit is contained in:
brad
2010-04-02 12:34:22 +00:00
parent 011c26ca9f
commit a89f158a85
49 changed files with 23439 additions and 0 deletions

51
simhv36-1/0readme_36.txt Normal file
View 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.

View 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

Binary file not shown.

BIN
simhv36-1/BIN/pdp11 Executable file

Binary file not shown.

BIN
simhv36-1/BIN/pdp4 Executable file

Binary file not shown.

BIN
simhv36-1/BIN/pdp7 Executable file

Binary file not shown.

BIN
simhv36-1/BIN/pdp8 Executable file

Binary file not shown.

BIN
simhv36-1/BIN/vax Executable file

Binary file not shown.

BIN
simhv36-1/BIN/vax730 Executable file

Binary file not shown.

BIN
simhv36-1/BIN/vax780 Executable file

Binary file not shown.

178
simhv36-1/PDP8/pdp8_clk.c Normal file
View 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

File diff suppressed because it is too large Load Diff

197
simhv36-1/PDP8/pdp8_defs.h Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

181
simhv36-1/PDP8/pdp8_lp.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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

File diff suppressed because it is too large Load Diff

408
simhv36-1/makefile Normal file
View 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

File diff suppressed because it is too large Load Diff

119
simhv36-1/scp.h Normal file
View 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

File diff suppressed because it is too large Load Diff

81
simhv36-1/sim_console.h Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

212
simhv36-1/sim_ether.h Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

314
simhv36-1/sim_sock.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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