diff --git a/simhv36-1/0readme_36.txt b/simhv36-1/0readme_36.txt new file mode 100644 index 0000000..b52e0f8 --- /dev/null +++ b/simhv36-1/0readme_36.txt @@ -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. diff --git a/simhv36-1/0readme_ethernet.txt b/simhv36-1/0readme_ethernet.txt new file mode 100644 index 0000000..06de278 --- /dev/null +++ b/simhv36-1/0readme_ethernet.txt @@ -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) + +=============================================================================== diff --git a/simhv36-1/BIN/pdp1 b/simhv36-1/BIN/pdp1 new file mode 100755 index 0000000..d9ae386 Binary files /dev/null and b/simhv36-1/BIN/pdp1 differ diff --git a/simhv36-1/BIN/pdp11 b/simhv36-1/BIN/pdp11 new file mode 100755 index 0000000..bb648c0 Binary files /dev/null and b/simhv36-1/BIN/pdp11 differ diff --git a/simhv36-1/BIN/pdp4 b/simhv36-1/BIN/pdp4 new file mode 100755 index 0000000..f7abe8e Binary files /dev/null and b/simhv36-1/BIN/pdp4 differ diff --git a/simhv36-1/BIN/pdp7 b/simhv36-1/BIN/pdp7 new file mode 100755 index 0000000..ca23e0b Binary files /dev/null and b/simhv36-1/BIN/pdp7 differ diff --git a/simhv36-1/BIN/pdp8 b/simhv36-1/BIN/pdp8 new file mode 100755 index 0000000..8fe4c5c Binary files /dev/null and b/simhv36-1/BIN/pdp8 differ diff --git a/simhv36-1/BIN/vax b/simhv36-1/BIN/vax new file mode 100755 index 0000000..1c43fcc Binary files /dev/null and b/simhv36-1/BIN/vax differ diff --git a/simhv36-1/BIN/vax730 b/simhv36-1/BIN/vax730 new file mode 100755 index 0000000..de32112 Binary files /dev/null and b/simhv36-1/BIN/vax730 differ diff --git a/simhv36-1/BIN/vax780 b/simhv36-1/BIN/vax780 new file mode 100755 index 0000000..cd33e93 Binary files /dev/null and b/simhv36-1/BIN/vax780 differ diff --git a/simhv36-1/PDP8/pdp8_clk.c b/simhv36-1/PDP8/pdp8_clk.c new file mode 100644 index 0000000..61c1d3d --- /dev/null +++ b/simhv36-1/PDP8/pdp8_clk.c @@ -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; +} diff --git a/simhv36-1/PDP8/pdp8_cpu.c b/simhv36-1/PDP8/pdp8_cpu.c new file mode 100644 index 0000000..3e27676 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_cpu.c @@ -0,0 +1,1534 @@ +/* pdp8_cpu.c: PDP-8 CPU 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. + + cpu central processor + + 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 16-Aug-05 RMS Fixed C++ declaration and cast problems + 06-Nov-04 RMS Added =n to SHOW HISTORY + 31-Dec-03 RMS Fixed bug in set_cpu_hist + 13-Oct-03 RMS Added instruction history + Added TSC8-75 support (from Bernhard Baehr) + 12-Mar-03 RMS Added logical name support + 04-Oct-02 RMS Revamped device dispatching, added device number support + 06-Jan-02 RMS Added device enable/disable routines + 30-Dec-01 RMS Added old PC queue + 16-Dec-01 RMS Fixed bugs in EAE + 07-Dec-01 RMS Revised to use new breakpoint package + 30-Nov-01 RMS Added RL8A, extended SET/SHOW support + 16-Sep-01 RMS Fixed bug in reset routine, added KL8A support + 10-Aug-01 RMS Removed register from declarations + 17-Jul-01 RMS Moved function prototype + 07-Jun-01 RMS Fixed bug in JMS to non-existent memory + 25-Apr-01 RMS Added device enable/disable support + 18-Mar-01 RMS Added DF32 support + 05-Mar-01 RMS Added clock calibration support + 15-Feb-01 RMS Added DECtape support + 14-Apr-99 RMS Changed t_addr to unsigned + + The register state for the PDP-8 is: + + AC<0:11> accumulator + MQ<0:11> multiplier-quotient + L link flag + PC<0:11> program counter + IF<0:2> instruction field + IB<0:2> instruction buffer + DF<0:2> data field + UF user flag + UB user buffer + SF<0:6> interrupt save field + + The PDP-8 has three instruction formats: memory reference, I/O transfer, + and operate. The memory reference format is: + + 0 1 2 3 4 5 6 7 8 9 10 11 + +--+--+--+--+--+--+--+--+--+--+--+--+ + | op |in|zr| page offset | memory reference + +--+--+--+--+--+--+--+--+--+--+--+--+ + + <0:2> mnemonic action + + 000 AND AC = AC & M[MA] + 001 TAD L'AC = AC + M[MA] + 010 DCA M[MA] = AC, AC = 0 + 011 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0 + 100 JMS M[MA] = PC, PC = MA + 1 + 101 JMP PC = MA + + <3:4> mode action + 00 page zero MA = IF'0'IR<5:11> + 01 current page MA = IF'PC<0:4>'IR<5:11> + 10 indirect page zero MA = xF'M[IF'0'IR<5:11>] + 11 indirect current page MA = xF'M[IF'PC<0:4>'IR<5:11>] + + where x is D for AND, TAD, ISZ, DCA, and I for JMS, JMP. + + Memory reference instructions can access an address space of 32K words. + The address space is divided into eight 4K word fields; each field is + divided into thirty-two 128 word pages. An instruction can directly + address, via its 7b offset, locations 0-127 on page zero or on the current + page. All 32k words can be accessed via indirect addressing and the + instruction and data field registers. If an indirect address is in + locations 0010-0017 of any field, the indirect address is incremented + and rewritten to memory before use. + + The I/O transfer format is as follows: + + 0 1 2 3 4 5 6 7 8 9 10 11 + +--+--+--+--+--+--+--+--+--+--+--+--+ + | op | device | pulse | I/O transfer + +--+--+--+--+--+--+--+--+--+--+--+--+ + + The IO transfer instruction sends the the specified pulse to the + specified I/O device. The I/O device may take data from the AC, + return data to the AC, initiate or cancel operations, or skip on + status. + + The operate format is as follows: + + +--+--+--+--+--+--+--+--+--+--+--+--+ + | 1| 1| 1| 0| | | | | | | | | operate group 1 + +--+--+--+--+--+--+--+--+--+--+--+--+ + | | | | | | | | + | | | | | | | +--- increment AC 3 + | | | | | | +--- rotate 1 or 2 4 + | | | | | +--- rotate left 4 + | | | | +--- rotate right 4 + | | | +--- complement L 2 + | | +--- complement AC 2 + | +--- clear L 1 + +-- clear AC 1 + + +--+--+--+--+--+--+--+--+--+--+--+--+ + | 1| 1| 1| 1| | | | | | | | 0| operate group 2 + +--+--+--+--+--+--+--+--+--+--+--+--+ + | | | | | | | + | | | | | | +--- halt 3 + | | | | | +--- or switch register 3 + | | | | +--- reverse skip sense 1 + | | | +--- skip on L != 0 1 + | | +--- skip on AC == 0 1 + | +--- skip on AC < 0 1 + +-- clear AC 2 + + +--+--+--+--+--+--+--+--+--+--+--+--+ + | 1| 1| 1| 1| | | | | | | | 1| operate group 3 + +--+--+--+--+--+--+--+--+--+--+--+--+ + | | | | \______/ + | | | | | + | | +--|-----+--- EAE command 3 + | | +--- AC -> MQ, 0 -> AC 2 + | +--- MQ v AC --> AC 2 + +-- clear AC 1 + + The operate instruction can be microprogrammed to perform operations + on the AC, MQ, and link. + + This routine is the instruction decode routine for the PDP-8. + It is called from the simulator control program to execute + instructions in simulated memory, starting at the simulated PC. + It runs until 'reason' is set non-zero. + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + HALT instruction + breakpoint encountered + unimplemented instruction and stop_inst flag set + I/O error in I/O simulator + + 2. Interrupts. Interrupts are maintained by three parallel variables: + + dev_done device done flags + int_enable interrupt enable flags + int_req interrupt requests + + In addition, int_req contains the interrupt enable flag, the + CIF not pending flag, and the ION not pending flag. If all + three of these flags are set, and at least one interrupt request + is set, then an interrupt occurs. + + 3. Non-existent memory. On the PDP-8, reads to non-existent memory + return zero, and writes are ignored. In the simulator, the + largest possible memory is instantiated and initialized to zero. + Thus, only writes outside the current field (indirect writes) need + be checked against actual memory size. + + 3. Adding I/O devices. These modules must be modified: + + pdp8_defs.h add device number and interrupt definitions + pdp8_sys.c add sim_devices table entry +*/ + +#include "pdp8_defs.h" + +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = MA +#define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */ +#define UNIT_NOEAE (1 << UNIT_V_NOEAE) +#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) + +#define HIST_PC 0x40000000 +#define HIST_MIN 64 +#define HIST_MAX 65536 + +typedef struct { + int32 pc; + int32 ea; + int16 ir; + int16 opnd; + int16 lac; + int16 mq; + } InstHistory; + +uint16 M[MAXMEMSIZE] = { 0 }; /* main memory */ +int32 saved_LAC = 0; /* saved L'AC */ +int32 saved_MQ = 0; /* saved MQ */ +int32 saved_PC = 0; /* saved IF'PC */ +int32 saved_DF = 0; /* saved Data Field */ +int32 IB = 0; /* Instruction Buffer */ +int32 SF = 0; /* Save Field */ +int32 emode = 0; /* EAE mode */ +int32 gtf = 0; /* EAE gtf flag */ +int32 SC = 0; /* EAE shift count */ +int32 UB = 0; /* User mode Buffer */ +int32 UF = 0; /* User mode Flag */ +int32 OSR = 0; /* Switch Register */ +int32 tsc_ir = 0; /* TSC8-75 IR */ +int32 tsc_pc = 0; /* TSC8-75 PC */ +int32 tsc_cdf = 0; /* TSC8-75 CDF flag */ +int32 tsc_enb = 0; /* TSC8-75 enabled */ +int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ +int32 dev_done = 0; /* dev done flags */ +int32 int_enable = INT_INIT_ENABLE; /* intr enables */ +int32 int_req = 0; /* intr requests */ +int32 stop_inst = 0; /* trap on ill inst */ +int32 (*dev_tab[DEV_MAX])(int32 IR, int32 dat); /* device dispatch */ +int32 hst_p = 0; /* history pointer */ +int32 hst_lnt = 0; /* history length */ +InstHistory *hst = NULL; /* instruction history */ + +extern int32 sim_interval; +extern int32 sim_int_char; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern DEVICE *sim_devices[]; +extern FILE *sim_log; +extern UNIT clk_unit, ttix_unit; + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); +t_bool build_dev_tab (void); + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifier list +*/ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; + +REG cpu_reg[] = { + { ORDATA (PC, saved_PC, 15) }, + { ORDATA (AC, saved_LAC, 12) }, + { FLDATA (L, saved_LAC, 12) }, + { ORDATA (MQ, saved_MQ, 12) }, + { ORDATA (SR, OSR, 12) }, + { GRDATA (IF, saved_PC, 8, 3, 12) }, + { GRDATA (DF, saved_DF, 8, 3, 12) }, + { GRDATA (IB, IB, 8, 3, 12) }, + { ORDATA (SF, SF, 7) }, + { FLDATA (UB, UB, 0) }, + { FLDATA (UF, UF, 0) }, + { ORDATA (SC, SC, 5) }, + { FLDATA (GTF, gtf, 0) }, + { FLDATA (EMODE, emode, 0) }, + { FLDATA (ION, int_req, INT_V_ION) }, + { FLDATA (ION_DELAY, int_req, INT_V_NO_ION_PENDING) }, + { FLDATA (CIF_DELAY, int_req, INT_V_NO_CIF_PENDING) }, + { FLDATA (PWR_INT, int_req, INT_V_PWR) }, + { FLDATA (UF_INT, int_req, INT_V_UF) }, + { ORDATA (INT, int_req, INT_V_ION+1), REG_RO }, + { ORDATA (DONE, dev_done, INT_V_DIRECT), REG_RO }, + { ORDATA (ENABLE, int_enable, INT_V_DIRECT), REG_RO }, + { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, + { FLDATA (STOP_INST, stop_inst, 0) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } + }; + +MTAB cpu_mod[] = { + { UNIT_NOEAE, UNIT_NOEAE, "no EAE", "NOEAE", NULL }, + { UNIT_NOEAE, 0, "EAE", "EAE", NULL }, + { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, + { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, + { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, + { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, + { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, + { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, + { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", + &cpu_set_hist, &cpu_show_hist }, + { 0 } + }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 8, 15, 1, 8, 12, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +static int dtrace = 1; +static int mtrace = 0; +extern void tt_service(void); + +static unsigned long cycles; +int need_stop; + +t_stat sim_instr (void) +{ +int32 IR, MB, IF, DF, LAC, MQ; +uint32 PC, MA; +int32 device, pulse, temp, iot_data; +t_stat reason; + +/* Restore register state */ + +if (build_dev_tab ()) return SCPE_STOP; /* build dev_tab */ +PC = saved_PC & 007777; /* load local copies */ +IF = saved_PC & 070000; +DF = saved_DF & 070000; +LAC = saved_LAC & 017777; +MQ = saved_MQ & 07777; +int_req = INT_UPDATE; +reason = 0; +sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init clk calib */ +sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init ttx calib */ + +/* Main instruction fetch/decode loop */ + +while (reason == 0) { /* loop until halted */ + +#if 1 + cycles++; + if (need_stop) { + printf("\r\nxxx %lu stop\n", cycles); + reason = STOP_HALT; + if (1) { sim_ttclose(); exit(0); } + break; + } + tt_service(); +#endif + + if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event ()) break; + } + + if (int_req > INT_PENDING) { /* interrupt? */ +#if 1 + if (UF && 0) { dtrace = 1; mtrace = 1; } + //if (dtrace) printf("interrupt @ %o\n", PC); + if (dtrace) printf("xxx %lu interrupt @ %o (UF%d IF%o DF%o)\n", + cycles, PC, UF, IF>>12, DF>>12); +#endif + int_req = int_req & ~INT_ION; /* interrupts off */ + SF = (UF << 6) | (IF >> 9) | (DF >> 12); /* form save field */ + IF = IB = DF = UF = UB = 0; /* clear mem ext */ + PCQ_ENTRY; /* save old PC */ + M[0] = PC; /* save PC in 0 */ + PC = 1; /* fetch next from 1 */ + } + + MA = IF | PC; /* form PC */ + if (sim_brk_summ && sim_brk_test (MA, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + IR = M[MA]; /* fetch instruction */ + PC = (PC + 1) & 07777; /* increment PC */ + int_req = int_req | INT_NO_ION_PENDING; /* clear ION delay */ + sim_interval = sim_interval - 1; + +/* Instruction decoding. + + The opcode (IR<0:2>), indirect flag (IR<3>), and page flag (IR<4>) + are decoded together. This produces 32 decode points, four per + major opcode. For IOT, the extra decode points are not useful; + for OPR, only the group flag (IR<3>) is used. + + AND, TAD, ISZ, DCA calculate a full 15b effective address. + JMS, JMP calculate a 12b field-relative effective address. + + Autoindex calculations always occur within the same field as the + instruction fetch. The field must exist; otherwise, the instruction + fetched would be 0000, and indirect addressing could not occur. + + Note that MA contains IF'PC. +*/ + +#if 1 + if (!dtrace) { + if (IR == 06603 && 0) + dtrace = 1; + } + + if (dtrace) { + printf("pc %04o ir %04o l%o ac %04o ion %d " + "(IF%o DF%o UF%o SF%o IB%o UB%o)\n", + MA, IR, LAC & 010000 ? 1 : 0, LAC & 07777, + int_req & INT_ION ? 1 : 0, + IF>>12, DF>>12, UF, SF, IB>>12, UB); + } +#endif + + if (hst_lnt) { /* history enabled? */ + int32 ea; + + hst_p = (hst_p + 1); /* next entry */ + if (hst_p >= hst_lnt) hst_p = 0; + hst[hst_p].pc = MA | HIST_PC; /* save PC, IR, LAC, MQ */ + hst[hst_p].ir = IR; + hst[hst_p].lac = LAC; + hst[hst_p].mq = MQ; + if (IR < 06000) { /* mem ref? */ + if (IR & 0200) ea = (MA & 077600) | (IR & 0177); + else ea = IF | (IR & 0177); /* direct addr */ + if (IR & 0400) { /* indirect? */ + if (IR < 04000) { /* mem operand? */ + if ((ea & 07770) != 00010) ea = DF | M[ea]; + else ea = DF | ((M[ea] + 1) & 07777); + } + else { /* no, jms/jmp */ + if ((ea & 07770) != 00010) ea = IB | M[ea]; + else ea = IB | ((M[ea] + 1) & 07777); + } + } + hst[hst_p].ea = ea; /* save eff addr */ + hst[hst_p].opnd = M[ea]; /* save operand */ + } + } + +switch ((IR >> 7) & 037) { /* decode IR<0:4> */ + +/* Opcode 0, AND */ + + case 000: /* AND, dir, zero */ + MA = IF | (IR & 0177); /* dir addr, page zero */ + LAC = LAC & (M[MA] | 010000); + break; + + case 001: /* AND, dir, curr */ + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + LAC = LAC & (M[MA] | 010000); + break; + + case 002: /* AND, indir, zero */ + MA = IF | (IR & 0177); /* dir addr, page zero */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + LAC = LAC & (M[MA] | 010000); + break; + + case 003: /* AND, indir, curr */ + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + LAC = LAC & (M[MA] | 010000); + break; + +/* Opcode 1, TAD */ + + case 004: /* TAD, dir, zero */ + MA = IF | (IR & 0177); /* dir addr, page zero */ + LAC = (LAC + M[MA]) & 017777; +#if 1 + if (mtrace) printf("mem read [%o] -> %o\n", MA, M[MA]); +#endif + break; + + case 005: /* TAD, dir, curr */ + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + LAC = (LAC + M[MA]) & 017777; +#if 1 + if (mtrace) printf("mem read [%o] -> %o\n", MA, M[MA]); +#endif + break; + + case 006: /* TAD, indir, zero */ + MA = IF | (IR & 0177); /* dir addr, page zero */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + LAC = (LAC + M[MA]) & 017777; +#if 1 + if (mtrace) printf("mem read [%o] -> %o\n", MA, M[MA]); +#endif + break; + + case 007: /* TAD, indir, curr */ + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + LAC = (LAC + M[MA]) & 017777; +#if 1 + if (mtrace) printf("mem read [%o] -> %o\n", MA, M[MA]); +#endif + break; + +/* Opcode 2, ISZ */ + + case 010: /* ISZ, dir, zero */ + MA = IF | (IR & 0177); /* dir addr, page zero */ + M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */ + if (MB == 0) PC = (PC + 1) & 07777; + break; + + case 011: /* ISZ, dir, curr */ + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + M[MA] = MB = (M[MA] + 1) & 07777; /* field must exist */ + if (MB == 0) PC = (PC + 1) & 07777; + break; + + case 012: /* ISZ, indir, zero */ + MA = IF | (IR & 0177); /* dir addr, page zero */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + MB = (M[MA] + 1) & 07777; + if (MEM_ADDR_OK (MA)) M[MA] = MB; + if (MB == 0) PC = (PC + 1) & 07777; + break; + + case 013: /* ISZ, indir, curr */ + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + MB = (M[MA] + 1) & 07777; + if (MEM_ADDR_OK (MA)) M[MA] = MB; + if (MB == 0) PC = (PC + 1) & 07777; + break; + +/* Opcode 3, DCA */ + + case 014: /* DCA, dir, zero */ + MA = IF | (IR & 0177); /* dir addr, page zero */ + M[MA] = LAC & 07777; + LAC = LAC & 010000; +#if 1 + if (mtrace) printf("mem write [%o] <- %o\n", MA, M[MA]); +#endif + break; + + case 015: /* DCA, dir, curr */ + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + M[MA] = LAC & 07777; + LAC = LAC & 010000; +#if 1 + if (mtrace) printf("mem write [%o] <- %o\n", MA, M[MA]); +#endif + break; + + case 016: /* DCA, indir, zero */ + MA = IF | (IR & 0177); /* dir addr, page zero */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777; + LAC = LAC & 010000; +#if 1 + if (mtrace) printf("mem write [%o] <- %o\n", MA, M[MA]); +#endif + break; + + case 017: /* DCA, indir, curr */ + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777; + LAC = LAC & 010000; +#if 1 + if (mtrace) printf("mem write [%o] <- %o\n", MA, M[MA]); +#endif + break; + +/* Opcode 4, JMS. From Bernhard Baehr's description of the TSC8-75: + + (In user mode) the current JMS opcode is moved to the ERIOT register, the ECDF + flag is cleared. The address of the JMS instruction is loaded into the ERTB + register and the TSC8-75 I/O flag is raised. When the TSC8-75 is enabled, the + target addess of the JMS is loaded into PC, but nothing else (loading of IF, UF, + clearing the interrupt inhibit flag, storing of the return address in the first + word of the subroutine) happens. When the TSC8-75 is disabled, the JMS is performed + as usual. */ + + case 020: /* JMS, dir, zero */ + PCQ_ENTRY; + MA = IR & 0177; /* dir addr, page zero */ + if (UF) { /* user mode? */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + } + if (UF && tsc_enb) { /* user mode, TSC enab? */ + tsc_pc = (PC - 1) & 07777; /* save PC */ + int_req = int_req | INT_TSC; /* request intr */ + } + else { /* normal */ + IF = IB; /* change IF */ + UF = UB; /* change UF */ + int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ + MA = IF | MA; + if (MEM_ADDR_OK (MA)) M[MA] = PC; + } + PC = (MA + 1) & 07777; + break; + + case 021: /* JMS, dir, curr */ + PCQ_ENTRY; + MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */ + if (UF) { /* user mode? */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + } + if (UF && tsc_enb) { /* user mode, TSC enab? */ + tsc_pc = (PC - 1) & 07777; /* save PC */ + int_req = int_req | INT_TSC; /* request intr */ + } + else { /* normal */ + IF = IB; /* change IF */ + UF = UB; /* change UF */ + int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ + MA = IF | MA; + if (MEM_ADDR_OK (MA)) M[MA] = PC; + } + PC = (MA + 1) & 07777; + break; + + case 022: /* JMS, indir, zero */ + PCQ_ENTRY; + MA = IF | (IR & 0177); /* dir addr, page zero */ + if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */ + else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + if (UF) { /* user mode? */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + } + if (UF && tsc_enb) { /* user mode, TSC enab? */ + tsc_pc = (PC - 1) & 07777; /* save PC */ + int_req = int_req | INT_TSC; /* request intr */ + } + else { /* normal */ + IF = IB; /* change IF */ + UF = UB; /* change UF */ + int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ + MA = IF | MA; + if (MEM_ADDR_OK (MA)) M[MA] = PC; + } + PC = (MA + 1) & 07777; + break; + + case 023: /* JMS, indir, curr */ + PCQ_ENTRY; + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ + if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */ + else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + if (UF) { /* user mode? */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + } + if (UF && tsc_enb) { /* user mode, TSC enab? */ + tsc_pc = (PC - 1) & 07777; /* save PC */ + int_req = int_req | INT_TSC; /* request intr */ + } + else { /* normal */ + IF = IB; /* change IF */ + UF = UB; /* change UF */ + int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ + MA = IF | MA; + if (MEM_ADDR_OK (MA)) M[MA] = PC; + } + PC = (MA + 1) & 07777; + break; + +/* Opcode 5, JMP. From Bernhard Baehr's description of the TSC8-75: + + (In user mode) the current JMP opcode is moved to the ERIOT register, the ECDF + flag is cleared. The address of the JMP instruction is loaded into the ERTB + register and the TSC8-75 I/O flag is raised. Then the JMP is performed as usual + (including the setting of IF, UF and clearing the interrupt inhibit flag). */ + + case 024: /* JMP, dir, zero */ + PCQ_ENTRY; + MA = IR & 0177; /* dir addr, page zero */ + if (UF) { /* user mode? */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + if (tsc_enb) { /* TSC8 enabled? */ + tsc_pc = (PC - 1) & 07777; /* save PC */ + int_req = int_req | INT_TSC; /* request intr */ + } + } + IF = IB; /* change IF */ + UF = UB; /* change UF */ + int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ + PC = MA; + break; + + case 025: /* JMP, dir, curr */ + PCQ_ENTRY; + MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */ + if (UF) { /* user mode? */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + if (tsc_enb) { /* TSC8 enabled? */ + tsc_pc = (PC - 1) & 07777; /* save PC */ + int_req = int_req | INT_TSC; /* request intr */ + } + } + IF = IB; /* change IF */ + UF = UB; /* change UF */ + int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ + PC = MA; + break; + + case 026: /* JMP, indir, zero */ + PCQ_ENTRY; + MA = IF | (IR & 0177); /* dir addr, page zero */ +#if 1 + if (mtrace) printf("mem read [%o] -> %o\n", MA, M[MA]); +#endif + if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */ + else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + if (UF) { /* user mode? */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + if (tsc_enb) { /* TSC8 enabled? */ + tsc_pc = (PC - 1) & 07777; /* save PC */ + int_req = int_req | INT_TSC; /* request intr */ + } + } + IF = IB; /* change IF */ + UF = UB; /* change UF */ + int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ + PC = MA; + break; + + case 027: /* JMP, indir, curr */ + PCQ_ENTRY; + MA = (MA & 077600) | (IR & 0177); /* dir addr, curr page */ +#if 1 + if (mtrace) printf("mem read [%o] -> %o\n", MA, M[MA]); +#endif + if ((MA & 07770) != 00010) MA = M[MA]; /* indirect; autoinc? */ + else MA = (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + if (UF) { /* user mode? */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + if (tsc_enb) { /* TSC8 enabled? */ + tsc_pc = (PC - 1) & 07777; /* save PC */ + int_req = int_req | INT_TSC; /* request intr */ + } + } + IF = IB; /* change IF */ + UF = UB; /* change UF */ + int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ + PC = MA; + break; + +/* Opcode 7, OPR group 1 */ + + case 034:case 035: /* OPR, group 1 */ + switch ((IR >> 4) & 017) { /* decode IR<4:7> */ + case 0: /* nop */ + break; + case 1: /* CML */ + LAC = LAC ^ 010000; + break; + case 2: /* CMA */ + LAC = LAC ^ 07777; + break; + case 3: /* CMA CML */ + LAC = LAC ^ 017777; + break; + case 4: /* CLL */ + LAC = LAC & 07777; + break; + case 5: /* CLL CML = STL */ + LAC = LAC | 010000; + break; + case 6: /* CLL CMA */ + LAC = (LAC ^ 07777) & 07777; + break; + case 7: /* CLL CMA CML */ + LAC = (LAC ^ 07777) | 010000; + break; + case 010: /* CLA */ + LAC = LAC & 010000; + break; + case 011: /* CLA CML */ + LAC = (LAC & 010000) ^ 010000; + break; + case 012: /* CLA CMA = STA */ + LAC = LAC | 07777; + break; + case 013: /* CLA CMA CML */ + LAC = (LAC | 07777) ^ 010000; + break; + case 014: /* CLA CLL */ + LAC = 0; + break; + case 015: /* CLA CLL CML */ + LAC = 010000; + break; + case 016: /* CLA CLL CMA */ + LAC = 07777; + break; + case 017: /* CLA CLL CMA CML */ + LAC = 017777; + break; + } /* end switch opers */ + + if (IR & 01) LAC = (LAC + 1) & 017777; /* IAC */ + switch ((IR >> 1) & 07) { /* decode IR<8:10> */ + case 0: /* nop */ + break; + case 1: /* BSW */ + LAC = (LAC & 010000) | ((LAC >> 6) & 077) | ((LAC & 077) << 6); + break; + case 2: /* RAL */ + LAC = ((LAC << 1) | (LAC >> 12)) & 017777; + break; + case 3: /* RTL */ + LAC = ((LAC << 2) | (LAC >> 11)) & 017777; + break; + case 4: /* RAR */ + LAC = ((LAC >> 1) | (LAC << 12)) & 017777; + break; + case 5: /* RTR */ + LAC = ((LAC >> 2) | (LAC << 11)) & 017777; + break; + case 6: /* RAL RAR - undef */ + LAC = LAC & (IR | 010000); /* uses AND path */ + break; + case 7: /* RTL RTR - undef */ + LAC = (LAC & 010000) | (MA & 07600) | (IR & 0177); + break; /* uses address path */ + } /* end switch shifts */ + break; /* end group 1 */ + +/* OPR group 2. From Bernhard Baehr's description of the TSC8-75: + + (In user mode) HLT (7402), OSR (7404) and microprogrammed combinations with + HLT and OSR: Additional to raising a user mode interrupt, the current OPR + opcode is moved to the ERIOT register and the ECDF flag is cleared. */ + + case 036:case 037: /* OPR, groups 2, 3 */ + if ((IR & 01) == 0) { /* group 2 */ + switch ((IR >> 3) & 017) { /* decode IR<6:8> */ + case 0: /* nop */ + break; + case 1: /* SKP */ + PC = (PC + 1) & 07777; + break; + case 2: /* SNL */ + if (LAC >= 010000) PC = (PC + 1) & 07777; + break; + case 3: /* SZL */ + if (LAC < 010000) PC = (PC + 1) & 07777; + break; + case 4: /* SZA */ + if ((LAC & 07777) == 0) PC = (PC + 1) & 07777; + break; + case 5: /* SNA */ + if ((LAC & 07777) != 0) PC = (PC + 1) & 07777; + break; + case 6: /* SZA | SNL */ + if ((LAC == 0) || (LAC >= 010000)) + PC = (PC + 1) & 07777; + break; + case 7: /* SNA & SZL */ + if ((LAC != 0) && (LAC < 010000)) PC = (PC + 1) & 07777; + break; + case 010: /* SMA */ + if ((LAC & 04000) != 0) PC = (PC + 1) & 07777; + break; + case 011: /* SPA */ + if ((LAC & 04000) == 0) PC = (PC + 1) & 07777; + break; + case 012: /* SMA | SNL */ + if (LAC >= 04000) PC = (PC + 1) & 07777; + break; + case 013: /* SPA & SZL */ + if (LAC < 04000) PC = (PC + 1) & 07777; + break; + case 014: /* SMA | SZA */ + if (((LAC & 04000) != 0) || ((LAC & 07777) == 0)) + PC = (PC + 1) & 07777; + break; + case 015: /* SPA & SNA */ + if (((LAC & 04000) == 0) && ((LAC & 07777) != 0)) + PC = (PC + 1) & 07777; + break; + case 016: /* SMA | SZA | SNL */ + if ((LAC >= 04000) || (LAC == 0)) PC = (PC + 1) & 07777; + break; + case 017: /* SPA & SNA & SZL */ + if ((LAC < 04000) && (LAC != 0)) PC = (PC + 1) & 07777; + break; + } /* end switch skips */ + if (IR & 0200) LAC = LAC & 010000; /* CLA */ + if ((IR & 06) && UF) { /* user mode? */ + int_req = int_req | INT_UF; /* request intr */ + tsc_ir = IR; /* save instruction */ + tsc_cdf = 0; /* clear flag */ + } + else { + if (IR & 04) LAC = LAC | OSR; /* OSR */ + if (IR & 02) reason = STOP_HALT; /* HLT */ + } + break; + } /* end if group 2 */ + +/* OPR group 3 standard + + MQA!MQL exchanges AC and MQ, as follows: + + temp = MQ; + MQ = LAC & 07777; + LAC = LAC & 010000 | temp; +*/ + + temp = MQ; /* group 3 */ + if (IR & 0200) LAC = LAC & 010000; /* CLA */ + if (IR & 0020) { /* MQL */ + MQ = LAC & 07777; + LAC = LAC & 010000; + } + if (IR & 0100) LAC = LAC | temp; /* MQA */ + if ((IR & 0056) && (cpu_unit.flags & UNIT_NOEAE)) { + reason = stop_inst; /* EAE not present */ + break; + } + +/* OPR group 3 EAE + + The EAE operates in two modes: + + Mode A, PDP-8/I compatible + Mode B, extended capability + + Mode B provides eight additional subfunctions; in addition, some + of the Mode A functions operate differently in Mode B. + + The mode switch instructions are decoded explicitly and cannot be + microprogrammed with other EAE functions (SWAB performs an MQL as + part of standard group 3 decoding). If mode switching is decoded, + all other EAE timing is suppressed. +*/ + + if (IR == 07431) { /* SWAB */ + emode = 1; /* set mode flag */ + break; + } + if (IR == 07447) { /* SWBA */ + emode = gtf = 0; /* clear mode, gtf */ + break; + } + +/* If not switching modes, the EAE operation is determined by the mode + and IR<6,8:10>: + + <6:10> mode A mode B comments + + 0x000 NOP NOP + 0x001 SCL ACS + 0x010 MUY MUY if mode B, next = address + 0x011 DVI DVI if mode B, next = address + 0x100 NMI NMI if mode B, clear AC if + result = 4000'0000 + 0x101 SHL SHL if mode A, extra shift + 0x110 ASR ASR if mode A, extra shift + 0x111 LSR LSR if mode A, extra shift + 1x000 SCA SCA + 1x001 SCA + SCL DAD + 1x010 SCA + MUY DST + 1x011 SCA + DVI SWBA NOP if not detected earlier + 1x100 SCA + NMI DPSZ + 1x101 SCA + SHL DPIC must be combined with MQA!MQL + 1x110 SCA + ASR DCM must be combined with MQA!MQL + 1x111 SCA + LSR SAM + + EAE instructions which fetch memory operands use the CPU's DEFER + state to read the first word; if the address operand is in locations + x0010 - x0017, it is autoincremented. +*/ + + if (emode == 0) gtf = 0; /* mode A? clr gtf */ + switch ((IR >> 1) & 027) { /* decode IR<6,8:10> */ + + case 020: /* mode A, B: SCA */ + LAC = LAC | SC; + break; + case 000: /* mode A, B: NOP */ + break; + + case 021: /* mode B: DAD */ + if (emode) { + MA = IF | PC; + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + MQ = MQ + M[MA]; + MA = DF | ((MA + 1) & 07777); + LAC = (LAC & 07777) + M[MA] + (MQ >> 12); + MQ = MQ & 07777; + PC = (PC + 1) & 07777; + break; + } + LAC = LAC | SC; /* mode A: SCA then */ + case 001: /* mode B: ACS */ + if (emode) { + SC = LAC & 037; + LAC = LAC & 010000; + } + else { /* mode A: SCL */ + SC = (~M[IF | PC]) & 037; + PC = (PC + 1) & 07777; + } + break; + + case 022: /* mode B: DST */ + if (emode) { + MA = IF | PC; + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + if (MEM_ADDR_OK (MA)) M[MA] = MQ & 07777; + MA = DF | ((MA + 1) & 07777); + if (MEM_ADDR_OK (MA)) M[MA] = LAC & 07777; + PC = (PC + 1) & 07777; + break; + } + LAC = LAC | SC; /* mode A: SCA then */ + case 002: /* MUY */ + MA = IF | PC; + if (emode) { /* mode B: defer */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + } + temp = (MQ * M[MA]) + (LAC & 07777); + LAC = (temp >> 12) & 07777; + MQ = temp & 07777; + PC = (PC + 1) & 07777; + SC = 014; /* 12 shifts */ + break; + + case 023: /* mode B: SWBA */ + if (emode) break; + LAC = LAC | SC; /* mode A: SCA then */ + case 003: /* DVI */ + MA = IF | PC; + if (emode) { /* mode B: defer */ + if ((MA & 07770) != 00010) MA = DF | M[MA]; /* indirect; autoinc? */ + else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */ + } + if ((LAC & 07777) >= M[MA]) { /* overflow? */ + LAC = LAC | 010000; /* set link */ + MQ = ((MQ << 1) + 1) & 07777; /* rotate MQ */ + SC = 01; /* 1 shift */ + } + else { + temp = ((LAC & 07777) << 12) | MQ; + MQ = temp / M[MA]; + LAC = temp % M[MA]; + SC = 015; /* 13 shifts */ + } + PC = (PC + 1) & 07777; + break; + + case 024: /* mode B: DPSZ */ + if (emode) { + if (((LAC | MQ) & 07777) == 0) PC = (PC + 1) & 07777; + break; + } + LAC = LAC | SC; /* mode A: SCA then */ + case 004: /* NMI */ + temp = (LAC << 12) | MQ; /* preserve link */ + for (SC = 0; ((temp & 017777777) != 0) && + (temp & 040000000) == ((temp << 1) & 040000000); SC++) + temp = temp << 1; + LAC = (temp >> 12) & 017777; + MQ = temp & 07777; + if (emode && ((LAC & 07777) == 04000) && (MQ == 0)) + LAC = LAC & 010000; /* clr if 4000'0000 */ + break; + + case 025: /* mode B: DPIC */ + if (emode) { + temp = (LAC + 1) & 07777; /* SWP already done! */ + LAC = MQ + (temp == 0); + MQ = temp; + break; + } + LAC = LAC | SC; /* mode A: SCA then */ + case 5: /* SHL */ + SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */ + if (SC > 25) temp = 0; /* >25? result = 0 */ + else temp = ((LAC << 12) | MQ) << SC; /* <=25? shift LAC:MQ */ + LAC = (temp >> 12) & 017777; + MQ = temp & 07777; + PC = (PC + 1) & 07777; + SC = emode? 037: 0; /* SC = 0 if mode A */ + break; + + case 026: /* mode B: DCM */ + if (emode) { + temp = (-LAC) & 07777; /* SWP already done! */ + LAC = (MQ ^ 07777) + (temp == 0); + MQ = temp; + break; + } + LAC = LAC | SC; /* mode A: SCA then */ + case 6: /* ASR */ + SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */ + temp = ((LAC & 07777) << 12) | MQ; /* sext from AC0 */ + if (LAC & 04000) temp = temp | ~037777777; + if (emode && (SC != 0)) gtf = (temp >> (SC - 1)) & 1; + if (SC > 25) temp = (LAC & 04000)? -1: 0; + else temp = temp >> SC; + LAC = (temp >> 12) & 017777; + MQ = temp & 07777; + PC = (PC + 1) & 07777; + SC = emode? 037: 0; /* SC = 0 if mode A */ + break; + + case 027: /* mode B: SAM */ + if (emode) { + temp = LAC & 07777; + LAC = MQ + (temp ^ 07777) + 1; /* L'AC = MQ - AC */ + gtf = (temp <= MQ) ^ ((temp ^ MQ) >> 11); + break; + } + LAC = LAC | SC; /* mode A: SCA then */ + case 7: /* LSR */ + SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */ + temp = ((LAC & 07777) << 12) | MQ; /* clear link */ + if (emode && (SC != 0)) gtf = (temp >> (SC - 1)) & 1; + if (SC > 24) temp = 0; /* >24? result = 0 */ + else temp = temp >> SC; /* <=24? shift AC:MQ */ + LAC = (temp >> 12) & 07777; + MQ = temp & 07777; + PC = (PC + 1) & 07777; + SC = emode? 037: 0; /* SC = 0 if mode A */ + break; + } /* end switch */ + break; /* end case 7 */ + +/* Opcode 6, IOT. From Bernhard Baehr's description of the TSC8-75: + + (In user mode) Additional to raising a user mode interrupt, the current IOT + opcode is moved to the ERIOT register. When the IOT is a CDF instruction (62x1), + the ECDF flag is set, otherwise it is cleared. */ + + case 030:case 031:case 032:case 033: /* IOT */ + if (UF) { /* privileged? */ + int_req = int_req | INT_UF; /* request intr */ + tsc_ir = IR; /* save instruction */ + if ((IR & 07707) == 06201) tsc_cdf = 1; /* set/clear flag */ + else tsc_cdf = 0; + break; + } + device = (IR >> 3) & 077; /* device = IR<3:8> */ + pulse = IR & 07; /* pulse = IR<9:11> */ + iot_data = LAC & 07777; /* AC unchanged */ + switch (device) { /* decode IR<3:8> */ + + case 000: /* CPU control */ + switch (pulse) { /* decode IR<9:11> */ + + case 0: /* SKON */ + if (int_req & INT_ION) PC = (PC + 1) & 07777; + int_req = int_req & ~INT_ION; + break; + + case 1: /* ION */ + int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING; + break; + + case 2: /* IOF */ + int_req = int_req & ~INT_ION; + break; + + case 3: /* SRQ */ + if (int_req & INT_ALL) PC = (PC + 1) & 07777; + break; + + case 4: /* GTF */ + LAC = (LAC & 010000) | + ((LAC & 010000) >> 1) | (gtf << 10) | + (((int_req & INT_ALL) != 0) << 9) | + (((int_req & INT_ION) != 0) << 7) | SF; + break; + + case 5: /* RTF */ + gtf = ((LAC & 02000) >> 10); + UB = (LAC & 0100) >> 6; + IB = (LAC & 0070) << 9; + DF = (LAC & 0007) << 12; + LAC = ((LAC & 04000) << 1) | iot_data; + int_req = (int_req | INT_ION) & ~INT_NO_CIF_PENDING; + break; + + case 6: /* SGT */ + if (gtf) PC = (PC + 1) & 07777; + break; + + case 7: /* CAF */ + gtf = 0; + emode = 0; + int_req = int_req & INT_NO_CIF_PENDING; + dev_done = 0; + int_enable = INT_INIT_ENABLE; + LAC = 0; + reset_all (1); /* reset all dev */ + break; + } /* end switch pulse */ + break; /* end case 0 */ + + case 020:case 021:case 022:case 023: + case 024:case 025:case 026:case 027: /* memory extension */ + switch (pulse) { /* decode IR<9:11> */ + + case 1: /* CDF */ + DF = (IR & 0070) << 9; + break; + + case 2: /* CIF */ + IB = (IR & 0070) << 9; + int_req = int_req & ~INT_NO_CIF_PENDING; + break; + + case 3: /* CDF CIF */ + DF = IB = (IR & 0070) << 9; + int_req = int_req & ~INT_NO_CIF_PENDING; + break; + + case 4: + switch (device & 07) { /* decode IR<6:8> */ + + case 0: /* CINT */ + int_req = int_req & ~INT_UF; + break; + + case 1: /* RDF */ + LAC = LAC | (DF >> 9); + break; + + case 2: /* RIF */ + LAC = LAC | (IF >> 9); + break; + + case 3: /* RIB */ + LAC = LAC | SF; + break; + + case 4: /* RMF */ + UB = (SF & 0100) >> 6; + IB = (SF & 0070) << 9; + DF = (SF & 0007) << 12; + int_req = int_req & ~INT_NO_CIF_PENDING; + break; + + case 5: /* SINT */ + if (int_req & INT_UF) PC = (PC + 1) & 07777; + break; + + case 6: /* CUF */ + UB = 0; + int_req = int_req & ~INT_NO_CIF_PENDING; + break; + + case 7: /* SUF */ + UB = 1; + int_req = int_req & ~INT_NO_CIF_PENDING; + break; + } /* end switch device */ + break; + + default: + reason = stop_inst; + break; + } /* end switch pulse */ + break; /* end case 20-27 */ + + case 010: /* power fail */ + switch (pulse) { /* decode IR<9:11> */ + + case 1: /* SBE */ + break; + + case 2: /* SPL */ + if (int_req & INT_PWR) PC = (PC + 1) & 07777; + break; + + case 3: /* CAL */ + int_req = int_req & ~INT_PWR; + break; + + default: + reason = stop_inst; + break; + } /* end switch pulse */ + break; /* end case 10 */ + + default: /* I/O device */ + if (dev_tab[device]) { /* dev present? */ + iot_data = dev_tab[device] (IR, iot_data); + LAC = (LAC & 010000) | (iot_data & 07777); + if (iot_data & IOT_SKP) PC = (PC + 1) & 07777; + if (iot_data >= IOT_REASON) + reason = iot_data >> IOT_V_REASON; + } + else reason = stop_inst; /* stop on flag */ + break; + } /* end switch device */ + break; /* end case IOT */ + } /* end switch opcode */ + } /* end while */ + +/* Simulation halted */ + +saved_PC = IF | (PC & 07777); /* save copies */ +saved_DF = DF & 070000; +saved_LAC = LAC & 017777; +saved_MQ = MQ & 07777; +pcq_r->qptr = pcq_p; /* update pc q ptr */ +return reason; +} /* end sim_instr */ + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING; +saved_DF = IB = saved_PC & 070000; +UF = UB = gtf = emode = 0; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r->qptr = 0; +else return SCPE_IERR; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= MEMSIZE) return SCPE_NXM; +if (vptr != NULL) *vptr = M[addr] & 07777; +return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= MEMSIZE) return SCPE_NXM; +M[addr] = val & 07777; +return SCPE_OK; +} + +/* Memory size change */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 mc = 0; +uint32 i; + +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) + return SCPE_ARG; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; +if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) + return SCPE_OK; +MEMSIZE = val; +for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; +return SCPE_OK; +} + +/* Change device number for a device */ + +t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DEVICE *dptr; +DIB *dibp; +uint32 newdev; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */ +if ((r != SCPE_OK) || (newdev == dibp->dev)) return r; +dibp->dev = newdev; /* store */ +return SCPE_OK; +} + +/* Show device number for a device */ + +t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +DIB *dibp; + +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +fprintf (st, "devno=%02o", dibp->dev); +if (dibp->num > 1) fprintf (st, "-%2o", dibp->dev + dibp->num - 1); +return SCPE_OK; +} + +/* CPU device handler - should never get here! */ + +int32 bad_dev (int32 IR, int32 AC) +{ +return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */ +} + +/* Build device dispatch table */ + +t_bool build_dev_tab (void) +{ +DEVICE *dptr; +DIB *dibp; +uint32 i, j; +static const uint8 std_dev[] = { + 000, 010, 020, 021, 022, 023, 024, 025, 026, 027 + }; + +for (i = 0; i < DEV_MAX; i++) dev_tab[i] = NULL; /* clr table */ +for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */ + dev_tab[std_dev[i]] = &bad_dev; +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ + for (j = 0; j < dibp->num; j++) { /* loop thru disp */ + if (dibp->dsp[j]) { /* any dispatch? */ + if (dev_tab[dibp->dev + j]) { /* already filled? */ + printf ("%s device number conflict at %02o\n", + sim_dname (dptr), dibp->dev + j); + if (sim_log) fprintf (sim_log, + "%s device number conflict at %02o\n", + sim_dname (dptr), dibp->dev + j); + return TRUE; + } + dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */ + } /* end if dsp */ + } /* end for j */ + } /* end if enb */ + } /* end for i */ +return FALSE; +} + +/* Set history */ + +t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i, lnt; +t_stat r; + +if (cptr == NULL) { + for (i = 0; i < hst_lnt; i++) hst[i].pc = 0; + hst_p = 0; + return SCPE_OK; + } +lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); +if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG; +hst_p = 0; +if (hst_lnt) { + free (hst); + hst_lnt = 0; + hst = NULL; + } +if (lnt) { + hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); + if (hst == NULL) return SCPE_MEM; + hst_lnt = lnt; + } +return SCPE_OK; +} + +/* Show history */ + +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 l, k, di, lnt; +char *cptr = (char *) desc; +t_stat r; +t_value sim_eval; +InstHistory *h; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); + +if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */ +if (cptr) { + lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); + if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; + } +else lnt = hst_lnt; +di = hst_p - lnt; /* work forward */ +if (di < 0) di = di + hst_lnt; +fprintf (st, "PC L AC MQ ea IR\n\n"); +for (k = 0; k < lnt; k++) { /* print specified */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + if (h->pc & HIST_PC) { /* instruction? */ + l = (h->lac >> 12) & 1; /* link */ + fprintf (st, "%05o %o %04o %04o ", h->pc & ADDRMASK, l, h->lac & 07777, h->mq); + if (h->ir < 06000) fprintf (st, "%05o ", h->ea); + else fprintf (st, " "); + sim_eval = h->ir; + if ((fprint_sym (st, h->pc & ADDRMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0) + fprintf (st, "(undefined) %04o", h->ir); + if (h->ir < 04000) fprintf (st, " [%04o]", h->opnd); + fputc ('\n', st); /* end line */ + } /* end else instruction */ + } /* end for */ +return SCPE_OK; +} diff --git a/simhv36-1/PDP8/pdp8_defs.h b/simhv36-1/PDP8/pdp8_defs.h new file mode 100644 index 0000000..80a7db1 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_defs.h @@ -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 diff --git a/simhv36-1/PDP8/pdp8_df.c b/simhv36-1/PDP8/pdp8_df.c new file mode 100644 index 0000000..a03d7d0 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_df.c @@ -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 + +#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 + pulse 4 = df_sta = df_sta | AC + AC = AC | old_df_sta + 6616 pulse 2 = clear AC, skip if address confirmed + pulse 4 = df_sta = df_sta | AC = 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; +} diff --git a/simhv36-1/PDP8/pdp8_dt.c b/simhv36-1/PDP8/pdp8_dt.c new file mode 100644 index 0000000..5b603fe --- /dev/null +++ b/simhv36-1/PDP8/pdp8_dt.c @@ -0,0 +1,1292 @@ +/* pdp8_dt.c: PDP-8 DECtape 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. + + dt TC08/TU56 DECtape + + 23-Jun-06 RMS Fixed switch conflict in ATTACH + 07-Jan-06 RMS Fixed unaligned register access bug (found by Doug Carman) + 16-Aug-05 RMS Fixed C++ declaration and cast problems + 25-Jan-04 RMS Revised for device debug support + 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR + 18-Oct-03 RMS Fixed bugs in read all, tightened timing + 25-Apr-03 RMS Revised for extended file support + 14-Mar-03 RMS Fixed sizing interaction with save/restore + 17-Oct-02 RMS Fixed bug in end of reel logic + 04-Oct-02 RMS Added DIB, device number support + 12-Sep-02 RMS Added support for 16b format + 30-May-02 RMS Widened POS to 32b + 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 POS, STATT, LASTT, FLG to arrays + 29-Aug-01 RMS Added casts to PDP-18b packup routine + 17-Jul-01 RMS Moved function prototype + 11-May-01 RMS Fixed bug in reset + 25-Apr-01 RMS Added device enable/disable support + 18-Apr-01 RMS Changed to rewind tape before boot + 19-Mar-01 RMS Changed bootstrap to support 4k disk monitor + 15-Mar-01 RMS Added 129th word to PDP-8 format + + PDP-8 DECtapes are represented in memory by fixed length buffer of 16b 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/36bb 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 read all and write all. Read all 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 all writes only the data words and dumps the non-data words in the + bit bucket. +*/ + +#include "pdp8_defs.h" + +#define DT_NUMDR 8 /* #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 DT_WC 07754 /* word count */ +#define DT_CA 07755 /* current addr */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ + +/* System independent DECtape constants */ + +#define DT_LPERMC 6 /* lines per mark track */ +#define DT_BLKWD 1 /* blk no word in h/t */ +#define DT_CSMWD 4 /* checksum word in h/t */ +#define DT_HTWRD 5 /* header/trailer words */ +#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */ +#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */ +#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */ +#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */ +#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */ + +/* 16b, 18b, 36b DECtape constants */ + +#define D18_WSIZE 6 /* word size in 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)) +#define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE) +#define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN) +#define DT_QREZ(u) (((u)->pos) < DT_EZLIN) +#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u))) +#define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u)) + +/* Status register A */ + +#define DTA_V_UNIT 9 /* unit select */ +#define DTA_M_UNIT 07 +#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) +#define DTA_V_MOT 7 /* motion */ +#define DTA_M_MOT 03 +#define DTA_V_MODE 6 /* mode */ +#define DTA_V_FNC 3 /* function */ +#define DTA_M_FNC 07 +#define FNC_MOVE 00 /* move */ +#define FNC_SRCH 01 /* search */ +#define FNC_READ 02 /* read */ +#define FNC_RALL 03 /* read all */ +#define FNC_WRIT 04 /* write */ +#define FNC_WALL 05 /* write all */ +#define FNC_WMRK 06 /* write timing */ +#define DTA_V_ENB 2 /* int enable */ +#define DTA_V_CERF 1 /* clr error flag */ +#define DTA_V_CDTF 0 /* clr DECtape flag */ +#define DTA_FWDRV (1u << (DTA_V_MOT + 1)) +#define DTA_STSTP (1u << DTA_V_MOT) +#define DTA_MODE (1u << DTA_V_MODE) +#define DTA_ENB (1u << DTA_V_ENB) +#define DTA_CERF (1u << DTA_V_CERF) +#define DTA_CDTF (1u << DTA_V_CDTF) +#define DTA_RW (07777 & ~(DTA_CERF | DTA_CDTF)) + +#define DTA_GETUNIT(x) (((x) >> DTA_V_UNIT) & DTA_M_UNIT) +#define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT) +#define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC) + +/* Status register B */ + +#define DTB_V_ERF 11 /* error flag */ +#define DTB_V_MRK 10 /* mark trk err */ +#define DTB_V_END 9 /* end zone err */ +#define DTB_V_SEL 8 /* select err */ +#define DTB_V_PAR 7 /* parity err */ +#define DTB_V_TIM 6 /* timing err */ +#define DTB_V_MEX 3 /* memory extension */ +#define DTB_M_MEX 07 +#define DTB_MEX (DTB_M_MEX << DTB_V_MEX) +#define DTB_V_DTF 0 /* DECtape flag */ +#define DTB_ERF (1u << DTB_V_ERF) +#define DTB_MRK (1u << DTB_V_MRK) +#define DTB_END (1u << DTB_V_END) +#define DTB_SEL (1u << DTB_V_SEL) +#define DTB_PAR (1u << DTB_V_PAR) +#define DTB_TIM (1u << DTB_V_TIM) +#define DTB_DTF (1u << DTB_V_DTF) +#define DTB_ALLERR (DTB_ERF | DTB_MRK | DTB_END | DTB_SEL | \ + DTB_PAR | DTB_TIM) +#define DTB_GETMEX(x) (((x) & DTB_MEX) << (12 - DTB_V_MEX)) + +/* DECtape state */ + +#define DTS_V_MOT 3 /* motion */ +#define DTS_M_MOT 07 +#define DTS_STOP 0 /* stopped */ +#define DTS_DECF 2 /* decel, fwd */ +#define DTS_DECR 3 /* decel, rev */ +#define DTS_ACCF 4 /* accel, fwd */ +#define DTS_ACCR 5 /* accel, rev */ +#define DTS_ATSF 6 /* @speed, fwd */ +#define DTS_ATSR 7 /* @speed, rev */ +#define DTS_DIR 01 /* dir mask */ +#define DTS_V_FNC 0 /* function */ +#define DTS_M_FNC 07 +#define DTS_OFR 7 /* "off reel" */ +#define DTS_GETMOT(x) (((x) >> DTS_V_MOT) & DTS_M_MOT) +#define DTS_GETFNC(x) (((x) >> DTS_V_FNC) & DTS_M_FNC) +#define DTS_V_2ND 6 /* next state */ +#define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */ +#define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC)) +#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z) +#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \ + ((DTS_STA (y, z)) << DTS_V_2ND) +#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \ + ((DTS_STA (y, z)) << DTS_V_3RD) +#define DTS_NXTSTA(x) (x >> DTS_V_2ND) + +/* Operation substates */ + +#define DTO_WCO 1 /* wc overflow */ +#define DTO_SOB 2 /* start of block */ + +/* Logging */ + +#define LOG_MS 001 /* move, search */ +#define LOG_RW 002 /* read, write */ +#define LOG_BL 004 /* block # lblk */ + +#define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \ + int_req = int_req | INT_DTA; \ + else int_req = int_req & ~INT_DTA; +#define ABS(x) (((x) < 0)? (-(x)): (x)) + +extern uint16 M[]; +extern int32 int_req; +extern UNIT cpu_unit; +extern int32 sim_switches; +extern FILE *sim_deb; + +int32 dtsa = 0; /* status A */ +int32 dtsb = 0; /* status B */ +int32 dt_ltime = 12; /* interline time */ +int32 dt_dctime = 40000; /* decel time */ +int32 dt_substate = 0; +int32 dt_logblk = 0; +int32 dt_stopoffr = 0; + +DEVICE dt_dev; +int32 dt76 (int32 IR, int32 AC); +int32 dt77 (int32 IR, int32 AC); +t_stat dt_svc (UNIT *uptr); +t_stat dt_reset (DEVICE *dptr); +t_stat dt_attach (UNIT *uptr, char *cptr); +t_stat dt_detach (UNIT *uptr); +t_stat dt_boot (int32 unitno, DEVICE *dptr); +void dt_deselect (int32 oldf); +void dt_newsa (int32 newf); +void dt_newfnc (UNIT *uptr, int32 newsta); +t_bool dt_setpos (UNIT *uptr); +void dt_schedez (UNIT *uptr, int32 dir); +void dt_seterr (UNIT *uptr, int32 e); +int32 dt_comobv (int32 val); +int32 dt_csum (UNIT *uptr, int32 blk); +int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos, int32 dir); +extern int32 sim_is_running; + +/* DT data structures + + dt_dev DT device descriptor + dt_unit DT unit list + dt_reg DT register list + dt_mod DT modifier list +*/ + +DIB dt_dib = { DEV_DTA, 2, { &dt76, &dt77 } }; + +UNIT dt_unit[] = { + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) } + }; + +REG dt_reg[] = { + { ORDATA (DTSA, dtsa, 12) }, + { ORDATA (DTSB, dtsb, 12) }, + { FLDATA (INT, int_req, INT_V_DTA) }, + { FLDATA (ENB, dtsa, DTA_V_ENB) }, + { FLDATA (DTF, dtsb, DTB_V_DTF) }, + { FLDATA (ERF, dtsb, DTB_V_ERF) }, + { ORDATA (WC, M[DT_WC], 12), REG_FIT }, + { ORDATA (CA, M[DT_CA], 12), REG_FIT }, + { DRDATA (LTIME, dt_ltime, 24), REG_NZ | PV_LEFT }, + { DRDATA (DCTIME, dt_dctime, 24), REG_NZ | PV_LEFT }, + { ORDATA (SUBSTATE, dt_substate, 2) }, + { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, + { URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 0, + DT_NUMDR, PV_LEFT | REG_RO) }, + { URDATA (STATT, dt_unit[0].STATE, 8, 18, 0, + DT_NUMDR, REG_RO) }, + { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0, + DT_NUMDR, REG_HRO) }, + { FLDATA (STOP_OFFR, dt_stopoffr, 0) }, + { ORDATA (DEVNUM, dt_dib.dev, 6), REG_HRO }, + { NULL } + }; + +MTAB dt_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 }, + { 0 } + }; + +DEBTAB dt_deb[] = { + { "MOTION", LOG_MS }, + { "DATA", LOG_RW }, + { "BLOCK", LOG_BL }, + { NULL, 0 } + }; + +DEVICE dt_dev = { + "DT", dt_unit, dt_reg, dt_mod, + DT_NUMDR, 8, 24, 1, 8, 12, + NULL, NULL, &dt_reset, + &dt_boot, &dt_attach, &dt_detach, + &dt_dib, DEV_DISABLE | DEV_DEBUG, 0, + dt_deb, NULL, NULL + }; + +/* IOT routines */ + +int32 dt76 (int32 IR, int32 AC) +{ +int32 pulse = IR & 07; +int32 old_dtsa = dtsa, fnc; +UNIT *uptr; + +if (pulse & 01) AC = AC | dtsa; /* DTRA */ +if (pulse & 06) { /* select */ + if (pulse & 02) dtsa = 0; /* DTCA */ + if (pulse & 04) { /* DTXA */ + if ((AC & DTA_CERF) == 0) dtsb = dtsb & ~DTB_ALLERR; + if ((AC & DTA_CDTF) == 0) dtsb = dtsb & ~DTB_DTF; + dtsa = dtsa ^ (AC & DTA_RW); + AC = 0; /* clr AC */ + } + if ((old_dtsa ^ dtsa) & DTA_UNIT) dt_deselect (old_dtsa); + uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */ + fnc = DTA_GETFNC (dtsa); /* get fnc */ + if (((uptr->flags) & UNIT_DIS) || /* disabled? */ + (fnc >= FNC_WMRK) || /* write mark? */ + ((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) || + ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT))) + dt_seterr (uptr, DTB_SEL); /* select err */ + else dt_newsa (dtsa); + DT_UPDINT; + } +return AC; +} + +int32 dt77 (int32 IR, int32 AC) +{ +int32 pulse = IR & 07; + +if ((pulse & 01) && (dtsb & (DTB_ERF |DTB_DTF))) /* DTSF */ + AC = IOT_SKP | AC; +if (pulse & 02) AC = AC | dtsb; /* DTRB */ +if (pulse & 04) { /* DTLB */ + dtsb = (dtsb & ~DTB_MEX) | (AC & DTB_MEX); + AC = AC & ~07777; /* clear AC */ + } +return AC; +} + +/* Unit deselect */ + +void dt_deselect (int32 oldf) +{ +int32 old_unit = DTA_GETUNIT (oldf); +UNIT *uptr = dt_dev.units + old_unit; +int32 old_mot = DTS_GETMOT (uptr->STATE); + +if (old_mot >= DTS_ATSF) /* at speed? */ + dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); +else if (old_mot >= DTS_ACCF) /* accelerating? */ + DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR); +return; +} + +/* Command register change + + 1. If change in motion, stop to start + - schedule acceleration + - set function as next state + 2. If change in motion, start to stop + - if not already decelerating (could be reversing), + schedule deceleration + 3. If change in direction, + - if not decelerating, schedule deceleration + - set accelerating (other dir) as next state + - set function as next next state + 4. If not accelerating or at speed, + - schedule acceleration + - set function as next state + 5. If not yet at speed, + - set function as next state + 6. If at speed, + - set function as current state, schedule function +*/ + +void dt_newsa (int32 newf) +{ +int32 new_unit, prev_mot, new_fnc; +int32 prev_mving, new_mving, prev_dir, new_dir; +UNIT *uptr; + +new_unit = DTA_GETUNIT (newf); /* new, old units */ +uptr = dt_dev.units + new_unit; +if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */ + dt_seterr (uptr, DTB_SEL); /* no, error */ + return; + } +prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */ +prev_mving = prev_mot != DTS_STOP; /* previous moving? */ +prev_dir = prev_mot & DTS_DIR; /* previous dir? */ +new_mving = (newf & DTA_STSTP) != 0; /* new moving? */ +new_dir = (newf & DTA_FWDRV) != 0; /* new dir? */ +new_fnc = DTA_GETFNC (newf); /* new function? */ + +if ((prev_mving | new_mving) == 0) return; /* stop to stop */ + +if (new_mving & ~prev_mving) { /* start? */ + if (dt_setpos (uptr)) return; /* update pos */ + sim_cancel (uptr); /* stop current */ + sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* schedule acc */ + DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ + DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ + return; + } + +if (prev_mving & ~new_mving) { /* stop? */ + if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ + if (dt_setpos (uptr)) return; /* update pos */ + sim_cancel (uptr); /* stop current */ + sim_activate (uptr, dt_dctime); /* schedule decel */ + } + DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */ + return; + } + +if (prev_dir ^ new_dir) { /* dir chg? */ + if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ + if (dt_setpos (uptr)) return; /* update pos */ + sim_cancel (uptr); /* stop current */ + sim_activate (uptr, dt_dctime); /* schedule decel */ + } + DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */ + DTS_SET2ND (DTS_ACCF | new_dir, 0); /* next = accel */ + DTS_SET3RD (DTS_ATSF | new_dir, new_fnc); /* next next = fnc */ + return; + } + +if (prev_mot < DTS_ACCF) { /* not accel/at speed? */ + if (dt_setpos (uptr)) return; /* update pos */ + sim_cancel (uptr); /* cancel cur */ + sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */ + DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ + DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ + return; + } + +if (prev_mot < DTS_ATSF) { /* not at speed? */ + DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ + return; + } + +dt_newfnc (uptr, DTS_STA (DTS_ATSF | new_dir, new_fnc));/* state = fnc */ +return; +} + +/* Schedule new DECtape function + + This routine is only called if + - the selected unit is attached + - the selected unit is at speed (forward or backward) + + This routine + - updates the selected unit's position + - updates the selected unit's state + - schedules the new operation +*/ + +void dt_newfnc (UNIT *uptr, int32 newsta) +{ +int32 fnc, dir, blk, unum, relpos, newpos; +uint32 oldpos; + +oldpos = uptr->pos; /* save old pos */ +if (dt_setpos (uptr)) return; /* update pos */ +uptr->STATE = newsta; /* update state */ +fnc = DTS_GETFNC (uptr->STATE); /* set variables */ +dir = DTS_GETMOT (uptr->STATE) & DTS_DIR; +unum = (int32) (uptr - dt_dev.units); +if (oldpos == uptr->pos) /* bump pos */ + uptr->pos = uptr->pos + (dir? -1: 1); +blk = DT_LIN2BL (uptr->pos, uptr); + +if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */ + dt_seterr (uptr, DTB_END); /* set ez flag, stop */ + return; + } +sim_cancel (uptr); /* cancel cur op */ +dt_substate = DTO_SOB; /* substate = block start */ +switch (fnc) { /* case function */ + + case DTS_OFR: /* off reel */ + if (dir) newpos = -1000; /* rev? < start */ + else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */ + break; + + case FNC_MOVE: /* move */ + dt_schedez (uptr, dir); /* sched end zone */ + if (DEBUG_PRI (dt_dev, LOG_MS)) fprintf (sim_deb, ">>DT%d: moving %s\n", + unum, (dir? "backward": "forward")); + return; /* done */ + + case FNC_SRCH: /* search */ + if (dir) newpos = DT_BLK2LN ((DT_QFEZ (uptr)? + DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE; + else newpos = DT_BLK2LN ((DT_QREZ (uptr)? + 0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1); + if (DEBUG_PRI (dt_dev, LOG_MS)) fprintf (sim_deb, ">>DT%d: searching %s]\n", + unum, (dir? "backward": "forward")); + break; + + case FNC_WRIT: /* write */ + case FNC_READ: /* read */ + case FNC_RALL: /* read all */ + case FNC_WALL: /* write all */ + if (DT_QEZ (uptr)) { /* in "ok" end zone? */ + if (dir) newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE; + else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1); + break; + } + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ + if ((relpos >= DT_HTLIN) && /* in data zone? */ + (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { + dt_seterr (uptr, DTB_SEL); + return; + } + if (dir) newpos = DT_BLK2LN (((relpos >= (DTU_LPERB (uptr) - DT_HTLIN))? + blk + 1: blk), uptr) - DT_HTLIN - DT_WSIZE; + else newpos = DT_BLK2LN (((relpos < DT_HTLIN)? + blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1); + break; + + default: + dt_seterr (uptr, DTB_SEL); /* bad state */ + return; + } + +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); +return; +} + +/* 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/dt_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 dt_setpos (UNIT *uptr) +{ +uint32 new_time, ut, ulin, udelt; +int32 mot = DTS_GETMOT (uptr->STATE); +int32 unum, 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 (mot & ~DTS_DIR) { /* case on motion */ + + case DTS_STOP: /* stop */ + delta = 0; + break; + + case DTS_DECF: /* slowing */ + ulin = ut / (uint32) dt_ltime; + udelt = dt_dctime / dt_ltime; + delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt); + break; + + case DTS_ACCF: /* accelerating */ + ulin = ut / (uint32) dt_ltime; + udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime; + delta = (ulin * ulin) / (2 * udelt); + break; + + case DTS_ATSF: /* at speed */ + delta = ut / (uint32) dt_ltime; + break; + } + +if (mot & DTS_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? */ + uptr->STATE = uptr->pos = 0; + unum = (int32) (uptr - dt_dev.units); + if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ + dt_seterr (uptr, DTB_SEL); /* error */ + return TRUE; + } +return FALSE; +} + +/* Unit service + + Unit must be attached, detach cancels operation +*/ + +t_stat dt_svc (UNIT *uptr) +{ +int32 mot = DTS_GETMOT (uptr->STATE); +int32 dir = mot & DTS_DIR; +int32 fnc = DTS_GETFNC (uptr->STATE); +int16 *fbuf = (int16 *) uptr->filebuf; +int32 unum = uptr - dt_dev.units; +int32 blk, wrd, ma, relpos, dat; +uint32 ba; + +/* Motion cases + + Decelerating - if next state != stopped, must be accel reverse + Accelerating - next state must be @speed, schedule function + At speed - do functional processing +*/ + +switch (mot) { + + case DTS_DECF: case DTS_DECR: /* decelerating */ + if (dt_setpos (uptr)) /* upd pos; off reel? */ + return IORETURN (dt_stopoffr, STOP_DTOFF); + uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ + if (uptr->STATE) /* not stopped? */ + sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* must be reversing */ + return SCPE_OK; + + case DTS_ACCF: case DTS_ACCR: /* accelerating */ + dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */ + return SCPE_OK; + + case DTS_ATSF: case DTS_ATSR: /* at speed */ + break; /* check function */ + + default: /* other */ + dt_seterr (uptr, DTB_SEL); /* state error */ + return SCPE_OK; + } + +/* Functional cases + + Move - must be at end zone + Search - transfer block number, schedule next block + Off reel - detach unit (it must be deselected) +*/ + +if (dt_setpos (uptr)) /* upd pos; off reel? */ + return IORETURN (dt_stopoffr, STOP_DTOFF); +if (DT_QEZ (uptr)) { /* in end zone? */ + dt_seterr (uptr, DTB_END); /* end zone error */ + return SCPE_OK; + } +blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */ +switch (fnc) { /* at speed, check fnc */ + + case FNC_MOVE: /* move */ + dt_seterr (uptr, DTB_END); /* end zone error */ + return SCPE_OK; + + case FNC_SRCH: /* search */ + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; + } + sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */ + M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr word cnt */ + ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */ + if (MEM_ADDR_OK (ma)) M[ma] = blk & 07777; /* store block # */ + if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) + dtsb = dtsb | DTB_DTF; /* set DTF */ + break; + + case DTS_OFR: /* off reel */ + detach_unit (uptr); /* must be deselected */ + uptr->STATE = uptr->pos = 0; /* no visible action */ + break; + +/* Read has four subcases + + Start of block, not wc ovf - check that DTF is clear, otherwise normal + Normal - increment MA, WC, copy word from tape to memory + if read dir != write dir, bits must be scrambled + if wc overflow, next state is wc overflow + if end of block, possibly set DTF, next state is start of block + Wc ovf, not start of block - + if end of block, possibly set DTF, next state is start of block + Wc ovf, start of block - if end of block reached, timing error, + otherwise, continue to next word +*/ + + case FNC_READ: /* read */ + wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ + switch (dt_substate) { /* case on substate */ + + case DTO_SOB: /* start of block */ + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; + } + if (DEBUG_PRI (dt_dev, LOG_RW) || + (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) + fprintf (sim_deb, ">>DT%d: reading block %d %s%s\n", + unum, blk, (dir? "backward": "forward"), + ((dtsa & DTA_MODE)? " continuous": " ")); + dt_substate = 0; /* fall through */ + case 0: /* normal read */ + M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ + M[DT_CA] = (M[DT_CA] + 1) & 07777; + ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */ + ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ + dat = fbuf[ba]; /* get tape word */ + if (dir) dat = dt_comobv (dat); /* rev? comp obv */ + if (MEM_ADDR_OK (ma)) M[ma] = dat; /* mem addr legal? */ + if (M[DT_WC] == 0) dt_substate = DTO_WCO; /* wc ovf? */ + case DTO_WCO: /* wc ovf, not sob */ + if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */ + sim_activate (uptr, DT_WSIZE * dt_ltime); + else { + dt_substate = dt_substate | DTO_SOB; + sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime); + if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) + dtsb = dtsb | DTB_DTF; /* set DTF */ + } + break; + + case DTO_WCO | DTO_SOB: /* next block */ + if (wrd == (dir? 0: DTU_BSIZE (uptr))) /* end of block? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + else sim_activate (uptr, DT_WSIZE * dt_ltime); + break; + } + + break; + +/* Write has four subcases + + Start of block, not wc ovf - check that DTF is clear, set block direction + Normal - increment MA, WC, copy word from memory to tape + if wc overflow, next state is wc overflow + if end of block, possibly set DTF, next state is start of block + Wc ovf, not start of block - + copy 0 to tape + if end of block, possibly set DTF, next state is start of block + Wc ovf, start of block - schedule end zone +*/ + + case FNC_WRIT: /* write */ + wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ + switch (dt_substate) { /* case on substate */ + + case DTO_SOB: /* start block */ + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; + } + if (DEBUG_PRI (dt_dev, LOG_RW) || + (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) + fprintf (sim_deb, ">>DT%d: writing block %d %s%s\n", unum, blk, + (dir? "backward": "forward"), + ((dtsa & DTA_MODE)? " continuous": " ")); + dt_substate = 0; /* fall through */ + case 0: /* normal write */ + M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ + M[DT_CA] = (M[DT_CA] + 1) & 07777; + case DTO_WCO: /* wc ovflo */ + ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */ + ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ + dat = dt_substate? 0: M[ma]; /* get word */ + if (dir) dat = dt_comobv (dat); /* rev? comp obv */ + fbuf[ba] = dat; /* write word */ + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; + if (M[DT_WC] == 0) dt_substate = DTO_WCO; + if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */ + sim_activate (uptr, DT_WSIZE * dt_ltime); + else { + dt_substate = dt_substate | DTO_SOB; + sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime); + if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) + dtsb = dtsb | DTB_DTF; /* set DTF */ + } + break; + + case DTO_WCO | DTO_SOB: /* all done */ + dt_schedez (uptr, dir); /* sched end zone */ + break; + } + + break; + +/* Read all has two subcases + + Not word count overflow - increment MA, WC, copy word from tape to memory + Word count overflow - schedule end zone +*/ + + case FNC_RALL: + switch (dt_substate) { /* case on substate */ + + case 0: case DTO_SOB: /* read in progress */ + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; + } + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ + M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ + M[DT_CA] = (M[DT_CA] + 1) & 07777; + ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */ + if ((relpos >= DT_HTLIN) && /* in data zone? */ + (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { + wrd = DT_LIN2WD (uptr->pos, uptr); + ba = (blk * DTU_BSIZE (uptr)) + wrd; + dat = fbuf[ba]; /* get tape word */ + if (dir) dat = dt_comobv (dat); /* rev? comp obv */ + } + else dat = dt_gethdr (uptr, blk, relpos, dir); /* get hdr */ + sim_activate (uptr, DT_WSIZE * dt_ltime); + if (MEM_ADDR_OK (ma)) M[ma] = dat; /* mem addr legal? */ + if (M[DT_WC] == 0) dt_substate = DTO_WCO; + if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) + dtsb = dtsb | DTB_DTF; /* set DTF */ + break; + + case DTO_WCO: case DTO_WCO | DTO_SOB: /* all done */ + dt_schedez (uptr, dir); /* sched end zone */ + break; + } /* end case substate */ + + break; + +/* Write all has two subcases + + Not word count overflow - increment MA, WC, copy word from memory to tape + Word count overflow - schedule end zone +*/ + + case FNC_WALL: + switch (dt_substate) { /* case on substate */ + + case 0: case DTO_SOB: /* read in progress */ + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; + } + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ + M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ + M[DT_CA] = (M[DT_CA] + 1) & 07777; + ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */ + if ((relpos >= DT_HTLIN) && /* in data zone? */ + (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { + dat = M[ma]; /* get mem word */ + if (dir) dat = dt_comobv (dat); + wrd = DT_LIN2WD (uptr->pos, uptr); + ba = (blk * DTU_BSIZE (uptr)) + wrd; + fbuf[ba] = dat; /* write word */ + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; + } +/* /* ignore hdr */ + sim_activate (uptr, DT_WSIZE * dt_ltime); + if (M[DT_WC] == 0) dt_substate = DTO_WCO; + if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) + dtsb = dtsb | DTB_DTF; /* set DTF */ + break; + + case DTO_WCO: case DTO_WCO | DTO_SOB: /* all done */ + dt_schedez (uptr, dir); /* sched end zone */ + break; + } /* end case substate */ + break; + + default: + dt_seterr (uptr, DTB_SEL); /* impossible state */ + break; + } + +DT_UPDINT; /* update interrupts */ +return SCPE_OK; +} + +/* Reading the header is complicated, because 18b words are being parsed + out 12b at a time. The sequence of word numbers is directionally + sensitive + + Forward Reverse + Word Word Content Word Word Content + (abs) (rel) (abs) (rel) + + 137 8 fwd csm'00 6 6 rev csm'00 + 138 9 0000 5 5 0000 + 139 10 0000 4 4 0000 + 140 11 0000 3 3 0000 + 141 12 00'lo rev blk 2 2 00'lo fwd blk + 142 13 hi rev blk 1 1 hi fwd blk + 143 14 0000 0 0 0000 + 0 0 0000 143 14 0000 + 1 1 0000 142 13 0000 + 2 2 hi fwd blk 141 12 hi rev blk + 3 3 lo fwd blk'00 140 11 lo rev blk'00 + 4 4 0000 139 10 0000 + 5 5 0000 138 9 0000 + 6 6 0000 137 8 0000 + 7 7 rev csm 136 7 00'fwd csm +*/ + +int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos, int32 dir) +{ +if (relpos >= DT_HTLIN) relpos = relpos - (DT_WSIZE * DTU_BSIZE (uptr)); +if (dir) { /* reverse */ + switch (relpos / DT_WSIZE) { + case 6: /* rev csm */ + return 077; + case 2: /* lo fwd blk */ + return dt_comobv ((blk & 077) << 6); + case 1: /* hi fwd blk */ + return dt_comobv (blk >> 6); + case 12: /* hi rev blk */ + return (blk >> 6) & 07777; + case 11: /* lo rev blk */ + return ((blk & 077) << 6); + case 7: /* fwd csum */ + return (dt_comobv (dt_csum (uptr, blk)) << 6); + default: /* others */ + return 07777; + } + } +else { /* forward */ + switch (relpos / DT_WSIZE) { + case 8: /* fwd csum */ + return (dt_csum (uptr, blk) << 6); + case 12: /* lo rev blk */ + return dt_comobv ((blk & 077) << 6); + case 13: /* hi rev blk */ + return dt_comobv (blk >> 6); + case 2: /* hi fwd blk */ + return ((blk >> 6) & 07777); + case 3: /* lo fwd blk */ + return ((blk & 077) << 6); + case 7: /* rev csum */ + return 077; + default: /* others */ + break; + } + } +return 0; +} + +/* Utility routines */ + +/* Set error flag */ + +void dt_seterr (UNIT *uptr, int32 e) +{ +int32 mot = DTS_GETMOT (uptr->STATE); + +dtsa = dtsa & ~DTA_STSTP; /* clear go */ +dtsb = dtsb | DTB_ERF | e; /* set error flag */ +if (mot >= DTS_ACCF) { /* ~stopped or stopping? */ + sim_cancel (uptr); /* cancel activity */ + if (dt_setpos (uptr)) return; /* update position */ + sim_activate (uptr, dt_dctime); /* sched decel */ + DTS_SETSTA (DTS_DECF | (mot & DTS_DIR), 0); /* state = decel */ + } +DT_UPDINT; +return; +} + +/* Schedule end zone */ + +void dt_schedez (UNIT *uptr, int32 dir) +{ +int32 newpos; + +if (dir) newpos = DT_EZLIN - DT_WSIZE; /* rev? rev ez */ +else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */ +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); +return; +} + +/* Complement obverse routine */ + +int32 dt_comobv (int32 dat) +{ +dat = dat ^ 07777; /* compl obverse */ +dat = ((dat >> 9) & 07) | ((dat >> 3) & 070) | + ((dat & 070) << 3) | ((dat & 07) << 9); +return dat; +} + +/* Checksum routine */ + +int32 dt_csum (UNIT *uptr, int32 blk) +{ +int16 *fbuf = (int16 *) uptr->filebuf; +int32 ba = blk * DTU_BSIZE (uptr); +int32 i, csum, wrd; + +csum = 077; /* init csum */ +for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ + wrd = fbuf[ba + i] ^ 07777; /* get ~word */ + csum = csum ^ (wrd >> 6) ^ wrd; + } +return (csum & 077); +} + +/* Reset routine */ + +t_stat dt_reset (DEVICE *dptr) +{ +int32 i, prev_mot; +UNIT *uptr; + +for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */ + uptr = dt_dev.units + i; + if (sim_is_running) { /* CAF? */ + prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */ + if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */ + if (dt_setpos (uptr)) continue; /* update pos */ + sim_cancel (uptr); + sim_activate (uptr, dt_dctime); /* sched decel */ + DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0); + } + } + else { + sim_cancel (uptr); /* sim reset */ + uptr->STATE = 0; + uptr->LASTT = sim_grtime (); + } + } +dtsa = dtsb = 0; /* clear status */ +DT_UPDINT; /* reset interrupt */ +return SCPE_OK; +} + +/* Bootstrap routine + + This is actually the 4K disk monitor bootstrap, which also + works with OS/8. The reverse is not true - the OS/8 bootstrap + doesn't work with the disk monitor. +*/ + +#define BOOT_START 0200 +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) + +static const uint16 boot_rom[] = { + 07600, /* 200, CLA CLL */ + 01216, /* TAD MVB ; move back */ + 04210, /* JMS DO ; action */ + 01217, /* TAD K7577 ; addr */ + 03620, /* DCA I CA */ + 01222, /* TAD RDF ; read fwd */ + 04210, /* JMS DO ; action */ + 05600, /* JMP I 200 ; enter boot */ + 00000, /* DO, 0 */ + 06766, /* DTCA!DTXA ; start tape */ + 03621, /* DCA I WC ; clear wc */ + 06771, /* DTSF ; wait */ + 05213, /* JMP .-1 */ + 05610, /* JMP I DO */ + 00600, /* MVB, 0600 */ + 07577, /* K7577, 7757 */ + 07755, /* CA, 7755 */ + 07754, /* WC, 7754 */ + 00220 /* RF, 0220 */ + }; + +t_stat dt_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; + +if (unitno) return SCPE_ARG; /* only unit 0 */ +if (dt_dib.dev != DEV_DTA) return STOP_NOTSTD; /* only std devno */ +dt_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 +*/ + +t_stat dt_attach (UNIT *uptr, char *cptr) +{ +uint32 pdp18b[D18_NBSIZE]; +uint16 pdp11b[D18_NBSIZE], *fbuf; +int32 i, k; +int32 u = uptr - dt_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 (uint16)); +if (uptr->filebuf == NULL) { /* can't alloc? */ + detach_unit (uptr); + return SCPE_MEM; + } +fbuf = (uint16 *) uptr->filebuf; /* file buffer */ +printf ("%s%d: ", sim_dname (&dt_dev), u); +if (uptr->flags & UNIT_8FMT) printf ("12b format"); +else if (uptr->flags & UNIT_11FMT) printf ("16b format"); +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 */ +return SCPE_OK; +} + +/* Detach routine + + Cancel in progress operation + 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 dt_detach (UNIT* uptr) +{ +uint32 pdp18b[D18_NBSIZE]; +uint16 pdp11b[D18_NBSIZE], *fbuf; +int32 i, k; +int32 u = uptr - dt_dev.units; +uint32 ba; + +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */ +if (sim_is_active (uptr)) { + sim_cancel (uptr); + if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) { + dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; + DT_UPDINT; + } + uptr->STATE = uptr->pos = 0; + } +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 (&dt_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 */ +return detach_unit (uptr); +} diff --git a/simhv36-1/PDP8/pdp8_lp.c b/simhv36-1/PDP8/pdp8_lp.c new file mode 100644 index 0000000..3479b23 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_lp.c @@ -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); +} diff --git a/simhv36-1/PDP8/pdp8_mt.c b/simhv36-1/PDP8/pdp8_mt.c new file mode 100644 index 0000000..add844a --- /dev/null +++ b/simhv36-1/PDP8/pdp8_mt.c @@ -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; +} diff --git a/simhv36-1/PDP8/pdp8_pt.c b/simhv36-1/PDP8/pdp8_pt.c new file mode 100644 index 0000000..3e23e2d --- /dev/null +++ b/simhv36-1/PDP8/pdp8_pt.c @@ -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; +} diff --git a/simhv36-1/PDP8/pdp8_rf.c b/simhv36-1/PDP8/pdp8_rf.c new file mode 100644 index 0000000..d4df799 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_rf.c @@ -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 + +#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; +} diff --git a/simhv36-1/PDP8/pdp8_rk.c b/simhv36-1/PDP8/pdp8_rk.c new file mode 100644 index 0000000..c92905d --- /dev/null +++ b/simhv36-1/PDP8/pdp8_rk.c @@ -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; +} diff --git a/simhv36-1/PDP8/pdp8_rl.c b/simhv36-1/PDP8/pdp8_rl.c new file mode 100644 index 0000000..9e72a90 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_rl.c @@ -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; +} diff --git a/simhv36-1/PDP8/pdp8_rx.c b/simhv36-1/PDP8/pdp8_rx.c new file mode 100644 index 0000000..c776ed2 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_rx.c @@ -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; +} diff --git a/simhv36-1/PDP8/pdp8_sys.c b/simhv36-1/PDP8/pdp8_sys.c new file mode 100644 index 0000000..2f1c2dc --- /dev/null +++ b/simhv36-1/PDP8/pdp8_sys.c @@ -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 + +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; +} diff --git a/simhv36-1/PDP8/pdp8_td.c b/simhv36-1/PDP8/pdp8_td.c new file mode 100644 index 0000000..ed04adc --- /dev/null +++ b/simhv36-1/PDP8/pdp8_td.c @@ -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; +} + diff --git a/simhv36-1/PDP8/pdp8_tsc.c b/simhv36-1/PDP8/pdp8_tsc.c new file mode 100644 index 0000000..12d6d05 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_tsc.c @@ -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; +} diff --git a/simhv36-1/PDP8/pdp8_tt.c b/simhv36-1/PDP8/pdp8_tt.c new file mode 100644 index 0000000..defd4e5 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_tt.c @@ -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 + +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; +} diff --git a/simhv36-1/PDP8/pdp8_ttx.c b/simhv36-1/PDP8/pdp8_ttx.c new file mode 100644 index 0000000..5bca088 --- /dev/null +++ b/simhv36-1/PDP8/pdp8_ttx.c @@ -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 + +#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; +} diff --git a/simhv36-1/build_mingw.bat b/simhv36-1/build_mingw.bat new file mode 100644 index 0000000..187cea2 --- /dev/null +++ b/simhv36-1/build_mingw.bat @@ -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 diff --git a/simhv36-1/build_mingw_ether.bat b/simhv36-1/build_mingw_ether.bat new file mode 100644 index 0000000..15c9a7c --- /dev/null +++ b/simhv36-1/build_mingw_ether.bat @@ -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 diff --git a/simhv36-1/descrip.mms b/simhv36-1/descrip.mms new file mode 100644 index 0000000..46524a4 --- /dev/null +++ b/simhv36-1/descrip.mms @@ -0,0 +1,1171 @@ +# DESCRIP.MMS +# Written By: Robert Alan Byer / byer@mail.ourservers.net +# Modified By: Mark Pizzolato / mark@infocomm.com +# Norman Lastovica / norman.lastovica@oracle.com +# +# This MMS/MMK build script is used to compile the various simulators in +# the SIMH package for OpenVMS using DEC C v6.0-001(AXP), v6.5-001(AXP), +# HP C V7.2-001 (IA64) and v6.4-005(VAX). +# +# Notes: On VAX, the PDP-10 and Eclipse simulators will not be built +# due to the fact that INT64 is required for that simulator. +# +# This build script will accept the following build options. +# +# ALL Just Build "Everything". +# ALTAIR Just Build The MITS Altair. +# ALTAIRZ80 Just Build The MITS Altair Z80. +# ECLIPSE Just Build The Data General Eclipse. +# GRI Just Build The GRI Corporation GRI-909. +# LGP Just Build The Royal-McBee LGP-30. +# H316 Just Build The Honewell 316/516. +# HP2100 Just Build The Hewlett-Packard HP-2100. +# I1401 Just Build The IBM 1401. +# I1620 Just Build The IBM 1620. +# IBM1130 Just Build The IBM 1130. +# ID16 Just Build The Interdata 16-bit CPU. +# ID32 Just Build The Interdata 32-bit CPU. +# NOVA Just Build The Data General Nova. +# PDP1 Just Build The DEC PDP-1. +# PDP4 Just Build The DEC PDP-4. +# PDP7 Just Build The DEC PDP-7. +# PDP8 Just Build The DEC PDP-8. +# PDP9 Just Build The DEC PDP-9. +# PDP10 Just Build The DEC PDP-10. +# PDP11 Just Build The DEC PDP-11. +# PDP15 Just Build The DEC PDP-15. +# S3 Just Build The IBM System 3. +# SDS Just Build The SDS 940. +# VAX Just Build The DEC VAX. +# VAX780 Just Build The DEC VAX780. +# CLEAN Will Clean Files Back To Base Kit. +# +# To build with debugging enabled (which will also enable traceback +# information) use.. +# +# MMK/MACRO=(DEBUG=1) +# +# This will produce an executable named {Simulator}-{I64|VAX|AXP}-DBG.EXE +# + +# Let's See If We Are Going To Build With DEBUG Enabled. Always compile +# /DEBUG so that the traceback and debug information is always available +# in the object files. + +CC_DEBUG = /DEB + +.IFDEF DEBUG +LINK_DEBUG = /DEBUG/TRACEBACK +CC_OPTIMIZE = /NOOPTIMIZE + +.IFDEF MMSALPHA +ALPHA_OR_IA64 = 1 +CC_FLAGS = /PREF=ALL +ARCH = AXP-DBG +CC_DEFS = _LARGEFILE +.ENDIF + +.IFDEF MMSIA64 +ALPHA_OR_IA64 = 1 +CC_FLAGS = /PREF=ALL +ARCH = I64-DBG +CC_DEFS = _LARGEFILE +.ENDIF + +.IFDEF MMSVAX +ALPHA_OR_IA64 = 0 +CC_FLAGS = $(CC_FLAGS) +ARCH = VAX-DBG +CC_DEFS = __VAX +.ENDIF + +.ELSE +LINK_DEBUG = /NODEBUG/NOTRACEBACK + +.IFDEF MMSALPHA +ALPHA_OR_IA64 = 1 +CC_OPTIMIZE = /OPT=(LEV=5)/ARCH=HOST +CC_FLAGS = /PREF=ALL +ARCH = AXP +CC_DEFS = _LARGEFILE +LINK_SECTION_BINDING = /SECTION_BINDING +.ENDIF + +.IFDEF MMSIA64 +ALPHA_OR_IA64 = 1 +CC_OPTIMIZE = /OPT=(LEV=5) +CC_FLAGS = /PREF=ALL +ARCH = I64 +CC_DEFS = _LARGEFILE +.ENDIF + +.IFDEF MMSVAX +ALPHA_OR_IA64 = 0 +CC_OPTIMIZE = /OPTIMIZE +CC_FLAGS = $(CC_FLAGS) +ARCH = VAX +CC_DEFS = __VAX +.ENDIF + +.ENDIF + +# Define Our Compiler Flags & Define The Compile Command +OUR_CC_FLAGS = $(CC_FLAGS)$(CC_DEBUG)$(CC_OPTIMIZE) \ + /NEST=PRIMARY/NAME=(AS_IS,SHORT) +CC = CC/DECC$(OUR_CC_FLAGS) + +# Define The BIN Directory Where The Executables Will Go. +# Define Our Library Directory. +# Define The platform specific Build Directory Where The Objects Will Go. +# +BIN_DIR = SYS$DISK:[.BIN] +LIB_DIR = SYS$DISK:[.LIB] +BLD_DIR = SYS$DISK:[.LIB.BLD-$(ARCH)] + +# Check To Make Sure We Have SYS$DISK:[.BIN] & SYS$DISK:[.LIB] Directory. +# +.FIRST + @ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") THEN CREATE/DIRECTORY $(BIN_DIR) + @ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) + @ IF (F$SEARCH("SYS$DISK:[.LIB]BLD-$(ARCH).DIR").EQS."") THEN CREATE/DIRECTORY $(BLD_DIR) + @ IF (F$SEARCH("$(BLD_DIR)*.*").NES."") THEN DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.*;* + @ IF "".NES."''CC'" THEN DELETE/SYMBOL/GLOBAL CC + +# Core SIMH File Definitions. +# +SIMH_DIR = SYS$DISK:[] +SIMH_LIB = $(LIB_DIR)SIMH-$(ARCH).OLB +SIMH_SOURCE = $(SIMH_DIR)SIM_CONSOLE.C,$(SIMH_DIR)SIM_SOCK.C,\ + $(SIMH_DIR)SIM_TMXR.C,$(SIMH_DIR)SIM_ETHER.C,\ + $(SIMH_DIR)SIM_TAPE.C,$(SIMH_DIR)SIM_FIO.C,\ + $(SIMH_DIR)SIM_TIMER.C + +# VMS PCAP File Definitions. +# +PCAP_DIR = SYS$DISK:[.PCAP-VMS.PCAP-VCI] +PCAP_LIB = $(LIB_DIR)PCAP-$(ARCH).OLB +PCAP_SOURCE = \ + $(PCAP_DIR)PCAPVCI.C,$(PCAP_DIR)VCMUTIL.C,\ + $(PCAP_DIR)BPF_DUMP.C,$(PCAP_DIR)BPF_FILTER.C,\ + $(PCAP_DIR)BPF_IMAGE.C,$(PCAP_DIR)ETHERENT.C,\ + $(PCAP_DIR)FAD-GIFC.C,$(PCAP_DIR)GENCODE.C,\ + $(PCAP_DIR)GRAMMAR.C,$(PCAP_DIR)INET.C,\ + $(PCAP_DIR)NAMETOADDR.C,$(PCAP_DIR)OPTIMIZE.C,\ + $(PCAP_DIR)PCAP.C,$(PCAP_DIR)SAVEFILE.C,\ + $(PCAP_DIR)SCANNER.C,$(PCAP_DIR)SNPRINTF.C,\ + $(PCAP_DIR)PCAP-VMS.C +PCAP_VCMDIR = SYS$DISK:[.PCAP-VMS.PCAPVCM] +PCAP_VCM_SOURCES = $(PCAP_VCMDIR)PCAPVCM.C,$(PCAP_VCMDIR)PCAPVCM_INIT.MAR,\ + $(PCAP_VCMDIR)VCI_JACKET.MAR,$(PCAP_VCMDIR)VCMUTIL.C +PCAP_VCI = SYS$COMMON:[SYS$LDR]PCAPVCM.EXE + +# PCAP is not available on OpenVMS VAX or IA64 right now +# +.IFDEF MMSALPHA +PCAP_EXECLET = $(PCAP_VCI) +PCAP_INC = ,$(PCAP_DIR) +PCAP_LIBD = $(PCAP_LIB) +PCAP_LIBR = ,$(PCAP_LIB)/LIB/SYSEXE +PCAP_DEFS = ,"USE_NETWORK=1" +PCAP_SIMH_INC = /INCL=($(PCAP_DIR)) +.ENDIF + +# MITS Altair Simulator Definitions. +# +ALTAIR_DIR = SYS$DISK:[.ALTAIR] +ALTAIR_LIB = $(LIB_DIR)ALTAIR-$(ARCH).OLB +ALTAIR_SOURCE = $(ALTAIR_DIR)ALTAIR_SIO.C,$(ALTAIR_DIR)ALTAIR_CPU.C,\ + $(ALTAIR_DIR)ALTAIR_DSK.C,$(ALTAIR_DIR)ALTAIR_SYS.C +ALTAIR_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIR_DIR))/DEF=($(CC_DEFS)) + +# +# MITS Altair Z80 Simulator Definitions. +# +ALTAIRZ80_DIR = SYS$DISK:[.ALTAIRZ80] +ALTAIRZ80_LIB = $(LIB_DIR)ALTAIRZ80-$(ARCH).OLB +ALTAIRZ80_SOURCE = $(ALTAIRZ80_DIR)ALTAIRZ80_CPU.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_DSK.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_SIO.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_SYS.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.C +ALTAIRZ80_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIRZ80_DIR))/DEF=($(CC_DEFS)) + +# +# Data General Nova Simulator Definitions. +# +NOVA_DIR = SYS$DISK:[.NOVA] +NOVA_LIB = $(LIB_DIR)NOVA-$(ARCH).OLB +NOVA_SOURCE = $(NOVA_DIR)NOVA_SYS.C,$(NOVA_DIR)NOVA_CPU.C,\ + $(NOVA_DIR)NOVA_DKP.C,$(NOVA_DIR)NOVA_DSK.C,\ + $(NOVA_DIR)NOVA_LP.C,$(NOVA_DIR)NOVA_MTA.C,\ + $(NOVA_DIR)NOVA_PLT.C,$(NOVA_DIR)NOVA_PT.C,\ + $(NOVA_DIR)NOVA_CLK.C,$(NOVA_DIR)NOVA_TT.C,\ + $(NOVA_DIR)NOVA_TT1.C,$(NOVA_DIR)NOVA_QTY.C +NOVA_OPTIONS = /INCL=($(SIMH_DIR),$(NOVA_DIR))/DEF=($(CC_DEFS)) + +# +# Data General Eclipse Simulator Definitions. +# +ECLIPSE_LIB = $(LIB_DIR)ECLIPSE-$(ARCH).OLB +ECLIPSE_SOURCE = $(NOVA_DIR)ECLIPSE_CPU.C,$(NOVA_DIR)ECLIPSE_TT.C,\ + $(NOVA_DIR)NOVA_SYS.C,$(NOVA_DIR)NOVA_DKP.C,\ + $(NOVA_DIR)NOVA_DSK.C,$(NOVA_DIR)NOVA_LP.C,\ + $(NOVA_DIR)NOVA_MTA.C,$(NOVA_DIR)NOVA_PLT.C,\ + $(NOVA_DIR)NOVA_PT.C,$(NOVA_DIR)NOVA_CLK.C,\ + $(NOVA_DIR)NOVA_TT1.C,$(NOVA_DIR)NOVA_QTY.C +ECLIPSE_OPTIONS = /INCL=($(SIMH_DIR),$(NOVA_DIR))\ + /DEF=($(CC_DEFS),"USE_INT64=1","ECLIPSE=1") + +# +# GRI Corporation GRI-909 Simulator Definitions. +# +GRI_DIR = SYS$DISK:[.GRI] +GRI_LIB = $(LIB_DIR)GRI-$(ARCH).OLB +GRI_SOURCE = $(GRI_DIR)GRI_CPU.C,$(GRI_DIR)GRI_STDDEV.C,$(GRI_DIR)GRI_SYS.C +GRI_OPTIONS = /INCL=($(SIMH_DIR),$(GRI_DIR))/DEF=($(CC_DEFS)) + +# +# Royal-McBee LGP-30 Simulator Definitions. +# +LGP_DIR = SYS$DISK:[.LGP] +LGP_LIB = $(LIB_DIR)LGP-$(ARCH).OLB +LGP_SOURCE = $(LGP_DIR)LGP_CPU.C,$(LGP_DIR)LGP_STDDEV.C,$(LGP_DIR)LGP_SYS.C +LGP_OPTIONS = /INCL=($(SIMH_DIR),$(LGP_DIR))/DEF=($(CC_DEFS)) + +# +# Honeywell 316/516 Simulator Definitions. +# +H316_DIR = SYS$DISK:[.H316] +H316_LIB = $(LIB_DIR)H316-$(ARCH).OLB +H316_SOURCE = $(H316_DIR)H316_STDDEV.C,$(H316_DIR)H316_LP.C,\ + $(H316_DIR)H316_CPU.C,$(H316_DIR)H316_SYS.C,\ + $(H316_DIR)H316_FHD.C,$(H316_DIR)H316_MT.C,\ + $(H316_DIR)H316_DP.C +H316_OPTIONS = /INCL=($(SIMH_DIR),$(H316_DIR))/DEF=($(CC_DEFS)) + +# +# Hewlett-Packard HP-2100 Simulator Definitions. +# +HP2100_DIR = SYS$DISK:[.HP2100] +HP2100_LIB = $(LIB_DIR)HP2100-$(ARCH).OLB +HP2100_SOURCE = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\ + $(HP2100_DIR)HP2100_DQ.C,$(HP2100_DIR)HP2100_DR.C,\ + $(HP2100_DIR)HP2100_LPS.C,$(HP2100_DIR)HP2100_MS.C,\ + $(HP2100_DIR)HP2100_MT.C,$(HP2100_DIR)HP2100_MUX.C,\ + $(HP2100_DIR)HP2100_CPU.C,$(HP2100_DIR)HP2100_FP.C,\ + $(HP2100_DIR)HP2100_SYS.C,$(HP2100_DIR)HP2100_LPT.C,\ + $(HP2100_DIR)HP2100_IPL.C,$(HP2100_DIR)HP2100_CPU1.C,\ + $(HP2100_DIR)HP2100_FP1.C +.IF ALPHA_OR_IA64 +HP2100_OPTIONS = /INCL=($(SIMH_DIR),$(HP2100_DIR))\ + /DEF=($(CC_DEFS),"HAVE_INT64=1") +.ELSE +HP2100_OPTIONS = /INCL=($(SIMH_DIR),$(HP2100_DIR))/DEF=($(CC_DEFS)) +.ENDIF + +# +# Interdata 16-bit CPU. +# +ID16_DIR = SYS$DISK:[.INTERDATA] +ID16_LIB = $(LIB_DIR)ID16-$(ARCH).OLB +ID16_SOURCE = $(ID16_DIR)ID16_CPU.C,$(ID16_DIR)ID16_SYS.C,$(ID16_DIR)ID_DP.C,\ + $(ID16_DIR)ID_FD.C,$(ID16_DIR)ID_FP.C,$(ID16_DIR)ID_IDC.C,\ + $(ID16_DIR)ID_IO.C,$(ID16_DIR)ID_LP.C,$(ID16_DIR)ID_MT.C,\ + $(ID16_DIR)ID_PAS.C,$(ID16_DIR)ID_PT.C,$(ID16_DIR)ID_TT.C,\ + $(ID16_DIR)ID_UVC.C,$(ID16_DIR)ID16_DBOOT.C,$(ID16_DIR)ID_TTP.C +ID16_OPTIONS = /INCL=($(SIMH_DIR),$(ID16_DIR))/DEF=($(CC_DEFS)) + +# +# Interdata 32-bit CPU. +# +ID32_DIR = SYS$DISK:[.INTERDATA] +ID32_LIB = $(LIB_DIR)ID32-$(ARCH).OLB +ID32_SOURCE = $(ID32_DIR)ID32_CPU.C,$(ID32_DIR)ID32_SYS.C,$(ID32_DIR)ID_DP.C,\ + $(ID32_DIR)ID_FD.C,$(ID32_DIR)ID_FP.C,$(ID32_DIR)ID_IDC.C,\ + $(ID32_DIR)ID_IO.C,$(ID32_DIR)ID_LP.C,$(ID32_DIR)ID_MT.C,\ + $(ID32_DIR)ID_PAS.C,$(ID32_DIR)ID_PT.C,$(ID32_DIR)ID_TT.C,\ + $(ID32_DIR)ID_UVC.C,$(ID32_DIR)ID32_DBOOT.C,$(ID32_DIR)ID_TTP.C +ID32_OPTIONS = /INCL=($(SIMH_DIR),$(ID32_DIR))/DEF=($(CC_DEFS)) + +# +# IBM 1130 Simulator Definitions. +# +IBM1130_DIR = SYS$DISK:[.IBM1130] +IBM1130_LIB = $(LIB_DIR)IBM1130-$(ARCH).OLB +IBM1130_SOURCE = $(IBM1130_DIR)IBM1130_CPU.C,$(IBM1130_DIR)IBM1130_CR.C,\ + $(IBM1130_DIR)IBM1130_DISK.C,$(IBM1130_DIR)IBM1130_STDDEV.C,\ + $(IBM1130_DIR)IBM1130_SYS.C,$(IBM1130_DIR)IBM1130_GDU.C,\ + $(IBM1130_DIR)IBM1130_GUI.C,$(IBM1130_DIR)IBM1130_PRT.C,\ + $(IBM1130_DIR)IBM1130_FMT.C,$(IBM1130_DIR)IBM1130_PTRP.C +IBM1130_OPTIONS = /INCL=($(SIMH_DIR),$(IBM1130_DIR))/DEF=($(CC_DEFS)) + +# +# IBM 1401 Simulator Definitions. +# +I1401_DIR = SYS$DISK:[.I1401] +I1401_LIB = $(LIB_DIR)I1401-$(ARCH).OLB +I1401_SOURCE = $(I1401_DIR)I1401_LP.C,$(I1401_DIR)I1401_CPU.C,\ + $(I1401_DIR)I1401_IQ.C,$(I1401_DIR)I1401_CD.C,\ + $(I1401_DIR)I1401_MT.C,$(I1401_DIR)I1401_DP.C,\ + $(I1401_DIR)I1401_SYS.C +I1401_OPTIONS = /INCL=($(SIMH_DIR),$(I1401_DIR))/DEF=($(CC_DEFS)) + + +# +# IBM 1620 Simulators Definitions. +# +I1620_DIR = SYS$DISK:[.I1620] +I1620_LIB = $(LIB_DIR)I1620-$(ARCH).OLB +I1620_SOURCE = $(I1620_DIR)I1620_CD.C,$(I1620_DIR)I1620_DP.C,\ + $(I1620_DIR)I1620_PT.C,$(I1620_DIR)I1620_TTY.C,\ + $(I1620_DIR)I1620_CPU.C,$(I1620_DIR)I1620_LP.C,\ + $(I1620_DIR)I1620_FP.C,$(I1620_DIR)I1620_SYS.C +I1620_OPTIONS = /INCL=($(SIMH_DIR),$(I1620_DIR))/DEF=($(CC_DEFS)) + +# +# PDP-1 Simulator Definitions. +# +PDP1_DIR = SYS$DISK:[.PDP1] +PDP1_LIB = $(LIB_DIR)PDP1-$(ARCH).OLB +PDP1_SOURCE = $(PDP1_DIR)PDP1_LP.C,$(PDP1_DIR)PDP1_CPU.C,\ + $(PDP1_DIR)PDP1_STDDEV.C,$(PDP1_DIR)PDP1_SYS.C,\ + $(PDP1_DIR)PDP1_DT.C,$(PDP1_DIR)PDP1_DRM.C +PDP1_OPTIONS = /INCL=($(SIMH_DIR),$(PDP1_DIR))/DEF=($(CC_DEFS)) + +# +# Digital Equipment PDP-8 Simulator Definitions. +# +PDP8_DIR = SYS$DISK:[.PDP8] +PDP8_LIB = $(LIB_DIR)PDP8-$(ARCH).OLB +PDP8_SOURCE = $(PDP8_DIR)PDP8_CPU.C,$(PDP8_DIR)PDP8_CLK.C,\ + $(PDP8_DIR)PDP8_DF.C,$(PDP8_DIR)PDP8_DT.C,\ + $(PDP8_DIR)PDP8_LP.C,$(PDP8_DIR)PDP8_MT.C,\ + $(PDP8_DIR)PDP8_PT.C,$(PDP8_DIR)PDP8_RF.C,\ + $(PDP8_DIR)PDP8_RK.C,$(PDP8_DIR)PDP8_RX.C,\ + $(PDP8_DIR)PDP8_SYS.C,$(PDP8_DIR)PDP8_TT.C,\ + $(PDP8_DIR)PDP8_TTX.C,$(PDP8_DIR)PDP8_RL.C,\ + $(PDP8_DIR)PDP8_TSC.C,$(PDP8_DIR)PDP8_TD.C +PDP8_OPTIONS = /INCL=($(SIMH_DIR),$(PDP8_DIR))/DEF=($(CC_DEFS)) + +# +# Digital Equipment PDP-4, PDP-7, PDP-9 And PDP-15 Simulator Definitions. +# +PDP18B_DIR = SYS$DISK:[.PDP18B] +PDP4_LIB = $(LIB_DIR)PDP4-$(ARCH).OLB +PDP7_LIB = $(LIB_DIR)PDP7-$(ARCH).OLB +PDP9_LIB = $(LIB_DIR)PDP9-$(ARCH).OLB +PDP15_LIB = $(LIB_DIR)PDP15-$(ARCH).OLB +PDP18B_SOURCE = $(PDP18B_DIR)PDP18B_DT.C,$(PDP18B_DIR)PDP18B_DRM.C,\ + $(PDP18B_DIR)PDP18B_CPU.C,$(PDP18B_DIR)PDP18B_LP.C,\ + $(PDP18B_DIR)PDP18B_MT.C,$(PDP18B_DIR)PDP18B_RF.C,\ + $(PDP18B_DIR)PDP18B_RP.C,$(PDP18B_DIR)PDP18B_STDDEV.C,\ + $(PDP18B_DIR)PDP18B_SYS.C,$(PDP18B_DIR)PDP18B_TT1.C,\ + $(PDP18B_DIR)PDP18B_RB.C,$(PDP18B_DIR)PDP18B_FPP.C +PDP4_OPTIONS = /INCL=($(SIMH_DIR),$(PDP18B_DIR))/DEF=($(CC_DEFS),"PDP4=1") +PDP7_OPTIONS = /INCL=($(SIMH_DIR),$(PDP18B_DIR))/DEF=($(CC_DEFS),"PDP7=1") +PDP9_OPTIONS = /INCL=($(SIMH_DIR),$(PDP18B_DIR))/DEF=($(CC_DEFS),"PDP9=1") +PDP15_OPTIONS = /INCL=($(SIMH_DIR),$(PDP18B_DIR))/DEF=($(CC_DEFS),"PDP15=1") + +# +# Digital Equipment PDP-11 Simulator Definitions. +# +PDP11_DIR = SYS$DISK:[.PDP11] +PDP11_LIB1 = $(LIB_DIR)PDP11L1-$(ARCH).OLB +PDP11_SOURCE1 = $(PDP11_DIR)PDP11_FP.C,$(PDP11_DIR)PDP11_CPU.C,\ + $(PDP11_DIR)PDP11_DZ.C,$(PDP11_DIR)PDP11_CIS.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_RK.C,\ + $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RP.C,\ + $(PDP11_DIR)PDP11_RX.C,$(PDP11_DIR)PDP11_STDDEV.C,\ + $(PDP11_DIR)PDP11_SYS.C,$(PDP11_DIR)PDP11_TC.C, \ + $(PDP11_DIR)PDP11_CPUMOD.C,$(PDP11_DIR)PDP11_CR.C +PDP11_LIB2 = $(LIB_DIR)PDP11L2-$(ARCH).OLB +PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ + $(PDP11_DIR)PDP11_IO.C,$(PDP11_DIR)PDP11_RQ.C,\ + $(PDP11_DIR)PDP11_TQ.C,$(PDP11_DIR)PDP11_PCLK.C,\ + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_PT.C,\ + $(PDP11_DIR)PDP11_HK.C,$(PDP11_DIR)PDP11_XQ.C,\ + $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_RH.C,\ + $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_TU.C,\ + $(PDP11_DIR)PDP11_DL.C,$(PDP11_DIR)PDP11_RF.C +PDP11_OPTIONS = /INCL=($(SIMH_DIR),$(PDP11_DIR)$(PCAP_INC))\ + /DEF=($(CC_DEFS),"VM_PDP11=1"$(PCAP_DEFS)) + +# +# Digital Equipment PDP-10 Simulator Definitions. +# +PDP10_DIR = SYS$DISK:[.PDP10] +PDP10_LIB = $(LIB_DIR)PDP10-$(ARCH).OLB +PDP10_SOURCE = $(PDP10_DIR)PDP10_FE.C,\ + $(PDP10_DIR)PDP10_CPU.C,$(PDP10_DIR)PDP10_KSIO.C,\ + $(PDP10_DIR)PDP10_LP20.C,$(PDP10_DIR)PDP10_MDFP.C,\ + $(PDP10_DIR)PDP10_PAG.C,$(PDP10_DIR)PDP10_XTND.C,\ + $(PDP10_DIR)PDP10_RP.C,$(PDP10_DIR)PDP10_SYS.C,\ + $(PDP10_DIR)PDP10_TIM.C,$(PDP10_DIR)PDP10_TU.C,\ + $(PDP11_DIR)PDP11_PT.C,$(PDP11_DIR)PDP11_DZ.C,\ + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_XU.C +PDP10_OPTIONS = /INCL=($(SIMH_DIR),$(PDP10_DIR),$(PDP11_DIR))\ + /DEF=($(CC_DEFS),"USE_INT64=1","VM_PDP10=1"$(PCAP_DEFS)) + +# +# IBM System 3 Simulator Definitions. +# +S3_DIR = SYS$DISK:[.S3] +S3_LIB = $(LIB_DIR)S3-$(ARCH).OLB +S3_SOURCE = $(S3_DIR)S3_CD.C,$(S3_DIR)S3_CPU.C,$(S3_DIR)S3_DISK.C,\ + $(S3_DIR)S3_LP.C,$(S3_DIR)S3_PKB.C,$(S3_DIR)S3_SYS.C +S3_OPTIONS = /INCL=($(SIMH_DIR),$(S3_DIR))/DEF=($(CC_DEFS)) + +# +# SDS 940 +# +SDS_DIR = SYS$DISK:[.SDS] +SDS_LIB = $(LIB_DIR)SDS-$(ARCH).OLB +SDS_SOURCE = $(SDS_DIR)SDS_CPU.C,$(SDS_DIR)SDS_DRM.C,$(SDS_DIR)SDS_DSK.C,\ + $(SDS_DIR)SDS_IO.C,$(SDS_DIR)SDS_LP.C,$(SDS_DIR)SDS_MT.C,\ + $(SDS_DIR)SDS_MUX.C,$(SDS_DIR)SDS_RAD.C,$(SDS_DIR)SDS_STDDEV.C,\ + $(SDS_DIR)SDS_SYS.C +SDS_OPTIONS = /INCL=($(SIMH_DIR),$(SDS_DIR))/DEF=($(CC_DEFS)) + +# +# Digital Equipment VAX Simulator Definitions. +# +VAX_DIR = SYS$DISK:[.VAX] +VAX_LIB = $(LIB_DIR)VAX-$(ARCH).OLB +VAX_SOURCE = $(VAX_DIR)VAX_CIS.C,$(VAX_DIR)VAX_CMODE.C,\ + $(VAX_DIR)VAX_CPU.C,$(VAX_DIR)VAX_CPU1.C,\ + $(VAX_DIR)VAX_FPA.C,$(VAX_DIR)VAX_MMU.C,\ + $(VAX_DIR)VAX_OCTA.C,$(VAX_DIR)VAX_SYS.C,\ + $(VAX_DIR)VAX_SYSCM.C,$(VAX_DIR)VAX_SYSDEV.C,\ + $(VAX_DIR)VAX_SYSLIST.C,$(VAX_DIR)VAX_IO.C,\ + $(VAX_DIR)VAX_STDDEV.C,\ + $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ + $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_XQ.C,$(PDP11_DIR)PDP11_CR.C,\ + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_VH.C +VAX_OPTIONS = /INCL=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR)$(PCAP_INC))\ + /DEF=($(CC_DEFS),"VM_VAX=1"$(PCAP_DEFS)) + +# Digital Equipment VAX780 Simulator Definitions. +# +VAX780_DIR = SYS$DISK:[.VAX] +VAX780_LIB = $(LIB_DIR)VAX780-$(ARCH).OLB +VAX780_SOURCE = $(VAX780_DIR)VAX_CIS.C,$(VAX780_DIR)VAX_CMODE.C,\ + $(VAX780_DIR)VAX_CPU.C,$(VAX780_DIR)VAX_CPU1.C,\ + $(VAX780_DIR)VAX_FPA.C,$(VAX780_DIR)VAX_MMU.C,\ + $(VAX780_DIR)VAX_OCTA.C,$(VAX780_DIR)VAX_SYS.C,\ + $(VAX780_DIR)VAX_SYSCM.C,\ + $(VAX780_DIR)VAX780_MBA.C,$(VAX780_DIR)VAX780_MEM.C,\ + $(VAX780_DIR)VAX780_SBI.C,$(VAX780_DIR)VAX780_STDDEV.C,\ + $(VAX780_DIR)VAX780_SYSLIST.C,$(VAX780_DIR)VAX780_UBA.C,\ + $(PDP11_DIR)PDP11_DZ.C,$(PDP11_DIR)PDP11_HK.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_RL.C,\ + $(PDP11_DIR)PDP11_RP.C,$(PDP11_DIR)PDP11_RQ.C,\ + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_TU.C,\ + $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_CR.C +VAX780_OPTIONS = /INCL=($(SIMH_DIR),$(VAX780_DIR),$(PDP11_DIR)$(PCAP_INC))\ + /DEF=($(CC_DEFS),"VM_VAX=1"$(PCAP_DEFS),"VAX_780=1") + +# IBM 7094 Simulator Definitions. +# +I7094_DIR = SYS$DISK:[.I7094] +I7094_LIB = $(LIB_DIR)I7094-$(ARCH).OLB +I7094_SOURCE = $(I7094_DIR)I7094_CPU.C,$(I7094_DIR)I7094_CPU1.C,\ + $(I7094_DIR)I7094_IO.C,$(I7094_DIR)I7094_SYS.C,\ + $(I7094_DIR)I7094_CD.C,$(I7094_DIR)I7094_COM.C,\ + $(I7094_DIR)I7094_DSK.C,$(I7094_DIR)I7094_DRM.C,\ + $(I7094_DIR)I7094_MT.C,\ + $(I7094_DIR)I7094_CLK.C,$(I7094_DIR)I7094_LP.C +I7094_OPTIONS = /INCL=($(SIMH_DIR),$(I7094_DIR))/DEF=($(CC_DEFS)) + +# If we're not a VAX, Build Everything +# +.IF ALPHA_OR_IA64 +ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 \ + ID32 NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 VAX VAX780 SDS \ + I7094 +.ELSE +# +# Else We Are On VAX And Build Everything EXCEPT the 64b simulators +# +ALL : ALTAIR ALTAIRZ80 GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ + NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 VAX VAX780 SDS +.ENDIF + +CLEAN : + $! + $! Clean out all targets and building Remnants + $! + $ IF (F$SEARCH("$(BIN_DIR)*.EXE;*").NES."") THEN - + DELETE/NOLOG/NOCONFIRM $(BIN_DIR)*.EXE;* + $ IF (F$SEARCH("$(LIB_DIR)*.OLB;*").NES."") THEN - + DELETE/NOLOG/NOCONFIRM $(LIB_DIR)*.OLB;* + $ IF (F$SEARCH("SYS$DISK:[...]*.OBJ;*").NES."") THEN - + DELETE/NOLOG/NOCONFIRM SYS$DISK:[...]*.OBJ;* + $ IF (F$SEARCH("SYS$DISK:[...]*.LIS;*").NES."") THEN - + DELETE/NOLOG/NOCONFIRM SYS$DISK:[...]*.LIS;* + $ IF (F$SEARCH("SYS$DISK:[...]*.MAP;*").NES."") THEN - + DELETE/NOLOG/NOCONFIRM SYS$DISK:[...]*.MAP;* + +# +# Build The Libraries. +# +$(SIMH_LIB) : $(SIMH_SOURCE) + $! + $! Building The $(SIMH_LIB) Library. + $! + $ $(CC)/DEF=($(CC_DEFS)$(PCAP_DEFS))$(PCAP_SIMH_INC) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(ALTAIR_LIB) : $(ALTAIR_SOURCE) + $! + $! Building The $(ALTAIR_LIB) Library. + $! + $ $(CC)$(ALTAIR_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(ALTAIRZ80_LIB) : $(ALTAIRZ80_SOURCE) + $! + $! Building The $(ALTAIRZ80_LIB) Library. + $! + $ $(CC)$(ALTAIRZ80_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +# +# If Not On VAX, Build The Eclipse Library. +# +.IF ALPHA_OR_IA64 +$(ECLIPSE_LIB) : $(ECLIPSE_SOURCE) + $! + $! Building The $(ECLIPSE_LIB) Library. + $! + $ $(CC)$(ECLIPSE_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +.ELSE +# +# We Are On VAX And Due To The Use of INT64 We Can't Build It. +# +$(ECLIPSE_LIB) : + $! + $! Due To The Use Of INT64 We Can't Build The + $! $(LIB_DIR)ECLIPSE-$(ARCH).OLB Library On VAX. + $! +.ENDIF + +$(GRI_LIB) : $(GRI_SOURCE) + $! + $! Building The $(GRI_LIB) Library. + $! + $ $(CC)$(GRI_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(LGP_LIB) : $(LGP_SOURCE) + $! + $! Building The $(LGP_LIB) Library. + $! + $ $(CC)$(LGP_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(H316_LIB) : $(H316_SOURCE) + $! + $! Building The $(H316_LIB) Library. + $! + $ $(CC)$(H316_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(HP2100_LIB) : $(HP2100_SOURCE) + $! + $! Building The $(HP2100_LIB) Library. + $! + $ $(CC)$(HP2100_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(I1401_LIB) : $(I1401_SOURCE) + $! + $! Building The $(I1401_LIB) Library. + $! + $ $(CC)$(I1401_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(I1620_LIB) : $(I1620_SOURCE) + $! + $! Building The $(I1620_LIB) Library. + $! + $ $(CC)$(I1620_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(IBM1130_LIB) : $(IBM1130_SOURCE) + $! + $! Building The $(IBM1130_LIB) Library. + $! + $ $(CC)$(IBM1130_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(ID16_LIB) : $(ID16_SOURCE) + $! + $! Building The $(ID16_LIB) Library. + $! + $ $(CC)$(ID16_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(ID32_LIB) : $(ID32_SOURCE) + $! + $! Building The $(ID32_LIB) Library. + $! + $ $(CC)$(ID32_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(NOVA_LIB) : $(NOVA_SOURCE) + $! + $! Building The $(NOVA_LIB) Library. + $! + $ $(CC)$(NOVA_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(PDP1_LIB) : $(PDP1_SOURCE) + $! + $! Building The $(PDP1_LIB) Library. + $! + $ $(CC)$(PDP1_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(PDP4_LIB) : $(PDP18B_SOURCE) + $! + $! Building The $(PDP4_LIB) Library. + $! + $ $(CC)$(PDP4_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(PDP7_LIB) : $(PDP18B_SOURCE) + $! + $! Building The $(PDP7_LIB) Library. + $! + $ $(CC)$(PDP7_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(PDP8_LIB) : $(PDP8_SOURCE) + $! + $! Building The $(PDP8_LIB) Library. + $! + $ $(CC)$(PDP8_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(PDP9_LIB) : $(PDP18B_SOURCE) + $! + $! Building The $(PDP9_LIB) Library. + $! + $ $(CC)$(PDP9_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +# +# If Not On VAX, Build The PDP-10 Library. +# +.IF ALPHA_OR_IA64 +$(PDP10_LIB) : $(PDP10_SOURCE) + $! + $! Building The $(PDP10_LIB) Library. + $! + $ $(CC)$(PDP10_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +.ELSE +# +# We Are On VAX And Due To The Use of INT64 We Can't Build It. +# +$(PDP10_LIB) : + $! Due To The Use Of INT64 We Can't Build The + $! $(LIB_DIR)PDP10-$(ARCH).OLB Library On VAX. +.ENDIF + +$(PDP11_LIB1) : $(PDP11_SOURCE1) + $! + $! Building The $(PDP11_LIB1) Library. + $! + $(CC)$(PDP11_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(PDP11_LIB2) : $(PDP11_SOURCE2) + $! + $! Building The $(PDP11_LIB2) Library. + $! + $(CC)$(PDP11_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(PDP15_LIB) : $(PDP18B_SOURCE) + $! + $! Building The $(PDP15_LIB) Library. + $! + $ $(CC)$(PDP15_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(S3_LIB) : $(S3_SOURCE) + $! + $! Building The $(S3_LIB) Library. + $! + $ $(CC)$(S3_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(SDS_LIB) : $(SDS_SOURCE) + $! + $! Building The $(SDS_LIB) Library. + $! + $ $(CC)$(SDS_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(VAX_LIB) : $(VAX_SOURCE) + $! + $! Building The $(VAX_LIB) Library. + $! + $ $(CC)$(VAX_OPTIONS)/OBJ=$(VAX_DIR) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(VAX780_LIB) : $(VAX780_SOURCE) + $! + $! Building The $(VAX_780LIB) Library. + $! + $ $(CC)$(VAX780_OPTIONS)/OBJ=$(VAX780_DIR) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(PCAP_LIB) : $(PCAP_SOURCE) + $! + $! Building The $(PCAP_LIB) Library. + $! + $ SET DEFAULT $(PCAP_DIR) + $ @VMS_PCAP $(DEBUG) + $ SET DEFAULT [--] + $ IF (F$SEARCH("$(PCAP_LIB)").NES."") THEN - + DELETE $(PCAP_LIB); + $ COPY $(PCAP_DIR)PCAP.OLB $(PCAP_LIB) + $ DELETE/NOLOG/NOCONFIRM $(PCAP_DIR)*.OBJ;*,$(PCAP_DIR)*.OLB;* + +# +# If Not On VAX, Build The IBM 7094 Library. +# +.IF ALPHA_OR_IA64 +$(I7094_LIB) : $(I7094_SOURCE) + $! + $! Building The $(I7094_LIB) Library. + $! + $ $(CC)$(I7094_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +.ELSE +# +# We Are On VAX And Due To The Use of INT64 We Can't Build It. +# +$(I7094_LIB) : + $! Due To The Use Of INT64 We Can't Build The + $! $(LIB_DIR)I7094-$(ARCH).OLB Library On VAX. +.ENDIF + +# +# Individual Simulator Builds. +# +ALTAIR : $(SIMH_LIB) $(ALTAIR_LIB) + $! + $! Building The $(BIN_DIR)ALTAIR-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ALTAIR_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ALTAIR-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(ALTAIR_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB) + $! + $! Building The $(BIN_DIR)ALTAIRZ80-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ALTAIRZ80_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ALTAIRZ80-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(ALTAIRZ80_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +# +# If Not On VAX, Build The PDP-10 Simulator. +# +.IF ALPHA_OR_IA64 +ECLIPSE : $(SIMH_LIB) $(ECLIPSE_LIB) + $! + $! Building The $(BIN_DIR)ECLIPSE-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ECLIPSE_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ECLIPSE-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(ECLIPSE_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +.ELSE +# +# Else We Are On VAX And Tell The User We Can't Build On VAX +# Due To The Use Of INT64. +# +ECLIPSE : + $! Sorry, Can't Build $(BIN_DIR)ECLIPSE-$(ARCH).EXE Simulator + $! Because It Requires The Use Of INT64. +.ENDIF + +GRI : $(SIMH_LIB) $(GRI_LIB) + $! + $! Building The $(BIN_DIR)GRI-$(ARCH).EXE Simulator. + $! + $ $(CC)$(GRI_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)GRI-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(GRI_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +LGP : $(SIMH_LIB) $(LGP_LIB) + $! + $! Building The $(BIN_DIR)LGP-$(ARCH).EXE Simulator. + $! + $ $(CC)$(LGP_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)LGP-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(LGP_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +H316 : $(SIMH_LIB) $(H316_LIB) + $! + $! Building The $(BIN_DIR)H316-$(ARCH).EXE Simulator. + $! + $ $(CC)$(H316_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)H316-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(H316_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +HP2100 : $(SIMH_LIB) $(HP2100_LIB) + $! + $! Building The $(BIN_DIR)HP2100-$(ARCH).EXE Simulator. + $! + $ $(CC)$(HP2100_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)HP2100-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(HP2100_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +I1401 : $(SIMH_LIB) $(I1401_LIB) + $! + $! Building The $(BIN_DIR)I1401-$(ARCH).EXE Simulator. + $! + $ $(CC)$(I1401_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)I1401-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(I1401_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +I1620 : $(SIMH_LIB) $(I1620_LIB) + $! + $! Building The $(BIN_DIR)I1620-$(ARCH).EXE Simulator. + $! + $ $(CC)$(I1620_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)I1620-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(I1620_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +IBM1130 : $(SIMH_LIB) $(IBM1130_LIB) + $! + $! Building The $(BIN_DIR)IBM1130-$(ARCH).EXE Simulator. + $! + $ $(CC)$(IBM1130_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)IBM1130-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(IBM1130_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +ID16 : $(SIMH_LIB) $(ID16_LIB) + $! + $! Building The $(BIN_DIR)ID16-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ID16_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ID16-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(ID16_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +ID32 : $(SIMH_LIB) $(ID32_LIB) + $! + $! Building The $(BIN_DIR)ID32-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ID32_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ID32-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(ID32_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +NOVA : $(SIMH_LIB) $(NOVA_LIB) + $! + $! Building The $(BIN_DIR)NOVA-$(ARCH).EXE Simulator. + $! + $ $(CC)$(NOVA_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)NOVA-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(NOVA_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +PDP1 : $(SIMH_LIB) $(PDP1_LIB) + $! + $! Building The $(BIN_DIR)PDP1-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP1_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP1-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(PDP1_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +PDP4 : $(SIMH_LIB) $(PDP4_LIB) + $! + $! Building The $(BIN_DIR)PDP4-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP4_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP4-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(PDP4_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +PDP7 : $(SIMH_LIB) $(PDP7_LIB) + $! + $! Building The $(BIN_DIR)PDP7-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP7_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP7-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(PDP7_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +PDP8 : $(SIMH_LIB) $(PDP8_LIB) + $! + $! Building The $(BIN_DIR)PDP8-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP8_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP8-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(PDP8_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +PDP9 : $(SIMH_LIB) $(PDP9_LIB) + $! + $! Building The $(BIN_DIR)PDP9-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP9_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP9-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(PDP9_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +# +# If Not On VAX, Build The PDP-10 Simulator. +# +.IF ALPHA_OR_IA64 +PDP10 : $(SIMH_LIB) $(PCAP_LIBD) $(PDP10_LIB) $(PCAP_EXECLET) + $! + $! Building The $(BIN_DIR)PDP10-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP10_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP10-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(PDP10_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY$(PCAP_LIBR) + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +.ELSE +# +# Else We Are On VAX And Tell The User We Can't Build On VAX +# Due To The Use Of INT64. +# +PDP10 : + $! Sorry, Can't Build $(BIN_DIR)PDP10-$(ARCH).EXE Simulator + $! Because It Requires The Use Of INT64. +.ENDIF + +PDP11 : $(SIMH_LIB) $(PCAP_LIBD) $(PDP11_LIB1) $(PDP11_LIB2) $(PCAP_EXECLET) + $! + $! Building The $(BIN_DIR)PDP11-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP11_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP11-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(PDP11_LIB1)/LIBRARY,$(PDP11_LIB2)/LIBRARY,$(SIMH_LIB)/LIBRARY$(PCAP_LIBR) + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +PDP15 : $(SIMH_LIB) $(PDP15_LIB) + $! + $! Building The $(BIN_DIR)PDP15-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP15_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP15-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(PDP15_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +S3 : $(SIMH_LIB) $(S3_LIB) + $! + $! Building The $(BIN_DIR)S3-$(ARCH).EXE Simulator. + $! + $ $(CC)$(S3_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)S3-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(S3_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +SDS : $(SIMH_LIB) $(SDS_LIB) + $! + $! Building The $(BIN_DIR)SDS-$(ARCH).EXE Simulator. + $! + $ $(CC)$(SDS_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)SDS-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(SDS_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +VAX : $(SIMH_LIB) $(PCAP_LIBD) $(VAX_LIB) $(PCAP_EXECLET) + $! + $! Building The $(BIN_DIR)VAX-$(ARCH).EXE Simulator. + $! + $ $(CC)$(VAX_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)$(LINK_SECTION_BINDING)- + /EXE=$(BIN_DIR)VAX-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(VAX_LIB)/LIBRARY,- + $(SIMH_LIB)/LIBRARY$(PCAP_LIBR) + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +VAX780 : $(SIMH_LIB) $(PCAP_LIBD) $(VAX780_LIB) $(PCAP_EXECLET) + $! + $! Building The $(BIN_DIR)VAX780-$(ARCH).EXE Simulator. + $! + $ $(CC)$(VAX780_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)$(LINK_SECTION_BINDING)- + /EXE=$(BIN_DIR)VAX780-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(VAX780_LIB)/LIBRARY,- + $(SIMH_LIB)/LIBRARY$(PCAP_LIBR) + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +# +# If Not On VAX, Build The IBM 7094 Simulator. +# +.IF ALPHA_OR_IA64 +I7094 : $(SIMH_LIB) $(I7094_LIB) + $! + $! Building The $(BIN_DIR)I7094-$(ARCH).EXE Simulator. + $! + $ $(CC)$(I7094_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)I7094-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(I7094_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY$(PCAP_LIBR) + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +.ELSE +# +# Else We Are On VAX And Tell The User We Can't Build On VAX +# Due To The Use Of INT64. +# +I7094 : + $! Sorry, Can't Build $(BIN_DIR)I7094-$(ARCH).EXE Simulator + $! Because It Requires The Use Of INT64. +.ENDIF + +# +# PCAP VCI Components +# +$(PCAP_VCI) : $(PCAP_VCMDIR)PCAPVCM.EXE + $! + $! Installing the PCAP VCI Execlet in SYS$LOADABLE_IMAGES + $! + $ COPY $(PCAP_VCMDIR)PCAPVCM.EXE SYS$COMMON:[SYS$LDR]PCAPVCM.EXE + +$(PCAP_VCMDIR)PCAPVCM.EXE : $(PCAP_VCM_SOURCES) + $! + $! Building The PCAP VCI Execlet + $! + $ @SYS$DISK:[.PCAP-VMS.PCAPVCM]BUILD_PCAPVCM + $ DELETE/NOLOG/NOCONFIRM $(PCAP_VCMDIR)*.OBJ;*,$(PCAP_VCMDIR)*.MAP;* + + +- - - +norm lastovica / oracle rdb engineering / salida, colorado, usa +reply to: norman.lastovica@oracle.com / phone: 719.339.6749 diff --git a/simhv36-1/makefile b/simhv36-1/makefile new file mode 100644 index 0000000..87b72e1 --- /dev/null +++ b/simhv36-1/makefile @@ -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} diff --git a/simhv36-1/scp.c b/simhv36-1/scp.c new file mode 100644 index 0000000..d7f3a1f --- /dev/null +++ b/simhv36-1/scp.c @@ -0,0 +1,4314 @@ +/* scp.c: simulator control program + + 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 + 14-Feb-06 RMS Upgraded save file format to V3.5 + 18-Jan-06 RMS Added fprint_stopped_gen + Added breakpoint spaces + Fixed unaligned register access (found by Doug Carman) + 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 30-Aug-05 RMS Revised to trim trailing spaces on file names + 25-Aug-05 RMS Added variable default device support + 23-Aug-05 RMS Added Linux line history support + 16-Aug-05 RMS Fixed C++ declaration and cast problems + 01-May-05 RMS Revised syntax for SET DEBUG (from Dave Bryan) + 22-Mar-05 JDB Modified DO command to allow ten-level nesting + 18-Mar-05 RMS Moved DETACH tests into detach_unit (from Dave Bryan) + Revised interface to fprint_sym, fparse_sym + 07-Feb-05 RMS Added ASSERT command (from Dave Bryan) + 02-Feb-05 RMS Fixed bug in global register search + 26-Dec-04 RMS Qualified SAVE examine, RESTORE deposit with SIM_SW_REST + 10-Nov-04 JDB Fixed logging of errors from cmds in "do" file + 05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy + Renamed unit OFFLINE/ONLINE to DISABLED/ENABLED (from Dave Bryan) + Revised to flush output files after simulation stop (from Dave Bryan) + 15-Oct-04 RMS Fixed HELP to suppress duplicate descriptions + 27-Sep-04 RMS Fixed comma-separation options in set (from David Bryan) + 09-Sep-04 RMS Added -p option for RESET + 13-Aug-04 RMS Qualified RESTORE detach with SIM_SW_REST + 17-Jul-04 RMS Added ECHO command (from Dave Bryan) + 12-Jul-04 RMS Fixed problem ATTACHing to read only files + (found by John Dundas) + 28-May-04 RMS Added SET/SHOW CONSOLE + 14-Feb-04 RMS Updated SAVE/RESTORE (V3.2) + RMS Added debug print routines (from Dave Hittner) + RMS Added sim_vm_parse_addr and sim_vm_fprint_addr + RMS Added REG_VMAD support + RMS Split out libraries + RMS Moved logging function to SCP + RMS Exposed step counter interface(s) + RMS Fixed double logging of SHOW BREAK (found by Mark Pizzolato) + RMS Fixed implementation of REG_VMIO + RMS Added SET/SHOW DEBUG, SET/SHOW DEBUG, + SHOW MODIFIERS, SHOW RADIX + RMS Changed sim_fsize to take uptr argument + 29-Dec-03 RMS Added Telnet console output stall support + 01-Nov-03 RMS Cleaned up implicit detach on attach/restore + Fixed bug in command line read while logging (found by Mark Pizzolato) + 01-Sep-03 RMS Fixed end-of-file problem in dep, idep + Fixed error on trailing spaces in dep, idep + 15-Jul-03 RMS Removed unnecessary test in reset_all + 15-Jun-03 RMS Added register flag REG_VMIO + 25-Apr-03 RMS Added extended address support (V3.0) + Fixed bug in SAVE (found by Peter Schorn) + Added u5, u6 fields + Added logical name support + 03-Mar-03 RMS Added sim_fsize + 27-Feb-03 RMS Fixed bug in multiword deposits to files + 08-Feb-03 RMS Changed sim_os_sleep to void, match_ext to char* + Added multiple actions, .ini file support + Added multiple switch evaluations per line + 07-Feb-03 RMS Added VMS support for ! (from Mark Pizzolato) + 01-Feb-03 RMS Added breakpoint table extension, actions + 14-Jan-03 RMS Added missing function prototypes + 10-Jan-03 RMS Added attach/restore flag, dynamic memory size support, + case sensitive SET options + 22-Dec-02 RMS Added ! (OS command) feature (from Mark Pizzolato) + 17-Dec-02 RMS Added get_ipaddr + 02-Dec-02 RMS Added EValuate command + 16-Nov-02 RMS Fixed bug in register name match algorithm + 13-Oct-02 RMS Fixed Borland compiler warnings (found by Hans Pufal) + 05-Oct-02 RMS Fixed bugs in set_logon, ssh_break (found by David Hittner) + Added support for fixed buffer devices + Added support for Telnet console, removed VT support + Added help + Added VMS file optimizations (from Robert Alan Byer) + Added quiet mode, DO with parameters, GUI interface, + extensible commands (from Brian Knittel) + Added device enable/disable commands + 14-Jul-02 RMS Fixed exit bug in do, added -v switch (from Brian Knittel) + 17-May-02 RMS Fixed bug in fxread/fxwrite error usage (found by + Norm Lastovic) + 02-May-02 RMS Added VT emulation interface, changed {NO}LOG to SET {NO}LOG + 22-Apr-02 RMS Fixed laptop sleep problem in clock calibration, added + magtape record length error (found by Jonathan Engdahl) + 26-Feb-02 RMS Fixed initialization bugs in do_cmd, get_aval + (found by Brian Knittel) + 10-Feb-02 RMS Fixed problem in clock calibration + 06-Jan-02 RMS Moved device enable/disable to simulators + 30-Dec-01 RMS Generalized timer packaged, added circular arrays + 19-Dec-01 RMS Fixed DO command bug (found by John Dundas) + 07-Dec-01 RMS Implemented breakpoint package + 05-Dec-01 RMS Fixed bug in universal register logic + 03-Dec-01 RMS Added read-only units, extended SET/SHOW, universal registers + 24-Nov-01 RMS Added unit-based registers + 16-Nov-01 RMS Added DO command + 28-Oct-01 RMS Added relative range addressing + 08-Oct-01 RMS Added SHOW VERSION + 30-Sep-01 RMS Relaxed attach test in BOOT + 27-Sep-01 RMS Added queue count routine, fixed typo in ex/mod + 17-Sep-01 RMS Removed multiple console support + 07-Sep-01 RMS Removed conditional externs on function prototypes + Added special modifier print + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze (V2.7) + 18-Jul-01 RMS Minor changes for Macintosh port + 12-Jun-01 RMS Fixed bug in big-endian I/O (found by Dave Conroy) + 27-May-01 RMS Added multiple console support + 16-May-01 RMS Added logging + 15-May-01 RMS Added features from Tim Litt + 12-May-01 RMS Fixed missing return in disable_cmd + 25-Mar-01 RMS Added ENABLE/DISABLE + 14-Mar-01 RMS Revised LOAD/DUMP interface (again) + 05-Mar-01 RMS Added clock calibration support + 05-Feb-01 RMS Fixed bug, DETACH buffered unit with hwmark = 0 + 04-Feb-01 RMS Fixed bug, RESTORE not using device's attach routine + 21-Jan-01 RMS Added relative time + 22-Dec-00 RMS Fixed find_device for devices ending in numbers + 08-Dec-00 RMS V2.5a changes + 30-Oct-00 RMS Added output file option to examine + 11-Jul-99 RMS V2.5 changes + 13-Apr-99 RMS Fixed handling of 32b addresses + 04-Oct-98 RMS V2.4 changes + 20-Aug-98 RMS Added radix commands + 05-Jun-98 RMS Fixed bug in ^D handling for UNIX + 10-Apr-98 RMS Added switches to all commands + 26-Oct-97 RMS Added search capability + 25-Jan-97 RMS Revised data types + 23-Jan-97 RMS Added bi-endian I/O + 06-Sep-96 RMS Fixed bug in variable length IEXAMINE + 16-Jun-96 RMS Changed interface to parse/print_sym + 06-Apr-96 RMS Added error checking in reset all + 07-Jan-96 RMS Added register buffers in save/restore + 11-Dec-95 RMS Fixed ordering bug in save/restore + 22-May-95 RMS Added symbolic input + 13-Apr-95 RMS Added symbolic printouts +*/ + +/* Macros and data structures */ + +#include "sim_defs.h" +#include "sim_rev.h" +#include +#include + +#if defined (HAVE_READLINE) +#include +#include +#endif + +#define EX_D 0 /* deposit */ +#define EX_E 1 /* examine */ +#define EX_I 2 /* interactive */ +#define SCH_OR 0 /* search logicals */ +#define SCH_AND 1 +#define SCH_XOR 2 +#define SCH_E 0 /* search booleans */ +#define SCH_N 1 +#define SCH_G 2 +#define SCH_L 3 +#define SCH_EE 4 +#define SCH_NE 5 +#define SCH_GE 6 +#define SCH_LE 7 +#define SSH_ST 0 /* set */ +#define SSH_SH 1 /* show */ +#define SSH_CL 2 /* clear */ + +#define DO_NEST_LVL 10 /* DO cmd nesting level */ +#define SRBSIZ 1024 /* save/restore buffer */ +#define SIM_BRK_INILNT 4096 /* bpt tbl length */ +#define SIM_BRK_ALLTYP 0xFFFFFFFF +#define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \ + sim_rtime = sim_rtime + ((uint32) (x - sim_interval)); \ + x = sim_interval + +#define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT]) +#define SZ_R(rp) \ + (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT]) +#if defined (USE_INT64) +#define SZ_LOAD(sz,v,mb,j) \ + if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \ + else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \ + else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + ((uint32) j)); \ + else v = *(((t_uint64 *) mb) + ((uint32) j)); +#define SZ_STORE(sz,v,mb,j) \ + if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \ + else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \ + else if (sz == sizeof (uint32)) *(((uint32 *) mb) + ((uint32) j)) = (uint32) v; \ + else *(((t_uint64 *) mb) + ((uint32) j)) = v; +#else +#define SZ_LOAD(sz,v,mb,j) \ + if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \ + else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + ((uint32) j)); \ + else v = *(((uint32 *) mb) + ((uint32) j)); +#define SZ_STORE(sz,v,mb,j) \ + if (sz == sizeof (uint8)) *(((uint8 *) mb) + ((uint32) j)) = (uint8) v; \ + else if (sz == sizeof (uint16)) *(((uint16 *) mb) + ((uint32) j)) = (uint16) v; \ + else *(((uint32 *) mb) + ((uint32) j)) = v; +#endif +#define GET_SWITCHES(cp) \ + if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW +#define GET_RADIX(val,dft) \ + if (sim_switches & SWMASK ('O')) val = 8; \ + else if (sim_switches & SWMASK ('D')) val = 10; \ + else if (sim_switches & SWMASK ('H')) val = 16; \ + else val = dft; + +/* VM interface */ + +extern char sim_name[]; +extern DEVICE *sim_devices[]; +extern REG *sim_PC; +extern const char *sim_stop_messages[]; +extern t_stat sim_instr (void); +extern t_stat sim_load (FILE *ptr, char *cptr, char *fnam, int32 flag); +extern int32 sim_emax; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); +extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, + int32 sw); + +/* The per-simulator init routine is a weak global that defaults to NULL + The other per-simulator pointers can be overrriden by the init routine */ + +void (*sim_vm_init) (void); +char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL; +void (*sim_vm_post) (t_bool from_scp) = NULL; +CTAB *sim_vm_cmd = NULL; +void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL; +t_addr (*sim_vm_parse_addr) (DEVICE *dptr, char *cptr, char **tptr) = NULL; + +/* Prototypes */ + +/* Set and show command processors */ + +t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat ssh_break (FILE *st, char *cptr, int32 flg); +t_stat show_cmd_fi (FILE *ofile, int32 flag, char *cptr); +t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_device (FILE *st, DEVICE *dptr, int32 flag); +t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag); +t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg); +t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, char *cptr, int32 flag); +t_stat sim_check_console (int32 sec); +t_stat sim_save (FILE *sfile); +t_stat sim_rest (FILE *rfile); + +/* Breakpoint package */ + +t_stat sim_brk_init (void); +t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, char *act); +t_stat sim_brk_clr (t_addr loc, int32 sw); +t_stat sim_brk_clrall (int32 sw); +t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw); +t_stat sim_brk_showall (FILE *st, int32 sw); +char *sim_brk_getact (char *buf, int32 size); +void sim_brk_clract (void); +void sim_brk_npc (uint32 cnt); +BRKTAB *sim_brk_new (t_addr loc); + +/* Commands support routines */ + +SCHTAB *get_search (char *cptr, int32 radix, SCHTAB *schptr); +int32 test_search (t_value val, SCHTAB *schptr); +char *get_glyph_gen (char *iptr, char *optr, char mchar, t_bool uc); +int32 get_switches (char *cptr); +char *get_sim_sw (char *cptr); +t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); +t_value get_rval (REG *rptr, uint32 idx); +void put_rval (REG *rptr, uint32 idx, t_value val); +t_value strtotv (char *inptr, char **endptr, uint32 radix); +void fprint_help (FILE *st); +void fprint_stopped (FILE *st, t_stat r); +void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr); +char *read_line (char *ptr, int32 size, FILE *stream); +REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); +char *sim_trim_endspc (char *cptr); + +/* Forward references within commands */ + +t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, char *cptr); +t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr); +t_bool qdisable (DEVICE *dptr); +t_stat attach_err (UNIT *uptr, t_stat stat); +t_stat detach_all (int32 start_device, t_bool shutdown); +t_stat assign_device (DEVICE *dptr, char *cptr); +t_stat deassign_device (DEVICE *dptr); +t_stat run_boot_prep (void); +t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, + REG *lowr, REG *highr, uint32 lows, uint32 highs); +t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx); +t_stat dep_reg (int32 flag, char *cptr, REG *rptr, uint32 idx); +t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, + t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr); +t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr); +t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr, + UNIT *uptr, int32 dfltinc); +t_stat step_svc (UNIT *ptr); +void sub_args (char *instr, char *tmpbuf, int32 maxstr, int32 nargs, char *do_arg[]); + +/* Global data */ + +DEVICE *sim_dflt_dev = NULL; +UNIT *sim_clock_queue = NULL; +int32 sim_interval = 0; +int32 sim_switches = 0; +FILE *sim_ofile = NULL; +SCHTAB *sim_schptr = FALSE; +DEVICE *sim_dfdev = NULL; +UNIT *sim_dfunit = NULL; +int32 sim_is_running = 0; +uint32 sim_brk_summ = 0; +uint32 sim_brk_types = 0; +uint32 sim_brk_dflt = 0; +char *sim_brk_act = NULL; +BRKTAB *sim_brk_tab = NULL; +int32 sim_brk_ent = 0; +int32 sim_brk_lnt = 0; +int32 sim_brk_ins = 0; +t_bool sim_brk_pend[SIM_BKPT_N_SPC] = { FALSE }; +t_addr sim_brk_ploc[SIM_BKPT_N_SPC] = { 0 }; +int32 sim_quiet = 0; +int32 sim_step = 0; +static double sim_time; +static uint32 sim_rtime; +static int32 noqueue_time; +volatile int32 stop_cpu = 0; +t_value *sim_eval = NULL; +int32 sim_deb_close = 0; /* 1 = close debug */ +FILE *sim_log = NULL; /* log file */ +FILE *sim_deb = NULL; /* debug file */ +static SCHTAB sim_stab; + +static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) }; +#if defined USE_INT64 +static const char *sim_si64 = "64b data"; +#else +static const char *sim_si64 = "32b data"; +#endif +#if defined USE_ADDR64 +static const char *sim_sa64 = "64b addresses"; +#else +static const char *sim_sa64 = "32b addresses"; +#endif +#if defined USE_NETWORK +static const char *sim_snet = "Ethernet support"; +#else +static const char *sim_snet = "no Ethernet"; +#endif + +/* Tables and strings */ + +const char save_vercur[] = "V3.5"; +const char save_ver32[] = "V3.2"; +const char save_ver30[] = "V3.0"; +const char *scp_error_messages[] = { + "Address space exceeded", + "Unit not attached", + "I/O error", + "Checksum error", + "Format error", + "Unit not attachable", + "File open error", + "Memory exhausted", + "Invalid argument", + "Step expired", + "Unknown command", + "Read only argument", + "Command not completed", + "Simulation stopped", + "Goodbye", + "Console input I/O error", + "Console output I/O error", + "End of file", + "Relocation error", + "No settable parameters", + "Unit already attached", + "Hardware timer error", + "SIGINT handler setup error", + "Console terminal setup error", + "Subscript out of range", + "Command not allowed", + "Unit disabled", + "Read only operation not allowed", + "Invalid switch", + "Missing value", + "Too few arguments", + "Too many arguments", + "Non-existent device", + "Non-existent unit", + "Non-existent register", + "Non-existent parameter", + "Nested DO command limit exceeded", + "Internal error", + "Invalid magtape record length", + "Console Telnet connection lost", + "Console Telnet connection timed out", + "Console Telnet output stall", + "" /* printed by assert */ + }; + +const size_t size_map[] = { sizeof (int8), + sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32) +#if defined (USE_INT64) + , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64) +#endif +}; + +const t_value width_mask[] = { 0, + 0x1, 0x3, 0x7, 0xF, + 0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, + 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, + 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, + 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF +#if defined (USE_INT64) + , 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF, + 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF, + 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF, + 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF, + 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF, + 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF, + 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, + 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF, + 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, + 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF +#endif + }; + +static CTAB cmd_table[] = { + { "RESET", &reset_cmd, 0, + "r{eset} {ALL|} reset simulator\n" }, + { "EXAMINE", &exdep_cmd, EX_E, + "e{xamine} examine memory or registers\n" }, + { "IEXAMINE", &exdep_cmd, EX_E+EX_I, + "ie{xamine} interactive examine memory or registers\n" }, + { "DEPOSIT", &exdep_cmd, EX_D, + "d{eposit} deposit in memory or registers\n" }, + { "IDEPOSIT", &exdep_cmd, EX_D+EX_I, + "id{eposit} interactive deposit in memory or registers\n" }, + { "EVALUATE", &eval_cmd, 0, + "ev{aluate} evaluate symbolic expression\n" }, + { "RUN", &run_cmd, RU_RUN, + "ru{n} {new PC} reset and start simulation\n" }, + { "GO", &run_cmd, RU_GO, + "go {new PC} start simulation\n" }, + { "STEP", &run_cmd, RU_STEP, + "s{tep} {n} simulate n instructions\n" }, + { "CONT", &run_cmd, RU_CONT, + "c{ont} continue simulation\n" }, + { "BOOT", &run_cmd, RU_BOOT, + "b{oot} bootstrap unit\n" }, + { "BREAK", &brk_cmd, SSH_ST, + "br{eak} set breakpoints\n" }, + { "NOBREAK", &brk_cmd, SSH_CL, + "nobr{eak} clear breakpoints\n" }, + { "ATTACH", &attach_cmd, 0, + "at{tach} attach file to simulated unit\n" }, + { "DETACH", &detach_cmd, 0, + "det{ach} detach file from simulated unit\n" }, + { "ASSIGN", &assign_cmd, 0, + "as{sign} assign logical name for device\n" }, + { "DEASSIGN", &deassign_cmd, 0, + "dea{ssign} deassign logical name for device\n" }, + { "SAVE", &save_cmd, 0, + "sa{ve} save simulator to file\n" }, + { "RESTORE", &restore_cmd, 0, + "rest{ore}|ge{t} restore simulator from file\n" }, + { "GET", &restore_cmd, 0, NULL }, + { "LOAD", &load_cmd, 0, + "l{oad} {} load binary file\n" }, + { "DUMP", &load_cmd, 1, + "du(mp) {} dump binary file\n" }, + { "EXIT", &exit_cmd, 0, + "exi{t}|q{uit}|by{e} exit from simulation\n" }, + { "QUIT", &exit_cmd, 0, NULL }, + { "BYE", &exit_cmd, 0, NULL }, + { "SET", &set_cmd, 0, + "set console arg{,arg...} set console options\n" + "set OCT|DEC|HEX set device display radix\n" + "set ENABLED enable device\n" + "set DISABLED disable device\n" + "set DEBUG{=arg} set device debug flags\n" + "set NODEBUG={arg} clear device debug flags\n" + "set arg{,arg...} set device parameters\n" + "set ENABLED enable unit\n" + "set DISABLED disable unit\n" + "set arg{,arg...} set unit parameters\n" + }, + { "SHOW", &show_cmd, 0, + "sh{ow} br{eak} show breakpoints on address list\n" + "sh{ow} con{figuration} show configuration\n" + "sh{ow} cons{ole} {arg} show console options\n" + "sh{ow} dev{ices} show devices\n" + "sh{ow} m{odifiers} show modifiers\n" + "sh{ow} n{ames} show logical names\n" + "sh{ow} q{ueue} show event queue\n" + "sh{ow} ti{me} show simulated time\n" + "sh{ow} ve{rsion} show simulator version\n" + "sh{ow} RADIX show device display radix\n" + "sh{ow} DEBUG show device debug flags\n" + "sh{ow} MODIFIERS show device modifiers\n" + "sh{ow} {arg,...} show device parameters\n" + "sh{ow} {arg,...} show unit parameters\n" }, + { "DO", &do_cmd, 1, + "do {arg,arg...} process command file\n" }, + { "ECHO", &echo_cmd, 0, + "echo display \n" }, + { "ASSERT", &assert_cmd, 0, + "assert {} test simulator state against condition\n" }, + { "HELP", &help_cmd, 0, + "h{elp} type this message\n" + "h{elp} type help for command\n" }, + { "!", &spawn_cmd, 0, + "! execute local command interpreter\n" + "! execute local host command\n" }, + { NULL, NULL, 0 } + }; + +/* Main command loop */ + +int main (int argc, char *argv[]) +{ +char cbuf[CBUFSIZE], gbuf[CBUFSIZE], *cptr; +int32 i, sw; +t_bool lookswitch; +t_stat stat; +CTAB *cmdp; + +#if defined (__MWERKS__) && defined (macintosh) +argc = ccommand (&argv); +#endif + +*cbuf = 0; /* init arg buffer */ +sim_switches = 0; /* init switches */ +lookswitch = TRUE; +for (i = 1; i < argc; i++) { /* loop thru args */ + if (argv[i] == NULL) continue; /* paranoia */ + if ((*argv[i] == '-') && lookswitch) { /* switch? */ + if ((sw = get_switches (argv[i])) < 0) { + fprintf (stderr, "Invalid switch %s\n", argv[i]); + return 0; + } + sim_switches = sim_switches | sw; + } + else { + if ((strlen (argv[i]) + strlen (cbuf) + 1) >= CBUFSIZE) { + fprintf (stderr, "Argument string too long\n"); + return 0; + } + if (*cbuf) strcat (cbuf, " "); /* concat args */ + strcat (cbuf, argv[i]); + lookswitch = FALSE; /* no more switches */ + } + } /* end for */ +sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ + +if (sim_vm_init != NULL) (*sim_vm_init)(); /* call once only */ +sim_finit (); /* init fio package */ +stop_cpu = 0; +sim_interval = 0; +sim_time = sim_rtime = 0; +noqueue_time = 0; +sim_clock_queue = NULL; +sim_is_running = 0; +sim_log = NULL; +if (sim_emax <= 0) sim_emax = 1; + +if ((stat = sim_ttinit ()) != SCPE_OK) { + fprintf (stderr, "Fatal terminal initialization error\n%s\n", + scp_error_messages[stat - SCPE_BASE]); + return 0; + } +if ((sim_eval = (t_value *) calloc (sim_emax, sizeof (t_value))) == NULL) { + fprintf (stderr, "Unable to allocate examine buffer\n"); + return 0; + }; +if ((stat = reset_all_p (0)) != SCPE_OK) { + fprintf (stderr, "Fatal simulator initialization error\n%s\n", + scp_error_messages[stat - SCPE_BASE]); + return 0; + } +if ((stat = sim_brk_init ()) != SCPE_OK) { + fprintf (stderr, "Fatal breakpoint table initialization error\n%s\n", + scp_error_messages[stat - SCPE_BASE]); + return 0; + } +if (!sim_quiet) { + printf ("\n"); + show_version (stdout, NULL, NULL, 0, NULL); + } +if (sim_dflt_dev == NULL) sim_dflt_dev = sim_devices[0]; /* if no default */ + +if (*cbuf) { /* cmd file arg? */ + stat = do_cmd (0, cbuf); /* proc cmd file */ + if (stat == SCPE_OPENERR) /* error? */ + fprintf (stderr, "Can't open file %s\n", cbuf); + } +else if (*argv[0]) { /* sim name arg? */ + char nbuf[PATH_MAX + 7], *np; /* "path.ini" */ + nbuf[0] = '"'; /* starting " */ + strncpy (nbuf + 1, argv[0], PATH_MAX + 1); /* copy sim name */ + if (np = match_ext (nbuf, "EXE")) *np = 0; /* remove .exe */ + strcat (nbuf, ".ini\""); /* add .ini" */ + stat = do_cmd (0, nbuf); /* proc cmd file */ + } + +while (stat != SCPE_EXIT) { /* in case exit */ + printf ("sim> "); /* prompt */ + if (cptr = sim_brk_getact (cbuf, CBUFSIZE)) /* pending action? */ + printf ("%s\n", cptr); /* echo */ + else if (sim_vm_read != NULL) /* sim routine? */ + cptr = (*sim_vm_read) (cbuf, CBUFSIZE, stdin); + else cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */ + if (cptr == NULL) continue; /* ignore EOF */ + if (*cptr == 0) continue; /* ignore blank */ + if (sim_log) fprintf (sim_log, "sim> %s\n", cptr); /* log cmd */ + cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ + sim_switches = 0; /* init switches */ + if (cmdp = find_cmd (gbuf)) /* lookup command */ + stat = cmdp->action (cmdp->arg, cptr); /* if found, exec */ + else stat = SCPE_UNK; + if (stat >= SCPE_BASE) { /* error? */ + printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); + if (sim_log) fprintf (sim_log, "%s\n", + scp_error_messages[stat - SCPE_BASE]); + } + if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); + } /* end while */ + +detach_all (0, TRUE); /* close files */ +sim_set_deboff (0, NULL); /* close debug */ +sim_set_logoff (0, NULL); /* close log */ +sim_set_notelnet (0, NULL); /* close Telnet */ +sim_ttclose (); /* close console */ +return 0; +} + +/* Find command routine */ + +CTAB *find_cmd (char *gbuf) +{ +CTAB *cmdp = NULL; + +if (sim_vm_cmd) cmdp = find_ctab (sim_vm_cmd, gbuf); /* try ext commands */ +if (cmdp == NULL) cmdp = find_ctab (cmd_table, gbuf); /* try regular cmds */ +return cmdp; +} + +/* Exit command */ + +t_stat exit_cmd (int32 flag, char *cptr) +{ +return SCPE_EXIT; +} + +/* Help command */ + +void fprint_help (FILE *st) +{ +CTAB *cmdp; + +for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) { + if (cmdp->help) fputs (cmdp->help, st); + } +for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) { + if (cmdp->help && (!sim_vm_cmd || !find_ctab (sim_vm_cmd, cmdp->name))) + fputs (cmdp->help, st); + } +return; +} + +t_stat help_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +CTAB *cmdp; + +GET_SWITCHES (cptr); +if (*cptr) { + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) return SCPE_2MARG; + if (cmdp = find_cmd (gbuf)) { + fputs (cmdp->help, stdout); + if (sim_log) fputs (cmdp->help, sim_log); + } + else return SCPE_ARG; + } +else { + fprint_help (stdout); + if (sim_log) fprint_help (sim_log); + } +return SCPE_OK; +} + +/* Spawn command */ + +t_stat spawn_cmd (int32 flag, char *cptr) +{ +int ret; +if ((cptr == NULL) || (strlen (cptr) == 0)) cptr = getenv("SHELL"); +if ((cptr == NULL) || (strlen (cptr) == 0)) cptr = getenv("ComSpec"); +#if defined (VMS) +if ((cptr == NULL) || (strlen (cptr) == 0)) cptr = "SPAWN/INPUT=SYS$COMMAND:"; +#endif +fflush(stdout); /* flush stdout */ +if (sim_log) fflush (sim_log); /* flush log if enabled */ +ret = system (cptr); +#if defined (VMS) +printf ("\n"); +#endif + +return SCPE_OK; +} + +/* Echo command */ + +t_stat echo_cmd (int32 flag, char *cptr) +{ +puts (cptr); +if (sim_log) fprintf (sim_log, "%s\n", cptr); +return SCPE_OK; +} + +/* Do command */ + +t_stat do_cmd (int32 flag, char *fcptr) +{ +char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE], *c, quote, *do_arg[10]; +FILE *fpin; +CTAB *cmdp; +int32 echo, nargs; +t_stat stat = SCPE_OK; + +if (flag > 0) { GET_SWITCHES (fcptr); } /* get switches */ +else flag = 1; /* start at level 1 */ +echo = sim_switches & SWMASK ('V'); /* -v means echo */ + +c = fcptr; +for (nargs = 0; nargs < 10; ) { /* extract arguments */ + while (isspace (*c)) c++; /* skip blanks */ + if (*c == 0) break; /* all done */ + if (*c == '\'' || *c == '"') quote = *c++; /* quoted string? */ + else quote = 0; + do_arg[nargs++] = c; /* save start */ + while (*c && (quote? (*c != quote): !isspace (*c))) c++; + if (*c) *c++ = 0; /* term at quote/spc */ + } /* end for */ +if (nargs <= 0) return SCPE_2FARG; /* need at least 1 */ +if ((fpin = fopen (do_arg[0], "r")) == NULL) /* cmd file failed to open? */ + return SCPE_OPENERR; + +do { + cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ + sub_args (cbuf, gbuf, CBUFSIZE, nargs, do_arg); + if (cptr == NULL) break; /* exit on eof */ + if (*cptr == 0) continue; /* ignore blank */ + if (echo) printf("do> %s\n", cptr); /* echo if -v */ + if (echo && sim_log) fprintf (sim_log, "do> %s\n", cptr); + cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ + sim_switches = 0; /* init switches */ + if (cmdp = find_cmd (gbuf)) { /* lookup command */ + if (cmdp->action == &do_cmd) { /* DO command? */ + if (flag >= DO_NEST_LVL) stat = SCPE_NEST; /* nest too deep? */ + else stat = do_cmd (flag + 1, cptr); /* exec DO cmd */ + } + else stat = cmdp->action (cmdp->arg, cptr); /* exec other cmd */ + } + else stat = SCPE_UNK; /* bad cmd given */ + if (stat >= SCPE_BASE) { /* error? */ + printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); + if (sim_log) fprintf (sim_log, "%s\n", + scp_error_messages[stat - SCPE_BASE]); + } + if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); + } while ((stat != SCPE_EXIT) && (stat != SCPE_AFAIL)); + +fclose (fpin); /* close file */ +return (stat == SCPE_EXIT)? SCPE_EXIT: SCPE_OK; +} + +/* Substitute_args - replace %n tokens in 'instr' with the do command's arguments + + Calling sequence + instr = input string + tmpbuf = temp buffer + maxstr = min (len (instr), len (tmpbuf)) + nargs = number of arguments + do_arg[10] = arguments +*/ + +void sub_args (char *instr, char *tmpbuf, int32 maxstr, int32 nargs, char *do_arg[]) +{ +char *ip, *op, *ap, *oend = tmpbuf + maxstr - 2; + +for (ip = instr, op = tmpbuf; *ip && (op < oend); ) { + if ((*ip == '\\') && (ip[1] == '%')) { /* \% = literal % */ + ip++; /* skip \ */ + if (*ip) *op++ = *ip++; /* copy next */ + } + else if ((*ip == '%') && /* %n = sub */ + ((ip[1] >= '1') && (ip[1] <= ('0'+ nargs - 1)))) { + ap = do_arg[ip[1] - '0']; + ip = ip + 2; + while (*ap && (op < oend)) *op++ = *ap++; /* copy the argument */ + } + else *op++ = *ip++; /* literal character */ + } +*op = 0; /* term buffer */ +strcpy (instr, tmpbuf); +return; +} + +/* Assert command + + Syntax: ASSERT {} {} + + If is not specified, CPU is assumed. is expressed in the radix + specified for . and are the same as that + allowed for examine and deposit search specifications. */ + +t_stat assert_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE], *gptr, *aptr, *tptr; +REG *rptr; +uint32 idx; +t_value val; +t_stat r; + +aptr = cptr; /* save assertion */ +cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, cptr, &r); /* get sw, default */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get register */ +rptr = find_reg (gbuf, &gptr, sim_dfdev); /* parse register */ +if (!rptr) return SCPE_NXREG; /* not there */ +if (*gptr == '[') { /* subscript? */ + if (rptr->depth <= 1) return SCPE_ARG; /* array register? */ + idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */ + if ((gptr == tptr) || (*tptr++ != ']')) return SCPE_ARG; + gptr = tptr; /* update */ + } +else idx = 0; /* not array */ +if (idx >= rptr->depth) return SCPE_SUB; /* validate subscript */ +if (*gptr != 0) get_glyph (gptr, gbuf, 0); /* more? must be search */ +else { + if (*cptr == 0) return SCPE_2FARG; /* must be more */ + cptr = get_glyph (cptr, gbuf, 0); /* get search cond */ + } +if (*cptr != 0) return SCPE_2MARG; /* must be done */ +if (!get_search (gbuf, rptr->radix, &sim_stab)) /* parse condition */ + return SCPE_MISVAL; +val = get_rval (rptr, idx); /* get register value */ +if (test_search (val, &sim_stab)) return SCPE_OK; /* test condition */ +printf ("Assertion failed (%s)", aptr); /* report failing assertion */ +if (sim_log) fprintf (sim_log, "Assertion failed (%s)", aptr); +return SCPE_AFAIL; /* condition fails */ +} + +/* Set command */ + +t_stat set_cmd (int32 flag, char *cptr) +{ +int32 lvl; +t_stat r; +char gbuf[CBUFSIZE], *cvptr, *svptr; +DEVICE *dptr; +UNIT *uptr; +MTAB *mptr; +CTAB *gcmdp; +C1TAB *ctbr, *glbr; + +static CTAB set_glob_tab[] = { + { "CONSOLE", &sim_set_console, 0 }, + { "BREAK", &brk_cmd, SSH_ST }, + { "TELNET", &sim_set_telnet, 0 }, /* deprecated */ + { "NOTELNET", &sim_set_notelnet, 0 }, /* deprecated */ + { "LOG", &sim_set_logon, 0 }, /* deprecated */ + { "NOLOG", &sim_set_logoff, 0 }, /* deprecated */ + { "DEBUG", &sim_set_debon, 0 }, /* deprecated */ + { "NODEBUG", &sim_set_deboff, 0 }, /* deprecated */ + { NULL, NULL, 0 } + }; + +static C1TAB set_dev_tab[] = { + { "OCTAL", &set_dev_radix, 8 }, + { "DECIMAL", &set_dev_radix, 10 }, + { "HEX", &set_dev_radix, 16 }, + { "ENABLED", &set_dev_enbdis, 1 }, + { "DISABLED", &set_dev_enbdis, 0 }, + { "DEBUG", &set_dev_debug, 1 }, + { "NODEBUG", &set_dev_debug, 0 }, + { NULL, NULL, 0 } + }; + +static C1TAB set_unit_tab[] = { + { "ENABLED", &set_unit_enbdis, 1 }, + { "DISABLED", &set_unit_enbdis, 0 }, + { NULL, NULL, 0 } + }; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get glob/dev/unit */ + +if (dptr = find_dev (gbuf)) { /* device match? */ + uptr = dptr->units; /* first unit */ + ctbr = set_dev_tab; /* global table */ + lvl = MTAB_VDV; /* device match */ + } +else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ + if (uptr == NULL) return SCPE_NXUN; /* invalid unit */ + ctbr = set_unit_tab; /* global table */ + lvl = MTAB_VUN; /* unit match */ + } +else if (gcmdp = find_ctab (set_glob_tab, gbuf)) /* global? */ + return gcmdp->action (gcmdp->arg, cptr); /* do the rest */ +else return SCPE_NXDEV; /* no match */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ + +while (*cptr != 0) { /* do all mods */ + cptr = get_glyph (svptr = cptr, gbuf, ','); /* get modifier */ + if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ + for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) { + if ((mptr->mstring) && /* match string */ + (MATCH_CMD (gbuf, mptr->mstring) == 0)) { /* matches option? */ + if (mptr->mask & MTAB_XTD) { /* extended? */ + if ((lvl & mptr->mask) == 0) return SCPE_ARG; + if ((lvl & MTAB_VUN) && (uptr->flags & UNIT_DIS)) + return SCPE_UDIS; /* unit disabled? */ + if (mptr->valid) { /* validation rtn? */ + if (cvptr && (mptr->mask & MTAB_NC)) + get_glyph_nc (svptr, gbuf, ','); + r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc); + if (r != SCPE_OK) return r; + } + else if (!mptr->desc) break; /* value desc? */ + else if (mptr->mask & MTAB_VAL) { /* take a value? */ + if (!cvptr) return SCPE_MISVAL; /* none? error */ + r = dep_reg (0, cvptr, (REG *) mptr->desc, 0); + if (r != SCPE_OK) return r; + } + else if (cvptr) return SCPE_ARG; /* = value? */ + else *((int32 *) mptr->desc) = mptr->match; + } /* end if xtd */ + else { /* old style */ + if (cvptr) return SCPE_ARG; /* = value? */ + if (uptr->flags & UNIT_DIS) /* disabled? */ + return SCPE_UDIS; + if ((mptr->valid) && ((r = mptr->valid + (uptr, mptr->match, cvptr, mptr->desc)) + != SCPE_OK)) return r; /* invalid? */ + uptr->flags = (uptr->flags & ~(mptr->mask)) | + (mptr->match & mptr->mask); /* set new value */ + } /* end else xtd */ + break; /* terminate for */ + } /* end if match */ + } /* end for */ + if (!mptr || (mptr->mask == 0)) { /* no match? */ + if (glbr = find_c1tab (ctbr, gbuf)) { /* global match? */ + r = glbr->action (dptr, uptr, glbr->arg, cvptr); /* do global */ + if (r != SCPE_OK) return r; + } + else if (!dptr->modifiers) return SCPE_NOPARAM; /* no modifiers? */ + else return SCPE_NXPAR; + } /* end if no mat */ + } /* end while */ +return SCPE_OK; /* done all */ +} + +/* Match CTAB/CTAB1 name */ + +CTAB *find_ctab (CTAB *tab, char *gbuf) +{ +for (; tab->name != NULL; tab++) { + if (MATCH_CMD (gbuf, tab->name) == 0) return tab; + } +return NULL; +} + +C1TAB *find_c1tab (C1TAB *tab, char *gbuf) +{ +for (; tab->name != NULL; tab++) { + if (MATCH_CMD (gbuf, tab->name) == 0) return tab; + } +return NULL; +} + +/* Set device data radix routine */ + +t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (cptr) return SCPE_ARG; +dptr->dradix = flag & 037; +return SCPE_OK; +} + +/* Set device enabled/disabled routine */ + +t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +UNIT *up; +uint32 i; + +if (cptr) return SCPE_ARG; +if ((dptr->flags & DEV_DISABLE) == 0) return SCPE_NOFNC;/* allowed? */ +if (flag) { /* enable? */ + if ((dptr->flags & DEV_DIS) == 0) /* already enb? ok */ + return SCPE_OK; + dptr->flags = dptr->flags & ~DEV_DIS; /* no, enable */ + } +else { + if (dptr->flags & DEV_DIS) return SCPE_OK; /* already dsb? ok */ + for (i = 0; i < dptr->numunits; i++) { /* check units */ + up = (dptr->units) + i; /* att or active? */ + if ((up->flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; /* can't do it */ + } + dptr->flags = dptr->flags | DEV_DIS; /* disable */ + } +if (dptr->reset) return dptr->reset (dptr); /* reset device */ +else return SCPE_OK; +} + +/* Set unit enabled/disabled routine */ + +t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (cptr) return SCPE_ARG; +if (!(uptr->flags & UNIT_DISABLE)) return SCPE_NOFNC; /* allowed? */ +if (flag) uptr->flags = uptr->flags & ~UNIT_DIS; /* enb? enable */ +else { + if ((uptr->flags & UNIT_ATT) || /* dsb */ + sim_is_active (uptr)) return SCPE_NOFNC; /* more tests */ + uptr->flags = uptr->flags | UNIT_DIS; /* disable */ + } +return SCPE_OK; +} + +/* Set device debug enabled/disabled routine */ + +t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEBTAB *dep; + +if ((dptr->flags & DEV_DEBUG) == 0) return SCPE_NOFNC; +if (cptr == NULL) { /* no arguments? */ + dptr->dctrl = flag; /* disable/enable w/o table */ + if (flag && dptr->debflags) { /* enable with table? */ + for (dep = dptr->debflags; dep->name != NULL; dep++) + dptr->dctrl = dptr->dctrl | dep->mask; /* set all */ + } + return SCPE_OK; + } +if (dptr->debflags == NULL) return SCPE_ARG; /* must have table */ +while (*cptr) { + cptr = get_glyph (cptr, gbuf, ';'); /* get debug flag */ + for (dep = dptr->debflags; dep->name != NULL; dep++) { + if (strcmp (dep->name, gbuf) == 0) { /* match? */ + if (flag) dptr->dctrl = dptr->dctrl | dep->mask; + else dptr->dctrl = dptr->dctrl & ~dep->mask; + break; + } + } /* end for */ + if (dep->mask == 0) return SCPE_ARG; /* no match? */ + } /* end while */ +return SCPE_OK; +} + +/* Show command */ + +t_stat show_cmd (int32 flag, char *cptr) +{ +t_stat r; + +cptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_OF, cptr, &r); /* get sw, ofile */ +if (!cptr) return r; /* error? */ +if (sim_ofile) { /* output file? */ + r = show_cmd_fi (sim_ofile, flag, cptr); /* do show */ + fclose (sim_ofile); + } +else { + r = show_cmd_fi (stdout, flag, cptr); /* no, stdout, log */ + if (sim_log) show_cmd_fi (sim_log, flag, cptr); + } +return r; +} + +t_stat show_cmd_fi (FILE *ofile, int32 flag, char *cptr) +{ +int32 lvl; +char gbuf[CBUFSIZE], *cvptr; +DEVICE *dptr; +UNIT *uptr; +MTAB *mptr; +SHTAB *shtb, *shptr; + +static SHTAB show_glob_tab[] = { + { "CONFIGURATION", &show_config, 0 }, + { "DEVICES", &show_config, 1 }, + { "QUEUE", &show_queue, 0 }, + { "TIME", &show_time, 0 }, + { "MODIFIERS", &show_mod_names, 0 }, + { "NAMES", &show_log_names, 0 }, + { "VERSION", &show_version, 1 }, + { "CONSOLE", &sim_show_console, 0 }, + { "BREAK", &show_break, 0 }, + { "LOG", &sim_show_log, 0 }, /* deprecated */ + { "TELNET", &sim_show_telnet, 0 }, /* deprecated */ + { "DEBUG", &sim_show_debug, 0 }, /* deprecated */ + { NULL, NULL, 0 } + }; + +static SHTAB show_dev_tab[] = { + { "RADIX", &show_dev_radix, 0 }, + { "DEBUG", &show_dev_debug, 0 }, + { "MODIFIERS", &show_dev_modifiers, 0 }, + { "NAMES", &show_dev_logicals, 0 }, + { NULL, NULL, 0 } + }; + +static SHTAB show_unit_tab[] = { + { NULL, NULL, 0 } + }; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +if (shptr = find_shtab (show_glob_tab, gbuf)) /* global? */ + return shptr->action (ofile, NULL, NULL, shptr->arg, cptr); + +if (dptr = find_dev (gbuf)) { /* device match? */ + uptr = dptr->units; /* first unit */ + shtb = show_dev_tab; /* global table */ + lvl = MTAB_VDV; /* device match */ + } +else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ + if (uptr == NULL) return SCPE_NXUN; /* invalid unit */ + if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ + shtb = show_unit_tab; /* global table */ + lvl = MTAB_VUN; /* unit match */ + } +else return SCPE_NXDEV; /* no match */ + +if (*cptr == 0) { /* now eol? */ + return (lvl == MTAB_VDV)? + show_device (ofile, dptr, 0): + show_unit (ofile, dptr, uptr, -1); + } +if (dptr->modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ + +while (*cptr != 0) { /* do all mods */ + cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ + if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ + for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { + if (((mptr->mask & MTAB_XTD)? /* right level? */ + (mptr->mask & lvl): (MTAB_VUN & lvl)) && + ((mptr->disp && mptr->pstring && /* named disp? */ + (MATCH_CMD (gbuf, mptr->pstring) == 0)) || + ((mptr->mask & MTAB_VAL) && /* named value? */ + mptr->mstring && + (MATCH_CMD (gbuf, mptr->mstring) == 0)))) { + if (cvptr && !(mptr->mask & MTAB_SHP)) return SCPE_ARG; + show_one_mod (ofile, dptr, uptr, mptr, cvptr, 1); + break; + } /* end if */ + } /* end for */ + if (mptr->mask == 0) { /* no match? */ + if (shptr = find_shtab (shtb, gbuf)) /* global match? */ + shptr->action (ofile, dptr, uptr, shptr->arg, cptr); + else return SCPE_ARG; + } /* end if */ + } /* end while */ +return SCPE_OK; +} + +SHTAB *find_shtab (SHTAB *tab, char *gbuf) +{ +for (; tab->name != NULL; tab++) { + if (MATCH_CMD (gbuf, tab->name) == 0) return tab; + } +return NULL; +} + +/* Show device and unit */ + +t_stat show_device (FILE *st, DEVICE *dptr, int32 flag) +{ +uint32 j, udbl, ucnt; +UNIT *uptr; + +fprintf (st, "%s", sim_dname (dptr)); /* print dev name */ +if (qdisable (dptr)) { /* disabled? */ + fprintf (st, ", disabled\n"); + return SCPE_OK; + } +for (j = ucnt = udbl = 0; j < dptr->numunits; j++) { /* count units */ + uptr = dptr->units + j; + if (uptr->flags & UNIT_DISABLE) udbl++; + if (!(uptr->flags & UNIT_DIS)) ucnt++; + } +show_all_mods (st, dptr, dptr->units, MTAB_VDV); /* show dev mods */ +if (dptr->numunits == 0) fprintf (st, "\n"); +else { + if (udbl && (ucnt == 0)) fprintf (st, ", all units disabled\n"); + else if (ucnt > 1) fprintf (st, ", %d units\n", ucnt); + else if (flag) fprintf (st, "\n"); + } +if (flag) return SCPE_OK; /* dev only? */ +for (j = 0; j < dptr->numunits; j++) { /* loop thru units */ + uptr = dptr->units + j; + if ((uptr->flags & UNIT_DIS) == 0) + show_unit (st, dptr, uptr, ucnt); + } +return SCPE_OK; +} + +t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag) +{ +int32 u = uptr - dptr->units; + +if (flag > 1) fprintf (st, " %s%d", sim_dname (dptr), u); +else if (flag < 0) fprintf (st, "%s%d", sim_dname (dptr), u); +if (uptr->flags & UNIT_FIX) { + fprintf (st, ", "); + fprint_capac (st, dptr, uptr); + } +if (uptr->flags & UNIT_ATT) { + fprintf (st, ", attached to %s", uptr->filename); + if (uptr->flags & UNIT_RO) fprintf (st, ", read only"); + } +else if (uptr->flags & UNIT_ATTABLE) + fprintf (st, ", not attached"); +show_all_mods (st, dptr, uptr, MTAB_VUN); /* show unit mods */ +fprintf (st, "\n"); +return SCPE_OK; +} + +void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr) +{ +t_addr kval = (uptr->flags & UNIT_BINK)? 1024: 1000; +t_addr mval = kval * kval; +t_addr psize = uptr->capac; +char scale, width; + +if ((dptr->dwidth / dptr->aincr) > 8) width = 'W'; +else width = 'B'; +if (uptr->capac < (kval * 10)) scale = 0; +else if (uptr->capac < (mval * 10)) { + scale = 'K'; + psize = psize / kval; + } +else { + scale = 'M'; + psize = psize / mval; + } +fprint_val (st, (t_value) psize, 10, T_ADDR_W, PV_LEFT); +if (scale) fputc (scale, st); +fputc (width, st); +return; +} + +/* Show processors */ + +t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH; + +if (cptr && (*cptr != 0)) return SCPE_2MARG; +fprintf (st, "%s simulator V%d.%d-%d", sim_name, vmaj, vmin, vpat); +if (flag) fprintf (st, " [%s, %s, %s]", sim_si64, sim_sa64, sim_snet); +fprintf (st, "\n"); +return SCPE_OK; +} + +t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr) +{ +int32 i; +DEVICE *dptr; + +if (cptr && (*cptr != 0)) return SCPE_2MARG; +fprintf (st, "%s simulator configuration\n\n", sim_name); +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) + show_device (st, dptr, flag); +return SCPE_OK; +} + +t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr) +{ +int32 i; +DEVICE *dptr; + +if (cptr && (*cptr != 0)) return SCPE_2MARG; +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) + show_dev_logicals (st, dptr, NULL, 1, cptr); +return SCPE_OK; +} + +t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (dptr->lname) fprintf (st, "%s -> %s\n", dptr->lname, dptr->name); +else if (!flag) fputs ("no logical name assigned\n", st); +return SCPE_OK; +} + +t_stat show_queue (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr) +{ +DEVICE *dptr; +UNIT *uptr; +int32 accum; + +if (cptr && (*cptr != 0)) return SCPE_2MARG; +if (sim_clock_queue == NULL) { + fprintf (st, "%s event queue empty, time = %.0f\n", + sim_name, sim_time); + return SCPE_OK; + } +fprintf (st, "%s event queue status, time = %.0f\n", + sim_name, sim_time); +accum = 0; +for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) { + if (uptr == &sim_step_unit) fprintf (st, " Step timer"); + else if ((dptr = find_dev_from_unit (uptr)) != NULL) { + fprintf (st, " %s", sim_dname (dptr)); + if (dptr->numunits > 1) fprintf (st, " unit %d", + (int32) (uptr - dptr->units)); + } + else fprintf (st, " Unknown"); + fprintf (st, " at %d\n", accum + uptr->time); + accum = accum + uptr->time; + } +return SCPE_OK; +} + +t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; +fprintf (st, "Time:\t%.0f\n", sim_time); +return SCPE_OK; +} + +t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +t_stat r; + +if (cptr && (*cptr != 0)) r = ssh_break (st, cptr, 1); /* more? */ +else r = sim_brk_showall (st, sim_switches); +return r; +} + +t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +fprintf (st, "Radix=%d\n", dptr->dradix); +return SCPE_OK; +} + +t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +int32 any = 0; +DEBTAB *dep; + +if (dptr->flags & DEV_DEBUG) { + if (dptr->dctrl == 0) fputs ("Debugging disabled", st); + else if (dptr->debflags == NULL) fputs ("Debugging enabled", st); + else { + fputs ("Debug=", st); + for (dep = dptr->debflags; dep->name != NULL; dep++) { + if (dptr->dctrl & dep->mask) { + if (any) fputc (';', st); + fputs (dep->name, st); + any = 1; + } + } + } + fputc ('\n', st); + return SCPE_OK; + } +else return SCPE_NOFNC; +} + +/* Show modifiers */ + +t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr) +{ +int32 i; +DEVICE *dptr; + +if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) + show_dev_modifiers (st, dptr, NULL, flag, cptr); +return SCPE_OK; +} + +t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +int any, enb; +MTAB *mptr; +DEBTAB *dep; + +any = enb = 0; +if (dptr->modifiers) { + for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { + if (mptr->mstring) { + if (strcmp (mptr->mstring, "ENABLED") == 0) enb = 1; + if (any++) fprintf (st, ", %s", mptr->mstring); + else fprintf (st, "%s\t%s", sim_dname (dptr), mptr->mstring); + } + } + } +if (dptr->flags & DEV_DEBUG) { + if (any++) fprintf (st, ", DEBUG, NODEBUG"); + else fprintf (st, "%s\tDEBUG, NODEBUG", sim_dname (dptr)); + } +if (!enb && (dptr->flags & DEV_DISABLE)) { + if (any++) fprintf (st, ", ENABLED, DISABLED"); + else fprintf (st, "%s\tENABLED, DISABLED", sim_dname (dptr)); + } +if (any) fprintf (st, "\n"); +if ((dptr->flags & DEV_DEBUG) && dptr->debflags) { + fprintf (st, "%s\tDEBUG=", sim_dname (dptr)); + for (dep = dptr->debflags; dep->name != NULL; dep++) + fprintf (st, "%s%s", ((dep == dptr->debflags) ? "" : ","), dep->name); + fprintf (st, "\n"); + } +return SCPE_OK; +} + +t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag) +{ +MTAB *mptr; + +if (dptr->modifiers == NULL) return SCPE_OK; +for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { + if (mptr->pstring && ((mptr->mask & MTAB_XTD)? + ((mptr->mask & flag) && !(mptr->mask & MTAB_NMO)): + ((MTAB_VUN & flag) && ((uptr->flags & mptr->mask) == mptr->match)))) { + fputs (", ", st); + show_one_mod (st, dptr, uptr, mptr, NULL, 0); + } + } +return SCPE_OK; +} + +t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, + char *cptr, int32 flag) +{ +t_value val; + +if (mptr->disp) mptr->disp (st, uptr, mptr->match, cptr? cptr: mptr->desc); +else if ((mptr->mask & MTAB_XTD) && (mptr->mask & MTAB_VAL)) { + REG *rptr = (REG *) mptr->desc; + fprintf (st, "%s=", mptr->pstring); + val = get_rval (rptr, 0); + fprint_val (st, val, rptr->radix, rptr->width, + rptr->flags & REG_FMT); + } +else fputs (mptr->pstring, st); +if (flag && !((mptr->mask & MTAB_XTD) && + (mptr->mask & MTAB_NMO))) fputc ('\n', st); +return SCPE_OK; +} + +/* Breakpoint commands */ + +t_stat brk_cmd (int32 flg, char *cptr) +{ +GET_SWITCHES (cptr); /* get switches */ +return ssh_break (NULL, cptr, flg); /* call common code */ +} + +t_stat ssh_break (FILE *st, char *cptr, int32 flg) +{ +char gbuf[CBUFSIZE], *tptr, *t1ptr, *aptr; +DEVICE *dptr = sim_dflt_dev; +UNIT *uptr = dptr->units; +t_stat r; +t_addr lo, hi, max = uptr->capac - 1; +int32 cnt; + +if (*cptr == 0) return SCPE_2FARG; +if (sim_brk_types == 0) return SCPE_NOFNC; +if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; +if (aptr = strchr (cptr, ';')) { /* ;action? */ + if (flg != SSH_ST) return SCPE_ARG; /* only on SET */ + *aptr++ = 0; /* separate strings */ + } +while (*cptr) { + cptr = get_glyph (cptr, gbuf, ','); + tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0); + if (tptr == NULL) return SCPE_ARG; + if (*tptr == '[') { + cnt = (int32) strtotv (tptr + 1, &t1ptr, 10); + if ((tptr == t1ptr) || (*t1ptr != ']') || + (flg != SSH_ST)) return SCPE_ARG; + tptr = t1ptr + 1; + } + else cnt = 0; + if (*tptr != 0) return SCPE_ARG; + if ((lo == 0) && (hi == max)) { + if (flg == SSH_CL) sim_brk_clrall (sim_switches); + else if (flg == SSH_SH) sim_brk_showall (st, sim_switches); + else return SCPE_ARG; + } + else { + for ( ; lo <= hi; lo = lo + 1) { + switch (flg) { + + case SSH_ST: + r = sim_brk_set (lo, sim_switches, cnt, aptr); + break; + + case SSH_CL: + r = sim_brk_clr (lo, sim_switches); + break; + + case SSH_SH: + r = sim_brk_show (st, lo, sim_switches); + break; + + default: + return SCPE_ARG; + } + + if (r != SCPE_OK) return r; + } + } + } +return SCPE_OK; +} + +/* Reset command and routines + + re[set] reset all devices + re[set] all reset all devices + re[set] device reset specific device +*/ + +t_stat reset_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEVICE *dptr; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return (reset_all (0)); /* reset(cr) */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +if (strcmp (gbuf, "ALL") == 0) return (reset_all (0)); +dptr = find_dev (gbuf); /* locate device */ +if (dptr == NULL) return SCPE_NXDEV; /* found it? */ +if (dptr->reset != NULL) return dptr->reset (dptr); +else return SCPE_OK; +} + +/* Reset devices start..end + + Inputs: + start = number of starting device + Outputs: + status = error status +*/ + +t_stat reset_all (uint32 start) +{ +DEVICE *dptr; +uint32 i; +t_stat reason; + +for (i = 0; i < start; i++) { + if (sim_devices[i] == NULL) return SCPE_IERR; + } +for (i = start; (dptr = sim_devices[i]) != NULL; i++) { + if (dptr->reset != NULL) { + reason = dptr->reset (dptr); + if (reason != SCPE_OK) return reason; + } + } +return SCPE_OK; +} + +/* Reset to powerup state + + Inputs: + start = number of starting device + Outputs: + status = error status +*/ + +t_stat reset_all_p (uint32 start) +{ +t_stat r; +int32 old_sw = sim_switches; + +sim_switches = SWMASK ('P'); +r = reset_all (start); +sim_switches = old_sw; +return r; +} + +/* Load and dump commands + + lo[ad] filename {arg} load specified file + du[mp] filename {arg} dump to specified file +*/ + +t_stat load_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +FILE *loadfile; +t_stat reason; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ +loadfile = sim_fopen (gbuf, flag? "wb": "rb"); /* open for wr/rd */ +if (loadfile == NULL) return SCPE_OPENERR; +GET_SWITCHES (cptr); /* get switches */ +reason = sim_load (loadfile, cptr, gbuf, flag); /* load or dump */ +fclose (loadfile); +return reason; +} + +/* Attach command + + at[tach] unit file attach specified unit to file +*/ + +t_stat attach_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEVICE *dptr; +UNIT *uptr; +t_stat r; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* now eol? */ +dptr = find_unit (gbuf, &uptr); /* locate unit */ +if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ +if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ +if (uptr->flags & UNIT_ATT) { /* already attached? */ + r = scp_detach_unit (dptr, uptr); /* detach it */ + if (r != SCPE_OK) return r; /* error? */ + } +sim_trim_endspc (cptr); /* trim trailing spc */ +return scp_attach_unit (dptr, uptr, cptr); /* attach */ +} + +/* Call device-specific or file-oriented attach unit routine */ + +t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, char *cptr) +{ +if (dptr->attach != NULL) /* device routine? */ + return dptr->attach (uptr, cptr); /* call it */ +return attach_unit (uptr, cptr); /* no, std routine */ +} + +/* Attach unit to file */ + +t_stat attach_unit (UNIT *uptr, char *cptr) +{ +DEVICE *dptr; + +if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ +if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOATT; /* not attachable? */ +if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; +if (dptr->flags & DEV_RAWONLY) return SCPE_NOFNC; /* raw mode only? */ +uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */ +if (uptr->filename == NULL) return SCPE_MEM; +strncpy (uptr->filename, cptr, CBUFSIZE); /* save name */ +if (sim_switches & SWMASK ('R')) { /* read only? */ + if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ + return attach_err (uptr, SCPE_NORO); /* no, error */ + uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */ + if (uptr->fileref == NULL) /* open fail? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ + if (!sim_quiet) printf ("%s: unit is read only\n", sim_dname (dptr)); + } +else { /* normal */ + uptr->fileref = sim_fopen (cptr, "rb+"); /* open r/w */ + if (uptr->fileref == NULL) { /* open fail? */ + if ((errno == EROFS) || (errno == EACCES)) { /* read only? */ + if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ + return attach_err (uptr, SCPE_NORO); /* no error */ + uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */ + if (uptr->fileref == NULL) /* open fail? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ + if (!sim_quiet) printf ("%s: unit is read only\n", sim_dname (dptr)); + } + else { /* doesn't exist */ + if (sim_switches & SWMASK ('E')) /* must exist? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + uptr->fileref = sim_fopen (cptr, "wb+"); /* open new file */ + if (uptr->fileref == NULL) /* open fail? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + if (!sim_quiet) printf ("%s: creating new file\n", sim_dname (dptr)); + } + } /* end if null */ + } /* end else */ +if (uptr->flags & UNIT_BUFABLE) { /* buffer? */ + uint32 cap = ((uint32) uptr->capac) / dptr->aincr; /* effective size */ + if (uptr->flags & UNIT_MUSTBUF) /* dyn alloc? */ + uptr->filebuf = calloc (cap, SZ_D (dptr)); /* allocate */ + if (uptr->filebuf == NULL) /* no buffer? */ + return attach_err (uptr, SCPE_MEM); /* error */ + if (!sim_quiet) printf ("%s: buffering file in memory\n", sim_dname (dptr)); + uptr->hwmark = sim_fread (uptr->filebuf, /* read file */ + SZ_D (dptr), cap, uptr->fileref); + uptr->flags = uptr->flags | UNIT_BUF; /* set buffered */ + } +uptr->flags = uptr->flags | UNIT_ATT; +uptr->pos = 0; +return SCPE_OK; +} + +t_stat attach_err (UNIT *uptr, t_stat stat) +{ +free (uptr->filename); +uptr->filename = NULL; +return stat; +} + +/* Detach command + + det[ach] all detach all units + det[ach] unit detach specified unit +*/ + +t_stat detach_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEVICE *dptr; +UNIT *uptr; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +if (strcmp (gbuf, "ALL") == 0) return (detach_all (0, FALSE)); +dptr = find_unit (gbuf, &uptr); /* locate unit */ +if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ +if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ +return scp_detach_unit (dptr, uptr); /* detach */ +} + +/* Detach devices start..end + + Inputs: + start = number of starting device + shutdown = TRUE if simulator shutting down + Outputs: + status = error status + + Note that during shutdown, detach routines for non-attachable devices + will be called. These routines can implement simulator shutdown. +*/ + +t_stat detach_all (int32 start, t_bool shutdown) +{ +uint32 i, j; +DEVICE *dptr; +UNIT *uptr; +t_stat r; + +if ((start < 0) || (start > 1)) return SCPE_IERR; +for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + for (j = 0; j < dptr->numunits; j++) { /* loop thru units */ + uptr = (dptr->units) + j; + if ((uptr->flags & UNIT_ATT) || /* attached? */ + (shutdown && dptr->detach && /* shutdown, spec rtn, */ + !(uptr->flags & UNIT_ATTABLE))) { /* !attachable? */ + r = scp_detach_unit (dptr, uptr); /* detach unit */ + if (r != SCPE_OK) return r; + } + } + } +return SCPE_OK; +} + +/* Call device-specific or file-oriented detach unit routine */ + +t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr) +{ +if (dptr->detach != NULL) return dptr->detach (uptr); /* device routine? */ +return detach_unit (uptr); /* no, standard */ +} + +/* Detach unit from file */ + +t_stat detach_unit (UNIT *uptr) +{ +DEVICE *dptr; + +if (uptr == NULL) return SCPE_IERR; +if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOATT; /* attachable? */ +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */ +if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK; +if (uptr->flags & UNIT_BUF) { + uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr; + if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { + if (!sim_quiet) printf ("%s: writing buffer to file\n", sim_dname (dptr)); + rewind (uptr->fileref); + sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref); + if (ferror (uptr->fileref)) perror ("I/O error"); + } + if (uptr->flags & UNIT_MUSTBUF) { /* dyn alloc? */ + free (uptr->filebuf); /* free buf */ + uptr->filebuf = NULL; + } + uptr->flags = uptr->flags & ~UNIT_BUF; + } +uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO); +free (uptr->filename); +uptr->filename = NULL; +if (fclose (uptr->fileref) == EOF) return SCPE_IOERR; +return SCPE_OK; +} + +/* Assign command + + as[sign] device name assign logical name to device +*/ + +t_stat assign_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEVICE *dptr; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* now eol? */ +dptr = find_dev (gbuf); /* locate device */ +if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +if (*cptr != 0) return SCPE_2MARG; /* must be eol */ +if (find_dev (gbuf)) return SCPE_ARG; /* name in use */ +deassign_device (dptr); /* release current */ +return assign_device (dptr, gbuf); +} + +t_stat assign_device (DEVICE *dptr, char *cptr) +{ +dptr->lname = (char *) calloc (CBUFSIZE, sizeof (char)); +if (dptr->lname == NULL) return SCPE_MEM; +strncpy (dptr->lname, cptr, CBUFSIZE); +return SCPE_OK; +} + +/* Deassign command + + dea[ssign] device deassign logical name +*/ + +t_stat deassign_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +DEVICE *dptr; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +dptr = find_dev (gbuf); /* locate device */ +if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ +return deassign_device (dptr); +} + +t_stat deassign_device (DEVICE *dptr) +{ +if (dptr->lname) free (dptr->lname); +dptr->lname = NULL; +return SCPE_OK; +} + +/* Get device display name */ + +char *sim_dname (DEVICE *dptr) +{ +return (dptr->lname? dptr->lname: dptr->name); +} + +/* Save command + + sa[ve] filename save state to specified file +*/ + +t_stat save_cmd (int32 flag, char *cptr) +{ +FILE *sfile; +t_stat r; +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +sim_trim_endspc (cptr); +if ((sfile = sim_fopen (cptr, "wb")) == NULL) return SCPE_OPENERR; +r = sim_save (sfile); +fclose (sfile); +return r; +} + +t_stat sim_save (FILE *sfile) +{ +void *mbuf; +int32 l, t; +uint32 i, j; +t_addr k, high; +t_value val; +t_stat r; +t_bool zeroflg; +size_t sz; +DEVICE *dptr; +UNIT *uptr; +REG *rptr; + +#define WRITE_I(xx) sim_fwrite (&(xx), sizeof (xx), 1, sfile) + +fprintf (sfile, "%s\n%s\n%s\n%s\n%s\n%.0f\n", + save_vercur, /* [V2.5] save format */ + sim_name, /* sim name */ + sim_si64, sim_sa64, sim_snet, /* [V3.5] options */ + sim_time); /* [V3.2] sim time */ +WRITE_I (sim_rtime); /* [V2.6] sim rel time */ + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */ + fputs (dptr->name, sfile); /* device name */ + fputc ('\n', sfile); + if (dptr->lname) fputs (dptr->lname, sfile); /* [V3.0] logical name */ + fputc ('\n', sfile); + WRITE_I (dptr->flags); /* [V2.10] flags */ + for (j = 0; j < dptr->numunits; j++) { + uptr = dptr->units + j; + t = sim_is_active (uptr); + WRITE_I (j); /* unit number */ + WRITE_I (t); /* activation time */ + WRITE_I (uptr->u3); /* unit specific */ + WRITE_I (uptr->u4); + WRITE_I (uptr->u5); /* [V3.0] more unit */ + WRITE_I (uptr->u6); + WRITE_I (uptr->flags); /* [V2.10] flags */ + WRITE_I (uptr->capac); /* [V3.5] capacity */ + if (uptr->flags & UNIT_ATT) fputs (uptr->filename, sfile); + fputc ('\n', sfile); + if (((uptr->flags & (UNIT_FIX + UNIT_ATTABLE)) == UNIT_FIX) && + (dptr->examine != NULL) && + ((high = uptr->capac) != 0)) { /* memory-like unit? */ + WRITE_I (high); /* [V2.5] write size */ + sz = SZ_D (dptr); + if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { + fclose (sfile); + return SCPE_MEM; + } + for (k = 0; k < high; ) { /* loop thru mem */ + zeroflg = TRUE; + for (l = 0; (l < SRBSIZ) && (k < high); l++, + k = k + (dptr->aincr)) { /* check for 0 block */ + r = dptr->examine (&val, k, uptr, SIM_SW_REST); + if (r != SCPE_OK) return r; + if (val) zeroflg = FALSE; + SZ_STORE (sz, val, mbuf, l); + } /* end for l */ + if (zeroflg) { /* all zero's? */ + l = -l; /* invert block count */ + WRITE_I (l); /* write only count */ + } + else { + WRITE_I (l); /* block count */ + sim_fwrite (mbuf, sz, l, sfile); + } + } /* end for k */ + free (mbuf); /* dealloc buffer */ + } /* end if mem */ + else { /* no memory */ + high = 0; /* write 0 */ + WRITE_I (high); + } /* end else mem */ + } /* end unit loop */ + t = -1; /* end units */ + WRITE_I (t); /* write marker */ + for (rptr = dptr->registers; (rptr != NULL) && /* loop thru regs */ + (rptr->name != NULL); rptr++) { + fputs (rptr->name, sfile); /* name */ + fputc ('\n', sfile); + WRITE_I (rptr->depth); /* [V2.10] depth */ + for (j = 0; j < rptr->depth; j++) { /* loop thru values */ + val = get_rval (rptr, j); /* get value */ + WRITE_I (val); /* store */ + } + } + fputc ('\n', sfile); /* end registers */ + } +fputc ('\n', sfile); /* end devices */ +return (ferror (sfile))? SCPE_IOERR: SCPE_OK; /* error during save? */ +} + +/* Restore command + + re[store] filename restore state from specified file +*/ + +t_stat restore_cmd (int32 flag, char *cptr) +{ +FILE *rfile; +t_stat r; + +GET_SWITCHES (cptr); /* get switches */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +sim_trim_endspc (cptr); +if ((rfile = sim_fopen (cptr, "rb")) == NULL) return SCPE_OPENERR; +r = sim_rest (rfile); +fclose (rfile); +return r; +} + +t_stat sim_rest (FILE *rfile) +{ +char buf[CBUFSIZE]; +void *mbuf; +int32 j, blkcnt, limit, unitno, time, flg; +uint32 us, depth; +t_addr k, high, old_capac; +t_value val, mask; +t_stat r; +size_t sz; +t_bool v35, v32; +DEVICE *dptr; +UNIT *uptr; +REG *rptr; + +#define READ_S(xx) if (read_line ((xx), CBUFSIZE, rfile) == NULL) \ + return SCPE_IOERR; +#define READ_I(xx) if (sim_fread (&xx, sizeof (xx), 1, rfile) == 0) \ + return SCPE_IOERR; + +READ_S (buf); /* [V2.5+] read version */ +v35 = v32 = FALSE; +if (strcmp (buf, save_vercur) == 0) v35 = v32 = TRUE; /* version 3.5? */ +else if (strcmp (buf, save_ver32) == 0) v32 = TRUE; /* version 3.2? */ +else if (strcmp (buf, save_ver30) != 0) { /* version 3.0? */ + printf ("Invalid file version: %s\n", buf); + return SCPE_INCOMP; + } +READ_S (buf); /* read sim name */ +if (strcmp (buf, sim_name)) { /* name match? */ + printf ("Wrong system type: %s\n", buf); + return SCPE_INCOMP; + } +if (v35) { /* [V3.5+] options */ + READ_S (buf); /* integer size */ + if (strcmp (buf, sim_si64) != 0) { + printf ("Incompatible integer size, save file = %s\n", buf); + return SCPE_INCOMP; + } + READ_S (buf); /* address size */ + if (strcmp (buf, sim_sa64) != 0) { + printf ("Incompatible address size, save file = %s\n", buf); + return SCPE_INCOMP; + } + READ_S (buf); /* Ethernet */ + } +if (v32) { /* [V3.2+] time as string */ + READ_S (buf); + sscanf (buf, "%lf", &sim_time); + } +else READ_I (sim_time); /* sim time */ +READ_I (sim_rtime); /* [V2.6+] sim rel time */ + +for ( ;; ) { /* device loop */ + READ_S (buf); /* read device name */ + if (buf[0] == 0) break; /* last? */ + if ((dptr = find_dev (buf)) == NULL) { /* locate device */ + printf ("Invalid device name: %s\n", buf); + return SCPE_INCOMP; + } + READ_S (buf); /* [V3.0+] logical name */ + deassign_device (dptr); /* delete old name */ + if ((buf[0] != 0) && + ((r = assign_device (dptr, buf)) != SCPE_OK)) return r; + READ_I (flg); /* [V2.10+] ctlr flags */ + if (!v32) flg = ((flg & DEV_UFMASK_31) << (DEV_V_UF - DEV_V_UF_31)) | + (flg & ~DEV_UFMASK_31); /* [V3.2+] flags moved */ + dptr->flags = (dptr->flags & ~DEV_RFLAGS) | /* restore ctlr flags */ + (flg & DEV_RFLAGS); + for ( ;; ) { /* unit loop */ + READ_I (unitno); /* unit number */ + if (unitno < 0) break; /* end units? */ + if ((uint32) unitno >= dptr->numunits) { /* too big? */ + printf ("Invalid unit number: %s%d\n", sim_dname (dptr), unitno); + return SCPE_INCOMP; + } + READ_I (time); /* event time */ + uptr = (dptr->units) + unitno; + sim_cancel (uptr); + if (time > 0) sim_activate (uptr, time - 1); + READ_I (uptr->u3); /* device specific */ + READ_I (uptr->u4); + READ_I (uptr->u5); /* [V3.0+] more dev spec */ + READ_I (uptr->u6); + READ_I (flg); /* [V2.10+] unit flags */ + old_capac = uptr->capac; /* save current capacity */ + if (v35) { /* [V3.5+] capacity */ + READ_I (uptr->capac); + } + if (!v32) flg = ((flg & UNIT_UFMASK_31) << (UNIT_V_UF - UNIT_V_UF_31)) | + (flg & ~UNIT_UFMASK_31); /* [V3.2+] flags moved */ + uptr->flags = (uptr->flags & ~UNIT_RFLAGS) | + (flg & UNIT_RFLAGS); /* restore */ + READ_S (buf); /* attached file */ + if ((uptr->flags & UNIT_ATTABLE) && /* if attachable and */ + (!(dptr->flags & DEV_NET) || /* not net dev or */ + !(uptr->flags & UNIT_ATT) || /* not currently att */ + (buf[0] == 0))) { /* or will not be att */ + sim_switches = SIM_SW_REST; /* att-det/rest */ + r = scp_detach_unit (dptr, uptr); /* detach old */ + if (r != SCPE_OK) return r; + if (buf[0] != 0) { /* any file? */ + uptr->flags = uptr->flags & ~UNIT_DIS; + if (flg & UNIT_RO) /* [V2.10+] saved flgs & RO? */ + sim_switches |= SWMASK ('R'); /* RO attach */ + r = scp_attach_unit (dptr, uptr, buf); + if (r != SCPE_OK) return r; + } + } + READ_I (high); /* memory capacity */ + if (high > 0) { /* [V2.5+] any memory? */ + if (((uptr->flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) || + (dptr->deposit == NULL)) { + printf ("Can't restore memory: %s%d\n", sim_dname (dptr), unitno); + return SCPE_INCOMP; + } + if (high != old_capac) { + if ((dptr->flags & DEV_DYNM) && + ((dptr->msize == NULL) || + (dptr->msize (uptr, (int32) high, NULL, NULL) != SCPE_OK))) { + printf ("Can't change memory size: %s%d\n", + sim_dname (dptr), unitno); + uptr->capac = old_capac; + return SCPE_INCOMP; + } + uptr->capac = high; + printf ("Memory size changed: %s%d = ", sim_dname (dptr), unitno); + fprint_capac (stdout, dptr, uptr); + printf ("\n"); + } + sz = SZ_D (dptr); /* allocate buffer */ + if ((mbuf = calloc (SRBSIZ, sz)) == NULL) + return SCPE_MEM; + for (k = 0; k < high; ) { /* loop thru mem */ + READ_I (blkcnt); /* block count */ + if (blkcnt < 0) limit = -blkcnt; /* compressed? */ + else limit = sim_fread (mbuf, sz, blkcnt, rfile); + if (limit <= 0) return SCPE_IOERR; /* invalid or err? */ + for (j = 0; j < limit; j++, k = k + (dptr->aincr)) { + if (blkcnt < 0) val = 0; /* compressed? */ + else SZ_LOAD (sz, val, mbuf, j); /* saved value */ + r = dptr->deposit (val, k, uptr, SIM_SW_REST); + if (r != SCPE_OK) return r; + } /* end for j */ + } /* end for k */ + free (mbuf); /* dealloc buffer */ + } /* end if high */ + } /* end unit loop */ + for ( ;; ) { /* register loop */ + READ_S (buf); /* read reg name */ + if (buf[0] == 0) break; /* last? */ + READ_I (depth); /* [V2.10+] depth */ + if ((rptr = find_reg (buf, NULL, dptr)) == NULL) { + printf ("Invalid register name: %s %s\n", sim_dname (dptr), buf); + for (us = 0; us < depth; us++) { /* skip values */ + READ_I (val); + } + continue; + } + if (depth != rptr->depth) /* [V2.10+] mismatch? */ + printf ("Register depth mismatch: %s %s, file = %d, sim = %d\n", + sim_dname (dptr), buf, depth, rptr->depth); + mask = width_mask[rptr->width]; /* get mask */ + for (us = 0; us < depth; us++) { /* loop thru values */ + READ_I (val); /* read value */ + if (val > mask) /* value ok? */ + printf ("Invalid register value: %s %s\n", sim_dname (dptr), buf); + else if (us < rptr->depth) /* in range? */ + put_rval (rptr, us, val); + } + } + } /* end device loop */ +return SCPE_OK; +} + +/* Run, go, cont, step commands + + ru[n] [new PC] reset and start simulation + go [new PC] start simulation + co[nt] start simulation + s[tep] [step limit] start simulation for 'limit' instructions + b[oot] device bootstrap from device and start simulation +*/ + +t_stat run_cmd (int32 flag, char *cptr) +{ +char *tptr, gbuf[CBUFSIZE]; +uint32 i, j; +int32 unitno; +t_value pcv; +t_stat r; +DEVICE *dptr; +UNIT *uptr; +void int_handler (int signal); + +GET_SWITCHES (cptr); /* get switches */ +sim_step = 0; +if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */ + if (*cptr != 0) { /* argument? */ + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + if (*cptr != 0) return SCPE_2MARG; /* should be end */ + if (sim_vm_parse_addr) /* address parser? */ + pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr); + else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */ + if ((tptr == gbuf) || (*tptr != 0) || /* error? */ + (pcv > width_mask[sim_PC->width])) return SCPE_ARG; + put_rval (sim_PC, 0, pcv); + } + if ((flag == RU_RUN) && /* run? */ + ((r = run_boot_prep ()) != SCPE_OK)) return r; /* reset sim */ + } + +else if (flag == RU_STEP) { /* step */ + if (*cptr != 0) { /* argument? */ + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + if (*cptr != 0) return SCPE_2MARG; /* should be end */ + sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r); + if ((r != SCPE_OK) || (sim_step <= 0)) /* error? */ + return SCPE_ARG; + } + else sim_step = 1; + } + +else if (flag == RU_BOOT) { /* boot */ + if (*cptr == 0) return SCPE_2FARG; /* must be more */ + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + if (*cptr != 0) return SCPE_2MARG; /* should be end */ + dptr = find_unit (gbuf, &uptr); /* locate unit */ + if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ + if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ + if (dptr->boot == NULL) return SCPE_NOFNC; /* can it boot? */ + if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ + if ((uptr->flags & UNIT_ATTABLE) && /* if attable, att? */ + !(uptr->flags & UNIT_ATT)) return SCPE_UNATT; + unitno = (int32) (uptr - dptr->units); /* recover unit# */ + if ((r = run_boot_prep ()) != SCPE_OK) return r; /* reset sim */ + if ((r = dptr->boot (unitno, dptr)) != SCPE_OK) /* boot device */ + return r; + } + +else if (flag != RU_CONT) return SCPE_IERR; /* must be cont */ + +for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* reposition all */ + for (j = 0; j < dptr->numunits; j++) { /* seq devices */ + uptr = dptr->units + j; + if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == + (UNIT_ATT + UNIT_SEQ)) + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); + } + } +stop_cpu = 0; +if (signal (SIGINT, int_handler) == SIG_ERR) { /* set WRU */ + return SCPE_SIGERR; + } +if (sim_ttrun () != SCPE_OK) { /* set console mode */ + sim_ttcmd (); + return SCPE_TTYERR; + } +if ((r = sim_check_console (30)) != SCPE_OK) { /* check console, error? */ + sim_ttcmd (); + return r; + } +if (sim_step) sim_activate (&sim_step_unit, sim_step); /* set step timer */ +sim_is_running = 1; /* flag running */ +sim_brk_clract (); /* defang actions */ +r = sim_instr(); + +sim_is_running = 0; /* flag idle */ +sim_ttcmd (); /* restore console */ +signal (SIGINT, SIG_DFL); /* cancel WRU */ +sim_cancel (&sim_step_unit); /* cancel step timer */ +if (sim_clock_queue != NULL) { /* update sim time */ + UPDATE_SIM_TIME (sim_clock_queue->time); + } +else { + UPDATE_SIM_TIME (noqueue_time); + } +if (sim_log) fflush (sim_log); /* flush console log */ +if (sim_deb) fflush (sim_deb); /* flush debug log */ +for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files */ + for (j = 0; j < dptr->numunits; j++) { /* if not buffered in mem */ + uptr = dptr->units + j; + if ((uptr->flags & UNIT_ATT) && /* attached, */ + !(uptr->flags & UNIT_BUF) && /* not buffered, */ + (uptr->fileref) && /* real file, */ + !(uptr->flags & UNIT_RAW) && /* not raw, */ + !(uptr->flags & UNIT_RO)) /* not read only? */ + fflush (uptr->fileref); + } + } +#if defined (VMS) +printf ("\n"); +#endif +fprint_stopped (stdout, r); /* print msg */ +if (sim_log) fprint_stopped (sim_log, r); /* log if enabled */ +return SCPE_OK; +} + +/* Common setup for RUN or BOOT */ + +t_stat run_boot_prep (void) +{ +sim_interval = 0; /* reset queue */ +sim_time = sim_rtime = 0; +noqueue_time = 0; +sim_clock_queue = NULL; +return reset_all_p (0); +} + +/* Print stopped message */ + +void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr) +{ +int32 i; +t_stat r = 0; +t_addr k; +t_value pcval; + +if (v >= SCPE_BASE) fprintf (st, "\n%s, %s: ", + scp_error_messages[v - SCPE_BASE], pc->name); +else fprintf (st, "\n%s, %s: ", sim_stop_messages[v], pc->name); +pcval = get_rval (pc, 0); +if (sim_vm_fprint_addr) sim_vm_fprint_addr (st, dptr, (t_addr) pcval); +else fprint_val (st, pcval, pc->radix, pc->width, + pc->flags & REG_FMT); +if ((dptr != NULL) && (dptr->examine != NULL)) { + for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; + for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) { + if ((r = dptr->examine (&sim_eval[i], k, dptr->units, + SWMASK ('V'))) != SCPE_OK) break; + } + if ((r == SCPE_OK) || (i > 0)) { + fprintf (st, " ("); + if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')|SIM_SW_STOP) > 0) + fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO); + fprintf (st, ")"); + } + } +fprintf (st, "\n"); +return; +} + +void fprint_stopped (FILE *st, t_stat v) +{ +fprint_stopped_gen (st, v, sim_PC, sim_dflt_dev); +return; +} + +/* Unit service for step timeout, originally scheduled by STEP n command + Return step timeout SCP code, will cause simulation to stop */ + +t_stat step_svc (UNIT *uptr) +{ +return SCPE_STEP; +} + +/* Cancel scheduled step service */ + +t_stat sim_cancel_step (void) +{ +return sim_cancel (&sim_step_unit); +} + +/* Signal handler for ^C signal - set stop simulation flag */ + +void int_handler (int sig) +{ +stop_cpu = 1; +return; +} + +/* Examine/deposit commands + + ex[amine] [modifiers] list examine + de[posit] [modifiers] list val deposit + ie[xamine] [modifiers] list interactive examine + id[eposit] [modifiers] list interactive deposit + + modifiers + @filename output file + -letter(s) switches + devname'n device name and unit number + [{&|^}value]{=|==|!|!=|>|>=|<|<=} value search specification + + list list of addresses and registers + addr[:addr|-addr] address range + ALL all addresses + register[:register|-register] register range + STATE all registers +*/ + +t_stat exdep_cmd (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE], *gptr, *tptr; +int32 opt; +t_addr low, high; +t_stat reason; +DEVICE *tdptr; +REG *lowr, *highr; +FILE *ofile; + +opt = CMD_OPT_SW|CMD_OPT_SCH|CMD_OPT_DFT; /* options for all */ +if (flag == EX_E) opt = opt | CMD_OPT_OF; /* extra for EX */ +cptr = get_sim_opt (opt, cptr, &reason); /* get cmd options */ +if (!cptr) return reason; /* error? */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ +if (sim_dfunit == NULL) return SCPE_NXUN; /* got a unit? */ +cptr = get_glyph (cptr, gbuf, 0); /* get list */ +if ((flag == EX_D) && (*cptr == 0)) return SCPE_2FARG; /* deposit needs more */ +ofile = sim_ofile? sim_ofile: stdout; /* no ofile? use stdout */ + +for (gptr = gbuf, reason = SCPE_OK; + (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) { + tdptr = sim_dfdev; /* working dptr */ + if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) { + tptr = gptr + strlen ("STATE"); + if (*tptr && (*tptr++ != ',')) return SCPE_ARG; + if ((lowr = sim_dfdev->registers) == NULL) return SCPE_NXREG; + for (highr = lowr; highr->name != NULL; highr++) ; + sim_switches = sim_switches | SIM_SW_HIDE; + reason = exdep_reg_loop (ofile, sim_schptr, flag, cptr, + lowr, --highr, 0, 0); + continue; + } + + if ((lowr = find_reg (gptr, &tptr, tdptr)) || + (lowr = find_reg_glob (gptr, &tptr, &tdptr))) { + low = high = 0; + if ((*tptr == '-') || (*tptr == ':')) { + highr = find_reg (tptr + 1, &tptr, tdptr); + if (highr == NULL) return SCPE_NXREG; + } + else { + highr = lowr; + if (*tptr == '[') { + if (lowr->depth <= 1) return SCPE_ARG; + tptr = get_range (NULL, tptr + 1, &low, &high, + 10, lowr->depth - 1, ']'); + if (tptr == NULL) return SCPE_ARG; + } + } + if (*tptr && (*tptr++ != ',')) return SCPE_ARG; + reason = exdep_reg_loop (ofile, sim_schptr, flag, cptr, + lowr, highr, (uint32) low, (uint32) high); + continue; + } + + tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix, + (((sim_dfunit->capac == 0) || (flag == EX_E))? 0: + sim_dfunit->capac - sim_dfdev->aincr), 0); + if (tptr == NULL) return SCPE_ARG; + if (*tptr && (*tptr++ != ',')) return SCPE_ARG; + reason = exdep_addr_loop (ofile, sim_schptr, flag, cptr, low, high, + sim_dfdev, sim_dfunit); + } /* end for */ +if (sim_ofile) fclose (sim_ofile); /* close output file */ +return reason; +} + +/* Loop controllers for examine/deposit + + exdep_reg_loop examine/deposit range of registers + exdep_addr_loop examine/deposit range of addresses +*/ + +t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, + REG *lowr, REG *highr, uint32 lows, uint32 highs) +{ +t_stat reason; +uint32 idx; +t_value val; +REG *rptr; + +if ((lowr == NULL) || (highr == NULL)) return SCPE_IERR; +if (lowr > highr) return SCPE_ARG; +for (rptr = lowr; rptr <= highr; rptr++) { + if ((sim_switches & SIM_SW_HIDE) && + (rptr->flags & REG_HIDDEN)) continue; + for (idx = lows; idx <= highs; idx++) { + if (idx >= rptr->depth) return SCPE_SUB; + val = get_rval (rptr, idx); + if (schptr && !test_search (val, schptr)) continue; + if (flag != EX_D) { + reason = ex_reg (ofile, val, flag, rptr, idx); + if (reason != SCPE_OK) return reason; + if (sim_log && (ofile == stdout)) + ex_reg (sim_log, val, flag, rptr, idx); + } + if (flag != EX_E) { + reason = dep_reg (flag, cptr, rptr, idx); + if (reason != SCPE_OK) return reason; + } + } + } +return SCPE_OK; +} + +t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, + t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr) +{ +t_addr i, mask; +t_stat reason; + +if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ +mask = (t_addr) width_mask[dptr->awidth]; +if ((low > mask) || (high > mask) || (low > high)) return SCPE_ARG; +for (i = low; i <= high; ) { /* all paths must incr!! */ + reason = get_aval (i, dptr, uptr); /* get data */ + if (reason != SCPE_OK) return reason; /* return if error */ + if (schptr && !test_search (sim_eval[0], schptr)) + i = i + dptr->aincr; /* sch fails, incr */ + else { /* no sch or success */ + if (flag != EX_D) { /* ex, ie, or id? */ + reason = ex_addr (ofile, flag, i, dptr, uptr); + if (reason > SCPE_OK) return reason; + if (sim_log && (ofile == stdout)) + ex_addr (sim_log, flag, i, dptr, uptr); + } + else reason = 1 - dptr->aincr; /* no, dflt incr */ + if (flag != EX_E) { /* ie, id, or d? */ + reason = dep_addr (flag, cptr, i, dptr, uptr, reason); + if (reason > SCPE_OK) return reason; + } + i = i + (1 - reason); /* incr */ + } + } +return SCPE_OK; +} + +/* Examine register routine + + Inputs: + ofile = output stream + val = current register value + flag = type of ex/mod command (ex, iex, idep) + rptr = pointer to register descriptor + idx = index + Outputs: + return = error status +*/ + +t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx) +{ +int32 rdx; + +if (rptr == NULL) return SCPE_IERR; +if (rptr->depth > 1) fprintf (ofile, "%s[%d]:\t", rptr->name, idx); +else fprintf (ofile, "%s:\t", rptr->name); +if (!(flag & EX_E)) return SCPE_OK; +GET_RADIX (rdx, rptr->radix); +if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr) + sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val); +else if (!(rptr->flags & REG_VMIO) || + (fprint_sym (ofile, rdx, &val, NULL, sim_switches | SIM_SW_REG) > 0)) + fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT); +if (flag & EX_I) fprintf (ofile, "\t"); +else fprintf (ofile, "\n"); +return SCPE_OK; +} + +/* Get register value + + Inputs: + rptr = pointer to register descriptor + idx = index + Outputs: + return = register value +*/ + +t_value get_rval (REG *rptr, uint32 idx) +{ +size_t sz; +t_value val; +UNIT *uptr; + +sz = SZ_R (rptr); +if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { + idx = idx + rptr->qptr; + if (idx >= rptr->depth) idx = idx - rptr->depth; + } +if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) { + uptr = ((UNIT *) rptr->loc) + idx; +#if defined (USE_INT64) + if (sz <= sizeof (uint32)) val = *((uint32 *) uptr); + else val = *((t_uint64 *) uptr); +#else + val = *((uint32 *) uptr); +#endif + } +else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) && + (sz == sizeof (uint8))) + val = *(((uint8 *) rptr->loc) + idx); +else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) && + (sz == sizeof (uint16))) + val = *(((uint16 *) rptr->loc) + idx); +#if defined (USE_INT64) +else if (sz <= sizeof (uint32)) + val = *(((uint32 *) rptr->loc) + idx); +else val = *(((t_uint64 *) rptr->loc) + idx); +#else +else val = *(((uint32 *) rptr->loc) + idx); +#endif +val = (val >> rptr->offset) & width_mask[rptr->width]; +return val; +} + +/* Deposit register routine + + Inputs: + flag = type of deposit (normal/interactive) + cptr = pointer to input string + rptr = pointer to register descriptor + idx = index + Outputs: + return = error status +*/ + +t_stat dep_reg (int32 flag, char *cptr, REG *rptr, uint32 idx) +{ +t_stat r; +t_value val, mask; +int32 rdx; +char *tptr, gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (rptr == NULL)) return SCPE_IERR; +if (rptr->flags & REG_RO) return SCPE_RO; +if (flag & EX_I) { + cptr = read_line (gbuf, CBUFSIZE, stdin); + if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); + if (cptr == NULL) return 1; /* force exit */ + if (*cptr == 0) return SCPE_OK; /* success */ + } +mask = width_mask[rptr->width]; +GET_RADIX (rdx, rptr->radix); +if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr) { /* address form? */ + val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr); + if ((tptr == cptr) || (*tptr != 0) || + (val > mask)) return SCPE_ARG; + } +else if (!(rptr->flags & REG_VMIO) || /* dont use sym? */ + (parse_sym (cptr, rdx, NULL, &val, sim_switches | SIM_SW_REG) > SCPE_OK)) { + val = get_uint (cptr, rdx, mask, &r); + if (r != SCPE_OK) return SCPE_ARG; + } +if ((rptr->flags & REG_NZ) && (val == 0)) return SCPE_ARG; +put_rval (rptr, idx, val); +return SCPE_OK; +} + +/* Put register value + + Inputs: + rptr = pointer to register descriptor + idx = index + val = new value + mask = mask + Outputs: + none +*/ + +void put_rval (REG *rptr, uint32 idx, t_value val) +{ +size_t sz; +t_value mask; +UNIT *uptr; + +#define PUT_RVAL(sz,rp,id,v,m) \ + *(((sz *) rp->loc) + id) = \ + (*(((sz *) rp->loc) + id) & \ + ~((m) << (rp)->offset)) | ((v) << (rp)->offset) + +if (rptr == sim_PC) sim_brk_npc (0); +sz = SZ_R (rptr); +mask = width_mask[rptr->width]; +if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { + idx = idx + rptr->qptr; + if (idx >= rptr->depth) idx = idx - rptr->depth; + } +if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) { + uptr = ((UNIT *) rptr->loc) + idx; +#if defined (USE_INT64) + if (sz <= sizeof (uint32)) + *((uint32 *) uptr) = (*((uint32 *) uptr) & + ~(((uint32) mask) << rptr->offset)) | + (((uint32) val) << rptr->offset); + else *((t_uint64 *) uptr) = (*((t_uint64 *) uptr) + & ~(mask << rptr->offset)) | (val << rptr->offset); +#else + *((uint32 *) uptr) = (*((uint32 *) uptr) & + ~(((uint32) mask) << rptr->offset)) | + (((uint32) val) << rptr->offset); +#endif + } +else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) && + (sz == sizeof (uint8))) + PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask); +else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) && + (sz == sizeof (uint16))) + PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask); +#if defined (USE_INT64) +else if (sz <= sizeof (uint32)) + PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask); +else PUT_RVAL (t_uint64, rptr, idx, val, mask); +#else +else PUT_RVAL (uint32, rptr, idx, val, mask); +#endif +return; +} + +/* Examine address routine + + Inputs: (sim_eval is an implicit argument) + ofile = output stream + flag = type of ex/mod command (ex, iex, idep) + addr = address to examine + dptr = pointer to device + uptr = pointer to unit + Outputs: + return = if > 0, error status + if <= 0,-number of extra addr units retired +*/ + +t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr) +{ +t_stat reason; +int32 rdx; + +if (sim_vm_fprint_addr) sim_vm_fprint_addr (ofile, dptr, addr); +else fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT); +fprintf (ofile, ":\t"); +if (!(flag & EX_E)) return (1 - dptr->aincr); + +GET_RADIX (rdx, dptr->dradix); +if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) { + fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO); + reason = 1 - dptr->aincr; + } +if (flag & EX_I) fprintf (ofile, "\t"); +else fprintf (ofile, "\n"); +return reason; +} + +/* Get address routine + + Inputs: + flag = type of ex/mod command (ex, iex, idep) + addr = address to examine + dptr = pointer to device + uptr = pointer to unit + Outputs: (sim_eval is an implicit output) + return = error status +*/ + +t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr) +{ +int32 i; +t_value mask; +t_addr j, loc; +size_t sz; +t_stat reason = SCPE_OK; + +if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; +mask = width_mask[dptr->dwidth]; +for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; +for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) { + if (dptr->examine != NULL) { + reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches); + if (reason != SCPE_OK) break; + } + else { + if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT; + if (uptr->flags & UNIT_RAW) return SCPE_NOFNC; + if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) { + reason = SCPE_NXM; + break; + } + sz = SZ_D (dptr); + loc = j / dptr->aincr; + if (uptr->flags & UNIT_BUF) { + SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc); + } + else { + sim_fseek (uptr->fileref, sz * loc, SEEK_SET); + sim_fread (&sim_eval[i], sz, 1, uptr->fileref); + if ((feof (uptr->fileref)) && + !(uptr->flags & UNIT_FIX)) { + reason = SCPE_EOF; + break; + } + else if (ferror (uptr->fileref)) { + clearerr (uptr->fileref); + reason = SCPE_IOERR; + break; + } + } + } + sim_eval[i] = sim_eval[i] & mask; + } +if ((reason != SCPE_OK) && (i == 0)) return reason; +return SCPE_OK; +} + +/* Deposit address routine + + Inputs: + flag = type of deposit (normal/interactive) + cptr = pointer to input string + addr = address to examine + dptr = pointer to device + uptr = pointer to unit + dfltinc = value to return on cr input + Outputs: + return = if > 0, error status + if <= 0, -number of extra address units retired +*/ + +t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr, + UNIT *uptr, int32 dfltinc) +{ +int32 i, count, rdx; +t_addr j, loc; +t_stat r, reason; +t_value mask; +size_t sz; +char gbuf[CBUFSIZE]; + +if (dptr == NULL) return SCPE_IERR; +if (flag & EX_I) { + cptr = read_line (gbuf, CBUFSIZE, stdin); + if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); + if (cptr == NULL) return 1; /* force exit */ + if (*cptr == 0) return dfltinc; /* success */ + } +if (uptr->flags & UNIT_RO) return SCPE_RO; /* read only? */ +mask = width_mask[dptr->dwidth]; + +GET_RADIX (rdx, dptr->dradix); +if ((reason = parse_sym (cptr, addr, uptr, sim_eval, sim_switches)) > 0) { + sim_eval[0] = get_uint (cptr, rdx, mask, &reason); + if (reason != SCPE_OK) return reason; + } +count = (1 - reason + (dptr->aincr - 1)) / dptr->aincr; + +for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) { + sim_eval[i] = sim_eval[i] & mask; + if (dptr->deposit != NULL) { + r = dptr->deposit (sim_eval[i], j, uptr, sim_switches); + if (r != SCPE_OK) return r; + } + else { + if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT; + if (uptr->flags & UNIT_RAW) return SCPE_NOFNC; + if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) + return SCPE_NXM; + sz = SZ_D (dptr); + loc = j / dptr->aincr; + if (uptr->flags & UNIT_BUF) { + SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc); + if (loc >= uptr->hwmark) uptr->hwmark = (uint32) loc + 1; + } + else { + sim_fseek (uptr->fileref, sz * loc, SEEK_SET); + sim_fwrite (&sim_eval[i], sz, 1, uptr->fileref); + if (ferror (uptr->fileref)) { + clearerr (uptr->fileref); + return SCPE_IOERR; + } + } + } + } +return reason; +} + +/* Evaluate command */ + +t_stat eval_cmd (int32 flg, char *cptr) +{ +DEVICE *dptr = sim_dflt_dev; +int32 i, rdx, a, lim; +t_stat r; + +GET_SWITCHES (cptr); +GET_RADIX (rdx, dptr->dradix); +for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; +if (*cptr == 0) return SCPE_2FARG; +if ((r = parse_sym (cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) { + sim_eval[0] = get_uint (cptr, rdx, width_mask[dptr->dwidth], &r); + if (r != SCPE_OK) return r; + } +lim = 1 - r; +for (i = a = 0; a < lim; ) { + printf ("%d:\t", a); + if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0) + r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO); + printf ("\n"); + if (sim_log) { + fprintf (sim_log, "%d\t", i); + if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0) + r = fprint_val (sim_log, sim_eval[i], rdx, dptr->dwidth, PV_RZRO); + fprintf (sim_log, "\n"); + } + if (r < 0) a = a + 1 - r; + else a = a + dptr->aincr; + i = a / dptr->aincr; + } +return SCPE_OK; +} + +/* String processing routines + + read_line read line + + Inputs: + cptr = pointer to buffer + size = maximum size + stream = pointer to input stream + Outputs: + optr = pointer to first non-blank character + NULL if EOF +*/ + +char *read_line (char *cptr, int32 size, FILE *stream) +{ +char *tptr; + +#if !defined (HAVE_READLINE) +cptr = fgets (cptr, size, stream); /* get cmd line */ + +#else +if (stream != stdin) cptr = fgets (cptr, size, stream); +else { + char *tmpc = readline (NULL); + if (tmpc == NULL) cptr = NULL; + else { + strncpy (cptr, tmpc, size); + free (tmpc); + } + } +#endif + +if (cptr == NULL) { + clearerr (stream); /* clear error */ + return NULL; /* ignore EOF */ + } +for (tptr = cptr; tptr < (cptr + size); tptr++) { /* remove cr or nl */ + if ((*tptr == '\n') || (*tptr == '\r') || + (tptr == (cptr + size - 1))) { /* str max length? */ + *tptr = 0; /* terminate */ + break; + } + } +while (isspace (*cptr)) cptr++; /* trim leading spc */ +if (*cptr == ';') *cptr = 0; /* ignore comment */ + +#if defined (HAVE_READLINE) +add_history (cptr); + +#endif +return cptr; +} + +/* get_glyph get next glyph (force upper case) + get_glyph_nc get next glyph (no conversion) + get_glyph_gen get next glyph (general case) + + Inputs: + iptr = pointer to input string + optr = pointer to output string + mchar = optional end of glyph character + flag = TRUE for convert to upper case (_gen only) + Outputs + result = pointer to next character in input string +*/ + +char *get_glyph_gen (char *iptr, char *optr, char mchar, t_bool uc) +{ +while ((isspace (*iptr) == 0) && (*iptr != 0) && (*iptr != mchar)) { + if (islower (*iptr) && uc) *optr = toupper (*iptr); + else *optr = *iptr; + iptr++; optr++; + } +*optr = 0; +if (mchar && (*iptr == mchar)) iptr++; /* skip terminator */ +while (isspace (*iptr)) iptr++; /* absorb spaces */ +return iptr; +} + +char *get_glyph (char *iptr, char *optr, char mchar) +{ +return get_glyph_gen (iptr, optr, mchar, TRUE); +} + +char *get_glyph_nc (char *iptr, char *optr, char mchar) +{ +return get_glyph_gen (iptr, optr, mchar, FALSE); +} + +/* Trim trailing spaces from a string + + Inputs: + cptr = pointer to string + Outputs: + cptr = pointer to string +*/ + +char *sim_trim_endspc (char *cptr) +{ +char *tptr; + +tptr = cptr + strlen (cptr); +while ((--tptr >= cptr) && isspace (*tptr)) *tptr = 0; +return cptr; +} + +/* get_yn yes/no question + + Inputs: + cptr = pointer to question + deflt = default answer + Outputs: + result = true if yes, false if no +*/ + +t_stat get_yn (char *ques, t_stat deflt) +{ +char cbuf[CBUFSIZE], *cptr; + +printf ("%s ", ques); +cptr = read_line (cbuf, CBUFSIZE, stdin); +if ((cptr == NULL) || (*cptr == 0)) return deflt; +if ((*cptr == 'Y') || (*cptr == 'y')) return TRUE; +return FALSE; +} + +/* get_uint unsigned number + + Inputs: + cptr = pointer to input string + radix = input radix + max = maximum acceptable value + *status = pointer to error status + Outputs: + val = value +*/ + +t_value get_uint (char *cptr, uint32 radix, t_value max, t_stat *status) +{ +t_value val; +char *tptr; + +*status = SCPE_OK; +val = strtotv (cptr, &tptr, radix); +if ((cptr == tptr) || (val > max)) *status = SCPE_ARG; +else { + while (isspace (*tptr)) tptr++; + if (*tptr != 0) *status = SCPE_ARG; + } +return val; +} + +/* get_range range specification + + Inputs: + dptr = pointer to device (NULL if none) + cptr = pointer to input string + *lo = pointer to low result + *hi = pointer to high result + aradix = radix + max = default high value + term = terminating character, 0 if none + Outputs: + tptr = input pointer after processing + NULL if error +*/ + +char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi, + uint32 rdx, t_addr max, char term) +{ +char *tptr; + +if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) { /* ALL? */ + tptr = cptr + strlen ("ALL"); + *lo = 0; + *hi = max; + } +else { + if (dptr && sim_vm_parse_addr) /* get low */ + *lo = sim_vm_parse_addr (dptr, cptr, &tptr); + else *lo = (t_addr) strtotv (cptr, &tptr, rdx); + if (cptr == tptr) return NULL; /* error? */ + if ((*tptr == '-') || (*tptr == ':')) { /* range? */ + cptr = tptr + 1; + if (dptr && sim_vm_parse_addr) /* get high */ + *hi = sim_vm_parse_addr (dptr, cptr, &tptr); + else *hi = (t_addr) strtotv (cptr, &tptr, rdx); + if (cptr == tptr) return NULL; + if (*lo > *hi) return NULL; + } + else if (*tptr == '/') { /* relative? */ + cptr = tptr + 1; + *hi = (t_addr) strtotv (cptr, &tptr, rdx); /* get high */ + if ((cptr == tptr) || (*hi == 0)) return NULL; + *hi = *lo + *hi - 1; + } + else *hi = *lo; + } +if (term && (*tptr++ != term)) return NULL; +return tptr; +} + +/* get_ipaddr IP address:port + + Inputs: + cptr = pointer to input string + Outputs: + ipa = pointer to IP address (may be NULL), 0 = none + ipp = pointer to IP port (may be NULL) + result = status +*/ + +t_stat get_ipaddr (char *cptr, uint32 *ipa, uint32 *ipp) +{ +char gbuf[CBUFSIZE]; +char *addrp, *portp, *octetp; +uint32 i, addr, port, octet; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0) || (ipa == NULL) || (ipp == NULL)) + return SCPE_ARG; +strncpy (gbuf, cptr, CBUFSIZE); +addrp = gbuf; /* default addr */ +if (portp = strchr (gbuf, ':')) *portp++ = '.'; /* x:y? */ +else if (strchr (gbuf, '.')) portp = NULL; /* x.y...? */ +else { + portp = gbuf; /* port only */ + addrp = NULL; /* x is port */ + } +if (portp) { /* port string? */ + port = (int32) get_uint (portp, 10, 65535, &r); + if ((r != SCPE_OK) || (port == 0)) return SCPE_ARG; + *ipp = port; + } +else *ipp = 0; +if (addrp) { + for (i = addr = 0; i < 4; i++) { + octetp = strchr (addrp, '.'); + if (octetp == NULL) return SCPE_ARG; + *octetp++ = 0; + octet = (int32) get_uint (addrp, 10, 255, &r); + if (r != SCPE_OK) return SCPE_ARG; + addr = (addr << 8) | octet; + addrp = octetp; + } + if (((addr & 0377) == 0) || ((addr & 0377) == 255)) + return SCPE_ARG; + *ipa = addr; + } +else *ipa = 0; +return SCPE_OK; +} + +/* Find_device find device matching input string + + Inputs: + cptr = pointer to input string + Outputs: + result = pointer to device +*/ + +DEVICE *find_dev (char *cptr) +{ +int32 i; +DEVICE *dptr; + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + if ((strcmp (cptr, dptr->name) == 0) || + (dptr->lname && + (strcmp (cptr, dptr->lname) == 0))) return dptr; + } +return NULL; +} + +/* Find_unit find unit matching input string + + Inputs: + cptr = pointer to input string + uptr = pointer to unit pointer + Outputs: + result = pointer to device (null if no dev) + *iptr = pointer to unit (null if nx unit) +*/ + +DEVICE *find_unit (char *cptr, UNIT **uptr) +{ +uint32 i, u; +char *nptr, *tptr; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) return NULL; /* arg error? */ +if (dptr = find_dev (cptr)) { /* exact match? */ + if (qdisable (dptr)) return NULL; /* disabled? */ + *uptr = dptr->units; /* unit 0 */ + return dptr; + } + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */ + if (dptr->numunits && /* any units? */ + (((nptr = dptr->name) && + (strncmp (cptr, nptr, strlen (nptr)) == 0)) || + ((nptr = dptr->lname) && + (strncmp (cptr, nptr, strlen (nptr)) == 0)))) { + tptr = cptr + strlen (nptr); + if (isdigit (*tptr)) { + if (qdisable (dptr)) return NULL; /* disabled? */ + u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r); + if (r != SCPE_OK) *uptr = NULL; /* error? */ + else *uptr = dptr->units + u; + return dptr; + } + } + } +return NULL; +} + +/* Find_dev_from_unit find device for unit + + Inputs: + uptr = pointer to unit + Outputs: + result = pointer to device +*/ + +DEVICE *find_dev_from_unit (UNIT *uptr) +{ +DEVICE *dptr; +uint32 i, j; + +if (uptr == NULL) return NULL; +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + for (j = 0; j < dptr->numunits; j++) { + if (uptr == (dptr->units + j)) return dptr; + } + } +return NULL; +} + +/* Test for disabled device */ + +t_bool qdisable (DEVICE *dptr) +{ +return (dptr->flags & DEV_DIS? TRUE: FALSE); +} + +/* find_reg_glob find globally unique register + + Inputs: + cptr = pointer to input string + optr = pointer to output pointer (can be null) + gdptr = pointer to global device + Outputs: + result = pointer to register, NULL if error + *optr = pointer to next character in input string + *gdptr = pointer to device where found +*/ + +REG *find_reg_glob (char *cptr, char **optr, DEVICE **gdptr) +{ +int32 i; +DEVICE *dptr; +REG *rptr, *srptr = NULL; + +for (i = 0; (dptr = sim_devices[i]) != 0; i++) { /* all dev */ + if (dptr->flags & DEV_DIS) continue; /* skip disabled */ + if (rptr = find_reg (cptr, optr, dptr)) { /* found? */ + if (srptr) return NULL; /* ambig? err */ + srptr = rptr; /* save reg */ + *gdptr = dptr; /* save unit */ + } + } +return srptr; +} + +/* find_reg find register matching input string + + Inputs: + cptr = pointer to input string + optr = pointer to output pointer (can be null) + dptr = pointer to device + Outputs: + result = pointer to register, NULL if error + *optr = pointer to next character in input string +*/ + +REG *find_reg (char *cptr, char **optr, DEVICE *dptr) +{ +char *tptr; +REG *rptr; +uint32 slnt; + +if ((cptr == NULL) || (dptr == NULL) || + (dptr->registers == NULL)) return NULL; +tptr = cptr; +do { + tptr++; + } while (isalnum (*tptr) || (*tptr == '*') || (*tptr == '_')); +slnt = tptr - cptr; +for (rptr = dptr->registers; rptr->name != NULL; rptr++) { + if ((slnt == strlen (rptr->name)) && + (strncmp (cptr, rptr->name, slnt) == 0)) { + if (optr != NULL) *optr = tptr; + return rptr; + } + } +return NULL; +} + +/* get_switches get switches from input string + + Inputs: + cptr = pointer to input string + Outputs: + sw = switch bit mask + 0 if no switches, -1 if error +*/ + +int32 get_switches (char *cptr) +{ +int32 sw; + +if (*cptr != '-') return 0; +sw = 0; +for (cptr++; (isspace (*cptr) == 0) && (*cptr != 0); cptr++) { + if (isalpha (*cptr) == 0) return -1; + sw = sw | SWMASK (toupper (*cptr)); + } +return sw; +} + +/* get_sim_sw accumulate sim_switches + + Inputs: + cptr = pointer to input string + Outputs: + ptr = pointer to first non-string glyph + NULL if error +*/ + +char *get_sim_sw (char *cptr) +{ +int32 lsw; +char gbuf[CBUFSIZE]; + +while (*cptr == '-') { /* while switches */ + cptr = get_glyph (cptr, gbuf, 0); /* get switch glyph */ + lsw = get_switches (gbuf); /* parse */ + if (lsw <= 0) return NULL; /* invalid? */ + sim_switches = sim_switches | lsw; /* accumulate */ + } +return cptr; +} + +/* get_sim_opt get simulator command options + + Inputs: + opt = command options + cptr = pointer to input string + Outputs: + ptr = pointer to next glypsh, NULL if error + *stat = error status +*/ + +char *get_sim_opt (int32 opt, char *cptr, t_stat *st) +{ +int32 t; +char *svptr, gbuf[CBUFSIZE]; +DEVICE *tdptr; +UNIT *tuptr; + +sim_switches = 0; /* no switches */ +sim_ofile = NULL; /* no output file */ +sim_schptr = NULL; /* no search */ +sim_stab.logic = SCH_OR; /* default search params */ +sim_stab.boolop = SCH_GE; +sim_stab.mask = 0; +sim_stab.comp = 0; +sim_dfdev = sim_dflt_dev; +sim_dfunit = sim_dfdev->units; +*st = SCPE_OK; +while (*cptr) { /* loop through modifiers */ + svptr = cptr; /* save current position */ + if ((opt & CMD_OPT_OF) && (*cptr == '@')) { /* output file spec? */ + if (sim_ofile) { /* already got one? */ + fclose (sim_ofile); /* one per customer */ + *st = SCPE_ARG; + return NULL; + } + cptr = get_glyph_nc (cptr + 1, gbuf, 0); + sim_ofile = sim_fopen (gbuf, "a"); /* open for append */ + if (sim_ofile) continue; /* if ok, look for more */ + *st = SCPE_OPENERR; /* open failed */ + return NULL; + } + cptr = get_glyph (cptr, gbuf, 0); + if ((t = get_switches (gbuf)) != 0) { /* try for switches */ + if (t < 0) { /* err if bad switch */ + *st = SCPE_INVSW; + return NULL; + } + sim_switches = sim_switches | t; /* or in new switches */ + } + else if ((opt & CMD_OPT_SCH) && /* if allowed, */ + get_search (gbuf, sim_dfdev->dradix, &sim_stab)) /* try for search */ + sim_schptr = &sim_stab; /* set search */ + else if ((opt & CMD_OPT_DFT) && /* if allowed, */ + (tdptr = find_unit (gbuf, &tuptr)) && /* try for default */ + (tuptr != NULL)) { + sim_dfdev = tdptr; /* set as default */ + sim_dfunit = tuptr; + } + else return svptr; /* not rec, break out */ + } +return cptr; +} + +/* Match file extension + + Inputs: + fnam = file name + ext = extension, without period + Outputs: + cp = pointer to final '.' if match, NULL if not +*/ + +char *match_ext (char *fnam, char *ext) +{ +char *pptr, *fptr, *eptr; + +if ((fnam == NULL) || (ext == NULL)) return NULL; +pptr = strrchr (fnam, '.'); +if (pptr) { + for (fptr = pptr + 1, eptr = ext; *fptr; fptr++, eptr++) { + if (toupper (*fptr) != toupper (*eptr)) return NULL; + } + if (*eptr) return NULL; + } +return pptr; +} + +/* Get search specification + + Inputs: + cptr = pointer to input string + radix = radix for numbers + schptr = pointer to search table + Outputs: + return = NULL if error + schptr if valid search specification +*/ + +SCHTAB *get_search (char *cptr, int32 radix, SCHTAB *schptr) +{ +int32 c, logop, cmpop; +t_value logval, cmpval; +char *sptr, *tptr; +const char logstr[] = "|&^", cmpstr[] = "=!><"; + +logval = cmpval = 0; +if (*cptr == 0) return NULL; /* check for clause */ +for (logop = cmpop = -1; c = *cptr++; ) { /* loop thru clauses */ + if (sptr = strchr (logstr, c)) { /* check for mask */ + logop = sptr - logstr; + logval = strtotv (cptr, &tptr, radix); + if (cptr == tptr) return NULL; + cptr = tptr; + } + else if (sptr = strchr (cmpstr, c)) { /* check for boolop */ + cmpop = sptr - cmpstr; + if (*cptr == '=') { + cmpop = cmpop + strlen (cmpstr); + cptr++; + } + cmpval = strtotv (cptr, &tptr, radix); + if (cptr == tptr) return NULL; + cptr = tptr; + } + else return NULL; + } /* end for */ +if (logop >= 0) { + schptr->logic = logop; + schptr->mask = logval; + } +if (cmpop >= 0) { + schptr->boolop = cmpop; + schptr->comp = cmpval; + } +return schptr; +} + +/* Test value against search specification + + Inputs: + val = value to test + schptr = pointer to search table + Outputs: + return = 1 if value passes search criteria, 0 if not +*/ + +int32 test_search (t_value val, SCHTAB *schptr) +{ +if (schptr == NULL) return 0; + +switch (schptr->logic) { /* case on logical */ + + case SCH_OR: + val = val | schptr->mask; + break; + + case SCH_AND: + val = val & schptr->mask; + break; + + case SCH_XOR: + val = val ^ schptr->mask; + break; + } + +switch (schptr->boolop) { /* case on comparison */ + + case SCH_E: case SCH_EE: + return (val == schptr->comp); + + case SCH_N: case SCH_NE: + return (val != schptr->comp); + + case SCH_G: + return (val > schptr->comp); + + case SCH_GE: + return (val >= schptr->comp); + + case SCH_L: + return (val < schptr->comp); + + case SCH_LE: + return (val <= schptr->comp); + } + +return 0; +} + +/* Radix independent input/output package + + strtotv - general radix input routine + + Inputs: + inptr = string to convert + endptr = pointer to first unconverted character + radix = radix for input + Outputs: + value = converted value + + On an error, the endptr will equal the inptr. +*/ + +t_value strtotv (char *inptr, char **endptr, uint32 radix) +{ +int32 nodigit; +t_value val; +uint32 c, digit; + +*endptr = inptr; /* assume fails */ +if ((radix < 2) || (radix > 36)) return 0; +while (isspace (*inptr)) inptr++; /* bypass white space */ +val = 0; +nodigit = 1; +for (c = *inptr; isalnum(c); c = *++inptr) { /* loop through char */ + if (islower (c)) c = toupper (c); + if (isdigit (c)) digit = c - (uint32) '0'; /* digit? */ + else digit = c + 10 - (uint32) 'A'; /* no, letter */ + if (digit >= radix) return 0; /* valid in radix? */ + val = (val * radix) + digit; /* add to value */ + nodigit = 0; + } +if (nodigit) return 0; /* no digits? */ +*endptr = inptr; /* result pointer */ +return val; +} + +/* fprint_val - general radix printing routine + + Inputs: + stream = stream designator + val = value to print + radix = radix to print + width = width to print + format = leading zeroes format + Outputs: + status = error status +*/ + +t_stat fprint_val (FILE *stream, t_value val, uint32 radix, + uint32 width, uint32 format) +{ +#define MAX_WIDTH ((int) (CHAR_BIT * sizeof (t_value))) +t_value owtest, wtest; +int32 d, digit, ndigits; +char dbuf[MAX_WIDTH + 1]; + +for (d = 0; d < MAX_WIDTH; d++) dbuf[d] = (format == PV_RZRO)? '0': ' '; +dbuf[MAX_WIDTH] = 0; +d = MAX_WIDTH; +do { + d = d - 1; + digit = (int32) (val % radix); + val = val / radix; + dbuf[d] = (digit <= 9)? '0' + digit: 'A' + (digit - 10); + } while ((d > 0) && (val != 0)); + +if (format != PV_LEFT) { + wtest = owtest = radix; + ndigits = 1; + while ((wtest < width_mask[width]) && (wtest >= owtest)) { + owtest = wtest; + wtest = wtest * radix; + ndigits = ndigits + 1; + } + if ((MAX_WIDTH - ndigits) < d) d = MAX_WIDTH - ndigits; + } +if (fputs (&dbuf[d], stream) == EOF) return SCPE_IOERR; +return SCPE_OK; +} + +/* Event queue package + + sim_activate add entry to event queue + sim_cancel remove entry from event queue + sim_process_event process entries on event queue + sim_is_active see if entry is on event queue + sim_atime return absolute time for an entry + sim_gtime return global time + sim_qcount return event queue entry count + + Asynchronous events are set up by queueing a unit data structure + to the event queue with a timeout (in simulator units, relative + to the current time). Each simulator 'times' these events by + counting down interval counter sim_interval. When this reaches + zero the simulator calls sim_process_event to process the event + and to see if further events need to be processed, or sim_interval + reset to count the next one. + + The event queue is maintained in clock order; entry timeouts are + RELATIVE to the time in the previous entry. + + sim_process_event - process event + + Inputs: + none + Outputs: + reason = reason code returned by any event processor, + or 0 (SCPE_OK) if no exceptions +*/ + +t_stat sim_process_event (void) +{ +UNIT *uptr; +t_stat reason; + +if (stop_cpu) return SCPE_STOP; /* stop CPU? */ +if (sim_clock_queue == NULL) { /* queue empty? */ + UPDATE_SIM_TIME (noqueue_time); /* update sim time */ + sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */ + return SCPE_OK; + } +UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */ +do { + uptr = sim_clock_queue; /* get first */ + sim_clock_queue = uptr->next; /* remove first */ + uptr->next = NULL; /* hygiene */ + uptr->time = 0; + if (sim_clock_queue != NULL) sim_interval = sim_clock_queue->time; + else sim_interval = noqueue_time = NOQUEUE_WAIT; + if (uptr->action != NULL) reason = uptr->action (uptr); + else reason = SCPE_OK; + } while ((reason == SCPE_OK) && (sim_interval == 0)); + +/* Empty queue forces sim_interval != 0 */ + +return reason; +} + +/* sim_activate - activate (queue) event + + Inputs: + uptr = pointer to unit + event_time = relative timeout + Outputs: + reason = result (SCPE_OK if ok) +*/ + +t_stat sim_activate (UNIT *uptr, int32 event_time) +{ +UNIT *cptr, *prvptr; +int32 accum; + +if (event_time < 0) return SCPE_IERR; +if (sim_is_active (uptr)) return SCPE_OK; /* already active? */ +if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } +else { UPDATE_SIM_TIME (sim_clock_queue->time); } /* update sim time */ + +prvptr = NULL; +accum = 0; +for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { + if (event_time < (accum + cptr->time)) break; + accum = accum + cptr->time; + prvptr = cptr; + } +if (prvptr == NULL) { /* insert at head */ + cptr = uptr->next = sim_clock_queue; + sim_clock_queue = uptr; + } +else { + cptr = uptr->next = prvptr->next; /* insert at prvptr */ + prvptr->next = uptr; + } +uptr->time = event_time - accum; +if (cptr != NULL) cptr->time = cptr->time - uptr->time; +sim_interval = sim_clock_queue->time; +return SCPE_OK; +} + +/* sim_activate_abs - activate (queue) event even if event already scheduled + + Inputs: + uptr = pointer to unit + event_time = relative timeout + Outputs: + reason = result (SCPE_OK if ok) +*/ + +t_stat sim_activate_abs (UNIT *uptr, int32 event_time) +{ +sim_cancel (uptr); +return sim_activate (uptr, event_time); +} + +/* sim_cancel - cancel (dequeue) event + + Inputs: + uptr = pointer to unit + Outputs: + reason = result (SCPE_OK if ok) + +*/ + +t_stat sim_cancel (UNIT *uptr) +{ +UNIT *cptr, *nptr; + +if (sim_clock_queue == NULL) return SCPE_OK; +UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */ +nptr = NULL; +if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr->next; +else { + for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { + if (cptr->next == uptr) { + nptr = cptr->next = uptr->next; + break; /* end queue scan */ + } + } + } +if (nptr != NULL) nptr->time = nptr->time + uptr->time; +uptr->next = NULL; /* hygiene */ +uptr->time = 0; +if (sim_clock_queue != NULL) sim_interval = sim_clock_queue->time; +else sim_interval = noqueue_time = NOQUEUE_WAIT; +return SCPE_OK; +} + +/* sim_is_active - test for entry in queue, return activation time + + Inputs: + uptr = pointer to unit + Outputs: + result = absolute activation time + 1, 0 if inactive +*/ + +int32 sim_is_active (UNIT *uptr) +{ +UNIT *cptr; +int32 accum; + +accum = 0; +for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { + accum = accum + cptr->time; + if (cptr == uptr) return accum + 1; + } +return 0; +} + +/* sim_gtime - return global time + sim_grtime - return global time with rollover + + Inputs: none + Outputs: + time = global time +*/ + +double sim_gtime (void) +{ +if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } +else { UPDATE_SIM_TIME (sim_clock_queue->time); } +return sim_time; +} + +uint32 sim_grtime (void) +{ +if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } +else { UPDATE_SIM_TIME (sim_clock_queue->time); } +return sim_rtime; +} + +/* sim_qcount - return queue entry count + + Inputs: none + Outputs: + count = number of entries on the queue +*/ + +int32 sim_qcount (void) +{ +int32 cnt; +UNIT *uptr; + +cnt = 0; +for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) cnt++; +return cnt; +} + +/* Breakpoint package. This module replaces the VM-implemented one + instruction breakpoint capability. + + Breakpoints are stored in table sim_brk_tab, which is ordered by address for + efficient binary searching. A breakpoint consists of a four entry structure: + + addr address of the breakpoint + type types of breakpoints set on the address + a bit mask representing letters A-Z + cnt number of iterations before breakp is taken + action pointer command string to be executed + when break is taken + + sim_brk_summ is a summary of the types of breakpoints that are currently set (it + is the bitwise OR of all the type fields). A simulator need only check for + a breakpoint of type X if bit SWMASK('X') is set in sim_brk_sum. + + The package contains the following public routines: + + sim_brk_init initialize + sim_brk_set set breakpoint + sim_brk_clr clear breakpoint + sim_brk_clrall clear all breakpoints + sim_brk_show show breakpoint + sim_brk_showall show all breakpoints + sim_brk_test test for breakpoint + sim_brk_npc PC has been changed + sim_brk_getact get next action + sim_brk_clract clear pending actions + + Initialize breakpoint system. +*/ + +t_stat sim_brk_init (void) +{ +sim_brk_lnt = SIM_BRK_INILNT; +sim_brk_tab = (BRKTAB *) calloc (sim_brk_lnt, sizeof (BRKTAB)); +if (sim_brk_tab == NULL) return SCPE_MEM; +sim_brk_ent = sim_brk_ins = 0; +sim_brk_act = NULL; +sim_brk_npc (0); +return SCPE_OK; +} + +/* Search for a breakpoint in the sorted breakpoint table */ + +BRKTAB *sim_brk_fnd (t_addr loc) +{ +int32 lo, hi, p; +BRKTAB *bp; + +if (sim_brk_ent == 0) { /* table empty? */ + sim_brk_ins = 0; /* insrt at head */ + return NULL; /* sch fails */ + } +lo = 0; /* initial bounds */ +hi = sim_brk_ent - 1; +do { + p = (lo + hi) >> 1; /* probe */ + bp = sim_brk_tab + p; /* table addr */ + if (loc == bp->addr) return bp; /* match? */ + else if (loc < bp->addr) hi = p - 1; /* go down? p is upper */ + else lo = p + 1; /* go up? p is lower */ + } while (lo <= hi); +if (loc < bp->addr) sim_brk_ins = p; /* insrt before or */ +else sim_brk_ins = p + 1; /* after last sch */ +return NULL; +} + +/* Insert a breakpoint */ + +BRKTAB *sim_brk_new (t_addr loc) +{ +int32 i, t; +BRKTAB *bp, *newp; + +if (sim_brk_ins < 0) return NULL; +if (sim_brk_ent >= sim_brk_lnt) { /* out of space? */ + t = sim_brk_lnt + SIM_BRK_INILNT; /* new size */ + newp = (BRKTAB *) calloc (t, sizeof (BRKTAB)); /* new table */ + if (newp == NULL) return NULL; /* can't extend */ + for (i = 0; i < sim_brk_lnt; i++) /* copy table */ + *(newp + i) = *(sim_brk_tab + i); + free (sim_brk_tab); /* free old table */ + sim_brk_tab = newp; /* new base, lnt */ + sim_brk_lnt = t; + } +if (sim_brk_ins != sim_brk_ent) { /* move needed? */ + for (bp = sim_brk_tab + sim_brk_ent; + bp > sim_brk_tab + sim_brk_ins; bp--) + *bp = *(bp - 1); + } +bp = sim_brk_tab + sim_brk_ins; +bp->addr = loc; +bp->typ = 0; +bp->cnt = 0; +bp->act = NULL; +sim_brk_ent = sim_brk_ent + 1; +return bp; +} + +/* Set a breakpoint of type sw */ + +t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, char *act) +{ +BRKTAB *bp; + +if (sw == 0) sw = sim_brk_dflt; +if ((sim_brk_types & sw) == 0) return SCPE_NOFNC; +bp = sim_brk_fnd (loc); /* present? */ +if (!bp) bp = sim_brk_new (loc); /* no, allocate */ +if (!bp) return SCPE_MEM; /* still no? mem err */ +bp->typ = sw; /* set type */ +bp->cnt = ncnt; /* set count */ +if ((bp->act != NULL) && (act != NULL)) { /* replace old action? */ + free (bp->act); /* deallocate */ + bp->act = NULL; /* now no action */ + } +if ((act != NULL) && (*act != 0)) { /* new action? */ + char *newp = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc buf */ + if (newp == NULL) return SCPE_MEM; /* mem err? */ + strncpy (newp, act, CBUFSIZE); /* copy action */ + bp->act = newp; /* set pointer */ + } +sim_brk_summ = sim_brk_summ | sw; +return SCPE_OK; +} + +/* Clear a breakpoint */ + +t_stat sim_brk_clr (t_addr loc, int32 sw) +{ +BRKTAB *bp = sim_brk_fnd (loc); + +if (!bp) return SCPE_OK; /* not there? ok */ +if (sw == 0) sw = SIM_BRK_ALLTYP; +bp->typ = bp->typ & ~sw; +if (bp->typ) return SCPE_OK; /* clear all types? */ +if (bp->act != NULL) free (bp->act); /* deallocate action */ +for ( ; bp < (sim_brk_tab + sim_brk_ent - 1); bp++) /* erase entry */ + *bp = *(bp + 1); +sim_brk_ent = sim_brk_ent - 1; /* decrement count */ +sim_brk_summ = 0; /* recalc summary */ +for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) + sim_brk_summ = sim_brk_summ | bp->typ; +return SCPE_OK; +} + +/* Clear all breakpoints */ + +t_stat sim_brk_clrall (int32 sw) +{ +BRKTAB *bp; + +if (sw == 0) sw = SIM_BRK_ALLTYP; +for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); ) { + if (bp->typ & sw) sim_brk_clr (bp->addr, sw); + else bp++; + } +return SCPE_OK; +} + +/* Show a breakpoint */ + +t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw) +{ +BRKTAB *bp = sim_brk_fnd (loc); +DEVICE *dptr; +int32 i, any; + +if (sw == 0) sw = SIM_BRK_ALLTYP; +if (!bp || (!(bp->typ & sw))) return SCPE_OK; +dptr = sim_dflt_dev; +if (dptr == NULL) return SCPE_OK; +if (sim_vm_fprint_addr) sim_vm_fprint_addr (st, dptr, loc); +else fprint_val (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); +fprintf (st, ":\t"); +for (i = any = 0; i < 26; i++) { + if ((bp->typ >> i) & 1) { + if (any) fprintf (st, ", "); + fputc (i + 'A', st); + any = 1; + } + } +if (bp->cnt > 0) fprintf (st, " [%d]", bp->cnt); +if (bp->act != NULL) fprintf (st, "; %s", bp->act); +fprintf (st, "\n"); +return SCPE_OK; +} + +/* Show all breakpoints */ + +t_stat sim_brk_showall (FILE *st, int32 sw) +{ +BRKTAB *bp; + +if (sw == 0) sw = SIM_BRK_ALLTYP; +for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) { + if (bp->typ & sw) sim_brk_show (st, bp->addr, sw); + } +return SCPE_OK; +} + +/* Test for breakpoint */ + +uint32 sim_brk_test (t_addr loc, uint32 btyp) +{ +BRKTAB *bp; +uint32 spc = (btyp >> SIM_BKPT_V_SPC) & (SIM_BKPT_N_SPC - 1); + +if ((bp = sim_brk_fnd (loc)) && (btyp & bp->typ)) { /* in table, type match? */ + if ((sim_brk_pend[spc] && (loc == sim_brk_ploc[spc])) || /* previous location? */ + (--bp->cnt > 0)) return 0; /* count > 0? */ + bp->cnt = 0; /* reset count */ + sim_brk_ploc[spc] = loc; /* save location */ + sim_brk_pend[spc] = TRUE; /* don't do twice */ + sim_brk_act = bp->act; /* set up actions */ + return (btyp & bp->typ); + } +sim_brk_pend[spc] = FALSE; +return 0; +} + +/* Get next pending action, if any */ + +char *sim_brk_getact (char *buf, int32 size) +{ +char *ep; +size_t lnt; + +if (sim_brk_act == NULL) return NULL; /* any action? */ +while (isspace (*sim_brk_act)) sim_brk_act++; /* skip spaces */ +if (*sim_brk_act == 0) return (sim_brk_act = NULL); /* now empty? */ +if (ep = strchr (sim_brk_act, ';')) { /* cmd delimiter? */ + lnt = ep - sim_brk_act; /* cmd length */ + memcpy (buf, sim_brk_act, lnt + 1); /* copy with ; */ + buf[lnt] = 0; /* erase ; */ + sim_brk_act = sim_brk_act + lnt + 1; /* adv ptr */ + } +else { + strncpy (buf, sim_brk_act, size); /* copy action */ + sim_brk_act = NULL; /* no more */ + } +return buf; +} + +/* Clear pending actions */ + +void sim_brk_clract (void) +{ +sim_brk_act = NULL; +} + +/* New PC */ + +void sim_brk_npc (uint32 cnt) +{ +uint32 i; + +if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC)) cnt = SIM_BKPT_N_SPC; +for (i = 0; i < cnt; i++) { + sim_brk_pend[i] = FALSE; + sim_brk_ploc[i] = 0; + } +return; +} + +/* Clear breakpoint space */ + +void sim_brk_clrspc (uint32 spc) +{ +if (spc < SIM_BKPT_N_SPC) { + sim_brk_pend[spc] = FALSE; + sim_brk_ploc[spc] = 0; + } +return; +} + +/* Debug printout routines, from Dave Hittner */ + +const char* debug_bstates = "01_^"; +const char* debug_fmt = "DBG> %s %s: "; +int32 debug_unterm = 0; + +/* Finds debug phrase matching bitmask from from device DEBTAB table */ + +static char* get_dbg_verb (uint32 dbits, DEVICE* dptr) +{ +static char* debtab_none = "DEBTAB_ISNULL"; +static char* debtab_nomatch = "DEBTAB_NOMATCH"; +int32 offset = 0; + +if (dptr->debflags == 0) return debtab_none; + +/* Find matching words for bitmask */ + +while (dptr->debflags[offset].name && (offset < 32)) { + if (dptr->debflags[offset].mask & dbits) + return dptr->debflags[offset].name; + offset++; + } +return debtab_nomatch; +} + +/* Prints standard debug prefix unless previous call unterminated */ + +static void sim_debug_prefix (uint32 dbits, DEVICE* dptr) +{ +if (!debug_unterm) { + char* debug_type = get_dbg_verb (dbits, dptr); + fprintf(sim_deb, debug_fmt, dptr->name, debug_type); + } +} + +/* Prints state of a register: bit translation + state (0,1,_,^) + indicating the state and transition of the bit. States: + 0=steady(0->0), 1=steady(1->1), _=falling(1->0), ^=rising(0->1) */ + +void sim_debug_u16(uint32 dbits, DEVICE* dptr, const char* const* bitdefs, + uint16 before, uint16 after, int terminate) +{ +if (sim_deb && (dptr->dctrl & dbits)) { + int32 i; + + sim_debug_prefix(dbits, dptr); /* print prefix if required */ + for (i = 15; i >= 0; i--) { /* print xlation, transition */ + int off = ((after >> i) & 1) + (((before ^ after) >> i) & 1) * 2; + fprintf(sim_deb, "%s%c ", bitdefs[i], debug_bstates[off]); + } + if (terminate) fprintf(sim_deb, "\r\n"); + debug_unterm = terminate ? 0 : 1; /* set unterm for next */ + } +} + +#if defined (_WIN32) +#define vsnprintf _vsnprintf +#endif +#if defined (__DECC) && defined (__VMS) +#define NO_vsnprintf +#endif +#if defined( NO_vsnprintf) +#define STACKBUFSIZE 16384 +#else +#define STACKBUFSIZE 2048 +#endif + +/* Inline debugging - will print debug message if debug file is + set and the bitmask matches the current device debug options. + Extra returns are added for un*x systems, since the output + device is set into 'raw' mode when the cpu is booted, + and the extra returns don't hurt any other systems. */ + +void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...) +{ +if (sim_deb && (dptr->dctrl & dbits)) { + + char stackbuf[STACKBUFSIZE]; + int32 bufsize = sizeof(stackbuf); + char *buf = stackbuf; + va_list arglist; + int32 i, j, len; + int ret; + + buf[bufsize-1] = '\0'; + sim_debug_prefix(dbits, dptr); /* print prefix if required */ + + while (1) { /* format passed string, args */ + va_start (arglist, fmt); +#if defined(NO_vsnprintf) +#if defined(HAS_vsprintf_void) + +/* Note, this could blow beyond the buffer, and we couldn't tell */ +/* That is a limitation of the C runtime library available on this platform */ + + vsprintf (buf, fmt, arglist); + for (len = 0; len < bufsize-1; len++) + if (buf[len] == 0) break; +#else + len = vsprintf (buf, fmt, arglist); +#endif /* HAS_vsprintf_void */ +#else /* NO_vsnprintf */ +#if defined(HAS_vsnprintf_void) + vsnprintf (buf, bufsize-1, fmt, arglist); + for (len = 0; len < bufsize-1; len++) + if (buf[len] == 0) break; +#else + len = vsnprintf (buf, bufsize-1, fmt, arglist); +#endif /* HAS_vsnprintf_void */ +#endif /* NO_vsnprintf */ + va_end (arglist); + +/* If it didn't fit into the buffer, then grow it and try again */ + + if ((len < 0) || (len >= bufsize-1)) { + if (buf != stackbuf) free (buf); + bufsize = bufsize * 2; + buf = (char *) malloc (bufsize); + if (buf == NULL) return; /* out of memory */ + buf[bufsize-1] = '\0'; + continue; + } + break; + } + +/* Output the formatted data expanding newlines where they exist */ + + for (i = j = 0; i < len; ++i) { + if ('\n' == buf[i]) { + if (i > j) ret =fwrite (&buf[j], 1, i-j, sim_deb); + j = i; + fputc('\r', sim_deb); + } + } + if (i > j) ret = fwrite (&buf[j], 1, i-j, sim_deb); + +/* Set unterminated flag for next time */ + + debug_unterm = (len && (buf[len-1]=='\n')) ? 0 : 1; + if (buf != stackbuf) free (buf); + } +return; +} diff --git a/simhv36-1/scp.h b/simhv36-1/scp.h new file mode 100644 index 0000000..4a42929 --- /dev/null +++ b/simhv36-1/scp.h @@ -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 diff --git a/simhv36-1/sim_console.c b/simhv36-1/sim_console.c new file mode 100644 index 0000000..a65df18 --- /dev/null +++ b/simhv36-1/sim_console.c @@ -0,0 +1,1092 @@ +/* sim_console.c: simulator console 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. + + 22-Jun-06 RMS Implemented SET/SHOW PCHAR + 31-May-06 JDB Fixed bug if SET CONSOLE DEBUG with no argument + 22-Nov-05 RMS Added central input/output conversion support + 05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy + 28-Oct-04 JDB Fixed SET CONSOLE to allow comma-separated parameters + 20-Aug-04 RMS Added OS/2 EMX fixes (from Holger Veit) + 14-Jul-04 RMS Revised Windows console code (from Dave Bryan) + 28-May-04 RMS Added SET/SHOW CONSOLE + RMS Added break, delete character maps + 02-Jan-04 RMS Removed timer routines, added Telnet console routines + RMS Moved console logging to OS-independent code + 25-Apr-03 RMS Added long seek support from Mark Pizzolato + Added Unix priority control from Mark Pizzolato + 24-Sep-02 RMS Removed VT support, added Telnet console support + Added CGI support (from Brian Knittel) + Added MacOS sleep (from Peter Schorn) + 14-Jul-02 RMS Added Windows priority control from Mark Pizzolato + 20-May-02 RMS Added Windows VT support from Fischer Franz + 01-Feb-02 RMS Added VAX fix from Robert Alan Byer + 19-Sep-01 RMS More Mac changes + 31-Aug-01 RMS Changed int64 to t_int64 for Windoze + 20-Jul-01 RMS Added Macintosh support (from Louis Chretien, Peter Schorn, + and Ben Supnik) + 15-May-01 RMS Added logging support + 05-Mar-01 RMS Added clock calibration support + 08-Dec-00 BKR Added OS/2 support (from Bruce Ray) + 18-Aug-98 RMS Added BeOS support + 13-Oct-97 RMS Added NetBSD terminal support + 25-Jan-97 RMS Added POSIX terminal I/O support + 02-Jan-97 RMS Fixed bug in sim_poll_kbd + + This module implements the following routines to support terminal I/O: + + sim_poll_kbd - poll for keyboard input + sim_putchar - output character to console + sim_putchar_s - output character to console, stall if congested + sim_set_console - set console parameters + sim_show_console - show console parameters + sim_tt_inpcvt - convert input character per mode + sim_tt_outcvt - convert output character per mode + + sim_ttinit - called once to get initial terminal state + sim_ttrun - called to put terminal into run state + sim_ttcmd - called to return terminal to command state + sim_ttclose - called once before the simulator exits + sim_os_poll_kbd - poll for keyboard input + sim_os_putchar - output character to console + + The first group is OS-independent; the second group is OS-dependent. + + The following routines are exposed but deprecated: + + sim_set_telnet - set console to Telnet port + sim_set_notelnet - close console Telnet port + sim_show_telnet - show console status +*/ + +#include "sim_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#define KMAP_WRU 0 +#define KMAP_BRK 1 +#define KMAP_DEL 2 +#define KMAP_MASK 0377 +#define KMAP_NZ 0400 + +int32 sim_int_char = 005; /* interrupt character */ +int32 sim_brk_char = 000; /* break character */ +int32 sim_tt_pchar = 0x00002780; +#if defined (_WIN32) || defined (__OS2__) || (defined (__MWERKS__) && defined (macintosh)) +int32 sim_del_char = '\b'; /* delete character */ +#else +int32 sim_del_char = 0177; +#endif +TMLN sim_con_ldsc = { 0 }; /* console line descr */ +TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */ + +extern volatile int32 stop_cpu; +extern int32 sim_quiet, sim_deb_close; +extern FILE *sim_log, *sim_deb; +extern DEVICE *sim_devices[]; + +/* Set/show data structures */ + +static CTAB set_con_tab[] = { + { "WRU", &sim_set_kmap, KMAP_WRU | KMAP_NZ }, + { "BRK", &sim_set_kmap, KMAP_BRK }, + { "DEL", &sim_set_kmap, KMAP_DEL |KMAP_NZ }, + { "PCHAR", &sim_set_pchar, 0 }, + { "TELNET", &sim_set_telnet, 0 }, + { "NOTELNET", &sim_set_notelnet, 0 }, + { "LOG", &sim_set_logon, 0 }, + { "NOLOG", &sim_set_logoff, 0 }, + { "DEBUG", &sim_set_debon, 0 }, + { "NODEBUG", &sim_set_deboff, 0 }, + { NULL, NULL, 0 } + }; + +static SHTAB show_con_tab[] = { + { "WRU", &sim_show_kmap, KMAP_WRU }, + { "BRK", &sim_show_kmap, KMAP_BRK }, + { "DEL", &sim_show_kmap, KMAP_DEL }, + { "PCHAR", &sim_show_pchar, 0 }, + { "LOG", &sim_show_log, 0 }, + { "TELNET", &sim_show_telnet, 0 }, + { "DEBUG", &sim_show_debug, 0 }, + { NULL, NULL, 0 } + }; + +static int32 *cons_kmap[] = { + &sim_int_char, + &sim_brk_char, + &sim_del_char + }; + +/* Console I/O package. + + The console terminal can be attached to the controlling window + or to a Telnet connection. If attached to a Telnet connection, + the console is described by internal terminal multiplexor + sim_con_tmxr and internal terminal line description sim_con_ldsc. +*/ + +/* SET CONSOLE command */ + +t_stat sim_set_console (int32 flag, char *cptr) +{ +char *cvptr, gbuf[CBUFSIZE]; +CTAB *ctptr; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; +while (*cptr != 0) { /* do all mods */ + cptr = get_glyph_nc (cptr, gbuf, ','); /* get modifier */ + if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ + get_glyph (gbuf, gbuf, 0); /* modifier to UC */ + if (ctptr = find_ctab (set_con_tab, gbuf)) { /* match? */ + r = ctptr->action (ctptr->arg, cvptr); /* do the rest */ + if (r != SCPE_OK) return r; + } + else return SCPE_NOPARAM; + } +return SCPE_OK; +} + +/* SHOW CONSOLE command */ + +t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +SHTAB *shptr; +int32 i; + +if (*cptr == 0) { /* show all */ + for (i = 0; show_con_tab[i].name; i++) + show_con_tab[i].action (st, dptr, uptr, show_con_tab[i].arg, cptr); + return SCPE_OK; + } +while (*cptr != 0) { + cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ + if (shptr = find_shtab (show_con_tab, gbuf)) + shptr->action (st, dptr, uptr, shptr->arg, cptr); + else return SCPE_NOPARAM; + } +return SCPE_OK; +} + +/* Set keyboard map */ + +t_stat sim_set_kmap (int32 flag, char *cptr) +{ +DEVICE *dptr = sim_devices[0]; +int32 val, rdx; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; +if (dptr->dradix == 16) rdx = 16; +else rdx = 8; +val = (int32) get_uint (cptr, rdx, 0177, &r); +if ((r != SCPE_OK) || + ((val == 0) && (flag & KMAP_NZ))) return SCPE_ARG; +*(cons_kmap[flag & KMAP_MASK]) = val; +return SCPE_OK; +} + +/* Show keyboard map */ + +t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (sim_devices[0]->dradix == 16) + fprintf (st, "%s = %X\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK])); +else fprintf (st, "%s = %o\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK])); +return SCPE_OK; +} + +/* Set printable characters */ + +t_stat sim_set_pchar (int32 flag, char *cptr) +{ +DEVICE *dptr = sim_devices[0]; +uint32 val, rdx; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; +if (dptr->dradix == 16) rdx = 16; +else rdx = 8; +val = (uint32) get_uint (cptr, rdx, 0xFFFFFFFF, &r); +if ((r != SCPE_OK) || + ((val & 0x00002400) == 0)) return SCPE_ARG; +sim_tt_pchar = val; +return SCPE_OK; +} + +/* Show printable characters */ + +t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (sim_devices[0]->dradix == 16) + fprintf (st, "pchar mask = %X\n", sim_tt_pchar); +else fprintf (st, "pchar mask = %o\n", sim_tt_pchar); +return SCPE_OK; +} + +/* Set log routine */ + +t_stat sim_set_logon (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; /* need arg */ +cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +sim_set_logoff (0, NULL); /* close cur log */ +sim_log = sim_fopen (gbuf, "a"); /* open log */ +if (sim_log == NULL) return SCPE_OPENERR; /* error? */ +if (!sim_quiet) printf ("Logging to file \"%s\"\n", gbuf); +fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); /* start of log */ +return SCPE_OK; +} + +/* Set nolog routine */ + +t_stat sim_set_logoff (int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ +if (sim_log == NULL) return SCPE_OK; /* no log? */ +if (!sim_quiet) printf ("Log file closed\n"); +fprintf (sim_log, "Log file closed\n"); /* close log */ +fclose (sim_log); +sim_log = NULL; +return SCPE_OK; +} + +/* Show log status */ + +t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; +if (sim_log) fputs ("Logging enabled\n", st); +else fputs ("Logging disabled\n", st); +return SCPE_OK; +} + +/* Set debug routine */ + +t_stat sim_set_debon (int32 flag, char *cptr) +{ +char *tptr, gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; /* too few arguments? */ +tptr = get_glyph (cptr, gbuf, 0); /* get file name */ +if (*tptr != 0) return SCPE_2MARG; /* now eol? */ +sim_set_deboff (0, NULL); /* close cur debug */ +if (strcmp (gbuf, "LOG") == 0) { /* debug to log? */ + if (sim_log == NULL) return SCPE_ARG; /* any log? */ + sim_deb = sim_log; + } +else if (strcmp (gbuf, "STDOUT") == 0) sim_deb = stdout; /* debug to stdout? */ +else if (strcmp (gbuf, "STDERR") == 0) sim_deb = stderr; /* debug to stderr? */ +else { + cptr = get_glyph_nc (cptr, gbuf, 0); /* reparse */ + sim_deb = sim_fopen (gbuf, "a"); /* open debug */ + if (sim_deb == NULL) return SCPE_OPENERR; /* error? */ + sim_deb_close = 1; /* need close */ + } +if (!sim_quiet) printf ("Debug output to \"%s\"\n", gbuf); +if (sim_log) fprintf (sim_log, "Debug output to \"%s\"\n", gbuf); +return SCPE_OK; +} + +/* Set nodebug routine */ + +t_stat sim_set_deboff (int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ +if (sim_deb == NULL) return SCPE_OK; /* no log? */ +if (!sim_quiet) printf ("Debug output disabled\n"); +if (sim_log) fprintf (sim_log, "Debug output disabled\n"); +if (sim_deb_close) fclose (sim_deb); /* close if needed */ +sim_deb_close = 0; +sim_deb = NULL; +return SCPE_OK; +} + +/* Show debug routine */ + +t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; +if (sim_deb) fputs ("Debug output enabled\n", st); +else fputs ("Debug output disabled\n", st); +return SCPE_OK; +} + +/* Set console to Telnet port */ + +t_stat sim_set_telnet (int32 flg, char *cptr) +{ +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; /* too few arguments? */ +if (sim_con_tmxr.master) return SCPE_ALATT; /* already open? */ +return tmxr_open_master (&sim_con_tmxr, cptr); /* open master socket */ +} + +/* Close console Telnet port */ + +t_stat sim_set_notelnet (int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; /* too many arguments? */ +if (sim_con_tmxr.master == 0) return SCPE_OK; /* ignore if already closed */ +return tmxr_close_master (&sim_con_tmxr); /* close master socket */ +} + +/* Show console Telnet status */ + +t_stat sim_show_telnet (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; +if (sim_con_tmxr.master == 0) + fprintf (st, "Connected to console window\n"); +else if (sim_con_ldsc.conn == 0) + fprintf (st, "Listening on port %d\n", sim_con_tmxr.port); +else { + fprintf (st, "Listening on port %d, connected to socket %d\n", + sim_con_tmxr.port, sim_con_ldsc.conn); + tmxr_fconns (st, &sim_con_ldsc, -1); + tmxr_fstats (st, &sim_con_ldsc, -1); + } +return SCPE_OK; +} + +/* Check connection before executing */ + +t_stat sim_check_console (int32 sec) +{ +int32 c, i; + +if (sim_con_tmxr.master == 0) return SCPE_OK; /* not Telnet? done */ +if (sim_con_ldsc.conn) { /* connected? */ + tmxr_poll_rx (&sim_con_tmxr); /* poll (check disconn) */ + if (sim_con_ldsc.conn) return SCPE_OK; /* still connected? */ + } +for (i = 0; i < sec; i++) { /* loop */ + if (tmxr_poll_conn (&sim_con_tmxr) >= 0) { /* poll connect */ + sim_con_ldsc.rcve = 1; /* rcv enabled */ + if (i) { /* if delayed */ + printf ("Running\n"); /* print transition */ + fflush (stdout); + } + return SCPE_OK; /* ready to proceed */ + } + c = sim_os_poll_kbd (); /* check for stop char */ + if ((c == SCPE_STOP) || stop_cpu) return SCPE_STOP; + if ((i % 10) == 0) { /* Status every 10 sec */ + printf ("Waiting for console Telnet connection\n"); + fflush (stdout); + } + sim_os_sleep (1); /* wait 1 second */ + } +return SCPE_TTMO; /* timed out */ +} + +/* Poll for character */ + +t_stat sim_poll_kbd (void) +{ +int32 c; + +c = sim_os_poll_kbd (); /* get character */ +if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */ + return c; /* in-window */ +if (sim_con_ldsc.conn == 0) return SCPE_LOST; /* no Telnet conn? */ +tmxr_poll_rx (&sim_con_tmxr); /* poll for input */ +if (c = tmxr_getc_ln (&sim_con_ldsc)) /* any char? */ + return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG; +return SCPE_OK; +} + +/* Output character */ + +t_stat sim_putchar (int32 c) +{ +if (sim_log) fputc (c, sim_log); /* log file? */ +if (sim_con_tmxr.master == 0) /* not Telnet? */ + return sim_os_putchar (c); /* in-window version */ +if (sim_con_ldsc.conn == 0) return SCPE_LOST; /* no Telnet conn? */ +tmxr_putc_ln (&sim_con_ldsc, c); /* output char */ +tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */ +return SCPE_OK; +} + +t_stat sim_putchar_s (int32 c) +{ +t_stat r; + +if (sim_log) fputc (c, sim_log); /* log file? */ +if (sim_con_tmxr.master == 0) /* not Telnet? */ + return sim_os_putchar (c); /* in-window version */ +if (sim_con_ldsc.conn == 0) return SCPE_LOST; /* no Telnet conn? */ +if (sim_con_ldsc.xmte == 0) r = SCPE_STALL; /* xmt disabled? */ +else r = tmxr_putc_ln (&sim_con_ldsc, c); /* no, Telnet output */ +tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */ +return r; /* return status */ +} + +/* Input character processing */ + +int32 sim_tt_inpcvt (int32 c, uint32 mode) +{ +uint32 md = mode & TTUF_M_MODE; + +if (md != TTUF_MODE_8B) { + c = c & 0177; + if (md == TTUF_MODE_UC) { + if (islower (c)) c = toupper (c); + if (mode & TTUF_KSR) c = c | 0200; + } + } +else c = c & 0377; +return c; +} + +/* Output character processing */ + +int32 sim_tt_outcvt (int32 c, uint32 mode) +{ +uint32 md = mode & TTUF_M_MODE; + +if (md != TTUF_MODE_8B) { + c = c & 0177; + if ((md == TTUF_MODE_UC) && islower (c)) c = toupper (c); + if (((md == TTUF_MODE_UC) || (md == TTUF_MODE_7P)) && + ((c == 0177) || + ((c < 040) && !((sim_tt_pchar >> c) & 1)))) + return -1; + } +else c = c & 0377; +return c; +} + +/* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */ + +#if defined (VMS) + +#if defined(__VAX) +#define sys$assign SYS$ASSIGN +#define sys$qiow SYS$QIOW +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define EFN 0 +uint32 tty_chan = 0; + +typedef struct { + unsigned short sense_count; + unsigned char sense_first_char; + unsigned char sense_reserved; + unsigned int stat; + unsigned int stat2; } SENSE_BUF; + +typedef struct { + unsigned short status; + unsigned short count; + unsigned int dev_status; } IOSB; + +SENSE_BUF cmd_mode = { 0 }; +SENSE_BUF run_mode = { 0 }; + +t_stat sim_ttinit (void) +{ +unsigned int status; +IOSB iosb; +$DESCRIPTOR (terminal_device, "tt"); + +status = sys$assign (&terminal_device, &tty_chan, 0, 0); +if (status != SS$_NORMAL) return SCPE_TTIERR; +status = sys$qiow (EFN, tty_chan, IO$_SENSEMODE, &iosb, 0, 0, + &cmd_mode, sizeof (cmd_mode), 0, 0, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR; +run_mode = cmd_mode; +run_mode.stat = cmd_mode.stat | TT$M_NOECHO & ~(TT$M_HOSTSYNC | TT$M_TTSYNC); +run_mode.stat2 = cmd_mode.stat2 | TT2$M_PASTHRU; +return SCPE_OK; +} + +t_stat sim_ttrun (void) +{ +unsigned int status; +IOSB iosb; + +status = sys$qiow (EFN, tty_chan, IO$_SETMODE, &iosb, 0, 0, + &run_mode, sizeof (run_mode), 0, 0, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR; +return SCPE_OK; +} + +t_stat sim_ttcmd (void) +{ +unsigned int status; +IOSB iosb; + +status = sys$qiow (EFN, tty_chan, IO$_SETMODE, &iosb, 0, 0, + &cmd_mode, sizeof (cmd_mode), 0, 0, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR; +return SCPE_OK; +} + +t_stat sim_ttclose (void) +{ +return sim_ttcmd (); +} + +t_stat sim_os_poll_kbd (void) +{ +unsigned int status, term[2]; +unsigned char buf[4]; +IOSB iosb; +SENSE_BUF sense; + +term[0] = 0; term[1] = 0; +status = sys$qiow (EFN, tty_chan, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb, + 0, 0, &sense, 8, 0, term, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR; +if (sense.sense_count == 0) return SCPE_OK; +term[0] = 0; term[1] = 0; +status = sys$qiow (EFN, tty_chan, + IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO, + &iosb, 0, 0, buf, 1, 0, term, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_OK; +if (buf[0] == sim_int_char) return SCPE_STOP; +if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK; +return (buf[0] | SCPE_KFLAG); +} + +t_stat sim_os_putchar (int32 out) +{ +unsigned int status; +char c; +IOSB iosb; + +c = out; +status = sys$qiow (EFN, tty_chan, IO$_WRITELBLK | IO$M_NOFORMAT, + &iosb, 0, 0, &c, 1, 0, 0, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTOERR; +return SCPE_OK; +} + +/* Win32 routines */ + +#elif defined (_WIN32) + +#include +#include +#include +#include +#define RAW_MODE 0 +static HANDLE std_input; +static DWORD saved_mode; + +t_stat sim_ttinit (void) +{ +std_input = GetStdHandle (STD_INPUT_HANDLE); +if ((std_input == INVALID_HANDLE_VALUE) || + !GetConsoleMode (std_input, &saved_mode)) return SCPE_TTYERR; +return SCPE_OK; +} + +t_stat sim_ttrun (void) +{ +if (!GetConsoleMode(std_input, &saved_mode) || + !SetConsoleMode(std_input, RAW_MODE)) return SCPE_TTYERR; +if (sim_log) { + fflush (sim_log); + _setmode (_fileno (sim_log), _O_BINARY); + } +SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); +return SCPE_OK; +} + +t_stat sim_ttcmd (void) +{ +if (sim_log) { + fflush (sim_log); + _setmode (_fileno (sim_log), _O_TEXT); + } +SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); +if (!SetConsoleMode(std_input, saved_mode)) return SCPE_TTYERR; +return SCPE_OK; +} + +t_stat sim_ttclose (void) +{ +return SCPE_OK; +} + +t_stat sim_os_poll_kbd (void) +{ +int c; + +if (!_kbhit ()) return SCPE_OK; +c = _getch (); +if ((c & 0177) == sim_del_char) c = 0177; +if ((c & 0177) == sim_int_char) return SCPE_STOP; +if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK; +return c | SCPE_KFLAG; +} + +t_stat sim_os_putchar (int32 c) +{ +if (c != 0177) _putch (c); +return SCPE_OK; +} + +/* OS/2 routines, from Bruce Ray and Holger Veit */ + +#elif defined (__OS2__) + +#include + +t_stat sim_ttinit (void) +{ +return SCPE_OK; +} + +t_stat sim_ttrun (void) +{ +return SCPE_OK; +} + +t_stat sim_ttcmd (void) +{ +return SCPE_OK; +} + +t_stat sim_ttclose (void) +{ +return SCPE_OK; +} + +t_stat sim_os_poll_kbd (void) +{ +int c; + +#if defined (__EMX__) +switch (c = _read_kbd(0,0,0)) { /* EMX has _read_kbd */ + + case -1: /* no char*/ + return SCPE_OK; + + case 0: /* char pending */ + c = _read_kbd(0,1,0); + break; + + default: /* got char */ + break; + } +#else +if (!kbhit ()) return SCPE_OK; +c = getch(); +#endif +if ((c & 0177) == sim_del_char) c = 0177; +if ((c & 0177) == sim_int_char) return SCPE_STOP; +if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK; +return c | SCPE_KFLAG; +} + +t_stat sim_os_putchar (int32 c) +{ +if (c != 0177) { +#if defined (__EMX__) + putchar (c); +#else + putch (c); +#endif + fflush (stdout); + } +return SCPE_OK; +} + +/* Metrowerks CodeWarrior Macintosh routines, from Louis Chretien and + Peter Schorn */ + +#elif defined (__MWERKS__) && defined (macintosh) + +#include +#include +#include +#include +#include +#include +#include +#include + +/* function prototypes */ + +Boolean SIOUXIsAppWindow(WindowPtr window); +void SIOUXDoMenuChoice(long menuValue); +void SIOUXUpdateMenuItems(void); +void SIOUXUpdateScrollbar(void); +int ps_kbhit(void); +int ps_getch(void); + +extern char sim_name[]; +extern pSIOUXWin SIOUXTextWindow; +static CursHandle iBeamCursorH = NULL; /* contains the iBeamCursor */ + +static void updateCursor(void) { + WindowPtr window; + window = FrontWindow(); + if (SIOUXIsAppWindow(window)) { + GrafPtr savePort; + Point localMouse; + GetPort(&savePort); + SetPort(window); +#if TARGET_API_MAC_CARBON + GetGlobalMouse(&localMouse); +#else + localMouse = LMGetMouseLocation(); +#endif + GlobalToLocal(&localMouse); + if (PtInRect(localMouse, &(*SIOUXTextWindow->edit)->viewRect) && iBeamCursorH) { + SetCursor(*iBeamCursorH); + } + else { + SetCursor(&qd.arrow); + } + TEIdle(SIOUXTextWindow->edit); + SetPort(savePort); + } + else { + SetCursor(&qd.arrow); + TEIdle(SIOUXTextWindow->edit); + } + return; +} + +int ps_kbhit(void) { + EventRecord event; + int c; + updateCursor(); + SIOUXUpdateScrollbar(); + while (GetNextEvent(updateMask | osMask | mDownMask | mUpMask | activMask | + highLevelEventMask | diskEvt, &event)) { + SIOUXHandleOneEvent(&event); + } + if (SIOUXQuitting) { + exit(1); + } + if (EventAvail(keyDownMask,&event)) { + c = event.message&charCodeMask; + if ((event.modifiers & cmdKey) && (c > 0x20)) { + GetNextEvent(keyDownMask, &event); + SIOUXHandleOneEvent(&event); + if (SIOUXQuitting) { + exit(1); + } + return false; + } + return true; + } + else { + return false; + } +} + +int ps_getch(void) { + int c; + EventRecord event; + fflush(stdout); + updateCursor(); + while(!GetNextEvent(keyDownMask,&event)) { + if (GetNextEvent(updateMask | osMask | mDownMask | mUpMask | activMask | + highLevelEventMask | diskEvt, &event)) { + SIOUXUpdateScrollbar(); + SIOUXHandleOneEvent(&event); + } + } + if (SIOUXQuitting) { + exit(1); + } + c = event.message&charCodeMask; + if ((event.modifiers & cmdKey) && (c > 0x20)) { + SIOUXUpdateMenuItems(); + SIOUXDoMenuChoice(MenuKey(c)); + } + if (SIOUXQuitting) { + exit(1); + } + return c; +} + +/* Note that this only works if the call to sim_ttinit comes before any output to the console */ + +t_stat sim_ttinit (void) { + int i; + /* this blank will later be replaced by the number of characters */ + char title[50] = " "; + unsigned char ptitle[50]; + SIOUXSettings.autocloseonquit = TRUE; + SIOUXSettings.asktosaveonclose = FALSE; + SIOUXSettings.showstatusline = FALSE; + SIOUXSettings.columns = 80; + SIOUXSettings.rows = 40; + SIOUXSettings.toppixel = 42; + SIOUXSettings.leftpixel = 6; + iBeamCursorH = GetCursor(iBeamCursor); + strcat(title, sim_name); + strcat(title, " Simulator"); + title[0] = strlen(title) - 1; /* Pascal string done */ + for (i = 0; i <= title[0]; i++) { /* copy to unsigned char */ + ptitle[i] = title[i]; + } + SIOUXSetTitle(ptitle); + return SCPE_OK; +} + +t_stat sim_ttrun (void) +{ +return SCPE_OK; +} + +t_stat sim_ttcmd (void) +{ +return SCPE_OK; +} + +t_stat sim_ttclose (void) +{ +return SCPE_OK; +} + +t_stat sim_os_poll_kbd (void) +{ +int c; + +if (!ps_kbhit ()) return SCPE_OK; +c = ps_getch(); +if ((c & 0177) == sim_del_char) c = 0177; +if ((c & 0177) == sim_int_char) return SCPE_STOP; +if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK; +return c | SCPE_KFLAG; +} + +t_stat sim_os_putchar (int32 c) +{ +if (c != 0177) { + putchar (c); + fflush (stdout); + } +return SCPE_OK; +} + +/* BSD UNIX routines */ + +#elif defined (BSDTTY) + +#include +#include +#include + +struct sgttyb cmdtty,runtty; /* V6/V7 stty data */ +struct tchars cmdtchars,runtchars; /* V7 editing */ +struct ltchars cmdltchars,runltchars; /* 4.2 BSD editing */ +int cmdfl,runfl; /* TTY flags */ + +t_stat sim_ttinit (void) +{ +cmdfl = fcntl (0, F_GETFL, 0); /* get old flags and status */ +runfl = cmdfl | FNDELAY; +if (ioctl (0, TIOCGETP, &cmdtty) < 0) return SCPE_TTIERR; +if (ioctl (0, TIOCGETC, &cmdtchars) < 0) return SCPE_TTIERR; +if (ioctl (0, TIOCGLTC, &cmdltchars) < 0) return SCPE_TTIERR; +runtty = cmdtty; /* initial run state */ +runtty.sg_flags = cmdtty.sg_flags & ~(ECHO|CRMOD) | CBREAK; +runtchars.t_intrc = sim_int_char; /* interrupt */ +runtchars.t_quitc = 0xFF; /* no quit */ +runtchars.t_startc = 0xFF; /* no host sync */ +runtchars.t_stopc = 0xFF; +runtchars.t_eofc = 0xFF; +runtchars.t_brkc = 0xFF; +runltchars.t_suspc = 0xFF; /* no specials of any kind */ +runltchars.t_dsuspc = 0xFF; +runltchars.t_rprntc = 0xFF; +runltchars.t_flushc = 0xFF; +runltchars.t_werasc = 0xFF; +runltchars.t_lnextc = 0xFF; +return SCPE_OK; /* return success */ +} + +t_stat sim_ttrun (void) +{ +runtchars.t_intrc = sim_int_char; /* in case changed */ +fcntl (0, F_SETFL, runfl); /* non-block mode */ +if (ioctl (0, TIOCSETP, &runtty) < 0) return SCPE_TTIERR; +if (ioctl (0, TIOCSETC, &runtchars) < 0) return SCPE_TTIERR; +if (ioctl (0, TIOCSLTC, &runltchars) < 0) return SCPE_TTIERR; +nice (10); /* lower priority */ +return SCPE_OK; +} + +t_stat sim_ttcmd (void) +{ +nice (-10); /* restore priority */ +fcntl (0, F_SETFL, cmdfl); /* block mode */ +if (ioctl (0, TIOCSETP, &cmdtty) < 0) return SCPE_TTIERR; +if (ioctl (0, TIOCSETC, &cmdtchars) < 0) return SCPE_TTIERR; +if (ioctl (0, TIOCSLTC, &cmdltchars) < 0) return SCPE_TTIERR; +return SCPE_OK; +} + +t_stat sim_ttclose (void) +{ +return sim_ttcmd (); +} + +t_stat sim_os_poll_kbd (void) +{ +int status; +unsigned char buf[1]; + +status = read (0, buf, 1); +if (status != 1) return SCPE_OK; +if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK; +else return (buf[0] | SCPE_KFLAG); +} + +t_stat sim_os_putchar (int32 out) +{ +char c; + +c = out; +write (1, &c, 1); +return SCPE_OK; +} + +/* POSIX UNIX routines, from Leendert Van Doorn */ + +#else + +#include +#include + +struct termios cmdtty, runtty; +static int prior_norm = 1; + +t_stat sim_ttinit (void) +{ +if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */ +if (tcgetattr (0, &cmdtty) < 0) return SCPE_TTIERR; /* get old flags */ +runtty = cmdtty; +runtty.c_lflag = runtty.c_lflag & ~(ECHO | ICANON); /* no echo or edit */ +runtty.c_oflag = runtty.c_oflag & ~OPOST; /* no output edit */ +runtty.c_iflag = runtty.c_iflag & ~ICRNL; /* no cr conversion */ +runtty.c_cc[VINTR] = sim_int_char; /* interrupt */ +runtty.c_cc[VQUIT] = 0; /* no quit */ +runtty.c_cc[VERASE] = 0; +runtty.c_cc[VKILL] = 0; +runtty.c_cc[VEOF] = 0; +runtty.c_cc[VEOL] = 0; +runtty.c_cc[VSTART] = 0; /* no host sync */ +runtty.c_cc[VSUSP] = 0; +runtty.c_cc[VSTOP] = 0; +#if defined (VREPRINT) +runtty.c_cc[VREPRINT] = 0; /* no specials */ +#endif +#if defined (VDISCARD) +runtty.c_cc[VDISCARD] = 0; +#endif +#if defined (VWERASE) +runtty.c_cc[VWERASE] = 0; +#endif +#if defined (VLNEXT) +runtty.c_cc[VLNEXT] = 0; +#endif +runtty.c_cc[VMIN] = 0; /* no waiting */ +runtty.c_cc[VTIME] = 0; +#if defined (VDSUSP) +runtty.c_cc[VDSUSP] = 0; +#endif +#if defined (VSTATUS) +runtty.c_cc[VSTATUS] = 0; +#endif +return SCPE_OK; +} + +t_stat sim_ttrun (void) +{ +int ret; +if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */ +runtty.c_cc[VINTR] = sim_int_char; /* in case changed */ +if (tcsetattr (0, TCSAFLUSH, &runtty) < 0) return SCPE_TTIERR; +if (prior_norm) { /* at normal pri? */ + errno = 0; + ret = nice (10); /* try to lower pri */ + prior_norm = errno; /* if no error, done */ + } +return SCPE_OK; +} + +t_stat sim_ttcmd (void) +{ +int ret; +if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */ +if (!prior_norm) { /* priority down? */ + errno = 0; + ret = nice (-10); /* try to raise pri */ + prior_norm = (errno == 0); /* if no error, done */ + } +if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) return SCPE_TTIERR; +return SCPE_OK; +} + +t_stat sim_ttclose (void) +{ +return sim_ttcmd (); +} + +t_stat sim_os_poll_kbd (void) +{ +int status; +unsigned char buf[1]; + +status = read (0, buf, 1); +if (status != 1) return SCPE_OK; +if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK; +else return (buf[0] | SCPE_KFLAG); +} + +t_stat sim_os_putchar (int32 out) +{ +char c; +int ret; + +c = out; +ret =write (1, &c, 1); +return SCPE_OK; +} + +#endif diff --git a/simhv36-1/sim_console.h b/simhv36-1/sim_console.h new file mode 100644 index 0000000..e5530ee --- /dev/null +++ b/simhv36-1/sim_console.h @@ -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 diff --git a/simhv36-1/sim_defs.h b/simhv36-1/sim_defs.h new file mode 100644 index 0000000..c7643a2 --- /dev/null +++ b/simhv36-1/sim_defs.h @@ -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 +#include +#include +#include +#include +#include +#include + +#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 diff --git a/simhv36-1/sim_ether.c b/simhv36-1/sim_ether.c new file mode 100644 index 0000000..61a9fe7 --- /dev/null +++ b/simhv36-1/sim_ether.c @@ -0,0 +1,1273 @@ +/* sim_ether.c: OS-dependent network routines + ------------------------------------------------------------------------------ + Copyright (c) 2002-2006, 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. + + ------------------------------------------------------------------------------ + + This ethernet simulation is based on the PCAP and WinPcap packages. + + PCAP/WinPcap was chosen as the basis for network code since it is the most + "universal" of the various network packages available. Using this style has + allowed rapid network development for the major SIMH platforms. Developing + a network package specifically for SIMH was rejected due to the time required; + the advantage would be a more easily compiled and integrated code set. + + There are various problems associated with use of ethernet networking, which + would be true regardless of the network package used, since there are no + universally accepted networking methods. The most serious of these is getting + the proper networking package loaded onto the system, since most environments + do not come with the network interface packages loaded. + + The second most serious network issue relates to security. The network + simulation needs to simulate operating system level functionality (packet + driving). However, the host network programming interfaces tend to operate at + the user level of functionality, so getting to the full functionality of + the network interface usually requires that the person executing the + network code be a privileged user of the host system. See the PCAP/WinPcap + documentation for the appropriate host platform if unprivileged use of + networking is needed - there may be known workarounds. + + ------------------------------------------------------------------------------ + + Supported/Tested Platforms: + + Windows(NT,2K,XP,2K3) WinPcap V3.0+ + Linux libpcap at least 0.9 + OpenBSD,FreeBSD,NetBSD libpcap at least 0.9 + MAC OS/X libpcap at least 0.9 + Solaris Sparc libpcap at least 0.9 + Solaris Intel libpcap at least 0.9 + AIX ?? + HP/UX ?? + Compaq Tru64 Unix ?? + VMS Alpha/Itanium VMS only, needs VMS libpcap + + WinPcap is available from: + http://winpcap.polito.it/ + libpcap for VMS is available from: + http://simh.trailing-edge.com/sources/vms-pcap.zip + libpcap for other Unix platforms is available at: + Current Version: http://www.tcpdump.org/daily/libpcap-current.tar.gz + Released Version: http://www.tcpdump.org/release/ + Note: You can only use the released version if it is at least + version 0.9 + + + We've gotten the tarball, unpacked, built and installed it with: + gzip -dc libpcap-current.tar.gz | tar xvf - + cd libpcap-directory-name + ./configure + make + make install + Note: The "make install" step generally will have to be done as root. + This will install libpcap in /usr/local/lib and /usr/local/include + It is then important to make sure that you get the just installed + libpcap components referenced during your build. This is generally + achieved by invoking gcc with: + -isystem /usr/local/include -L /usr/local/lib + + + Note: Building for the platforms indicated above, with the indicated libpcap, + should automatically leverage the appropriate mechanisms contained here. + Things are structured so that it is likely to work for any other as yet + untested platform. If it works for you, please let the author know so we + can update the table above. If it doesn't work, then the following #define + variables can influence the operation on an untested platform. + + USE_BPF - Determines if this code leverages a libpcap/WinPcap + provided bpf packet filtering facility. All tested + environments have bpf facilities that work the way we + need them to. However a new one might not. undefine + this variable to let this code do its own filtering. + USE_SETNONBLOCK - Specifies whether the libpcap environment's non-blocking + semantics are to be leveraged. This helps to manage the + varying behaviours of the kernel packet facilities + leveraged by libpcap. + USE_READER_THREAD - Specifies that packet reading should be done in the + context of a separate thread. The Posix threading + APIs are used. This option is less efficient than the + default non-threaded approach, but it exists since some + platforms don't want to work with nonblocking libpcap + semantics. OpenBSD and NetBSD either don't have pthread + APIs available, or they are too buggy to be useful. + Using the threaded approach may require special compile + and/or link time switches (i.e. -lpthread or -pthread, + etc.) Consult the documentation for your platform as + needed. + MUST_DO_SELECT - Specifies that when USE_READER_THREAD is active, that + select() should be used to determin when available + packets are ready for reading. Otherwise, we depend + on the libpcap/kernel packet timeout specified on + pcap_open_live. If USE_READER_THREAD is not set, then + MUST_DO_SELECT is irrelevant + + NEED_PCAP_SENDPACKET + - Specifies that you are using an older version of libpcap + which doesn't provide a pcap_sendpacket API. + + NOTE: Changing these defines is done in either sim_ether.h OR on the global + compiler command line which builds all of the modules included in a + simulator. + + ------------------------------------------------------------------------------ + + Modification history: + + 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman) + 15-Dec-05 DTH Patched eth_host_devices [remove non-ethernet devices] + (from Mark Pizzolato and Galen Tackett, 08-Jun-05) + Patched eth_open [tun fix](from Antal Ritter, 06-Oct-05) + 30-Nov-05 DTH Added option to regenerate CRC on received packets; some + ethernet devices need to pass it on to the simulation, and by + the time libpcap/winpcap gets the packet, the host OS network + layer has already stripped CRC out of the packet + 01-Dec-04 DTH Added Windows user-defined adapter names (from Timothe Litt) + 25-Mar-04 MP Revised comments and minor #defines to deal with updated + libpcap which now provides pcap_sendpacket on all platforms. + 04-Feb-04 MP Returned success/fail status from eth_write to support + determining if the current libpcap connection can successfully + write packets. + Added threaded approach to reading packets since + this works better on some platforms (solaris intel) than the + inconsistently implemented non-blocking read approach. + 04-Feb-04 DTH Converted ETH_DEBUG to sim_debug + 13-Jan-04 MP tested and fixed on OpenBSD, NetBS and FreeBSD. + 09-Jan-04 MP removed the BIOCSHDRCMPLT ioctl() for OS/X + 05-Jan-04 DTH Added eth_mac_scan + 30-Dec-03 DTH Cleaned up queue routines, added no network support message + 26-Dec-03 DTH Added ethernet show and queue functions from pdp11_xq + 15-Dec-03 MP polished generic libpcap support. + 05-Dec-03 DTH Genericized eth_devices() and #ifdefs + 03-Dec-03 MP Added Solaris support + 02-Dec-03 DTH Corrected decnet fix to use reflection counting + 01-Dec-03 DTH Added BPF source filtering and reflection counting + 28-Nov-03 DTH Rewrote eth_devices using universal pcap_findalldevs() + 25-Nov-03 DTH Verified DECNET_FIX, reversed ifdef to mainstream code + 19-Nov-03 MP Fixed BPF functionality on Linux/BSD. + 17-Nov-03 DTH Added xBSD simplification + 14-Nov-03 DTH Added #ifdef DECNET_FIX for problematic duplicate detection code + 13-Nov-03 DTH Merged in __FreeBSD__ support + 21-Oct-03 MP Added enriched packet dumping for debugging + 20-Oct-03 MP Added support for multiple ethernet devices on VMS + 20-Sep-03 Ankan Add VMS support (Alpha only) + 29-Sep-03 MP Changed separator character in eth_fmt_mac to be ":" to + format ethernet addresses the way the BPF compile engine + wants to see them. + Added BPF support to filter packets + Added missing printf in eth_close + 07-Jun-03 MP Added WIN32 support for DECNET duplicate address detection. + 06-Jun-03 MP Fixed formatting of Ethernet Protocol Type in eth_packet_trace + 30-May-03 DTH Changed WIN32 to _WIN32 for consistency + 07-Mar-03 MP Fixed Linux implementation of PacketGetAdapterNames to also + work on Red Hat 6.2-sparc and Debian 3.0r1-sparc. + 03-Mar-03 MP Changed logging to be consistent on stdout and sim_log + 01-Feb-03 MP Changed type of local variables in eth_packet_trace to + conform to the interface needs of eth_mac_fmt wich produces + char data instead of unsigned char data. Suggested by the + DECC compiler. + 15-Jan-03 DTH Corrected PacketGetAdapterNames parameter2 datatype + 26-Dec-02 DTH Merged Mark Pizzolato's enhancements with main source + Added networking documentation + Changed _DEBUG to ETH_DEBUG + 20-Dec-02 MP Added display of packet CRC to the eth_packet_trace. + This helps distinguish packets with identical lengths + and protocols. + 05-Dec-02 MP With the goal of draining the input buffer more rapidly + changed eth_read to call pcap_dispatch repeatedly until + either a timeout returns nothing or a packet allowed by + the filter is seen. This more closely reflects how the + pcap layer will work when the filtering is actually done + by a bpf filter. + 31-Oct-02 DTH Added USE_NETWORK conditional + Reworked not attached test + Added OpenBSD support (from Federico Schwindt) + Added ethX detection simplification (from Megan Gentry) + Removed sections of temporary code + Added parameter validation + 23-Oct-02 DTH Beta 5 released + 22-Oct-02 DTH Added all_multicast and promiscuous support + Fixed not attached behavior + 21-Oct-02 DTH Added NetBSD support (from Jason Thorpe) + Patched buffer size to make sure entire packet is read in + Made 'ethX' check characters passed as well as length + Corrected copyright again + 16-Oct-02 DTH Beta 4 released + Corrected copyright + 09-Oct-02 DTH Beta 3 released + Added pdp11 write acceleration (from Patrick Caulfield) + 08-Oct-02 DTH Beta 2 released + Integrated with 2.10-0p4 + Added variable vector and copyrights + 04-Oct-02 DTH Added linux support (from Patrick Caulfield) + 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11 + 24-Sep-02 DTH Finished eth_devices, eth_getname + 18-Sep-02 DTH Callbacks implemented + 13-Sep-02 DTH Basic packet read/write written + 20-Aug-02 DTH Created Sim_Ether for O/S independant ethernet implementation + + ------------------------------------------------------------------------------ +*/ + +#include +#include "sim_ether.h" +#include "sim_sock.h" + +extern FILE *sim_log; + + +/*============================================================================*/ +/* OS-independant ethernet routines */ +/*============================================================================*/ + +t_stat eth_mac_scan (ETH_MAC* mac, char* strmac) +{ + int i, j; + short int num; + char cptr[18]; + int len = strlen(strmac); + const ETH_MAC zeros = {0,0,0,0,0,0}; + const ETH_MAC ones = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + ETH_MAC newmac; + + /* format of string must be 6 double-digit hex bytes with valid separators + ideally, this mac scanner could allow more flexible formatting later */ + if (len != 17) return SCPE_ARG; + + /* copy string to local storage for mangling */ + strcpy(cptr, strmac); + + /* make sure byte separators are OK */ + for (i=2; i> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ]; + return(crc ^ mask); +} + +void eth_add_crc32(ETH_PACK* packet) +{ + if (packet->len <= ETH_MAX_PACKET) { + uint32 crc = eth_crc32(0, packet->msg, packet->len); /* calculate CRC */ + uint32 ncrc = htonl(crc); /* CRC in network order */ + int size = sizeof(ncrc); /* size of crc field */ + memcpy(&packet->msg[packet->len], &ncrc, size); /* append crc to packet */ + packet->crc_len = packet->len + size; /* set packet crc length */ + } else { + packet->crc_len = 0; /* appending crc would destroy packet */ + } +} + +void eth_setcrc(ETH_DEV* dev, int need_crc) +{ + dev->need_crc = need_crc; +} + +void eth_packet_trace_ex(ETH_DEV* dev, const uint8 *msg, int len, char* txt, int dmp) +{ + if (dev->dptr->dctrl & dev->dbit) { + char src[20]; + char dst[20]; + unsigned short* proto = (unsigned short*) &msg[12]; + uint32 crc = eth_crc32(0, msg, len); + eth_mac_fmt((ETH_MAC*)&msg[0], dst); + eth_mac_fmt((ETH_MAC*)&msg[6], src); + sim_debug(dev->dbit, dev->dptr, "%s dst: %s src: %s proto: 0x%04X len: %d crc: %X\n", + txt, dst, src, ntohs(*proto), len, crc); + if (dmp) { + int i, same, group, sidx, oidx; + char outbuf[80], strbuf[18]; + static char hex[] = "0123456789ABCDEF"; + for (i=same=0; i 0) && (0 == memcmp(&msg[i], &msg[i-16], 16))) { + ++same; + continue; + } + if (same > 0) { + sim_debug(dev->dbit, dev->dptr, "%04X thru %04X same as above\r\n", i-(16*same), i-1); + same = 0; + } + group = (((len - i) > 16) ? 16 : (len - i)); + for (sidx=oidx=0; sidx>4)&0xf]; + outbuf[oidx++] = hex[msg[i+sidx]&0xf]; + if (isprint(msg[i+sidx])) + strbuf[sidx] = msg[i+sidx]; + else + strbuf[sidx] = '.'; + } + outbuf[oidx] = '\0'; + strbuf[sidx] = '\0'; + sim_debug(dev->dbit, dev->dptr, "%04X%-48s %s\r\n", i, outbuf, strbuf); + } + if (same > 0) + sim_debug(dev->dbit, dev->dptr, "%04X thru %04X same as above\r\n", i-(16*same), len-1); + } + } +} + +void eth_packet_trace(ETH_DEV* dev, const uint8 *msg, int len, char* txt) +{ + eth_packet_trace_ex(dev, msg, len, txt, 1/*len > ETH_MAX_PACKET*/); +} + +char* eth_getname(int number, char* name) +{ + ETH_LIST list[ETH_MAX_DEVICE]; + int count = eth_devices(ETH_MAX_DEVICE, list); + + if (count < number) return 0; + strcpy(name, list[number].name); + return name; +} + +char* eth_getname_bydesc(char* desc, char* name) +{ + ETH_LIST list[ETH_MAX_DEVICE]; + int count = eth_devices(ETH_MAX_DEVICE, list); + int i; + int j=strlen(desc); + + for (i=0; i s2) + return 1; + if (s1 == 0) return 0; + } + return 0; +} + +char* eth_getname_byname(char* name, char* temp) +{ + ETH_LIST list[ETH_MAX_DEVICE]; + int count = eth_devices(ETH_MAX_DEVICE, list); + int i, n, found; + + found = 0; + n = strlen(name); + for (i=0; ireflections = -1; /* not established yet */ +} + +t_stat eth_show (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + ETH_LIST list[ETH_MAX_DEVICE]; + int number = eth_devices(ETH_MAX_DEVICE, list); + + fprintf(st, "ETH devices:\n"); + if (number == -1) + fprintf(st, " network support not available in simulator\n"); + else + if (number == 0) + fprintf(st, " no network devices are available\n"); + else { + int i, min, len; + for (i=0, min=0; i min) min = len; + for (i=0; iitem) { + size_t size = sizeof(struct eth_item) * max; + que->max = max; + que->item = (struct eth_item *) malloc(size); + if (que->item) { + /* init dynamic memory */ + memset(que->item, 0, size); + } else { + /* failed to allocate memory */ + char* msg = "EthQ: failed to allocate dynamic queue[%d]\r\n"; + printf(msg, max); + if (sim_log) fprintf(sim_log, msg, max); + return SCPE_MEM; + }; + }; + return SCPE_OK; +} + +void ethq_clear(ETH_QUE* que) +{ + /* clear packet array */ + memset(que->item, 0, sizeof(struct eth_item) * que->max); + /* clear rest of structure */ + que->count = que->head = que->tail = que->loss = que->high = 0; +} + +void ethq_remove(ETH_QUE* que) +{ + struct eth_item* item = &que->item[que->head]; + + if (que->count) { + memset(item, 0, sizeof(struct eth_item)); + if (++que->head == que->max) + que->head = 0; + que->count--; + } +} + +void ethq_insert(ETH_QUE* que, int32 type, ETH_PACK* pack, int32 status) +{ + struct eth_item* item; + + /* if queue empty, set pointers to beginning */ + if (!que->count) { + que->head = 0; + que->tail = -1; + } + + /* find new tail of the circular queue */ + if (++que->tail == que->max) + que->tail = 0; + if (++que->count > que->max) { + que->count = que->max; + /* lose oldest packet */ + if (++que->head == que->max) + que->head = 0; + que->loss++; + } + if (que->count > que->high) + que->high = que->count; + + /* set information in (new) tail item */ + item = &que->item[que->tail]; + item->type = type; + item->packet.len = pack->len; + item->packet.used = 0; + item->packet.crc_len = pack->crc_len; + memcpy(item->packet.msg, pack->msg, ((pack->len > pack->crc_len) ? pack->len : pack->crc_len)); + item->packet.status = status; +} + +/*============================================================================*/ +/* Non-implemented versions */ +/*============================================================================*/ + +#if !defined (USE_NETWORK) +t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit) + {return SCPE_NOFNC;} +t_stat eth_close (ETH_DEV* dev) + {return SCPE_NOFNC;} +t_stat eth_write (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) + {return SCPE_NOFNC;} +t_stat eth_read (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) + {return SCPE_NOFNC;} +t_stat eth_filter (ETH_DEV* dev, int addr_count, ETH_MAC* addresses, + ETH_BOOL all_multicast, ETH_BOOL promiscuous) + {return SCPE_NOFNC;} +int eth_devices (int max, ETH_LIST* dev) + {return -1;} +#else /* endif unimplemented */ + +/*============================================================================*/ +/* WIN32, Linux, and xBSD routines use WinPcap and libpcap packages */ +/* OpenVMS Alpha uses a WinPcap port and an associated execlet */ +/*============================================================================*/ + +#if defined (xBSD) && !defined(__APPLE__) +#include +#include +#endif /* xBSD */ + +#include +#include + +/* Allows windows to look up user-defined adapter names */ +#if defined(_WIN32) +#include +#endif + +/* Some platforms have always had pcap_sendpacket */ +#if defined(_WIN32) || defined(VMS) +#define HAS_PCAP_SENDPACKET 1 +#else +/* The latest libpcap and WinPcap all have pcap_sendpacket */ +#if !defined (NEED_PCAP_SENDPACKET) +#define HAS_PCAP_SENDPACKET 1 +#endif +#endif + +#if !defined (HAS_PCAP_SENDPACKET) +/* libpcap has no function to write a packet, so we need to implement + pcap_sendpacket() for compatibility with the WinPcap base code. + Return value: 0=Success, -1=Failure */ +int pcap_sendpacket(pcap_t* handle, const u_char* msg, int len) +{ +#if defined (__linux) + return (send(pcap_fileno(handle), msg, len, 0) == len)? 0 : -1; +#else + return (write(pcap_fileno(handle), msg, len) == len)? 0 : -1; +#endif /* linux */ +} +#endif /* !HAS_PCAP_SENDPACKET */ + +#if defined (USE_READER_THREAD) +#include + +void eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data); + +static void * +_eth_reader(void *arg) +{ +ETH_DEV* volatile dev = (ETH_DEV*)arg; +int status; +struct timeval timeout; + + timeout.tv_sec = 0; + timeout.tv_usec = 200*1000; + + sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n"); + + while (dev->handle) { +#if defined (MUST_DO_SELECT) + int sel_ret; + + fd_set setl; + FD_ZERO(&setl); + FD_SET(pcap_get_selectable_fd((pcap_t *)dev->handle), &setl); + sel_ret = select(1+pcap_get_selectable_fd((pcap_t *)dev->handle), &setl, NULL, NULL, &timeout); + if (sel_ret < 0 && errno != EINTR) break; + if (sel_ret > 0) { + /* dispatch read request queue available packets */ + status = pcap_dispatch((pcap_t*)dev->handle, -1, ð_callback, (u_char*)dev); + } +#else + /* dispatch read request queue available packets */ + status = pcap_dispatch((pcap_t*)dev->handle, 1, ð_callback, (u_char*)dev); +#endif + } + + sim_debug(dev->dbit, dev->dptr, "Reader Thread Exiting\n"); + return NULL; +} +#endif + +t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit) +{ + const int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ; + char errbuf[PCAP_ERRBUF_SIZE]; + char temp[1024]; + char* savname = name; + int num; + char* msg; + + /* initialize device */ + eth_zero(dev); + + /* translate name of type "ethX" to real device name */ + if ((strlen(name) == 4) + && (tolower(name[0]) == 'e') + && (tolower(name[1]) == 't') + && (tolower(name[2]) == 'h') + && isdigit(name[3]) + ) { + num = atoi(&name[3]); + savname = eth_getname(num, temp); + if (savname == 0) /* didn't translate */ + return SCPE_OPENERR; + } else { + /* are they trying to use device description? */ + savname = eth_getname_bydesc(name, temp); + if (savname == 0) { /* didn't translate */ + /* probably is not ethX and has no description */ + savname = eth_getname_byname(name, temp); + if (savname == 0) /* didn't translate */ + return SCPE_OPENERR; + } + } + + /* attempt to connect device */ + memset(errbuf, 0, sizeof(errbuf)); + dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf); + if (!dev->handle) { /* can't open device */ + msg = "Eth: pcap_open_live error - %s\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + return SCPE_OPENERR; + } else { + msg = "Eth: opened %s\r\n"; + printf (msg, savname); + if (sim_log) fprintf (sim_log, msg, savname); + } + + /* save name of device */ + dev->name = malloc(strlen(savname)+1); + strcpy(dev->name, savname); + + /* save debugging information */ + dev->dptr = dptr; + dev->dbit = dbit; + +#if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__) + /* Tell the kernel that the header is fully-formed when it gets it. + This is required in order to fake the src address. */ + { + int one = 1; + ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one); + } +#endif /* xBSD */ + +#if defined (USE_READER_THREAD) + { + pthread_attr_t attr; + + ethq_init (&dev->read_queue, 200); /* initialize FIFO queue */ + pthread_mutex_init (&dev->lock, NULL); + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_create (&dev->reader_thread, &attr, _eth_reader, (void *)dev); + pthread_attr_destroy(&attr); + } +#else /* !defined (USE_READER_THREAD */ +#ifdef USE_SETNONBLOCK + /* set ethernet device non-blocking so pcap_dispatch() doesn't hang */ + if (pcap_setnonblock (dev->handle, 1, errbuf) == -1) { + msg = "Eth: Failed to set non-blocking: %s\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + } +#endif +#endif /* !defined (USE_READER_THREAD */ + return SCPE_OK; +} + +t_stat eth_close(ETH_DEV* dev) +{ + char* msg = "Eth: closed %s\r\n"; + pcap_t *pcap; + + /* make sure device exists */ + if (!dev) return SCPE_UNATT; + + /* close the device */ + pcap = (pcap_t *)dev->handle; + dev->handle = NULL; + pcap_close(pcap); + printf (msg, dev->name); + if (sim_log) fprintf (sim_log, msg, dev->name); + +#if defined (USE_READER_THREAD) + pthread_join (dev->reader_thread, NULL); +#endif + + /* clean up the mess */ + free(dev->name); + eth_zero(dev); + + return SCPE_OK; +} + +t_stat eth_reflect(ETH_DEV* dev, ETH_MAC mac) +{ + ETH_PACK send, recv; + t_stat status; + int i; + struct timeval delay; + + /* build a packet */ + memset (&send, 0, sizeof(ETH_PACK)); + send.len = ETH_MIN_PACKET; /* minimum packet size */ + memcpy(&send.msg[0], mac, sizeof(ETH_MAC)); /* target address */ + memcpy(&send.msg[6], mac, sizeof(ETH_MAC)); /* source address */ + send.msg[12] = 0x90; /* loopback packet type */ + for (i=14; ireflections = 0; + eth_filter(dev, 1, (ETH_MAC *)mac, 0, 0); + + /* send the packet */ + status = eth_write (dev, &send, NULL); + if (status != SCPE_OK) { + char *msg; + msg = "Eth: Error Transmitting packet: %s\r\n" + "You may need to run as root, or install a libpcap version\r\n" + "which is at least 0.9 from www.tcpdump.org\r\n"; + printf(msg, strerror(errno)); + if (sim_log) fprintf (sim_log, msg, strerror(errno)); + return status; + } + + /* if/when we have a sim_os_msleep() we'll use it here instead of this select() */ + delay.tv_sec = 0; + delay.tv_usec = 50*1000; + select(0, NULL, NULL, NULL, &delay); /* make sure things settle into the read path */ + + /* empty the read queue and count the reflections */ + do { + memset (&recv, 0, sizeof(ETH_PACK)); + status = eth_read (dev, &recv, NULL); + if (memcmp(send.msg, recv.msg, ETH_MIN_PACKET)== 0) + dev->reflections++; + } while (recv.len > 0); + + sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections); + return dev->reflections; +} + +t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) +{ + int status = 1; /* default to failure */ + + /* make sure device exists */ + if (!dev) return SCPE_UNATT; + + /* make sure packet exists */ + if (!packet) return SCPE_ARG; + + /* make sure packet is acceptable length */ + if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) { + eth_packet_trace (dev, packet->msg, packet->len, "writing"); + + /* dispatch write request (synchronous; no need to save write info to dev) */ + status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len); + + /* detect sending of decnet loopback packet */ + if ((status == 0) && DECNET_SELF_FRAME(dev->decnet_addr, packet->msg)) + dev->decnet_self_sent += dev->reflections; + + } /* if packet->len */ + + /* call optional write callback function */ + if (routine) + (routine)(status); + + return ((status == 0) ? SCPE_OK : SCPE_IOERR); +} + +void eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data) +{ + ETH_DEV* dev = (ETH_DEV*) info; +#ifdef USE_BPF + int to_me = 1; +#else /* !USE_BPF */ + int to_me = 0; + int from_me = 0; + int i; + +#ifdef ETH_DEBUG +// eth_packet_trace (dev, data, header->len, "received"); +#endif + for (i = 0; i < dev->addr_count; i++) { + if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1; + if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1; + } + + /* all multicast mode? */ + if (dev->all_multicast && (data[0] & 0x01)) to_me = 1; + + /* promiscuous mode? */ + if (dev->promiscuous) to_me = 1; +#endif /* USE_BPF */ + + /* detect sending of decnet loopback packet */ + if (DECNET_SELF_FRAME(dev->decnet_addr, data)) { + /* lower reflection count - if already zero, pass it on */ + if (dev->decnet_self_sent > 0) { + dev->decnet_self_sent--; + to_me = 0; + } +#ifndef USE_BPF + else + from_me = 0; +#endif + } + +#ifdef USE_BPF + if (to_me) { +#else /* !USE_BPF */ + if (to_me && !from_me) { +#endif +#if defined (USE_READER_THREAD) + ETH_PACK tmp_packet; + + /* set data in passed read packet */ + tmp_packet.len = header->len; + memcpy(tmp_packet.msg, data, header->len); + if (dev->need_crc) + eth_add_crc32(&tmp_packet); + + eth_packet_trace (dev, tmp_packet.msg, tmp_packet.len, "rcvqd"); + + pthread_mutex_lock (&dev->lock); + ethq_insert(&dev->read_queue, 2, &tmp_packet, 0); + pthread_mutex_unlock (&dev->lock); +#else + /* set data in passed read packet */ + dev->read_packet->len = header->len; + memcpy(dev->read_packet->msg, data, header->len); + if (dev->need_crc) + eth_add_crc32(dev->read_packet); + + eth_packet_trace (dev, dev->read_packet->msg, dev->read_packet->len, "reading"); + + /* call optional read callback function */ + if (dev->read_callback) + (dev->read_callback)(0); +#endif + } +} + +t_stat eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) +{ + int status; + + /* make sure device exists */ + + if (!dev) return SCPE_UNATT; + + /* make sure packet exists */ + if (!packet) return SCPE_ARG; + +#if !defined (USE_READER_THREAD) + /* set read packet */ + dev->read_packet = packet; + packet->len = 0; + + /* set optional callback routine */ + dev->read_callback = routine; + + /* dispatch read request to either receive a filtered packet or timeout */ + do { + status = pcap_dispatch((pcap_t*)dev->handle, 1, ð_callback, (u_char*)dev); + } while ((status) && (0 == packet->len)); + +#else /* USE_READER_THREAD */ + + status = 0; + pthread_mutex_lock (&dev->lock); + if (dev->read_queue.count > 0) { + ETH_ITEM* item = &dev->read_queue.item[dev->read_queue.head]; + packet->len = item->packet.len; + memcpy(packet->msg, item->packet.msg, packet->len); + if (routine) + routine(status); + ethq_remove(&dev->read_queue); + } + pthread_mutex_unlock (&dev->lock); +#endif + + return SCPE_OK; +} + +t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses, + ETH_BOOL all_multicast, ETH_BOOL promiscuous) +{ + int i; + bpf_u_int32 bpf_subnet, bpf_netmask; + char buf[110+66*ETH_FILTER_MAX]; + char errbuf[PCAP_ERRBUF_SIZE]; + char mac[20]; + char* buf2; + t_stat status; +#ifdef USE_BPF + struct bpf_program bpf; + char* msg; +#endif + + /* make sure device exists */ + if (!dev) return SCPE_UNATT; + + /* filter count OK? */ + if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX)) + return SCPE_ARG; + else + if (!addresses) return SCPE_ARG; + + /* set new filter addresses */ + for (i = 0; i < addr_count; i++) + memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC)); + dev->addr_count = addr_count; + + /* store other flags */ + dev->all_multicast = all_multicast; + dev->promiscuous = promiscuous; + + /* print out filter information if debugging */ + if (dev->dptr->dctrl & dev->dbit) { + sim_debug(dev->dbit, dev->dptr, "Filter Set\n"); + for (i = 0; i < addr_count; i++) { + char mac[20]; + eth_mac_fmt(&dev->filter_address[i], mac); + sim_debug(dev->dbit, dev->dptr, " Addr[%d]: %s\n", i, mac); + } + if (dev->all_multicast) + sim_debug(dev->dbit, dev->dptr, "All Multicast\n"); + if (dev->promiscuous) + sim_debug(dev->dbit, dev->dptr, "Promiscuous\n"); + } + + /* test reflections */ + if (dev->reflections == -1) + status = eth_reflect(dev, dev->filter_address[0]); + + /* setup BPF filters and other fields to minimize packet delivery */ + strcpy(buf, ""); + + /* construct destination filters - since the real ethernet interface was set + into promiscuous mode by eth_open(), we need to filter out the packets that + our simulated interface doesn't want. */ + if (!dev->promiscuous) { + for (i = 0; i < addr_count; i++) { + eth_mac_fmt(&dev->filter_address[i], mac); + if (!strstr(buf, mac)) /* eliminate duplicates */ + sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "", mac); + } + if (dev->all_multicast) + sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : ""); + } + + /* construct source filters - this prevents packets from being reflected back + by systems where WinPcap and libpcap cause packet reflections. Note that + some systems do not reflect packets at all. This *assumes* that the + simulated NIC will not send out packets with multicast source fields. */ + if ((addr_count > 0) && (dev->reflections > 0)) { + if (strlen(buf) > 0) + sprintf(&buf[strlen(buf)], " and "); + sprintf (&buf[strlen(buf)], "not ("); + buf2 = &buf[strlen(buf)]; + for (i = 0; i < addr_count; i++) { + if (dev->filter_address[i][0] & 0x01) continue; /* skip multicast addresses */ + eth_mac_fmt(&dev->filter_address[i], mac); + if (!strstr(buf2, mac)) /* eliminate duplicates */ + sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac); + } + sprintf (&buf[strlen(buf)], ")"); + } + /* When starting, DECnet sends out a packet with the source and destination + addresses set to the same value as the DECnet MAC address. This packet is + designed to find and help diagnose DECnet address conflicts. Normally, this + packet would not be seen by the sender, only by the other machine that has + the same DECnet address. If the ethernet subsystem is reflecting packets, + DECnet will fail to start if it sees the reflected packet, since it thinks + another system is using this DECnet address. We have to let these packets + through, so that if another machine has the same DECnet address that we + can detect it. Both eth_write() and eth_callback() help by checking the + reflection count - eth_write() adds the reflection count to + dev->decnet_self_sent, and eth_callback() check the value - if the + dev->decnet_self_sent count is zero, then the packet has come from another + machine with the same address, and needs to be passed on to the simulated + machine. */ + memset(dev->decnet_addr, 0, sizeof(ETH_MAC)); + /* check for decnet address in filters */ + if ((addr_count) && (dev->reflections > 0)) { + for (i = 0; i < addr_count; i++) { + eth_mac_fmt(&dev->filter_address[i], mac); + if (memcmp(mac, "AA:00:04", 8) == 0) { + memcpy(dev->decnet_addr, &dev->filter_address[i], sizeof(ETH_MAC)); + /* let packets through where dst and src are the same as our decnet address */ + sprintf (&buf[strlen(buf)], " or ((ether dst %s) and (ether src %s))", mac, mac); + break; + } + } + } + sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf); + + + /* get netmask, which is required for compiling */ + if (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0) { + bpf_netmask = 0; + } + +#ifdef USE_BPF + /* compile filter string */ + if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) { + sprintf(errbuf, "%s", pcap_geterr(dev->handle)); + msg = "Eth: pcap_compile error: %s\r\n"; + printf(msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + /* show erroneous BPF string */ + msg = "Eth: BPF string is: |%s|\r\n"; + printf (msg, buf); + if (sim_log) fprintf (sim_log, msg, buf); + } else { + /* apply compiled filter string */ + if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) { + sprintf(errbuf, "%s", pcap_geterr(dev->handle)); + msg = "Eth: pcap_setfilter error: %s\r\n"; + printf(msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + } else { +#ifdef USE_SETNONBLOCK + /* set file non-blocking */ + status = pcap_setnonblock (dev->handle, 1, errbuf); +#endif /* USE_SETNONBLOCK */ + } + pcap_freecode(&bpf); + } +#endif /* USE_BPF */ + + return SCPE_OK; +} + +/* + The libpcap provided API pcap_findalldevs() on most platforms, will + leverage the getifaddrs() API if it is available in preference to + alternate platform specific methods of determining the interface list. + + A limitation of getifaddrs() is that it returns only interfaces which + have associated addresses. This may not include all of the interesting + interfaces that we are interested in since a host may have dedicated + interfaces for a simulator, which is otherwise unused by the host. + + One could hand craft the the build of libpcap to specifically use + alternate methods to implement pcap_findalldevs(). However, this can + get tricky, and would then result in a sort of deviant libpcap. + + This routine exists to allow platform specific code to validate and/or + extend the set of available interfaces to include any that are not + returned by pcap_findalldevs. + +*/ +int eth_host_devices(int used, int max, ETH_LIST* list) +{ + pcap_t* conn; + int i, j, datalink; + char errbuf[PCAP_ERRBUF_SIZE]; + + for (i=0; i sizeof(regval))) { + RegCloseKey (reghnd); + continue; + } + /* registry value seems OK, finish up and replace description */ + RegCloseKey (reghnd ); + sprintf (list[i].desc, "%s", regval); + } + } /* for */ +#endif + + return used; +} + +int eth_devices(int max, ETH_LIST* list) +{ + pcap_if_t* alldevs; + pcap_if_t* dev; + int i = 0; + char errbuf[PCAP_ERRBUF_SIZE]; + +#ifndef DONT_USE_PCAP_FINDALLDEVS + /* retrieve the device list */ + if (pcap_findalldevs(&alldevs, errbuf) == -1) { + char* msg = "Eth: error in pcap_findalldevs: %s\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + } else { + /* copy device list into the passed structure */ + for (i=0, dev=alldevs; dev; dev=dev->next) { + if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; + list[i].num = i; + sprintf(list[i].name, "%s", dev->name); + if (dev->description) + sprintf(list[i].desc, "%s", dev->description); + else + sprintf(list[i].desc, "%s", "No description available"); + if (i++ >= max) break; + } + + /* free device list */ + pcap_freealldevs(alldevs); + } +#endif + + /* Add any host specific devices and/or validate those already found */ + i = eth_host_devices(i, max, list); + + /* return device count */ + return i; +} + +#endif /* USE_NETWORK */ diff --git a/simhv36-1/sim_ether.h b/simhv36-1/sim_ether.h new file mode 100644 index 0000000..04b3845 --- /dev/null +++ b/simhv36-1/sim_ether.h @@ -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 +#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 */ diff --git a/simhv36-1/sim_fio.c b/simhv36-1/sim_fio.c new file mode 100644 index 0000000..b3c1e12 --- /dev/null +++ b/simhv36-1/sim_fio.c @@ -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_; diff --git a/simhv36-1/sim_fio.h b/simhv36-1/sim_fio.h new file mode 100644 index 0000000..d69b447 --- /dev/null +++ b/simhv36-1/sim_fio.h @@ -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 diff --git a/simhv36-1/sim_rev.h b/simhv36-1/sim_rev.h new file mode 100644 index 0000000..e44adb9 --- /dev/null +++ b/simhv36-1/sim_rev.h @@ -0,0 +1,1744 @@ +/* sim_rev.h: simulator revisions and current rev level + + 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. +*/ + +#ifndef _SIM_REV_H_ +#define _SIM_REV_H_ 0 + +#define SIM_MAJOR 3 +#define SIM_MINOR 6 +#define SIM_PATCH 1 + +/* V3.6 revision history + +patch date module(s) and fix(es) + + 1 25-Jul-06 sim_console.c: + - implemented SET/SHOW PCHAR + + all DECtapes: + - fixed conflict in ATTACH switches + + hp2100_ms.c (from Dave Bryan): + - added CAPACITY as alternate for REEL + - fixed EOT test for unlimited reel size + + i1620_cd.c (from Tom McBride): + - fixed card reader fgets call + - fixed card reader boot sequence + + i7094_cd.c: + - fixed problem with 80 column full cards + + i7094_cpu.c: + - fixed bug in halt IO wait loop + + i7094_sys.c: + - added binary loader (courtesy of Dave Pitt) + + pdp1_cpu.c: + - fixed bugs in MUS and DIV + + pdp11_cis.c: + - added interrupt tests to character instructions + - added 11/44 stack probe test to MOVCx (only) + + pdp11_dl.c: + - first release + + pdp11_rf.c: + - first release + + pdp11_stddev.c: + - added UC support to TTI, TTO + + pdp18b_cpu.c: + - fixed RESET to clear AC, L, and MQ + + pdp18b_dt.c: + - fixed checksum calculation bug for Type 550 + + pdp18b_fpp.c: + - fixed bugs in left shift, multiply + + pdp18b_stddev.c: + - fixed Baudot letters/figures inversion for PDP-4 + - fixed letters/figures tracking for PDP-4 + - fixed PDP-4/PDP-7 default terminal to be local echo + + pdp18b_sys.c: + - added Fiodec, Baudot display + - generalized LOAD to handle HRI, RIM, and BIN files + + pdp8_ttx.c: + - fixed bug in DETACH routine + + 0 15-May-06 scp.c: + - revised save file format to save options, unit capacity + + sim_tape.c, sim_tape.h: + - added support for finite reel size + - fixed bug in P7B write record + + most magtapes: + - added support for finite reel size + + h316_cpu.c: fixed bugs in LLL, LRL (found by Theo Engel) + + h316_lp.c: fixed bug in blanks backscanning (found by Theo Engel) + + h316_stddev.c: fixed bugs in punch state handling (found by Theo Engel) + + i1401_cpu.c: fixed bug in divide (reported by Van Snyder) + + i16_cpu.c: fixed bug in DH (found by Mark Hittinger) + + i32_cpu.c: + - fixed bug in DH (found by Mark Hittinger) + - added support for 8 register banks in 8/32 + + i7094: first release + + id_io.c: fixed bug, GO preserves EXA and SSTA (found by Davis Johnson) + + id_idc.c: + - fixed WD/WH handling (found by Davis Johnson) + - fixed bug, nop command should be ignored (found by Davis Johnson) + + nova_cpu.c: fixed bug in DIVS (found by Mark Hittinger) + + pdp11_cis.c: (all reported by John Dundas) + - fixed bug in decode table + - fixed bug in ASHP + - fixed bug in write decimal string with mmgt enabled + - fixed bug in 0-length strings in multiply/divide + + pdp11_cpu.c: fixed order of operand fetching in XOR for SDSD models + + pdp11_cr.c: added CR11/CD11 support + + pdp11_tc.c: + - fixed READ to set extended data bits in TCST (found by Alan Frisbie) + + vax780_fload.c: added FLOAD command + + vax780_sbi.c: fixed writes to ACCS + + vax780_stddev.c: revised timer logic for EVKAE (reported by Tim Stark) + + vax_cis.c: (all reported by Tim Stark) + - fixed MOVTC, MOVTUC to preserve cc's through page faults + - fixed MOVTUC to stop on translated == escape + - fixed CVTPL to set registers before destination reg write + - fixed CVTPL to set correct cc bit on overflow + - fixed EDITPC to preserve cc's through page faults + - fixed EDITPC EO$BLANK_ZERO count, cc test + - fixed EDITPC EO$INSERT to insert fill instead of blank + - fixed EDITPC EO$LOAD_PLUS/MINUS to skip character + + vax_cpu.c: + - added KESU capability to virtual examine + - fixed bugs in virtual examine + - rewrote CPU history function for improved usability + (bugs below reported by Tim Stark) + - fixed fault cleanup to clear PSL + - fixed ADAWI r-mode to preserve dst<31:16> + - fixed ACBD/G to test correct operand + - fixed access checking on modify-class specifiers + - fixed branch address calculation in CPU history + - fixed bug in reported VA on faulting cross-page write + + vax_cpu1.c: (all reported by Tim Stark) + - added access check on system PTE for 11/780 + - added mbz check in LDPCTX for 11/780 + + vax_cmode.c: (all reported by Tim Stark) + - fixed omission of SXT + - fixed order of operand fetching in XOR + + vax_fpa.c: (all reported by Tim Stark) + - fixed POLYD, POLYG to clear R4, R5 + - fixed POLYD, POLYG to set R3 correctly + - fixed POLYD, POLYG to not exit prematurely if arg = 0 + - fixed POLYD, POLYG to do full 64b multiply + - fixed POLYF, POLYD, POLYG to remove truncation on add + - fixed POLYF, POLYD, POLYG to mask mul reslt to 31b/63b/63b + - fixed fp add routine to test for zero via fraction + to support "denormal" argument from POLYF, POLYD, POLYG + - fixed bug in 32b floating multiply routine + - fixed bug in 64b extended modulus routine + + vax_mmu.c: + - added access check on system PTE for 11/780 + + vax_octa.c: (all reported by Tim Stark) + - fixed MNEGH to test negated sign, clear C + - fixed carry propagation in qp_inc, qp_neg, qp_add + - fixed pack routines to test for zero via fraction + - fixed ACBH to set cc's on result + - fixed POLYH to set R3 correctly + - fixed POLYH to not exit prematurely if arg = 0 + - fixed POLYH to mask mul reslt to 127b + - fixed fp add routine to test for zero via fraction + to support "denormal" argument from POLYH + - fixed EMODH to concatenate 15b of 16b extension + - fixed bug in reported VA on faulting cross-page write + + +/* V3.5 revision history + +patch date module(s) and fix(es) + + 2 07-Jan-06 scp.c: + - added breakpoint spaces + - added REG_FIT support + + sim_console.c: added ASCII character processing routines + + sim_tape.c, sim_tape.h: + - added write support for P7B format + - fixed bug in write forward (found by Dave Bryan) + + h316_stddev.c, hp2100_stddev.c, hp2100_mux.c, id_tt.c, + id_ttp.c, id_pas.c, pdp8_tt.c, pdp8_ttx.c, pdp11_stddev.c, + pdp11_dz.c, pdp18b_stddev.c, pdp18b_tt1.c, vax_stddev, + gri_stddev.c: + - revised to support new character handling routines + + pdp10_rp.c: fixed DCLR not to clear disk address + + pdp11_hk.c: fixed overlapped seek interaction with NOP, etc + + pdp11_rh.c: added enable/disable routine + + pdp11_rq.c, pdp11_tm.c, pdp11_tq.c, pdp11_ts.c + - widened address display to 64b when USE_ADDR64 + + pdp11_rp.c: + - fixed DCLR not to clear disk address + - fixed device enable/disable logic to include Massbus adapter + - widened address display to 64b when USE_ADDR64 + + pdp11_tu.c: + - fixed device enable/disable logic to include Massbus adapter + - widened address display to 64b when USE_ADDR64 + - changed default adapter to TM03 (for VMS) + + pdp8_df.c, pdp8_dt.c, pdp8_rf.c: + - fixed unaligned access bug (found by Doug Carman) + + pdp8_rl.c: fixed IOT 61 decoding bug (found by David Gesswein) + + vax_cpu.c: + - fixed breakpoint detection when USE_ADDR64 option is active + - fixed CVTfi to trap on integer overflow if PSW set + + 1 15-Oct-05 All CPU's, other sources: fixed declaration inconsistencies + (from Sterling Garwood) + + i1401_cpu.c: added control for old/new character encodings + + i1401_cd.c, i1401_lpt.c, i1401_tty.c: + - changed character encodings to be consistent with 7094 + - changed column binary format to be consistent with 7094 + - added choice of business or Fortran set for output encoding + + i1401_sys.c: changed WM character to ` under new encodings + + i1620_cd.c, i1620_lpt.c, i1620_tty.c: + - changed character encodings to be consistent with 7094 + + pdp10_cpu.c: changed MOVNI to eliminate gcc warning + + pdp11_io.c: fixed bug in autoconfiguration (missing XU) + + vax_io.c: fixed bug in autoconfiguration (missing XU) + + vax_fpa.c: fixed bug in 32b structure definitions (from Jason Stevens) + + 0 1-Sep-05 Note: most source modules have been edited to improve + readability and to fix declaration and cast problems in C++ + + all instruction histories: fixed reversed arguments to calloc + + scp.c: revised to trim trailing spaces on file inputs + + sim_sock.c: fixed SIGPIPE error on Unix + + sim_ether.c: added Windows user-defined adapter names (from Timothe Litt) + + sim_tape.c: fixed misallocation of TPC map array + + sim_tmxr.c: added support for SET DISCONNECT + + hp2100_mux.c: added SET MUXLn DISCONNECT + + i1401_cpu.c: + - fixed SSB-SSG clearing on RESET (reported by Ralph Reinke) + - removed error stops in MCE + + i1401_cd.c: fixed read, punch to ignore modifier on 1, 4 char inst + (reported by Van Snyder) + + id_pas.c: + - fixed bug in SHOW CONN/STATS + - added SET PASLn DISCONNECT + + pdp10_ksio.c: revised for new autoconfiguration interface + + pdp11_cpu.c: replaced WAIT clock queue check with API call + + pdp11_cpumod.c: added additional 11/60 registers + + pdp11_io.c: revised autoconfiguration algorithm and interface + + pdp11_dz.c: revised for new autoconfiguration interface + + pdp11_vh.c: + - revised for new autoconfiguration interface + - fixed bug in vector display routine + + pdp11_xu.c: fixed runt packet processing (found by Tim Chapman) + + pdp18b_cpu.c, pdp18b_sys.c: + - removed spurious AAS instruction + + pdp18b_tt1.c: + - fixed bug in SHOW CONN/STATS + - fixed bug in SET LOG/NOLOG + - added SET TTOXn DISCONNECT + + pdp8_ttx.c: + - fixed bug in SHOW CONN/STATS + - fixed bug in SET LOG/NOLOG + - added SET TTOXn DISCONNECT + + sds_mux.c: + - fixed bug in SHOW CONN/STATS + - added SET MUXLn DISCONNECT + + vaxmod_defs.h: added QDSS support + + vax_io.c: revised autoconfiguration algorithm and interface + +/* V3.4 revision history + + 0 01-May-04 scp.c: + - fixed ASSERT code + - revised syntax for SET DEBUG (from Dave Bryan) + - revised interpretation of fprint_sym, fparse_sym returns + - moved DETACH sanity tests into detach_unit + + sim_sock.h and sim_sock.c: + - added test for WSAEINPROGRESS (from Tim Riker) + + many: revised detach routines to test for attached state + + hp2100_cpu.c: reorganized CPU options (from Dave Bryan) + + hp2100_cpu1.c: reorganized EIG routines (from Dave Bryan) + + hp2100_fp1.c: added FFP support (from Dave Bryan) + + id16_cpu.c: + - fixed bug in show history routine (from Mark Hittinger) + - revised examine/deposit to do words rather than bytes + + id32_cpu.c: + - fixed bug in initial memory allocation + - fixed bug in show history routine (from Mark Hittinger) + - revised examine/deposit to do words rather than bytes + + id16_sys.c, id32_sys: + - revised examine/deposit to do words rather than bytes + + pdp10_tu.c: + - fixed bug, ERASE and WREOF should not clear done (reported + by Rich Alderson) + - fixed error reporting + + pdp11_tu.c: fixed error reporting + +/* V3.3 revision history + + 2 08-Mar-05 scp.c: added ASSERT command (from Dave Bryan) + + h316_defs.h: fixed IORETURN macro + + h316_mt.c: fixed error reporting from OCP (found by Philipp Hachtmann) + + h316_stddev.c: fixed bug in OCP '0001 (found by Philipp Hachtmann) + + hp2100_cpu.c: split out EAU and MAC instructions + + hp2100_cpu1.c: (from Dave Bryan) + - fixed missing MPCK on JRS target + - removed EXECUTE instruction (is NOP in actual microcode) + + hp2100_fp: (from Dave Bryan) + - fixed missing negative overflow renorm in StoreFP + + i1401_lp.c: fixed bug in write_line (reported by Van Snyder) + + id32_cpu.c: fixed branches to mask new PC (from Greg Johnson) + + pdp11_cpu.c: fixed bugs in RESET for 11/70 (reported by Tim Chapman) + + pdp11_cpumod.c: + - fixed bug in SHOW MODEL (from Sergey Okhapkin) + - made SYSID variable for 11/70 (from Tim Chapman) + - added MBRK write case for 11/70 (from Tim Chapman) + + pdp11_rq: added RA60, RA71, RA81 disks + + pdp11_ry: fixed bug in boot code (reported by Graham Toal) + + vax_cpu.c: fixed initial state of cpu_extmem + + 1 05-Jan-05 h316_cpu.c: fixed bug in DIV + + h316_stddev.c: + - fixed bug in SKS '104 (reported by Philipp Hachtmann) + - fixed bug in SKS '504 + - adder reader/punch ASCII file support + - added Teletype reader/punch support + + h316_dp.c: fixed bug in skip on !seeking + + h316_mt.c: fixed bug in DMA/DMC support + + h316_lp.c: fixed bug in DMA/DMC support + + hp2100_cpu.c: + - fixed DMA reset to clear alternate CTL flop (from Dave Bryan) + - fixed DMA reset to not clear control words (from Dave Bryan) + - fixed SBS, CBS, TBS to do virtual reads + - separated A/B from M[0/1], for DMA IO (from Dave Bryan) + - added SET CPU 21MX-M, 21MX-E (from Dave Brian) + - disabled TIMER/EXECUTE/DIAG instructions for 21MX-M (from Dave Bryan) + - added post-processor to maintain T/M consistency (from Dave Bryan) + + hp2100_ds.c: first release + + hp2100_lps.c (all changes from Dave Bryan) + - added restart when set online, etc. + - fixed col count for non-printing chars + + hp2100_lpt.c (all changes from Dave Bryan) + - added restart when set online, etc. + + hp2100_sys.c (all changes from Dave Bryan): + - added STOP_OFFLINE, STOP_PWROFF messages + + i1401_sys.c: added address argument support (from Van Snyder) + + id_mt.c: added read-only file support + + lgp_cpu.c, lgp_sys.c: modified VM pointer setup + + pdp11_cpu.c: fixed WAIT to work in all modes (from John Dundas) + + pdp11_tm.c, pdp11_ts.c: added read-only file support + + sds_mt.c: added read-only file support + + 0 23-Nov-04 scp.c: + - added reset_all_p (powerup) + - fixed comma-separated SET options (from Dave Bryan) + - changed ONLINE/OFFLINE to ENABLED/DISABLED (from Dave Bryan) + - modified to flush device buffers on stop (from Dave Bryan) + - changed HELP to suppress duplicate command displays + + sim_console.c: + - moved SET/SHOW DEBUG under CONSOLE hierarchy + + hp2100_cpu.c: (all fixes by Dave Bryan) + - moved MP into its own device; added MP option jumpers + - modified DMA to allow disabling + - modified SET CPU 2100/2116 to truncate memory > 32K + - added -F switch to SET CPU to force memory truncation + - fixed S-register behavior on 2116 + - fixed LIx/MIx behavior for DMA on 2116 and 2100 + - fixed LIx/MIx behavior for empty I/O card slots + - modified WRU to be REG_HRO + - added BRK and DEL to save console settings + - fixed use of "unsigned int16" in cpu_reset + + hp2100_dp.c: (all fixes by Dave Bryan) + - fixed enable/disable from either device + - fixed ANY ERROR status for 12557A interface + - fixed unattached drive status for 12557A interface + - status cmd without prior STC DC now completes (12557A) + - OTA/OTB CC on 13210A interface also does CLC CC + - fixed RAR model + - fixed seek check on 13210 if sector out of range + + hp2100_dq.c: (all fixes by Dave Bryan) + - fixed enable/disable from either device + - shortened xtime from 5 to 3 (drive avg 156KW/second) + - fixed not ready/any error status + - fixed RAR model + + hp2100_dr.c: (all fixes by Dave Bryan) + - fixed enable/disable from either device + - fixed sector return in status word + - provided protected tracks and "Writing Enabled" status bit + - fixed DMA last word write, incomplete sector fill value + - added "parity error" status return on writes for 12606 + - added track origin test for 12606 + - added SCP test for 12606 + - fixed 12610 SFC operation + - added "Sector Flag" status bit + - added "Read Inhibit" status bit for 12606 + - fixed current-sector determination + - added TRACKPROT modifier + + hp2100_ipl.c, hp2100_ms.c: (all fixes by Dave Bryan) + - fixed enable/disable from either device + + hp2100_lps.c: (all fixes by Dave Bryan) + - added SET OFFLINE/ONLINE, POWEROFF/POWERON + - fixed status returns for error conditions + - fixed handling of non-printing characters + - fixed handling of characters after column 80 + - improved timing model accuracy for RTE + - added fast/realistic timing + - added debug printouts + + hp2100_lpt.c: (all fixes by Dave Bryan) + - added SET OFFLINE/ONLINE, POWEROFF/POWERON + - fixed status returns for error conditions + - fixed TOF handling so form remains on line 0 + + hp2100_stddev.c (all fixes by Dave Bryan) + - added paper tape loop mode, DIAG/READER modifiers to PTR + - added PV_LEFT to PTR TRLLIM register + - modified CLK to permit disable + + hp2100_sys.c: (all fixes by Dave Bryan) + - added memory protect device + - fixed display of CCA/CCB/CCE instructions + + i1401_cpu.c: added =n to SHOW HISTORY + + id16_cpu.c: added instruction history + + id32_cpu.c: added =n to SHOW HISTORY + + pdp10_defs.h: revised Unibus DMA API's + + pdp10_ksio.c: revised Unibus DMA API's + + pdp10_lp20.c: revised Unibus DMA API's + + pdp10_rp.c: replicated register state per drive + + pdp10_tu.c: + - fixed to set FCE on short record + - fixed to return bit<15> in drive type + - fixed format specification, 1:0 are don't cares + - implemented write check + - TMK is cleared by new motion command, not DCLR + - DONE is set on data transfers, ATA on non data transfers + + pdp11_defs.h: + - revised Unibus/Qbus DMA API's + - added CPU type and options flags + + pdp11_cpumod.h, pdp11_cpumod.c: + - new routines for setting CPU type and options + + pdp11_io.c: revised Unibus/Qbus DMA API's + + all PDP-11 DMA peripherals: + - revised Unibus/Qbus DMA API's + + pdp11_hk.c: CS2 OR must be zero for M+ + + pdp11_rh.c, pdp11_rp.c, pdp11_tu.c: + - split Massbus adapter from controllers + - replicated RP register state per drive + - added TM02/TM03 with TE16/TU45/TU77 drives + + pdp11_rq.c, pdp11_tq.c: + - provided different default timing for PDP-11, VAX + - revised to report CPU bus type in stage 1 + - revised to report controller type reflecting bus type + - added -L switch (LBNs) to RAUSER size specification + + pdp15_cpu.c: added =n to SHOW HISTORY + + pdp15_fpp.c: + - fixed URFST to mask low 9b of fraction + - fixed exception PC setting + + pdp8_cpu.c: added =n to SHOW HISTORY + + vax_defs.h: + - added octaword, compatibility mode support + + vax_moddefs.h: + - revised Unibus/Qbus DMA API's + + vax_cpu.c: + - moved processor-specific code to vax_sysdev.c + - added =n to SHOW HISTORY + + vax_cpu1.c: + - moved processor-specific IPR's to vax_sysdev.c + - moved emulation trap to vax_cis.c + - added support for compatibility mode + + vax_cis.c: new full VAX CIS instruction emulator + + vax_octa.c: new full VAX octaword and h_floating instruction emulator + + vax_cmode.c: new full VAX compatibility mode instruction emulator + + vax_io.c: + - revised Unibus/Qbus DMA API's + + vax_io.c, vax_stddev.c, vax_sysdev.c: + - integrated powerup into RESET (with -p) + + vax_sys.c: + - fixed bugs in parsing indirect displacement modes + - fixed bugs in displaying and parsing character data + + vax_syscm.c: added display and parse for compatibility mode + + vax_syslist.c: + - split from vax_sys.c + - removed PTR, PTP + +/* V3.2 revision history + + 3 03-Sep-04 scp.c: + - added ECHO command (from Dave Bryan) + - qualified RESTORE detach with SIM_SW_REST + + sim_console: added OS/2 EMX fixes (from Holger Veit) + + sim_sock.h: added missing definition for OS/2 (from Holger Veit) + + hp2100_cpu.c: changed error stops to report PC not PC + 1 + (from Dave Bryan) + + hp2100_dp.c: functional and timing fixes (from Dave Bryan) + - controller sets ATN for all commands except read status + - controller resumes polling for ATN interrupts after read status + - check status on unattached drive set busy and not ready + - check status tests wrong unit for write protect status + - drive on line sets ATN, will set FLG if polling + + hp2100_dr.c: fixed CLC to stop operation (from Dave Bryan) + + hp2100_ms.c: functional and timing fixes (from Dave Bryan) + - fixed erroneous execution of rejected command + - fixed erroneous execution of select-only command + - fixed erroneous execution of clear command + - fixed odd byte handling for read + - fixed spurious odd byte status on 13183A EOF + - modified handling of end of medium + - added detailed timing, with fast and realistic modes + - added reel sizes to simulate end of tape + - added debug printouts + + hp2100_mt.c: modified handling of end of medium (from Dave Bryan) + + hp2100_stddev.c: added tab to control char set (from Dave Bryan) + + pdp11_rq.c: VAX controllers luns start at 0 (from Andreas Cejna) + + vax_cpu.c: fixed bug in EMODD/G, second word of quad dst not probed + + 2 17-Jul-04 scp.c: fixed problem ATTACHing to read only files + (found by John Dundas) + + sim_console.c: revised Windows console code (from Dave Bryan) + + sim_fio.c: fixed problem in big-endian read + (reported by Scott Bailey) + + gri_cpu.c: updated MSR, EAO functions + + hp_stddev.c: generalized handling of control char echoing + (from Dave Bryan) + + vax_sys.c: fixed bad block initialization routine + + 1 10-Jul-04 scp.c: added SET/SHOW CONSOLE subhierarchy + + hp2100_cpu.c: fixes and added features (from Dave Bryan) + - SBT increments B after store + - DMS console map must check dms_enb + - SFS x,C and SFC x,C work + - MP violation clears automatically on interrupt + - SFS/SFC 5 is not gated by protection enabled + - DMS enable does not disable mem prot checks + - DMS status inconsistent at simulator halt + - Examine/deposit are checking wrong addresses + - Physical addresses are 20b not 15b + - Revised DMS to use memory rather than internal format + - Added instruction printout to HALT message + - Added M and T internal registers + - Added N, S, and U breakpoints + Revised IBL facility to conform to microcode + Added DMA EDT I/O pseudo-opcode + Separated DMA SRQ (service request) from FLG + + all HP2100 peripherals: + - revised to make SFS x,C and SFC x,C work + - revised to separate SRQ from FLG + + all HP2100 IBL bootable peripherals: + - revised boot ROMs to use IBL facility + - revised SR values to preserve SR<5:3> + + hp2100_lps.c, hp2100_lpt.c: fixed timing + + hp2100_dp.c: fixed interpretation of SR<0> + + hp2100_dr.c: revised boot code to use IBL algorithm + + hp2100_mt.c, hp2100_ms.c: fixed spurious timing error after CLC + (found by Dave Bryan) + + hp2100_stddev.c: + - fixed input behavior during typeout for RTE-IV + - suppressed nulls on TTY output for RTE-IV + + hp2100_sys.c: added SFS x,C and SFC x,C to print/parse routines + + pdp10_fe.c, pdp11_stddev.c, pdp18b_stddev.c, pdp8_tt.c, vax_stddev.c: + - removed SET TTI CTRL-C option + + pdp11_tq.c: + - fixed bug in reporting write protect (reported by Lyle Bickley) + - fixed TK70 model number and media ID (found by Robert Schaffrath) + + pdp11_vh.c: added DHQ11 support (from John Dundas) + + pdp11_io.c, vax_io.c: fixed DHQ11 autoconfigure (from John Dundas) + + pdp11_sys.c, vax_sys.c: added DHQ11 support (from John Dundas) + + vax_cpu.c: fixed bug in DIVBx, DIVWx (reported by Peter Trimmel) + + 0 04-Apr-04 scp.c: + - added sim_vm_parse_addr and sim_vm_fprint_addr + - added REG_VMAD + - moved console logging to SCP + - changed sim_fsize to use descriptor rather than name + - added global device/unit show modifiers + - added device debug support (Dave Hittner) + - moved device and unit flags, updated save format + + sim_ether.c: + - further generalizations (Dave Hittner, Mark Pizzolato) + + sim_tmxr.h, sim_tmxr.c: + - added tmxr_linemsg + - changed TMXR definition to support variable number of lines + + sim_libraries: + - new console library (sim_console.h, sim_console.c) + - new file I/O library (sim_fio.h, sim_fio.c) + - new timer library (sim_timer.h, sim_timer.c) + + all terminal multiplexors: revised for tmxr library changes + + all DECtapes: + - added STOP_EOR to enable end-of-reel stop + - revised for device debug support + + all variable-sized devices: revised for sim_fsize change + + eclipse_cpu.c, nova_cpu.c: fixed device enable/disable support + (found by Bruce Ray) + + nova_defs.h, nova_sys.c, nova_qty.c: + - added QTY and ALM support (Bruce Ray) + + id32_cpu.c, id_dp.c: revised for device debug support + + lgp: added LGP-30 [LGP-21] simulator + + pdp1_sys.c: fixed bug in LOAD (found by Mark Crispin) + + pdp10_mdfp.c: + - fixed bug in floating unpack + - fixed bug in FIXR (found by Philip Stone, fixed by Chris Smith) + + pdp11_dz.c: added per-line logging + + pdp11_rk.c: + - added formatting support + - added address increment inhibit support + - added transfer overrun detection + + pdp11_hk.c, pdp11_rp.c: revised for device debug support + + pdp11_rq.c: fixed bug in interrupt control (found by Tom Evans) + + pdp11_ry.c: added VAX support + + pdp11_tm.c, pdp11_tq.c, pdp11_ts.c: revised for device debug support + + pdp11_xu.c: replaced stub with real implementation (Dave Hittner) + + pdp18b_cpu.c: + - fixed bug in XVM g_mode implementation + - fixed bug in PDP-15 indexed address calculation + - fixed bug in PDP-15 autoindexed address calculation + + pdp18b_fpp.c: fixed bugs in instruction decode + + pdp18b_stddev.c: + - fixed clock response to CAF + - fixed bug in hardware read-in mode bootstrap + + pdp18b_sys.c: fixed XVM instruction decoding errors + + pdp18b_tt1.c: added support for 1-16 additional terminals + + vax_moddef.h, vax_cpu.c, vax_sysdev.c: + - added extended physical memory support (Mark Pizzolato) + - added RXV21 support + + vax_cpu1.c: + - added PC read fault in EXTxV + - fixed PC write fault in INSV + +/* V3.1 revision history + + 0 29-Dec-03 sim_defs.h, scp.c: added output stall status + + all console emulators: added output stall support + + sim_ether.c (Dave Hittner, Mark Pizzolato, Anders Ahgren): + - added Alpha/VMS support + - added FreeBSD, Mac OS/X support + - added TUN/TAP support + - added DECnet duplicate address detection + + all memory buffered devices (fixed head disks, floppy disks): + - cleaned up buffer copy code + + all DECtapes: + - fixed reverse checksum in read all + - added DECtape off reel message + - simplified timing + + eclipse_cpu.c (Charles Owen): + - added floating point support + - added programmable interval timer support + - bug fixes + + h316_cpu.c: + - added instruction history + - added DMA/DMC support + - added device ENABLE/DISABLE support + - change default to HSA option included + + h316_dp.c: added moving head disk support + + h316_fhd.c: added fixed head disk support + + h316_mt.c: added magtape support + + h316_sys.c: added new device support + + nova_dkp.c (Charles Owen): + - fixed bug in flag clear sequence + - added diagnostic mode support for disk sizing + +` nova_mt.c (Charles Owen): + - fixed bug, space operations return record count + - fixed bug, reset doesn't cancel rewind + + nova_sys.c: added floating point, timer support (from Charles Owen) + + i1620_cpu.c: fixed bug in branch digit (found by Dave Babcock) + + pdp1_drm.c: + - added parallel drum support + - fixed bug in serial drum instructin decoding + + pdp1_sys.c: added parallel drum support, mnemonics + + pdp11_cpu.c: + - added autoconfiguration controls + - added support for 18b-only Qbus devices + - cleaned up addressing/bus definitions + + pdp11_rk.c, pdp11_ry.c, pdp11_tm.c, pdp11_hk.c: + - added Q18 attribute + + pdp11_io.c: + - added autoconfiguration controls + - fixed bug in I/O configuration (found by Dave Hittner) + + pdp11_rq.c: + - revised MB->LBN conversion for greater accuracy + - fixed bug with multiple RAUSER drives + + pdp11_tc.c: changed to be off by default (base config is Qbus) + + pdp11_xq.c (Dave Hittner, Mark Pizzolato): + - fixed second controller interrupts + - fixed bugs in multicast and promiscuous setup + + pdp18b_cpu.c: + - added instruction history + - fixed PDP-4,-7,-9 autoincrement bug + - change PDP-7,-9 default to API option included + + pdp8_defs.h, pdp8_sys.c: + - added DECtape off reel message + - added support for TSC8-75 (ETOS) option + - added support for TD8E controller + + pdp8_cpu.c: added instruction history + + pdp8_rx.c: + - fixed bug in RX28 read status (found by Charles Dickman) + - fixed double density write + + pdp8_td.c: added TD8E controller + + pdp8_tsc.c: added TSC8-75 option + + vax_cpu.c: + - revised instruction history for dynamic sizing + - added autoconfiguration controls + + vax_io.c: + - added autoconfiguration controls + - fixed bug in I/O configuration (found by Dave Hittner) + + id16_cpu.c: revised instruction decoding + + id32_cpu.c: + - revised instruction decoding + - added instruction history + +/* V3.0 revision history + + 2 15-Sep-03 scp.c: + - fixed end-of-file problem in dep, idep + - fixed error on trailing spaces in dep, idep + + pdp1_stddev.c + - fixed system hang if continue after PTR error + - added PTR start/stop functionality + - added address switch functionality to PTR BOOT + + pdp1_sys.c: added multibank capability to LOAD + + pdp18b_cpu.c: + - fixed priorities in PDP-15 API (PI between 3 and 4) + - fixed sign handling in PDP-15 unsigned mul/div + - fixed bug in CAF, must clear API subsystem + + i1401_mt.c: + - fixed tape read end-of-record handling based on real 1401 + - added diagnostic read (space forward) + + i1620_cpu.c + - fixed bug in immediate index add (found by Michael Short) + + 1 27-Jul-03 pdp1_cpu.c: updated to detect indefinite I/O wait + + pdp1_drm.c: fixed incorrect logical, missing activate, break + + pdp1_lp.c: + - fixed bugs in instruction decoding, overprinting + - updated to detect indefinite I/O wait + + pdp1_stddev.c: + - changed RIM loader to be "hardware" + - updated to detect indefinite I/O wait + + pdp1_sys.c: added block loader format support to LOAD + + pdp10_rp.c: fixed bug in read header + + pdp11_rq: fixed bug in user disk size (found by Chaskiel M Grundman) + + pdp18b_cpu.c: + - added FP15 support + - added XVM support + - added EAE support to the PDP-4 + - added PDP-15 "re-entrancy ECO" + - fixed memory protect/skip interaction + - fixed CAF to only reset peripherals + + pdp18b_fpp.c: added FP15 + + pdp18b_lp.c: fixed bug in Type 62 overprinting + + pdp18b_rf.c: fixed bug in set size routine + + pdp18b_stddev.c: + - increased PTP TIME for PDP-15 operating systems + - added hardware RIM loader for PDP-7, PDP-9, PDP-15 + + pdp18b_sys.c: added FP15, KT15, XVM instructions + + pdp8b_df.c, pdp8_rf.c: fixed bug in set size routine + + hp2100_dr.c: + - fixed drum sizes + - fixed variable capacity interaction with SAVE/RESTORE + + i1401_cpu.c: revised fetch to model hardware more closely + + ibm1130: fixed bugs found by APL 1130 + + nova_dsk.c: fixed bug in set size routine + + altairz80: fixed bug in real-time clock on Windows host + + 0 15-Jun-03 scp.c: + - added ASSIGN/DEASSIGN + - changed RESTORE to detach files + - added u5, u6 unit fields + - added USE_ADDR64 support + - changed some structure fields to unsigned + + scp_tty.c: added extended file seek + + sim_sock.c: fixed calling sequence in stubs + + sim_tape.c: + - added E11 and TPC format support + - added extended file support + + sim_tmxr.c: fixed bug in SHOW CONNECTIONS + + all magtapes: + - added multiformat support + - added extended file support + + i1401_cpu.c: + - fixed mnemonic, instruction lengths, and reverse + scan length check bug for MCS + - fixed MCE bug, BS off by 1 if zero suppress + - fixed chaining bug, D lost if return to SCP + - fixed H branch, branch occurs after continue + - added check for invalid 8 character MCW, LCA + + i1401_mt.c: fixed load-mode end of record response + + nova_dsk.c: fixed variable size interaction with restore + + pdp1_dt.c: fixed variable size interaction with restore + + pdp10_rp.c: fixed ordering bug in attach + + pdp11_cpu.c: + - fixed bug in MMR1 update (found by Tim Stark) + - fixed bug in memory size table + + pdp11_lp.c, pdp11_rq.c: added extended file support + + pdp11_rl.c, pdp11_rp.c, pdp11_ry.c: fixed ordering bug in attach + + pdp11_tc.c: fixed variable size interaction with restore + + pdp11_xq.c: + - corrected interrupts on IE state transition (code by Tom Evans) + - added interrupt clear on soft reset (first noted by Bob Supnik) + - removed interrupt when setting XL or RL (multiple people) + - added SET/SHOW XQ STATS + - added SHOW XQ FILTERS + - added ability to split received packet into multiple buffers + - added explicit runt & giant packet processing + + vax_fpa.c: + - fixed integer overflow bug in CVTfi + - fixed multiple bugs in EMODf + + vax_io.c: optimized byte and word DMA routines + + vax_sysdev.c: + - added calibrated delay to ROM reads (from Mark Pizzolato) + - fixed calibration problems in interval timer (from Mark Pizzolato) + + pdp1_dt.c: fixed variable size interaction with restore + + pdp18b_dt.c: fixed variable size interaction with restore + + pdp18b_mt.c: fixed bug in MTTR + + pdp18b_rf.c: fixed variable size interaction with restore + + pdp8_df.c, pdp8_rf.c: fixed variable size interaction + with restore + + pdp8_dt.c: fixed variable size interaction with restore + + pdp8_mt.c: fixed bug in SKTR + + hp2100_dp.c,hp2100_dq.c: + - fixed bug in read status (13210A controller) + - fixed bug in seek completion + + id_pt.c: fixed type declaration (found by Mark Pizzolato) + + gri_cpu.c: fixed bug in SC queue pointer management + +/* V2.10 revision history + + 4 03-Mar-03 scp.c + - added .ini startup file capability + - added multiple breakpoint actions + - added multiple switch evaluation points + - fixed bug in multiword deposits to file + + sim_tape.c: magtape simulation library + + h316_stddev.c: added set line frequency command + + hp2100_mt.c, hp2100_ms.c: revised to use magtape library + + i1401_mt.c: revised to use magtape library + + id_dp.c, id_idc.c: fixed cylinder overflow on writes + + id_mt.c: + - fixed error handling to stop selector channel + - revised to use magtape library + + id16_sys.c, id32_sys.c: added relative addressing support + + id_uvc.c: + - added set frequency command to line frequency clock + - improved calibration algorithm for precision clock + + nova_clk.c: added set line frequency command + + nova_dsk.c: fixed autosizing algorithm + + nova_mt.c: revised to use magtape library + + pdp10_tu.c: revised to use magtape library + + pdp11_cpu.c: fixed bug in MMR1 update (found by Tim Stark) + + pdp11_stddev.c + - added set line frequency command + - added set ctrl-c command + + pdp11_rq.c: + - fixed ordering problem in queue process + - fixed bug in vector calculation for VAXen + - added user defined drive support + + pdp11_ry.c: fixed autosizing algorithm + + pdp11_tm.c, pdp11_ts.c: revised to use magtape library + + pdp11_tq.c: + - fixed ordering problem in queue process + - fixed overly restrictive test for bad modifiers + - fixed bug in vector calculation for VAXen + - added variable controller, user defined drive support + - revised to use magtape library + + pdp18b_cpu.c: fixed three EAE bugs (found by Hans Pufal) + + pdp18b_mt.c: + - fixed bugs in BOT error handling, interrupt handling + - revised to use magtape library + + pdp18b_rf.c: + - removed 22nd bit from disk address + - fixed autosizing algorithm + + pdp18b_stddev.c: + - added set line frequency command + - added set ctrl-c command + + pdp18b_sys.c: fixed FMTASC printouts (found by Hans Pufal) + + pdp8_clk.c: added set line frequency command + + pdp8_df.c, pdp8_rf.c, pdp8_rx.c: fixed autosizing algorithm + + pdp8_mt.c: + - fixed bug in BOT error handling + - revised to use magtape library + + pdp8_tt.c: added set ctrl-c command + + sds_cpu.c: added set line frequency command + + sds_mt.c: revised to use magtape library + + vax_stddev.c: added set ctrl-c command + + 3 06-Feb-03 scp.c: + - added dynamic extension of the breakpoint table + - added breakpoint actions + + hp2100_cpu.c: fixed last cycle bug in DMA output (found by + Mike Gemeny) + + hp2100_ipl.c: individual links are full duplex (found by + Mike Gemeny) + + pdp11_cpu.c: changed R, SP to track PSW respectively + + pdp18b_defs.h, pdp18b_sys.c: added RB09 fixed head disk, + LP09 printer + + pdp18b_rf.c: + - fixed IOT decoding (found by Hans Pufal) + - fixed address overrun logic + - added variable number of platters and autosizing + + pdp18b_rf.c: + - fixed IOT decoding + - fixed bug in command initiation + + pdp18b_rb.c: new RB09 fixed head disk + + pdp18b_lp.c: new LP09 line printer + + pdp8_df.c: added variable number of platters and autosizing + + pdp8_rf.c: added variable number of platters and autosizing + + nova_dsk.c: added variable number of platters and autosizing + + id16_cpu.c: fixed bug in SETM, SETMR (found by Mark Pizzolato) + + 2 15-Jan-03 scp.c: + - added dynamic memory size flag and RESTORE support + - added EValuate command + - added get_ipaddr routine + - added ! (OS command) feature (from Mark Pizzolato) + - added BREAK support to sim_poll_kbd (from Mark Pizzolato) + + sim_tmxr.c: + - fixed bugs in IAC+IAC handling (from Mark Pizzolato) + - added IAC+BRK handling (from Mark Pizzolato) + + sim_sock.c: + - added use count for Windows start/stop + - added sim_connect_sock + + pdp1_defs.h, pdp1_cpu.c, pdp1_sys.c, pdp1_drm.c: + added Type 24 serial drum + + pdp18_defs.h: added PDP-4 drum support + + hp2100_cpu.c: added 21MX IOP support + + hp2100_ipl.c: added HP interprocessor link support + + pdp11_tq.c: fixed bug in transfer end packet length + + pdp11_xq.c: + - added VMScluster support (thanks to Mark Pizzolato) + - added major performance enhancements (thanks to Mark Pizzolato) + - added local packet processing + - added system id broadcast + + pdp11_stddev.c: changed default to 7b (for early UNIX) + + vax_cpu.c, vax_io.c, vax_stddev.c, vax_sysdev.c: + added console halt capability (from Mark Pizzolato) + + all terminals and multiplexors: added BREAK support + + 1 21-Nov-02 pdp1_stddev.c: changed typewriter to half duplex + (found by Derek Peschel) + + pdp10_tu.c: + - fixed bug in bootstrap (reported by Michael Thompson) + - fixed bug in read (reported by Harris Newman) + + 0 15-Nov-02 SCP and libraries + scp.c: + - added Telnet console support + - removed VT emulation support + - added support for statically buffered devices + - added HELP + - fixed bugs in set_logon, ssh_break (found by David Hittner) + - added VMS file optimization (from Robert Alan Byer) + - added quiet mode, DO with parameters, GUI interface, + extensible commands (from Brian Knittel) + - added DEVICE context and flags + - added central device enable/disable support + - modified SAVE/GET to save and restore flags + - modified boot routine calling sequence + scp_tty.c: + - removed VT emulation support + - added sim_os_sleep, renamed sim_poll_kbd, sim_putchar + sim_tmxr.c: + - modified for Telnet console support + - fixed bug in binary (8b) support + sim_sock.c: modified for Telnet console support + sim_ether.c: new library for Ethernet (from David Hittner) + + all magtapes: + - added support for end of medium + - cleaned up BOT handling + + all DECtapes: added support for RT11 image file format + + most terminals and multiplexors: + - added support for 7b vs 8b character processing + + PDP-1 + pdp1_cpu.c, pdp1_sys.c, pdp1_dt.c: added PDP-1 DECtape support + + PDP-8 + pdp8_cpu.c, all peripherals: + - added variable device number support + - added new device enabled/disable support + pdp8_rx.c: added RX28/RX02 support + + PDP-11 + pdp11_defs.h, pdp11_io.c, pdp11_sys.c, all peripherals: + - added variable vector support + - added new device enable/disable support + - added autoconfiguration support + all bootstraps: modified to support variable addresses + dec_mscp.h, pdp11_tq.c: added TK50 support + pdp11_rq.c: + - added multicontroller support + - fixed bug in HBE error log packet + - fixed bug in ATP processing + pdp11_ry.c: added RX211/RX02 support + pdp11_hk.c: added RK611/RK06/RK07 support + pdp11_tq.c: added TMSCP support + pdp11_xq.c: added DEQNA/DELQA support (from David Hittner) + pdp11_pclk.c: added KW11P support + pdp11_ts.c: + - fixed bug in CTL decoding + - fixed bug in extended status XS0_MOT + pdp11_stddev.c: removed paper tape to its own module + + PDP-18b + pdp18b_cpu.c, all peripherals: + - added variable device number support + - added new device enabled/disabled support + + VAX + dec_dz.h: fixed bug in number of boards calculation + vax_moddefs.h, vax_io.c, vax_sys.c, all peripherals: + - added variable vector support + - added new device enable/disable support + - added autoconfiguration support + vax_sys.c: + - generalized examine/deposit + - added TMSCP, multiple RQDX3, DEQNA/DELQA support + vax_stddev.c: removed paper tape, now uses PDP-11 version + vax_sysdev.c: + - allowed NVR to be attached to file + - removed unused variables (found by David Hittner) + + PDP-10 + pdp10_defs.h, pdp10_ksio.c, all peripherals: + - added variable vector support + - added new device enable/disable support + pdp10_defs.h, pdp10_ksio.c: added support for standard PDP-11 + peripherals, added RX211 support + pdp10_pt.c: rewritten to reference common implementation + + Nova, Eclipse: + nova_cpu.c, eclipse_cpu.c, all peripherals: + - added new device enable/disable support + + HP2100 + hp2100_cpu: + - fixed bugs in the EAU, 21MX, DMS, and IOP instructions + - fixed bugs in the memory protect and DMS functions + - created new options to enable/disable EAU, MPR, DMS + - added new device enable/disable support + hp2100_fp.c: + - recoded to conform to 21MX microcode algorithms + hp2100_stddev.c: + - fixed bugs in TTY reset, OTA, time base generator + - revised BOOT support to conform to RBL loader + - added clock calibration + hp2100_dp.c: + - changed default to 13210A + - added BOOT support + hp2100_dq.c: + - finished incomplete functions, fixed head switching + - added BOOT support + hp2100_ms.c: + - fixed bugs found by diagnostics + - added 13183 support + - added BOOT support + hp2100_mt.c: + - fixed bugs found by diagnostics + - disabled by default + hp2100_lpt.c: implemented 12845A controller + hp2100_lps.c: + - renamed 12653A controller + - added diagnostic mode for MPR, DCPC diagnostics + - disabled by default + + IBM 1620: first release + +/* V2.9 revision history + + 11 20-Jul-02 i1401_mt.c: on read, end of record stores group mark + without word mark (found by Van Snyder) + + i1401_dp.c: reworked address generation and checking + + vax_cpu.c: added infinite loop detection and halt to + boot ROM option (from Mark Pizzolato) + + vax_fpa.c: changed function names to prevent conflict + with C math library + + pdp11_cpu.c: fixed bug in MMR0 update logic (from + John Dundas) + + pdp18b_stddev.c: added "ASCII mode" for reader and + punch (from Hans Pufal) + + gri_*.c: added GRI-909 simulator + + scp.c: added DO echo, DO exit (from Brian Knittel) + + scp_tty.c: added Windows priority hacking (from + Mark Pizzolato) + + 10 15-Jun-02 scp.c: fixed error checking on calls to fxread/fxwrite + (found by Norm Lastovic) + + scp_tty.c, sim_vt.h, sim_vt.c: added VTxxx emulation + support for Windows (from Fischer Franz) + + sim_sock.c: added OS/2 support (from Holger Veit) + + pdp11_cpu.c: fixed bugs (from John Dundas) + - added special case for PS<15:12> = 1111 to MFPI + - removed special case from MTPI + - added masking of relocation adds + + i1401_cpu.c: + - added multiply/divide + - fixed bugs (found by Van Snyder) + o 5 and 7 character H, 7 character doesn't branch + o 8 character NOP + o 1401-like memory dump + + i1401_dp.c: added 1311 disk + + 9 04-May-02 pdp11_rq: fixed bug in polling routine + + 8 03-May-02 scp.c: + - changed LOG/NOLOG to SET LOG/NOLOG + - added SHOW LOG + - added SET VT/NOVT and SHOW VT for VT emulation + + sim_sock.h: changed VMS stropt.h include to ioctl.h + + vax_cpu.c + - added TODR powerup routine to set date, time on boot + - fixed exception flows to clear trap request + - fixed register logging in autoincrement indexed + + vax_stddev.c: added TODR powerup routine + + vax_cpu1.c: fixed exception flows to clear trap request + + 7 30-Apr-02 scp.c: fixed bug in clock calibration when (real) clock + jumps forward due too far (found by Jonathan Engdahl) + + pdp11_cpu.c: fixed bugs, added features (from John Dundas + and Wolfgang Helbig) + - added HTRAP and BPOK to maintenance register + - added trap on kernel HALT if MAINT set + - fixed red zone trap, clear odd address and nxm traps + - fixed RTS SP, don't increment restored SP + - fixed TSTSET, write dst | 1 rather than prev R0 | 1 + - fixed DIV, set N=0,Z=1 on div by zero (J11, 11/70) + - fixed DIV, set set N=Z=0 on overfow (J11, 11/70) + - fixed ASH, ASHC, count = -32 used implementation- + dependent 32 bit right shift + - fixed illegal instruction test to detect 000010 + - fixed write-only page test + + pdp11_rp.c: fixed SHOW ADDRESS command + + vaxmod_defs.h: fixed DZ vector base and number of lines + + dec_dz.h: + - fixed interrupt acknowledge routines + - fixed SHOW ADDRESS command + + all magtape routines: added test for badly formed + record length (suggested by Jonathan Engdahl) + + 6 18-Apr-02 vax_cpu.c: fixed CASEL condition codes + + vax_cpu1.c: fixed vfield pos > 31 test to be unsigned + + vax_fpu.c: fixed EDIV overflow test for 0 quotient + + 5 14-Apr-02 vax_cpu1.c: + - fixed interrupt, prv_mode set to 0 (found by Tim Stark) + - fixed PROBEx to mask mode to 2b (found by Kevin Handy) + + 4 1-Apr-02 pdp11_rq.c: fixed bug, reset cleared write protect status + + pdp11_ts.c: fixed bug in residual frame count after space + + 3 15-Mar-02 pdp11_defs.h: changed default model to KDJ11A (11/73) + + pdp11_rq.c: adjusted delays for M+ timing bugs + + hp2100_cpu.c, pdp10_cpu.c, pdp11_cpu.c: tweaked abort + code for ANSI setjmp/longjmp compliance + + hp2100_cpu.c, hp2100_fp.c, hp2100_stddev.c, hp2100_sys.c: + revised to allocate memory dynamically + + 2 01-Mar-02 pdp11_cpu.c: + - fixed bugs in CPU registers + - fixed double operand evaluation order for M+ + + pdp11_rq.c: added delays to initialization for + RSX11M+ prior to V4.5 + + 1 20-Feb-02 scp.c: fixed bug in clock calibration when (real) + time runs backwards + + pdp11_rq.c: fixed bug in host timeout logic + + pdp11_ts.c: fixed bug in message header logic + + pdp18b_defs.h, pdp18b_dt.c, pdp18b_sys.c: added + PDP-7 DECtape support + + hp2100_cpu.c: + - added floating point and DMS + - fixed bugs in DIV, ASL, ASR, LBT, SBT, CBT, CMW + + hp2100_sys.c: added floating point, DMS + + hp2100_fp.c: added floating point + + ibm1130: added Brian Knittel's IBM 1130 simulator + + 0 30-Jan-02 scp.c: + - generalized timer package for multiple timers + - added circular register arrays + - fixed bugs, line spacing in modifier display + - added -e switch to attach + - moved device enable/disable to simulators + + scp_tty.c: VAX specific fix (from Robert Alan Byer) + + sim_tmxr.c, sim_tmxr.h: + - added tmxr_fstats, tmxr_dscln + - renamed tmxr_fstatus to tmxr_fconns + + sim_sock.c, sim_sock.h: added VMS support (from + Robert Alan Byer) + + pdp_dz.h, pdp18b_tt1.c, nova_tt1.c: + - added SET DISCONNECT + - added SHOW STATISTICS + + pdp8_defs.h: fixed bug in interrupt enable initialization + + pdp8_ttx.c: rewrote as unified multiplexor + + pdp11_cpu.c: fixed calc_MMR1 macro (found by Robert Alan Byer) + + pdp11_stddev.c: fixed bugs in KW11L (found by John Dundas) + + pdp11_rp.c: fixed bug in 18b mode boot + + pdp11 bootable I/O devices: fixed register setup at boot + exit (found by Doug Carman) + + hp2100_cpu.c: + - fixed DMA register tables (found by Bill McDermith) + - fixed SZx,SLx,RSS bug (found by Bill McDermith) + - fixed flop restore logic (found by Bill McDermith) + + hp2100_mt.c: fixed bug on write of last character + + hp2100_dq,dr,ms,mux.c: added new disk, magtape, and terminal + multiplexor controllers + + i1401_cd.c, i1401_mt.c: new zero footprint bootstraps + (from Van Snyder) + + i1401_sys.c: fixed symbolic display of H, NOP with no trailing + word mark (found by Van Snyder) + + most CPUs: + - replaced OLDPC with PC queue + - implemented device enable/disable locally + + V2.8 revision history + +5 25-Dec-01 scp.c: fixed bug in DO command (found by John Dundas) + + pdp10_cpu.c: + - moved trap-in-progress to separate variable + - cleaned up declarations + - cleaned up volatile state for GNU C longjmp + + pdp11_cpu.c: cleaned up declarations + + pdp11_rq.c: added RA-class disks + +4 17-Dec-01 pdp11_rq.c: added delayed processing of packets + +3 16-Dec-01 pdp8_cpu.c: + - mode A EAE instructions didn't clear GTF + - ASR shift count > 24 mis-set GTF + - effective shift count == 32 didn't work + +2 07-Dec-01 scp.c: added breakpoint package + + all CPU's: revised to use new breakpoint package + +1 05-Dec-01 scp.c: fixed bug in universal register name logic + +0 30-Nov-01 Reorganized simh source and documentation tree + + scp: Added DO command, universal registers, extended + SET/SHOW logic + + pdp11: overhauled PDP-11 for DMA map support, shared + sources with VAX, dynamic buffer allocation + + 18b pdp: overhauled interrupt structure + + pdp8: added RL8A + + pdp10: fixed two ITS-related bugs (found by Dave Conroy) + + V2.7 revision history + +patch date module(s) and fix(es) + +15 23-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: fixed bugs + error interrupt handling + + pdp10_defs.h, pdp10_ksio.c, pdp10_fe.c, pdp10_fe.c, + pdp10_rp.c, pdp10_tu.c: reworked I/O page interface + to use symbolic base addresses and lengths + +14 20-Oct-01 dec_dz.h, sim_tmxr_h, sim_tmxr.c: fixed bug in Telnet + state handling (found by Thord Nilson), removed + tmxr_getchar, added tmxr_rqln and tmxr_tqln + +13 18-Oct-01 pdp11_tm.c: added stub diagnostic register clock + for RSTS/E (found by Thord Nilson) + +12 15-Oct-01 pdp11_defs.h, pdp11_cpu.c, pdp11_tc.c, pdp11_ts.c, + pdp11_rp.c: added operations logging + +11 8-Oct-01 scp.c: added sim_rev.h include and version print + + pdp11_cpu.c: fixed bug in interrupt acknowledge, + multiple outstanding interrupts caused the lowest + rather than the highest to be acknowledged + +10 7-Oct-01 pdp11_stddev.c: added monitor bits (CSR<7>) for full + KW11L compatibility, needed for RSTS/E autoconfiguration + +9 6-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: rewrote interrupt + logic from RH11/RH70 schematics, to mimic hardware quirks + + dec_dz.c: fixed bug in carrier detect logic, carrier + detect was being cleared on next modem poll + +8 4-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: undid edit of + 28-Sep-01; real problem was level-sensitive nature of + CS1_SC, but CS1_SC can only trigger an interrupt if + DONE is set + +7 2-Oct-01 pdp11_rp.c, pdp10_rp.c: CS1_SC is evaluated as a level- + sensitive, rather than an edge-sensitive, input to + interrupt request + +6 30-Sep-01 pdp11_rp.c, pdp10_rp.c: separated out CS1<5:0> to per- + drive registers + + pdp10_tu.c: based on above, cleaned up handling of + non-existent formatters, fixed non-data transfer + commands clearing DONE + +5 28-Sep-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: controller should + interrupt if ATA or SC sets when IE is set, was + interrupting only if DON = 1 as well + +4 27-Sep-01 pdp11_ts.c: + - NXM errors should return TC4 or TC5; were returning TC3 + - extended features is part of XS2; was returned in XS3 + - extended characteristics (fifth) word needed for RSTS/E + + pdp11_tc.c: stop, stop all do cause an interrupt + + dec_dz.h: scanner should find a ready output line, even + if there are no connections; needed for RSTS/E autoconfigure + + scp.c: + - added routine sim_qcount for 1130 + - added "simulator exit" detach routine for 1130 + + sim_defs.h: added header for sim_qcount + +3 20-Sep-01 pdp11_ts.c: boot code binary was incorrect + +2 19-Sep-01 pdp18b_cpu.c: EAE should interpret initial count of 00 + as 100 + + scp.c: modified Macintosh support + +1 17-Sep-01 pdp8_ttx.c: new module for PDP-8 multi-terminal support + + pdp18b_tt1.c: modified to use sim_tmxr library + + nova_tt1.c: modified to use sim_tmxr library + + dec_dz.h: added autodisconnect support + + scp.c: removed old multiconsole support + + sim_tmxr.c: modified calling sequence for sim_putchar_ln + + sim_sock.c: added Macintosh sockets support +*/ + +#endif diff --git a/simhv36-1/sim_sock.c b/simhv36-1/sim_sock.c new file mode 100644 index 0000000..dfad690 --- /dev/null +++ b/simhv36-1/sim_sock.c @@ -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 + +/* 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 */ diff --git a/simhv36-1/sim_sock.h b/simhv36-1/sim_sock.h new file mode 100644 index 0000000..2d33cb8 --- /dev/null +++ b/simhv36-1/sim_sock.h @@ -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 + +#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 /* for fcntl, getpid */ +#include /* for sockets */ +#include +#include +#include /* for sockaddr_in */ +#include +#include /* for EMX */ +#endif + +#if defined (VMS) /* VMS unique */ +#include /* 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 diff --git a/simhv36-1/sim_tape.c b/simhv36-1/sim_tape.c new file mode 100644 index 0000000..09ee37e --- /dev/null +++ b/simhv36-1/sim_tape.c @@ -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; +} diff --git a/simhv36-1/sim_tape.h b/simhv36-1/sim_tape.h new file mode 100644 index 0000000..45bcf34 --- /dev/null +++ b/simhv36-1/sim_tape.h @@ -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 diff --git a/simhv36-1/sim_timer.c b/simhv36-1/sim_timer.c new file mode 100644 index 0000000..5465758 --- /dev/null +++ b/simhv36-1/sim_timer.c @@ -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 +#include + +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 + +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 +#include +#include +#include +#include + +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 +#include + +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); +} diff --git a/simhv36-1/sim_timer.h b/simhv36-1/sim_timer.h new file mode 100644 index 0000000..c2aa309 --- /dev/null +++ b/simhv36-1/sim_timer.h @@ -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 diff --git a/simhv36-1/sim_tmxr.c b/simhv36-1/sim_tmxr.c new file mode 100644 index 0000000..5f5583d --- /dev/null +++ b/simhv36-1/sim_tmxr.c @@ -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 + +/* 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 */ +} diff --git a/simhv36-1/sim_tmxr.h b/simhv36-1/sim_tmxr.h new file mode 100644 index 0000000..a6c74f4 --- /dev/null +++ b/simhv36-1/sim_tmxr.h @@ -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 +