diff --git a/0readme_31.txt b/0readme_31.txt deleted file mode 100644 index 0725c3c4..00000000 --- a/0readme_31.txt +++ /dev/null @@ -1,254 +0,0 @@ -Notes For V3.1-0 - -RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially -debugged. Do NOT enable these features for normal operations. - -1. New Features in 3.1-0 - -1.1 SCP and libraries - -- Added simulated Ethernet support for VMS, FreeBSD, Mac OS/X. -- Added status return to tmxr_putc_ln. -- Added sim_putchar_s to handle possible output stalls. - -1.2 All DECtapes - -- Added "DECtape off reel" error stop. - -1.3 All Asynchronous Consoles - -- Added support for output congestion stall if using a Telnet connection. - -1.4 PDP-1 - -- Added Type 23 parallel drum support. - -1.5 PDP-8 - -- Added instruction history. -- Added TSC8-75 option support for ETOS. -- Added TD8E DECtape support. - -1.6 PDP-18b - -- Added instruction history. -- Changed PDP-9, PDP-15 API default to enabled. - -1.7 PDP-11 - -- Added support for 18b only Qbus devices. -- Formalized bus and addressing definitions. -- Added control to enable/disable autoconfiguration. -- Added stub support for second Unibus Ethernet controller. - -1.7 Interdata 32b - -- Added instruction history. - -1.8 Eclipse - -- Added floating point support. -- Added programmable interval timer support. - -1.9 H316 - -- Added DMA/DMC support. -- Added fixed head disk support. -- Added moving head disk support. -- Added magtape support. - -1.10 IBM 1130 (Brian Knittel) - -- Added support for physical card reader, using the Cardread -interface (www.ibm1130.org/sim/downloads). -- Added support for physical printer (flushes output buffer after -each line). - -2. Bugs Fixed in 3.1-0 - -2.1 SCP and libraries - -- Fixed numerous bugs in Ethernet library. - -2.2 All DECtapes - -- Fixed reverse checksum value in 'read all' mode. -- Simplified (and sped up) timing. - -2.3 PDP-8 - -- Fixed bug in RX28 read status (found by Charles Dickman). -- Fixed RX28 double density write. - -2.4 PDP-18b - -- Fixed autoincrement bug in PDP-4, PDP-7, PDP-9. - -2.5 PDP-11/VAX - -- Revised RQ MB->LBN conversion for greater accuracy. -- Fixed bug in IO configuration (found by David Hittner). -- Fixed bug with multiple RQ RAUSER drives. -- Fixed bug in second Qbus Ethernet controller interrupts. - -2.6 Nova/Eclipse - -- Fixed bugs in DKP flag clear, map setup, map usage (Charles Owen). -- Fixed bug in MT, reset completes despite I/O reset (Charles Owen). -- Fixed bug in MT, space operations return word count (Charles Owen). - -2.7 IBM 1130 (Brian Knittel) - -- Fixed bug in setting carry bit in subtract and subtract double. -- Fixed timing problem in console printer simulation. - -2.8 1620 - -- Fixed bug in branch digit (found by Dave Babcock). - -3. New Features in 3.0 vs prior releases - -3.1 SCP and Libraries - -- Added ASSIGN/DEASSIGN (logical name) commands. -- Changed RESTORE to unconditionally detach files. -- Added E11 and TPC format support to magtape library. -- Fixed bug in SHOW CONNECTIONS. -- Added USE_ADDR64 support. - -3.2 All magtapes - -- Magtapes support SIMH format, E11 format, and TPC format (read only). -- SET FORMAT=format sets the specified tape unit's format. -- SHOW FORMAT displays the specified tape unit's format. -- Tape format can also be set as part of the ATTACH command, using - the -F switch. - -3.3 VAX - -- VAX can be compiled without USE_INT64. -- If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support - files > 2GB. -- VAX ROM has speed control (SET ROM DELAY/NODELAY). - -3.4 PDP-1 - -- Added block loader format support to LOAD. -- Changed BOOT PTR to allow loading of all of the first bank of memory. -- The LOAD command takes an optional argument specifying the memory field - to be loaded. -- The PTR BOOT command takes its starting memory field from the TA (address - switch) register. - -3.5 PDP-18b Family - -- Added PDP-4 EAE support. -- Added PDP-15 FP15 support. -- Added PDP-15 XVM support. -- Added PDP-15 "re-entrancy ECO". -- Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR. - -4. Bugs Fixed in 3.0 vs prior releases - -4.1 SCP and Libraries - -- Fixed end of file problem in dep, idep. -- Fixed handling of trailing spaces in dep, idep. - -4.2 VAX - -- Fixed CVTfi bug: integer overflow not set if exponent out of range -- Fixed EMODx bugs: - o First and second operands reversed - o Separated fraction received wrong exponent - o Overflow calculation on separated integer incorrect - o Fraction not set to zero if exponent out of range -- Fixed interval timer and ROM access to pass power-up self-test even on very - fast host processors (fixes from Mark Pizzolato). -- Fixed bug in user disk size (found by Chaskiel M Grundman). - -4.3 1401 - -- Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS. -- Fixed MCE bug, BS off by 1 if zero suppress. -- Fixed chaining bug, D lost if return to SCP. -- Fixed H branch, branch occurs after continue. -- Added check for invalid 8 character MCW, LCA. -- Fixed magtape load-mode end of record response. -- Revised fetch to model hardware more closely. -- Fixed tape read end-of-record handling based on real 1401. -- Added diagnostic read (space forward). - -4.4 Nova - -- Fixed DSK variable size interaction with restore. -- Fixed bug in DSK set size routine. - -4.5 PDP-1 - -- Fixed DT variable size interaction with restore. -- Updated CPU, line printer, standard devices to detect indefinite I/O wait. -- Fixed incorrect logical, missing activate, break in drum simulator. -- Fixed bugs in instruction decoding, overprinting for line printer. -- Fixed system hang if continue after PTR error. -- Fixed PTR to start/stop on successive rpa instructions. - -4.6 PDP-11 - -- Fixed DT variable size interaction with restore. -- Fixed bug in MMR1 update (found by Tim Stark). -- Added XQ features and fixed bugs: - o Corrected XQ interrupts on IE state transition (code by Tom Evans). - o Added XQ interrupt clear on soft reset. - o Removed XQ interrupt when setting XL or RL (multiple people). - o Added SET/SHOW XQ STATS. - o Added SHOW XQ FILTERS. - o Added ability to split received packet into multiple buffers. - o Added explicit runt and giant packet processing. -- Fixed bug in user disk size (found by Chaskiel M Grundman). - -4.7 PDP-18B - -- Fixed DT, RF variable size interaction with restore. -- Fixed MT bug in MTTR. -- Fixed bug in PDP-4 line printer overprinting. -- Fixed bug in PDP-15 memory protect/skip interaction. -- Fixed bug in RF set size routine. -- Increased PTP TIME for PDP-15 operating systems. -- Fixed priorities in PDP-15 API (differs from PDP-9). -- Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9). -- Fixed bug in CAF, clears API subsystem. - -4.8 PDP-8 - -- Fixed DT, DF, RF, RX variable size interaction with restore. -- Fixed MT bug in SKTR. -- Fixed bug in DF, RF set size routine. - -4.9 HP2100 - -- Fixed bug in DP (13210A controller only), DQ read status. -- Fixed bug in DP, DQ seek complete. -- Fixed DR drum sizes. -- Fixed DR variable capacity interaction with SAVE/RESTORE. - -4.10 GRI - -- Fixed bug in SC queue pointer management. - -4.11 PDP-10 - -- Fixed bug in RP read header. - -4.12 Ibm1130 - -- Fixed bugs found by APL 1130. - -4.13 Altairz80 - -- Fixed bug in real-time clock on Windows host. - -4.14 1620 - -- Fixed bug in immediate index add (found by Michael Short). - diff --git a/0readme_32.txt b/0readme_32.txt new file mode 100644 index 00000000..38076c30 --- /dev/null +++ b/0readme_32.txt @@ -0,0 +1,103 @@ +Notes For V3.2-0 + +RESTRICTION: The PDP-15 FPP is only partially debugged. Do NOT +enable this feature for normal operations. + +WARNING: The core simulator files (scp.c, sim_*.c) have been +reorganized. Unzip V3.2-0 to an empty directory before attempting +to compile the source. + +IMPORTANT: If you are compiling for UNIX, please read the notes +for Ethernet very carefully. You may need to download a new +version of the pcap library, or make changes to the makefile, +to get Ethernet support to work. + +1. New Features in 3.2-0 + +1.1 SCP and libraries + +- Added SHOW RADIX command. +- Added SHOW MODIFIERS command. +- Added SHOW NAMES command. +- Added SET/SHOW DEBUG command. +- Added sim_vm_parse_addr and sim_vm_fprint_addr optional interfaces. +- Added REG_VMAD flag. +- Split SCP into separate libraries for easier modification. +- Added more room to the device and unit flag fields. +- Changed terminal multiplexor library to support unlimited. + number of async lines. + +1.2 All DECtapes + +- Added STOP_EOR flag to enable end-of-reel error stop +- Added device debug support. + +1.3 Nova and Eclipse + +- Added QTY and ALM multiplexors (Bruce Ray). + +1.4 LGP-30 + +- Added LGP-30/LGP-21 simulator. + +1.5 PDP-11 + +- Added format, address increment inhibit, transfer overrun + detection to RK. +- Added device debug support to HK, RP, TM, TQ, TS. +- Added DEUNA/DELUA (XU) support (Dave Hittner). +- Add DZ per-line logging. + +1.6 18b PDP's + +- Added support for 1-4 (PDP-9)/1-16 (PDP-15) additional + terminals. + +1.7 PDP-10 + +- Added DEUNA/DELUA (XU) support (Dave Hittner). + +1.8 VAX + +- Added extended memory to 512MB (Mark Pizzolato). +- Added RXV21 support. + +2. Bugs Fixed in 3.2-0 + +2.1 SCP + +- Fixed double logging of SHOW BREAK (found by Mark Pizzolato). +- Fixed implementation of REG_VMIO. + +2.2 Nova and Eclipse + +- Fixed device enable/disable support (found by Bruce Ray). + +2.3 PDP-1 + +- Fixed bug in LOAD (found by Mark Crispin). + +2.4 PDP-10 + +- Fixed bug in floating point unpack. +- Fixed bug in FIXR (found by Phil Stone, fixed by Chris Smith). + +2.6 PDP-11 + +- Fixed bug in RQ interrupt control (found by Tom Evans). + +2.6 PDP-18B + +- Fixed bug in PDP-15 XVM g_mode implementation. +- Fixed bug in PDP-15 indexed address calculation. +- Fixed bug in PDP-15 autoindexed address calculation. +- Fixed bugs in FPP-15 instruction decode. +- Fixed clock response to CAF. +- Fixed bug in hardware read-in mode bootstrap. +- Fixed PDP-15 XVM instruction decoding errors. + +2.7 VAX + +- Fixed PC read fault in EXTxV. +- Fixed PC write fault in INSV. + diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 6ffc7a84..cff3c22e 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -1,16 +1,19 @@ -This file contains information about the XQ/SIM_ETHER package. +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 XQ emulator uses the Sim_Ether module to execute host-specific ethernet -packet reads and writes, since all operating systems talk to real ethernet -cards/controllers differently. The host-dependant Sim_Ether module currently -supports Windows, Linux, NetBSD, OpenBSD, FreeBSD, OS/X, and Alpha VMS. +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. -Currently, the Sim_Ether module sets the selected ethernet card into +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). @@ -67,26 +70,58 @@ Building on Windows: 4. If you're using Borland C++, use COFF2OMF to convert the .lib files into a format that can be used by the compiler. - 5. Define USE_NETWORK if you want the network functionality. + 5. Define USE_NETWORK. 6. Build it! ------------------------------------------------------------------------------- Linux, {Free|Net|Open}BSD, OS/X, and Un*x notes: - 1. You must run SIMH(scp) as root so that the ethernet card can be set into - promiscuous mode by the driver. Alternative methods for avoiding the - 'run as root' requirement will be welcomed. + +----- 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. -Linux, {Free|Net|Open}BSD, OS/X, Un*x notes: +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? - Others : http://sourceforge.net/projects/libpcap/ - 2. Use 'make USE_NETWORK=1' if you want the network functionality. + 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! @@ -114,7 +149,8 @@ OpenVMS Alpha notes: no network devices are available 2. You must place the PCAPVCM.EXE execlet in SYS$LOADABLE_IMAGES before - running a simulator with ethernet support. + 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. @@ -125,25 +161,16 @@ OpenVMS Alpha notes: The execlet is not written to create an I/O structure for the device. Building on OpenVMS Alpha: - 1. Build the PCAP library and execlet. They are in the [.PCAP-VMS] - directory in the simh source distribution. The following builds - both the pcap library and the pcap execlet: - $ set def [.pcap-vms] - $ @build_all - Building VCI version of pcap... - Building the PCAP VCM execlet... - In order to use it, place PCAPVCM.EXE in the - SYS$LOADABLE_IMAGES directory. - %DCL-I-SUPERSEDE, previous value of PCAPVCM$OBJ has been superseded - - To use the PCAPVCM.EXE execlet you must copy it to - the SYS$LOADABLE_IMAGES directory. - - Build done... - - 2. To build the simulators with ethernet support, you - need to build them with MMS or MMK as follows: - $ MMx/MACRO=("__ALPHA__=1", "__PCAP__=1") + 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...} ------------------------------------------------------------------------------- @@ -160,7 +187,28 @@ 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: @@ -168,7 +216,6 @@ Things planned for future releases: 2. Full MOP implementation 3. DESQA support (if someone can get me the user manuals) 4. DETQA support [DELQA-Turbo] (I have the manual) - 5. DEUNA/DELUA support ------------------------------------------------------------------------------- @@ -190,12 +237,21 @@ 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 Software Reset (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) diff --git a/AltairZ80/altairZ80.txt b/AltairZ80/altairZ80.txt index 48f83a1e..6099fc23 100644 --- a/AltairZ80/altairZ80.txt +++ b/AltairZ80/altairZ80.txt @@ -3,6 +3,7 @@ Altair 8800 Simulator with Z80 support 0. Revision History +- 26-Jan-2004, Peter Schorn (added support for t-state stepping) - 25-Feb-2003, Peter Schorn (added support for real time simulation) - 9-Oct-2002, Peter Schorn (added support for simulated hard disk) - 28-Sep-2002, Peter Schorn (number of tracks per disk can be configured) @@ -842,6 +843,9 @@ following commands: 4. Special simulator features + +4.1 Memory access breakpoints + In addition to the regular SIMH features such as PC queue, breakpoints etc., this simulator supports memory access breakpoints. A memory access breakpoint is triggered when a pre-defined memory location is accessed @@ -855,6 +859,21 @@ a memory access breakpoint is not triggered by fetching code from memory by using the typing facility of the SIMH breakpoints. +4.2 T-state stepping + + The SIMH step command supports the "-t" modifier to allow steppping for +a predefined number of t-states. For example + +sim> step -t 1000 + +will cause the simulated CPU to execute 1000 t-states (note that the shortest +instruction will have 4 t-states). On the other hand, the command + +sim> step 1000 + +will cause the simulated CPU to execute 1000 instructions. + + 5. Brief summary of all major changes to the original Altair simulator - Full support for Z80. CP/M software requiring a Z80 CPU now runs properly. DDTZ and PROLOGZ are included for demonstration purposes. diff --git a/AltairZ80/altairZ80_cpu.c b/AltairZ80/altairZ80_cpu.c index ecd6eccd..b62e9133 100644 --- a/AltairZ80/altairZ80_cpu.c +++ b/AltairZ80/altairZ80_cpu.c @@ -1,5622 +1,5825 @@ -/* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) - - Copyright (c) 2002-2003, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. - - Based on work by Charles E Owen (c) 1997 - Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license) -*/ - -#include "altairz80_defs.h" - -#if !defined (_WIN32) -#include -#endif - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_SIZE_LOG2 6 /* log2 of PCQ_SIZE */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY(PC) pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC - -/* simulator stop codes */ -#define STOP_HALT 0 /* HALT */ -#define STOP_IBKPT 1 /* breakpoint (program counter) */ -#define STOP_MEM 2 /* breakpoint (memory access) */ -#define STOP_OPCODE 3 /* unknown 8080 or Z80 instruction */ - -/*-------------------------------- definitions for memory space --------------------*/ - -static uint8 M[MAXMEMSIZE][MAXBANKS]; /* RAM which is present */ - -/* two sets of accumulator / flags */ -static uint16 af[2]; -static int af_sel; - -/* two sets of 16-bit registers */ -static struct ddregs { - uint16 bc; - uint16 de; - uint16 hl; -} regs[2]; -static int regs_sel; - -static uint16 ir; -static uint16 ix; -static uint16 iy; -static uint16 sp; -static uint16 pc; -static uint16 IFF; - -#define FLAG_C 1 -#define FLAG_N 2 -#define FLAG_P 4 -#define FLAG_H 16 -#define FLAG_Z 64 -#define FLAG_S 128 - -#define SETFLAG(f,c) AF = (c) ? AF | FLAG_ ## f : AF & ~FLAG_ ## f -#define TSTFLAG(f) ((AF & FLAG_ ## f) != 0) - -#define ldig(x) ((x) & 0xf) -#define hdig(x) (((x) >> 4) & 0xf) -#define lreg(x) ((x) & 0xff) -#define hreg(x) (((x) >> 8) & 0xff) - -#define Setlreg(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) -#define Sethreg(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) - -#define parity(x) parityTable[(x) & 0xff] -/* SetPV and SetPV2 are used to provide correct parity flag semantics for the 8080 in cases - where the Z80 uses the overflow flag -*/ -#define SetPVS(s) ((cpu_unit.flags & UNIT_CHIP) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (parity(s))) -#define SetPV (SetPVS(sum)) -#define SetPV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (parity(temp))) - -/* checkCPU8080 must be invoked whenever a Z80 only instruction is executed */ -#define checkCPU8080 \ - if (((cpu_unit.flags & UNIT_CHIP) == 0) && (cpu_unit.flags & UNIT_OPSTOP)) {\ - reason = STOP_OPCODE; \ - goto end_decode; \ - } - -/* checkCPUZ80 must be invoked whenever a non Z80 instruction is executed */ -#define checkCPUZ80 \ - if (cpu_unit.flags & UNIT_OPSTOP) { \ - reason = STOP_OPCODE; \ - goto end_decode; \ - } - -#define POP(x) do { \ - register uint32 y = RAM_pp(SP); \ - x = y + (RAM_pp(SP) << 8); \ -} while (0) - -#define JPC(cond) { \ - tStates += 10; \ - if (cond) { \ - PCQ_ENTRY(PC - 1); \ - PC = GetWORD(PC); \ - } \ - else { \ - PC += 2; \ - } \ -} - -#define CALLC(cond) { \ - if (cond) { \ - register uint32 adrr = GetWORD(PC); \ - CheckBreakWord(SP - 2); \ - PUSH(PC + 2); \ - PCQ_ENTRY(PC - 1); \ - PC = adrr; \ - tStates += 17; \ - } \ - else { \ - sim_brk_pend = FALSE; \ - PC += 2; \ - tStates += 10; \ - } \ -} - -extern int32 sim_int_char; -extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern int32 sio0s (const int32 port, const int32 io, const int32 data); -extern int32 sio0d (const int32 port, const int32 io, const int32 data); -extern int32 sio1s (const int32 port, const int32 io, const int32 data); -extern int32 sio1d (const int32 port, const int32 io, const int32 data); -extern int32 dsk10 (const int32 port, const int32 io, const int32 data); -extern int32 dsk11 (const int32 port, const int32 io, const int32 data); -extern int32 dsk12 (const int32 port, const int32 io, const int32 data); -extern int32 nulldev (const int32 port, const int32 io, const int32 data); -extern int32 hdsk_io (const int32 port, const int32 io, const int32 data); -extern int32 simh_dev (const int32 port, const int32 io, const int32 data); -extern int32 sr_dev (const int32 port, const int32 io, const int32 data); -extern int32 bootrom[bootrom_size]; -extern char memoryAccessMessage[]; -extern char messageBuffer[]; -extern void printMessage(void); - -/* function prototypes */ -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); -static t_stat cpu_set_rom (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_norom (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_altairrom (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_warnrom (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_banked (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_nonbanked (UNIT *uptr, int32 value, char *cptr, void *desc); -static void prepareMemoryAccessMessage(t_addr loc); -static void checkROMBoundaries(void); -static void warnUnsuccessfulWriteAttempt(const uint32 Addr); -static uint8 warnUnsuccessfulReadAttempt(const uint32 Addr); -static void reset_memory(void); -static uint32 in(const uint32 Port); -static void out(const uint32 Port, const uint32 Value); -uint8 GetBYTE(register uint32 Addr); -void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value); -void PutBYTE(register uint32 Addr, register uint32 Value); -void PutBYTEForced(register uint32 Addr, register uint32 Value); -int32 addressIsInROM(const uint32 Addr); -int32 addressExists(const uint32 Addr); -static uint16 GetWORD(register uint32 a); -static void PutWORD(register uint32 a, register uint32 v); -int32 sim_instr(void); -int32 install_bootrom(void); -static t_bool sim_brk_lookup (const t_addr bloc, const int32 btyp); -void protect(const int32 l, const int32 h); -static void resetCell(const int32 address, const int32 bank); -void printROMMessage(const uint32 cntROM); - -#ifndef NO_INLINE -/* in case of using inline we need to ensure that the GetBYTE and PutBYTE - are accessible externally */ -uint8 GetBYTEWrapper(register uint32 Addr); -void PutBYTEWrapper(register uint32 Addr, register uint32 Value); -#endif - -/* CPU data structures - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list -*/ - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_ROM + UNIT_ALTAIRROM, MAXMEMSIZE) }; - - int32 PCX; /* external view of PC */ - int32 saved_PC = 0; /* program counter */ -static int32 AF_S; /* AF register */ -static int32 BC_S; /* BC register */ -static int32 DE_S; /* DE register */ -static int32 HL_S; /* HL register */ -static int32 IX_S; /* IX register */ -static int32 IY_S; /* IY register */ -static int32 SP_S; /* SP register */ -static int32 AF1_S; /* alternate AF register */ -static int32 BC1_S; /* alternate BC register */ -static int32 DE1_S; /* alternate DE register */ -static int32 HL1_S; /* alternate HL register */ -static int32 IFF_S; /* interrupt Flip Flop */ -static int32 IR_S; /* interrupt (upper)/refresh (lower) register */ - int32 SR = 0; /* switch register */ - int32 bankSelect = 0; /* determines selected memory bank */ - uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ -static uint32 ROMLow = defaultROMLow; /* lowest address of ROM */ -static uint32 ROMHigh = defaultROMHigh; /* highest address of ROM */ -static uint32 previousCapacity= 0; /* safe for previous memory capacity */ -static uint32 clockFrequency = 0; /* in kHz, 0 means as fast as possible */ -static uint32 sliceLength = 10; /* length of time-slice for CPU speed */ - /* adjustment in milliseonds */ -static uint32 executedTStates = 0; /* executed t-states */ -static uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -static int32 pcq_p = 0; /* PC queue ptr */ -static REG *pcq_r = NULL; /* PC queue reg ptr */ - - -REG cpu_reg[] = { - { HRDATA (PC, saved_PC, 16) }, - { HRDATA (AF, AF_S, 16) }, - { HRDATA (BC, BC_S, 16) }, - { HRDATA (DE, DE_S, 16) }, - { HRDATA (HL, HL_S, 16) }, - { HRDATA (IX, IX_S, 16) }, - { HRDATA (IY, IY_S, 16) }, - { HRDATA (SP, SP_S, 16) }, - { HRDATA (AF1, AF1_S, 16) }, - { HRDATA (BC1, BC1_S, 16) }, - { HRDATA (DE1, DE1_S, 16) }, - { HRDATA (HL1, HL1_S, 16) }, - { GRDATA (IFF, IFF_S, 2, 2, 0) }, - { FLDATA (IR, IR_S, 8) }, - { FLDATA (Z80, cpu_unit.flags, UNIT_V_CHIP), REG_HRO }, - { FLDATA (OPSTOP, cpu_unit.flags, UNIT_V_OPSTOP), REG_HRO }, - { HRDATA (SR, SR, 8) }, - { HRDATA (BANK, bankSelect, MAXBANKSLOG2) }, - { HRDATA (COMMON, common, 16) }, - { HRDATA (ROMLOW, ROMLow, 16) }, - { HRDATA (ROMHIGH, ROMHigh, 16) }, - { DRDATA (CLOCK, clockFrequency, 32) }, - { DRDATA (SLICE, sliceLength, 16) }, - { DRDATA (TSTATES, executedTStates, 32), REG_RO }, - { HRDATA (CAPACITY, cpu_unit.capac, 32), REG_RO }, - { HRDATA (PREVCAP, previousCapacity, 32), REG_RO }, - { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO + REG_CIRC }, - { DRDATA (PCQP, pcq_p, PCQ_SIZE_LOG2), REG_HRO }, - { HRDATA (WRU, sim_int_char, 8) }, - { NULL } }; - -static MTAB cpu_mod[] = { - { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL }, - { UNIT_CHIP, 0, "8080", "8080", NULL }, - { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, - { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, - { UNIT_BANKED, UNIT_BANKED, "BANKED", "BANKED", &cpu_set_banked }, - { UNIT_BANKED, 0, "NONBANKED", "NONBANKED", &cpu_set_nonbanked }, - { UNIT_ROM, UNIT_ROM, "ROM", "ROM", &cpu_set_rom }, - { UNIT_ROM, 0, "NOROM", "NOROM", &cpu_set_norom }, - { UNIT_ALTAIRROM, UNIT_ALTAIRROM, "ALTAIRROM", "ALTAIRROM", &cpu_set_altairrom }, - { UNIT_ALTAIRROM, 0, "NOALTAIRROM", "NOALTAIRROM", NULL }, - { UNIT_WARNROM, UNIT_WARNROM, "WARNROM", "WARNROM", &cpu_set_warnrom }, - { UNIT_WARNROM, 0, "NOWARNROM", "NOWARNROM", NULL }, - { UNIT_MSIZE, 4 * KB, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8 * KB, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12 * KB, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16 * KB, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20 * KB, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24 * KB, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28 * KB, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32 * KB, NULL, "32K", &cpu_set_size }, - { UNIT_MSIZE, 36 * KB, NULL, "36K", &cpu_set_size }, - { UNIT_MSIZE, 40 * KB, NULL, "40K", &cpu_set_size }, - { UNIT_MSIZE, 44 * KB, NULL, "44K", &cpu_set_size }, - { UNIT_MSIZE, 48 * KB, NULL, "48K", &cpu_set_size }, - { UNIT_MSIZE, 52 * KB, NULL, "52K", &cpu_set_size }, - { UNIT_MSIZE, 56 * KB, NULL, "56K", &cpu_set_size }, - { UNIT_MSIZE, 60 * KB, NULL, "60K", &cpu_set_size }, - { UNIT_MSIZE, 64 * KB, NULL, "64K", &cpu_set_size }, - { 0 } }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 16, 16, 1, 16, 8, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, NULL, 0, NULL, NULL }; - -/* data structure for IN/OUT instructions */ -struct idev { - int32 (*routine)(const int32, const int32, const int32); -}; - -/* This is the I/O configuration table. There are 255 possible - device addresses, if a device is plugged to a port it's routine - address is here, 'nulldev' means no device is available -*/ -static const struct idev dev_table[256] = { - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04 */ - {&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 08 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C */ - {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 10 */ - {&sio0s}, {&sio0d}, {&sio0s}, {&sio0d}, /* 14 */ - {&sio0s}, {&sio0d}, {&nulldev}, {&nulldev}, /* 18 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 28 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 30 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 40 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 44 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 48 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 4C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 50 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 54 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 58 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 5C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 60 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 64 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 68 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 6C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 70 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 74 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 78 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 7C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 80 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 84 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 88 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 8C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 90 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 94 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 98 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 9C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* AC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* BC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* CC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* DC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* EC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */ - {&nulldev}, {&hdsk_io}, {&simh_dev}, {&sr_dev} /* FC */ -}; - -static INLINE void out(const uint32 Port, const uint32 Value) { - dev_table[Port].routine(Port, 1, Value); -} - -static INLINE uint32 in(const uint32 Port) { - return dev_table[Port].routine(Port, 0, 0); -} - -/* the following tables precompute some common subexpressions - parityTable[i] 0..255 (number of 1's in i is odd) ? 0 : 4 - incTable[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4) - decTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2 - cbitsTable[i] 0..511 (i & 0x10) | ((i >> 8) & 1) - cbitsDup8Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | - (((i & 0xff) == 0) << 6) - cbitsDup16Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | (i & 0x28) - cbits2Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | 2 - rrcaTable[i] 0..255 ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) - rraTable[i] 0..255 ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) - addTable[i] 0..511 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) - subTable[i] 0..255 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2 - andTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i] - xororTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i] - rotateShiftTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff] - incZ80Table[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | - (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2) - decZ80Table[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | - (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2 - cbitsZ80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) - cbitsZ80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | - ((i >> 8) & 1) | (i & 0xa8) - cbits2Z80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 - cbits2Z80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | - (i & 0xa8) - negTable[i] 0..255 (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0) - rrdrldTable[i] 0..255 (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i] - cpTable[i] 0..255 (i & 0x80) | (((i & 0xff) == 0) << 6) -*/ - -/* parityTable[i] = (number of 1's in i is odd) ? 0 : 4, i = 0..255 */ -static const uint8 parityTable[256] = { - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, -}; - -/* incTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4), i = 0..256 */ -static const uint8 incTable[257] = { - 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80 -}; - -/* decTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2, i = 0..255 */ -static const uint8 decTable[256] = { - 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, -}; - -/* cbitsTable[i] = (i & 0x10) | ((i >> 8) & 1), i = 0..511 */ -static const uint8 cbitsTable[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, -}; - -/* cbitsDup8Table[i] = (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | - (((i & 0xff) == 0) << 6), i = 0..511 */ -static const uint16 cbitsDup8Table[512] = { - 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, - 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, - 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, - 0x1818,0x1918,0x1a18,0x1b18,0x1c18,0x1d18,0x1e18,0x1f18, - 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, - 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, - 0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730, - 0x3838,0x3938,0x3a38,0x3b38,0x3c38,0x3d38,0x3e38,0x3f38, - 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, - 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, - 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, - 0x5818,0x5918,0x5a18,0x5b18,0x5c18,0x5d18,0x5e18,0x5f18, - 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, - 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, - 0x7030,0x7130,0x7230,0x7330,0x7430,0x7530,0x7630,0x7730, - 0x7838,0x7938,0x7a38,0x7b38,0x7c38,0x7d38,0x7e38,0x7f38, - 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, - 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, - 0x9090,0x9190,0x9290,0x9390,0x9490,0x9590,0x9690,0x9790, - 0x9898,0x9998,0x9a98,0x9b98,0x9c98,0x9d98,0x9e98,0x9f98, - 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, - 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, - 0xb0b0,0xb1b0,0xb2b0,0xb3b0,0xb4b0,0xb5b0,0xb6b0,0xb7b0, - 0xb8b8,0xb9b8,0xbab8,0xbbb8,0xbcb8,0xbdb8,0xbeb8,0xbfb8, - 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, - 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, - 0xd090,0xd190,0xd290,0xd390,0xd490,0xd590,0xd690,0xd790, - 0xd898,0xd998,0xda98,0xdb98,0xdc98,0xdd98,0xde98,0xdf98, - 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, - 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, - 0xf0b0,0xf1b0,0xf2b0,0xf3b0,0xf4b0,0xf5b0,0xf6b0,0xf7b0, - 0xf8b8,0xf9b8,0xfab8,0xfbb8,0xfcb8,0xfdb8,0xfeb8,0xffb8, - 0x0041,0x0101,0x0201,0x0301,0x0401,0x0501,0x0601,0x0701, - 0x0809,0x0909,0x0a09,0x0b09,0x0c09,0x0d09,0x0e09,0x0f09, - 0x1011,0x1111,0x1211,0x1311,0x1411,0x1511,0x1611,0x1711, - 0x1819,0x1919,0x1a19,0x1b19,0x1c19,0x1d19,0x1e19,0x1f19, - 0x2021,0x2121,0x2221,0x2321,0x2421,0x2521,0x2621,0x2721, - 0x2829,0x2929,0x2a29,0x2b29,0x2c29,0x2d29,0x2e29,0x2f29, - 0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731, - 0x3839,0x3939,0x3a39,0x3b39,0x3c39,0x3d39,0x3e39,0x3f39, - 0x4001,0x4101,0x4201,0x4301,0x4401,0x4501,0x4601,0x4701, - 0x4809,0x4909,0x4a09,0x4b09,0x4c09,0x4d09,0x4e09,0x4f09, - 0x5011,0x5111,0x5211,0x5311,0x5411,0x5511,0x5611,0x5711, - 0x5819,0x5919,0x5a19,0x5b19,0x5c19,0x5d19,0x5e19,0x5f19, - 0x6021,0x6121,0x6221,0x6321,0x6421,0x6521,0x6621,0x6721, - 0x6829,0x6929,0x6a29,0x6b29,0x6c29,0x6d29,0x6e29,0x6f29, - 0x7031,0x7131,0x7231,0x7331,0x7431,0x7531,0x7631,0x7731, - 0x7839,0x7939,0x7a39,0x7b39,0x7c39,0x7d39,0x7e39,0x7f39, - 0x8081,0x8181,0x8281,0x8381,0x8481,0x8581,0x8681,0x8781, - 0x8889,0x8989,0x8a89,0x8b89,0x8c89,0x8d89,0x8e89,0x8f89, - 0x9091,0x9191,0x9291,0x9391,0x9491,0x9591,0x9691,0x9791, - 0x9899,0x9999,0x9a99,0x9b99,0x9c99,0x9d99,0x9e99,0x9f99, - 0xa0a1,0xa1a1,0xa2a1,0xa3a1,0xa4a1,0xa5a1,0xa6a1,0xa7a1, - 0xa8a9,0xa9a9,0xaaa9,0xaba9,0xaca9,0xada9,0xaea9,0xafa9, - 0xb0b1,0xb1b1,0xb2b1,0xb3b1,0xb4b1,0xb5b1,0xb6b1,0xb7b1, - 0xb8b9,0xb9b9,0xbab9,0xbbb9,0xbcb9,0xbdb9,0xbeb9,0xbfb9, - 0xc081,0xc181,0xc281,0xc381,0xc481,0xc581,0xc681,0xc781, - 0xc889,0xc989,0xca89,0xcb89,0xcc89,0xcd89,0xce89,0xcf89, - 0xd091,0xd191,0xd291,0xd391,0xd491,0xd591,0xd691,0xd791, - 0xd899,0xd999,0xda99,0xdb99,0xdc99,0xdd99,0xde99,0xdf99, - 0xe0a1,0xe1a1,0xe2a1,0xe3a1,0xe4a1,0xe5a1,0xe6a1,0xe7a1, - 0xe8a9,0xe9a9,0xeaa9,0xeba9,0xeca9,0xeda9,0xeea9,0xefa9, - 0xf0b1,0xf1b1,0xf2b1,0xf3b1,0xf4b1,0xf5b1,0xf6b1,0xf7b1, - 0xf8b9,0xf9b9,0xfab9,0xfbb9,0xfcb9,0xfdb9,0xfeb9,0xffb9, -}; - -/* cbitsDup16Table[i] = (i & 0x10) | ((i >> 8) & 1) | (i & 0x28), i = 0..511 */ -static const uint8 cbitsDup16Table[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, - 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, - 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, - 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, - 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, - 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, - 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, - 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, - 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, - 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, - 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, - 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, - 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, - 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, - 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, - 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, - 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, - 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, - 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, - 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, - 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, -}; - -/* cbits2Table[i] = (i & 0x10) | ((i >> 8) & 1) | 2, i = 0..511 */ -static const uint8 cbits2Table[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, -}; - -/* rrcaTable[i] = ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ -static const uint16 rrcaTable[256] = { - 0x0000,0x8001,0x0100,0x8101,0x0200,0x8201,0x0300,0x8301, - 0x0400,0x8401,0x0500,0x8501,0x0600,0x8601,0x0700,0x8701, - 0x0808,0x8809,0x0908,0x8909,0x0a08,0x8a09,0x0b08,0x8b09, - 0x0c08,0x8c09,0x0d08,0x8d09,0x0e08,0x8e09,0x0f08,0x8f09, - 0x1000,0x9001,0x1100,0x9101,0x1200,0x9201,0x1300,0x9301, - 0x1400,0x9401,0x1500,0x9501,0x1600,0x9601,0x1700,0x9701, - 0x1808,0x9809,0x1908,0x9909,0x1a08,0x9a09,0x1b08,0x9b09, - 0x1c08,0x9c09,0x1d08,0x9d09,0x1e08,0x9e09,0x1f08,0x9f09, - 0x2020,0xa021,0x2120,0xa121,0x2220,0xa221,0x2320,0xa321, - 0x2420,0xa421,0x2520,0xa521,0x2620,0xa621,0x2720,0xa721, - 0x2828,0xa829,0x2928,0xa929,0x2a28,0xaa29,0x2b28,0xab29, - 0x2c28,0xac29,0x2d28,0xad29,0x2e28,0xae29,0x2f28,0xaf29, - 0x3020,0xb021,0x3120,0xb121,0x3220,0xb221,0x3320,0xb321, - 0x3420,0xb421,0x3520,0xb521,0x3620,0xb621,0x3720,0xb721, - 0x3828,0xb829,0x3928,0xb929,0x3a28,0xba29,0x3b28,0xbb29, - 0x3c28,0xbc29,0x3d28,0xbd29,0x3e28,0xbe29,0x3f28,0xbf29, - 0x4000,0xc001,0x4100,0xc101,0x4200,0xc201,0x4300,0xc301, - 0x4400,0xc401,0x4500,0xc501,0x4600,0xc601,0x4700,0xc701, - 0x4808,0xc809,0x4908,0xc909,0x4a08,0xca09,0x4b08,0xcb09, - 0x4c08,0xcc09,0x4d08,0xcd09,0x4e08,0xce09,0x4f08,0xcf09, - 0x5000,0xd001,0x5100,0xd101,0x5200,0xd201,0x5300,0xd301, - 0x5400,0xd401,0x5500,0xd501,0x5600,0xd601,0x5700,0xd701, - 0x5808,0xd809,0x5908,0xd909,0x5a08,0xda09,0x5b08,0xdb09, - 0x5c08,0xdc09,0x5d08,0xdd09,0x5e08,0xde09,0x5f08,0xdf09, - 0x6020,0xe021,0x6120,0xe121,0x6220,0xe221,0x6320,0xe321, - 0x6420,0xe421,0x6520,0xe521,0x6620,0xe621,0x6720,0xe721, - 0x6828,0xe829,0x6928,0xe929,0x6a28,0xea29,0x6b28,0xeb29, - 0x6c28,0xec29,0x6d28,0xed29,0x6e28,0xee29,0x6f28,0xef29, - 0x7020,0xf021,0x7120,0xf121,0x7220,0xf221,0x7320,0xf321, - 0x7420,0xf421,0x7520,0xf521,0x7620,0xf621,0x7720,0xf721, - 0x7828,0xf829,0x7928,0xf929,0x7a28,0xfa29,0x7b28,0xfb29, - 0x7c28,0xfc29,0x7d28,0xfd29,0x7e28,0xfe29,0x7f28,0xff29, -}; - -/* rraTable[i] = ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ -static const uint16 rraTable[256] = { - 0x0000,0x0001,0x0100,0x0101,0x0200,0x0201,0x0300,0x0301, - 0x0400,0x0401,0x0500,0x0501,0x0600,0x0601,0x0700,0x0701, - 0x0808,0x0809,0x0908,0x0909,0x0a08,0x0a09,0x0b08,0x0b09, - 0x0c08,0x0c09,0x0d08,0x0d09,0x0e08,0x0e09,0x0f08,0x0f09, - 0x1000,0x1001,0x1100,0x1101,0x1200,0x1201,0x1300,0x1301, - 0x1400,0x1401,0x1500,0x1501,0x1600,0x1601,0x1700,0x1701, - 0x1808,0x1809,0x1908,0x1909,0x1a08,0x1a09,0x1b08,0x1b09, - 0x1c08,0x1c09,0x1d08,0x1d09,0x1e08,0x1e09,0x1f08,0x1f09, - 0x2020,0x2021,0x2120,0x2121,0x2220,0x2221,0x2320,0x2321, - 0x2420,0x2421,0x2520,0x2521,0x2620,0x2621,0x2720,0x2721, - 0x2828,0x2829,0x2928,0x2929,0x2a28,0x2a29,0x2b28,0x2b29, - 0x2c28,0x2c29,0x2d28,0x2d29,0x2e28,0x2e29,0x2f28,0x2f29, - 0x3020,0x3021,0x3120,0x3121,0x3220,0x3221,0x3320,0x3321, - 0x3420,0x3421,0x3520,0x3521,0x3620,0x3621,0x3720,0x3721, - 0x3828,0x3829,0x3928,0x3929,0x3a28,0x3a29,0x3b28,0x3b29, - 0x3c28,0x3c29,0x3d28,0x3d29,0x3e28,0x3e29,0x3f28,0x3f29, - 0x4000,0x4001,0x4100,0x4101,0x4200,0x4201,0x4300,0x4301, - 0x4400,0x4401,0x4500,0x4501,0x4600,0x4601,0x4700,0x4701, - 0x4808,0x4809,0x4908,0x4909,0x4a08,0x4a09,0x4b08,0x4b09, - 0x4c08,0x4c09,0x4d08,0x4d09,0x4e08,0x4e09,0x4f08,0x4f09, - 0x5000,0x5001,0x5100,0x5101,0x5200,0x5201,0x5300,0x5301, - 0x5400,0x5401,0x5500,0x5501,0x5600,0x5601,0x5700,0x5701, - 0x5808,0x5809,0x5908,0x5909,0x5a08,0x5a09,0x5b08,0x5b09, - 0x5c08,0x5c09,0x5d08,0x5d09,0x5e08,0x5e09,0x5f08,0x5f09, - 0x6020,0x6021,0x6120,0x6121,0x6220,0x6221,0x6320,0x6321, - 0x6420,0x6421,0x6520,0x6521,0x6620,0x6621,0x6720,0x6721, - 0x6828,0x6829,0x6928,0x6929,0x6a28,0x6a29,0x6b28,0x6b29, - 0x6c28,0x6c29,0x6d28,0x6d29,0x6e28,0x6e29,0x6f28,0x6f29, - 0x7020,0x7021,0x7120,0x7121,0x7220,0x7221,0x7320,0x7321, - 0x7420,0x7421,0x7520,0x7521,0x7620,0x7621,0x7720,0x7721, - 0x7828,0x7829,0x7928,0x7929,0x7a28,0x7a29,0x7b28,0x7b29, - 0x7c28,0x7c29,0x7d28,0x7d29,0x7e28,0x7e29,0x7f28,0x7f29, -}; - -/* addTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6), i = 0..511 */ -static const uint16 addTable[512] = { - 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, - 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, - 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, - 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, - 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, - 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, - 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, - 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, - 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, - 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, - 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, - 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, - 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, - 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, - 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, - 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, - 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, - 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, - 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, - 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, - 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, - 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, - 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, - 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, - 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, - 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, - 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, - 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, - 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, - 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, - 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, - 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, - 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, - 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, - 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, - 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, - 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, - 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, - 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, - 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, - 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, - 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, - 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, - 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, - 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, - 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, - 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, - 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, - 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, - 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, - 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, - 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, - 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, - 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, - 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, - 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, - 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, - 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, - 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, - 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, - 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, - 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, - 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, - 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, -}; - -/* subTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2, i = 0..255 */ -static const uint16 subTable[256] = { - 0x0042,0x0102,0x0202,0x0302,0x0402,0x0502,0x0602,0x0702, - 0x080a,0x090a,0x0a0a,0x0b0a,0x0c0a,0x0d0a,0x0e0a,0x0f0a, - 0x1002,0x1102,0x1202,0x1302,0x1402,0x1502,0x1602,0x1702, - 0x180a,0x190a,0x1a0a,0x1b0a,0x1c0a,0x1d0a,0x1e0a,0x1f0a, - 0x2022,0x2122,0x2222,0x2322,0x2422,0x2522,0x2622,0x2722, - 0x282a,0x292a,0x2a2a,0x2b2a,0x2c2a,0x2d2a,0x2e2a,0x2f2a, - 0x3022,0x3122,0x3222,0x3322,0x3422,0x3522,0x3622,0x3722, - 0x382a,0x392a,0x3a2a,0x3b2a,0x3c2a,0x3d2a,0x3e2a,0x3f2a, - 0x4002,0x4102,0x4202,0x4302,0x4402,0x4502,0x4602,0x4702, - 0x480a,0x490a,0x4a0a,0x4b0a,0x4c0a,0x4d0a,0x4e0a,0x4f0a, - 0x5002,0x5102,0x5202,0x5302,0x5402,0x5502,0x5602,0x5702, - 0x580a,0x590a,0x5a0a,0x5b0a,0x5c0a,0x5d0a,0x5e0a,0x5f0a, - 0x6022,0x6122,0x6222,0x6322,0x6422,0x6522,0x6622,0x6722, - 0x682a,0x692a,0x6a2a,0x6b2a,0x6c2a,0x6d2a,0x6e2a,0x6f2a, - 0x7022,0x7122,0x7222,0x7322,0x7422,0x7522,0x7622,0x7722, - 0x782a,0x792a,0x7a2a,0x7b2a,0x7c2a,0x7d2a,0x7e2a,0x7f2a, - 0x8082,0x8182,0x8282,0x8382,0x8482,0x8582,0x8682,0x8782, - 0x888a,0x898a,0x8a8a,0x8b8a,0x8c8a,0x8d8a,0x8e8a,0x8f8a, - 0x9082,0x9182,0x9282,0x9382,0x9482,0x9582,0x9682,0x9782, - 0x988a,0x998a,0x9a8a,0x9b8a,0x9c8a,0x9d8a,0x9e8a,0x9f8a, - 0xa0a2,0xa1a2,0xa2a2,0xa3a2,0xa4a2,0xa5a2,0xa6a2,0xa7a2, - 0xa8aa,0xa9aa,0xaaaa,0xabaa,0xacaa,0xadaa,0xaeaa,0xafaa, - 0xb0a2,0xb1a2,0xb2a2,0xb3a2,0xb4a2,0xb5a2,0xb6a2,0xb7a2, - 0xb8aa,0xb9aa,0xbaaa,0xbbaa,0xbcaa,0xbdaa,0xbeaa,0xbfaa, - 0xc082,0xc182,0xc282,0xc382,0xc482,0xc582,0xc682,0xc782, - 0xc88a,0xc98a,0xca8a,0xcb8a,0xcc8a,0xcd8a,0xce8a,0xcf8a, - 0xd082,0xd182,0xd282,0xd382,0xd482,0xd582,0xd682,0xd782, - 0xd88a,0xd98a,0xda8a,0xdb8a,0xdc8a,0xdd8a,0xde8a,0xdf8a, - 0xe0a2,0xe1a2,0xe2a2,0xe3a2,0xe4a2,0xe5a2,0xe6a2,0xe7a2, - 0xe8aa,0xe9aa,0xeaaa,0xebaa,0xecaa,0xedaa,0xeeaa,0xefaa, - 0xf0a2,0xf1a2,0xf2a2,0xf3a2,0xf4a2,0xf5a2,0xf6a2,0xf7a2, - 0xf8aa,0xf9aa,0xfaaa,0xfbaa,0xfcaa,0xfdaa,0xfeaa,0xffaa, -}; - -/* andTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i], i = 0..255 */ -static const uint16 andTable[256] = { - 0x0054,0x0110,0x0210,0x0314,0x0410,0x0514,0x0614,0x0710, - 0x0818,0x091c,0x0a1c,0x0b18,0x0c1c,0x0d18,0x0e18,0x0f1c, - 0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,0x1610,0x1714, - 0x181c,0x1918,0x1a18,0x1b1c,0x1c18,0x1d1c,0x1e1c,0x1f18, - 0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,0x2630,0x2734, - 0x283c,0x2938,0x2a38,0x2b3c,0x2c38,0x2d3c,0x2e3c,0x2f38, - 0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,0x3634,0x3730, - 0x3838,0x393c,0x3a3c,0x3b38,0x3c3c,0x3d38,0x3e38,0x3f3c, - 0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,0x4610,0x4714, - 0x481c,0x4918,0x4a18,0x4b1c,0x4c18,0x4d1c,0x4e1c,0x4f18, - 0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,0x5614,0x5710, - 0x5818,0x591c,0x5a1c,0x5b18,0x5c1c,0x5d18,0x5e18,0x5f1c, - 0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,0x6634,0x6730, - 0x6838,0x693c,0x6a3c,0x6b38,0x6c3c,0x6d38,0x6e38,0x6f3c, - 0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,0x7630,0x7734, - 0x783c,0x7938,0x7a38,0x7b3c,0x7c38,0x7d3c,0x7e3c,0x7f38, - 0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,0x8690,0x8794, - 0x889c,0x8998,0x8a98,0x8b9c,0x8c98,0x8d9c,0x8e9c,0x8f98, - 0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,0x9694,0x9790, - 0x9898,0x999c,0x9a9c,0x9b98,0x9c9c,0x9d98,0x9e98,0x9f9c, - 0xa0b4,0xa1b0,0xa2b0,0xa3b4,0xa4b0,0xa5b4,0xa6b4,0xa7b0, - 0xa8b8,0xa9bc,0xaabc,0xabb8,0xacbc,0xadb8,0xaeb8,0xafbc, - 0xb0b0,0xb1b4,0xb2b4,0xb3b0,0xb4b4,0xb5b0,0xb6b0,0xb7b4, - 0xb8bc,0xb9b8,0xbab8,0xbbbc,0xbcb8,0xbdbc,0xbebc,0xbfb8, - 0xc094,0xc190,0xc290,0xc394,0xc490,0xc594,0xc694,0xc790, - 0xc898,0xc99c,0xca9c,0xcb98,0xcc9c,0xcd98,0xce98,0xcf9c, - 0xd090,0xd194,0xd294,0xd390,0xd494,0xd590,0xd690,0xd794, - 0xd89c,0xd998,0xda98,0xdb9c,0xdc98,0xdd9c,0xde9c,0xdf98, - 0xe0b0,0xe1b4,0xe2b4,0xe3b0,0xe4b4,0xe5b0,0xe6b0,0xe7b4, - 0xe8bc,0xe9b8,0xeab8,0xebbc,0xecb8,0xedbc,0xeebc,0xefb8, - 0xf0b4,0xf1b0,0xf2b0,0xf3b4,0xf4b0,0xf5b4,0xf6b4,0xf7b0, - 0xf8b8,0xf9bc,0xfabc,0xfbb8,0xfcbc,0xfdb8,0xfeb8,0xffbc, -}; - -/* xororTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i], i = 0..255 */ -static const uint16 xororTable[256] = { - 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, - 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, - 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, - 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, - 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, - 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, - 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, - 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, - 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, - 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, - 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, - 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, - 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, - 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, - 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, - 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, - 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, - 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, - 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, - 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, - 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, - 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, - 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, - 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, - 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, - 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, - 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, - 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, - 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, - 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, - 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, - 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, -}; - -/* rotateShiftTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff], i = 0..255 */ -static const uint8 rotateShiftTable[256] = { - 68, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, - 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, - 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, - 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, - 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, - 4, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, - 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, - 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, - 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, - 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, - 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, - 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, - 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, - 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, - 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, - 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, -}; - -/* incZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | - (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2), i = 0..256 */ -static const uint8 incZ80Table[257] = { - 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 148,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80, -}; - -/* decZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | - (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2, i = 0..255 */ -static const uint8 decZ80Table[256] = { - 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 62, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, -}; - -/* cbitsZ80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1), i = 0..511 */ -static const uint8 cbitsZ80Table[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, -}; - -/* cbitsZ80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | - ((i >> 8) & 1) | (i & 0xa8), i = 0..511 */ -static const uint8 cbitsZ80DupTable[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, - 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, - 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, - 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, - 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, - 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, - 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, - 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, - 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, - 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, - 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, - 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, - 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, - 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, - 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, - 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, - 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, - 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, - 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, - 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, - 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, - 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, - 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, - 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, - 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, - 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, - 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, -}; - -/* cbits2Z80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2, i = 0..511 */ -static const uint8 cbits2Z80Table[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, -}; - -/* cbits2Z80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | - (i & 0xa8), i = 0..511 */ -static const uint8 cbits2Z80DupTable[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, - 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, - 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, - 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, - 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, - 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, - 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, - 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, - 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, - 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, - 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, - 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, - 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, - 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, - 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, - 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, - 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, - 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, - 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, - 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, - 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, - 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, - 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, - 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, - 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, - 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, - 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, - 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, - 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, -}; - -/* negTable[i] = (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0), i = 0..255 */ -static const uint8 negTable[256] = { - 2,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 7,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, -}; - -/* rrdrldTable[i] = (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i], i = 0..255 */ -static const uint16 rrdrldTable[256] = { - 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, - 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, - 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, - 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, - 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, - 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, - 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, - 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, - 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, - 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, - 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, - 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, - 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, - 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, - 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, - 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, - 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, - 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, - 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, - 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, - 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, - 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, - 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, - 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, - 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, - 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, - 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, - 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, - 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, - 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, - 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, - 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, -}; - -/* cpTable[i] = (i & 0x80) | (((i & 0xff) == 0) << 6), i = 0..255 */ -static const uint8 cpTable[256] = { - 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, -}; - -/* remove comments to generate table contents -static void altairz80_init(void); -void (*sim_vm_init) (void) = &altairz80_init; -static void altairz80_init(void) { -*/ -/* parityTable */ -/* - uint32 i, v; - for (i = 0; i < 256; i++) { - v = ((i & 1) + ((i & 2) >> 1) + ((i & 4) >> 2) + ((i & 8) >> 3) + - ((i & 16) >> 4) + ((i & 32) >> 5) + ((i & 64) >> 6) + ((i & 128) >> 7)) % 2 ? 0 : 4; - printf("%1d,", v); - if ( ((i+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* incTable */ -/* - uint32 temp, v; - for (temp = 0; temp <= 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4); - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* decTable */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | 2; - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbitsTable */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | ((cbits >> 8) & 1); - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbitsDup8Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | ((cbits >> 8) & 1) | ((cbits & 0xff) << 8) | (cbits & 0xa8) | (((cbits & 0xff) == 0) << 6); - printf("0x%04x,", v); - if ( ((cbits+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* cbitsDup16Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | ((cbits >> 8) & 1) | (cbits & 0x28); - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbits2Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | ((cbits >> 8) & 1) | 2; - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* rrcaTable */ -/* - uint32 temp, sum, v; - for (temp = 0; temp < 256; temp++) { - sum = temp >> 1; - v = ((temp & 1) << 15) | (sum << 8) | (sum & 0x28) | (temp & 1); - printf("0x%04x,", v); - if ( ((temp+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* rraTable */ -/* - uint32 temp, sum, v; - for (temp = 0; temp < 256; temp++) { - sum = temp >> 1; - v = (sum << 8) | (sum & 0x28) | (temp & 1); - printf("0x%04x,", v); - if ( ((temp+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* addTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 512; sum++) { - v = ((sum & 0xff) << 8) | (sum & 0xa8) | (((sum & 0xff) == 0) << 6); - printf("0x%04x,", v); - if ( ((sum+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* subTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 256; sum++) { - v = ((sum & 0xff) << 8) | (sum & 0xa8) | (((sum & 0xff) == 0) << 6) | 2; - printf("0x%04x,", v); - if ( ((sum+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* andTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 256; sum++) { - v = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | parityTable[sum]; - printf("0x%04x,", v); - if ( ((sum+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* xororTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 256; sum++) { - v = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | parityTable[sum]; - printf("0x%04x,", v); - if ( ((sum+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* rotateShiftTable */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | parity(temp); - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* incZ80Table */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | - (((temp & 0xf) == 0) << 4) | ((temp == 0x80) << 2); - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* decZ80Table */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | - (((temp & 0xf) == 0xf) << 4) | ((temp == 0x7f) << 2) | 2; - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbitsZ80Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | - ((cbits >> 8) & 1); - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbitsZ80DupTable */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | - ((cbits >> 8) & 1) | (cbits & 0xa8); - printf("%3d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbits2Z80Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1); - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbits2Z80DupTable */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1) | - (cbits & 0xa8); - printf("%3d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* negTable */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (((temp & 0x0f) != 0) << 4) | ((temp == 0x80) << 2) | 2 | (temp != 0); - printf("%2d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* rrdrldTable */ -/* - uint32 acu, v; - for (acu = 0; acu < 256; acu++) { - v = (acu << 8) | (acu & 0xa8) | (((acu & 0xff) == 0) << 6) | parityTable[acu]; - printf("0x%04x,", v); - if ( ((acu+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* cpTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 256; sum++) { - v = (sum & 0x80) | (((sum & 0xff) == 0) << 6); - printf("%3d,", v); - if ( ((sum+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* remove comments to generate table contents -} -*/ - -static void warnUnsuccessfulWriteAttempt(const uint32 Addr) { - if (cpu_unit.flags & UNIT_WARNROM) { - if (addressIsInROM(Addr)) { - message2("Attempt to write to ROM " AddressFormat ".\n", Addr); - } - else { - message2("Attempt to write to non existing memory " AddressFormat ".\n", Addr); - } - } -} - -static uint8 warnUnsuccessfulReadAttempt(const uint32 Addr) { - if (cpu_unit.flags & UNIT_WARNROM) { - message2("Attempt to read from non existing memory " AddressFormat ".\n", Addr); - } - return 0xff; -} - -/* determine whether Addr points to Read Only Memory */ -int32 addressIsInROM(const uint32 Addr) { - uint32 addr = Addr & ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - return (cpu_unit.flags & UNIT_ROM) && ( /* must have ROM enabled */ - /* in banked case we have standard Altair ROM */ - ((cpu_unit.flags & UNIT_BANKED) && (defaultROMLow <= addr)) || - /* in non-banked case we check the bounds of the ROM */ - (((cpu_unit.flags & UNIT_BANKED) == 0) && (ROMLow <= addr) && (addr <= ROMHigh))); -} - -/* determine whether Addr points to a valid memory address */ -int32 addressExists(const uint32 Addr) { - uint32 addr = Addr & ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - return (cpu_unit.flags & UNIT_BANKED) || (addr < MEMSIZE) || - ((cpu_unit.flags & UNIT_BANKED) == 0) && (cpu_unit.flags & UNIT_ROM) - && (ROMLow <= addr) && (addr <= ROMHigh); -} - -INLINE uint8 GetBYTE(register uint32 Addr) { - Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if (cpu_unit.flags & UNIT_BANKED) { /* banked memory case */ - /* if Addr below "common" take from selected bank, otherwise from bank 0 */ - return Addr < common ? M[Addr][bankSelect] : M[Addr][0]; - } - else { /* non-banked memory case */ - return ((Addr < MEMSIZE) || - (cpu_unit.flags & UNIT_ROM) && (ROMLow <= Addr) && (Addr <= ROMHigh)) ? - M[Addr][0] : warnUnsuccessfulReadAttempt(Addr); - } -} - -INLINE void PutBYTE(register uint32 Addr, register uint32 Value) { - Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if (cpu_unit.flags & UNIT_BANKED) { - if (Addr < common) { - M[Addr][bankSelect] = Value; - } - else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { - M[Addr][0] = Value; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - } - else { - if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { - M[Addr][0] = Value; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - } -} - -void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value) { - M[Addr & ADDRMASK][Bank & BANKMASK] = Value; -} - -void PutBYTEForced(register uint32 Addr, register uint32 Value) { - Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if ((cpu_unit.flags & UNIT_BANKED) && (Addr < common)) { - M[Addr][bankSelect] = Value; - } - else { - M[Addr][0] = Value; - } -} - -static INLINE void PutWORD(register uint32 Addr, register uint32 Value) { - Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if (cpu_unit.flags & UNIT_BANKED) { - if (Addr < common) { - M[Addr][bankSelect] = Value; - } - else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { - M[Addr][0] = Value; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - Addr = (Addr + 1) & ADDRMASK; - if (Addr < common) { - M[Addr][bankSelect] = Value >> 8; - } - else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { - M[Addr][0] = Value >> 8; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - } - else { - if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { - M[Addr][0] = Value; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - Addr = (Addr + 1) & ADDRMASK; - if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { - M[Addr][0] = Value >> 8; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - } -} - -#ifndef NO_INLINE -uint8 GetBYTEWrapper(register uint32 Addr) { /* make sure that non-inlined version exists */ - return GetBYTE(Addr); -} - -void PutBYTEWrapper(register uint32 Addr, register uint32 Value) { - PutBYTE(Addr, Value); -} -#endif - -#define RAM_mm(a) GetBYTE(a--) -#define RAM_pp(a) GetBYTE(a++) - -#define PutBYTE_pp(a,v) PutBYTE(a++, v) -#define PutBYTE_mm(a,v) PutBYTE(a--, v) -#define mm_PutBYTE(a,v) PutBYTE(--a, v) - -static INLINE uint16 GetWORD(register uint32 a) { - return GetBYTE(a) | (GetBYTE(a + 1) << 8); -} - -#define MASK_BRK (TRUE + 1) - -/* this is a modified version of sim_brk_test with two differences: - 1) is does not set sim_brk_pend to FALSE (this if left to the instruction decode) - 2) it returns MASK_BRK if a breakpoint is found but should be ignored -*/ -static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) { - extern t_bool sim_brk_pend; - extern t_addr sim_brk_ploc; - extern char *sim_brk_act; - BRKTAB *bp; - if ((bp = sim_brk_fnd (loc)) && /* entry in table? */ - (btyp & bp -> typ) && /* type match? */ - (!sim_brk_pend || (loc != sim_brk_ploc)) && /* new location? */ - (--(bp -> cnt) <= 0)) { /* count reach 0? */ - bp -> cnt = 0; /* reset count */ - sim_brk_ploc = loc; /* save location */ - sim_brk_act = bp -> act; /* set up actions */ - sim_brk_pend = TRUE; /* don't do twice */ - return TRUE; - } - return (sim_brk_pend && (loc == sim_brk_ploc)) ? MASK_BRK : FALSE; -} - -static void prepareMemoryAccessMessage(t_addr loc) { - sprintf(memoryAccessMessage, "Memory access breakpoint [%04xh]", loc); -} - -#define PUSH(x) do { \ - mm_PutBYTE(SP, (x) >> 8); \ - mm_PutBYTE(SP, x); \ -} while (0) - -#define CheckBreakByte(a) \ - if (sim_brk_summ && sim_brk_test(a, SWMASK('M'))) { \ - reason = STOP_MEM; \ - prepareMemoryAccessMessage(a); \ - goto end_decode; \ - } - -#define CheckBreakTwoBytesExtended(a1, a2, iCode) \ - if (sim_brk_summ) { \ - br1 = sim_brk_lookup(a1, SWMASK('M')); \ - br2 = br1 ? FALSE : sim_brk_lookup(a2, SWMASK('M')); \ - if ((br1 == MASK_BRK) || (br2 == MASK_BRK)) { \ - sim_brk_pend = FALSE; \ - } \ - else if (br1 || br2) { \ - reason = STOP_MEM; \ - if (br1) { \ - prepareMemoryAccessMessage(a1); \ - } \ - else { \ - prepareMemoryAccessMessage(a2); \ - } \ - iCode; \ - goto end_decode; \ - } \ - else { \ - sim_brk_pend = FALSE; \ - } \ - } - -#define CheckBreakTwoBytes(a1, a2) CheckBreakTwoBytesExtended(a1, a2,;) - -#define CheckBreakWord(a) CheckBreakTwoBytes(a, (a + 1)) - -int32 sim_instr (void) { - extern int32 sim_interval; - extern t_bool sim_brk_pend; - extern int32 timerInterrupt; - extern int32 timerInterruptHandler; - extern uint32 sim_os_msec(void); - extern t_bool rtc_avail; - int32 reason = 0; - register uint32 specialProcessing; - register uint32 AF; - register uint32 BC; - register uint32 DE; - register uint32 HL; - register uint32 PC; - register uint32 SP; - register uint32 IX; - register uint32 IY; - register uint32 temp = 0; - register uint32 acu = 0; - register uint32 sum; - register uint32 cbits; - register uint32 op; - register uint32 adr; - /* tStates contains the number of t-states executed. One t-state is executed - in one microsecond on a 1MHz CPU. tStates is used real-time simulation */ - register uint32 tStates; - uint32 tStatesInSlice; /* number of t-states in 10 mSec time-slice */ - uint32 startTime; - int32 br1, br2, tStateModifier = FALSE; - - pc = saved_PC & ADDRMASK; /* load local PC */ - af[af_sel] = AF_S; - regs[regs_sel].bc = BC_S; - regs[regs_sel].de = DE_S; - regs[regs_sel].hl = HL_S; - ix = IX_S; - iy = IY_S; - sp = SP_S; - af[1 - af_sel] = AF1_S; - regs[1 - regs_sel].bc = BC1_S; - regs[1 - regs_sel].de = DE1_S; - regs[1 - regs_sel].hl = HL1_S; - IFF = IFF_S; - ir = IR_S; - - AF = af[af_sel]; - BC = regs[regs_sel].bc; - DE = regs[regs_sel].de; - HL = regs[regs_sel].hl; - PC = pc; - SP = sp; - IX = ix; - IY = iy; - specialProcessing = clockFrequency | timerInterrupt | sim_brk_summ; - tStates = 0; - if (rtc_avail) { - startTime = sim_os_msec(); - tStatesInSlice = sliceLength*clockFrequency; - } - else { /* make sure that sim_os_msec() is not called later */ - clockFrequency = startTime = tStatesInSlice = 0; - } - - /* main instruction fetch/decode loop */ - while (TRUE) { /* loop until halted */ - if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event()) { - break; - } - else { - specialProcessing = clockFrequency | timerInterrupt | sim_brk_summ; - } - } - - if (specialProcessing) { /* quick check for special processing */ - if (clockFrequency && (tStates >= tStatesInSlice)) { - /* clockFrequency != 0 implies that real time clock is available */ - startTime += sliceLength; - tStates -= tStatesInSlice; -#if defined (_WIN32) - while (sim_os_msec() <= startTime) {} /* poor man's sleep */ -#else - { - uint32 now; - if (startTime > (now = sim_os_msec())) { - usleep(1000 * (startTime - now)); - } - } -#endif - } - - if (timerInterrupt && (IFF & 1)) { - timerInterrupt = FALSE; - specialProcessing = clockFrequency | sim_brk_summ; - IFF = 0; /* disable interrupts */ - CheckBreakTwoBytesExtended(SP - 2, SP - 1, (timerInterrupt = TRUE, IFF |= 1)); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = timerInterruptHandler & ADDRMASK; - } - - if (sim_brk_summ && (sim_brk_lookup(PC, SWMASK('E')) == TRUE)) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - } - - PCX = PC; - sim_interval--; - - /* make sure that each instructions properly sets sim_brk_pend: - 1) Either directly to FALSE if no memory access takes place or - 2) through a call to a Check... routine - */ - switch(RAM_pp(PC)) { - case 0x00: /* NOP */ - tStates += 4; - sim_brk_pend = FALSE; - break; - case 0x01: /* LD BC,nnnn */ - tStates += 10; - sim_brk_pend = FALSE; - BC = GetWORD(PC); - PC += 2; - break; - case 0x02: /* LD (BC),A */ - tStates += 7; - CheckBreakByte(BC) - PutBYTE(BC, hreg(AF)); - break; - case 0x03: /* INC BC */ - tStates += 6; - sim_brk_pend = FALSE; - ++BC; - break; - case 0x04: /* INC B */ - tStates += 4; - sim_brk_pend = FALSE; - BC += 0x100; - temp = hreg(BC); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); - break; - case 0x05: /* DEC B */ - tStates += 4; - sim_brk_pend = FALSE; - BC -= 0x100; - temp = hreg(BC); - AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); - break; - case 0x06: /* LD B,nn */ - tStates += 7; - sim_brk_pend = FALSE; - Sethreg(BC, RAM_pp(PC)); - break; - case 0x07: /* RLCA */ - tStates += 4; - sim_brk_pend = FALSE; - AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | - (AF & 0xc4) | ((AF >> 15) & 1); - break; - case 0x08: /* EX AF,AF' */ - tStates += 4; - sim_brk_pend = FALSE; - checkCPU8080; - af[af_sel] = AF; - af_sel = 1 - af_sel; - AF = af[af_sel]; - break; - case 0x09: /* ADD HL,BC */ - tStates += 11; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - BC &= ADDRMASK; - sum = HL + BC; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ BC ^ sum) >> 8]; - HL = sum; - break; - case 0x0a: /* LD A,(BC) */ - tStates += 7; - CheckBreakByte(BC) - Sethreg(AF, GetBYTE(BC)); - break; - case 0x0b: /* DEC BC */ - tStates += 6; - sim_brk_pend = FALSE; - --BC; - break; - case 0x0c: /* INC C */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(BC) + 1; - Setlreg(BC, temp); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); - break; - case 0x0d: /* DEC C */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(BC) - 1; - Setlreg(BC, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); - break; - case 0x0e: /* LD C,nn */ - tStates += 7; - sim_brk_pend = FALSE; - Setlreg(BC, RAM_pp(PC)); - break; - case 0x0f: /* RRCA */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & 0xc4) | rrcaTable[hreg(AF)]; - break; - case 0x10: /* DJNZ dd */ - sim_brk_pend = FALSE; - checkCPU8080; - if ((BC -= 0x100) & 0xff00) { - PCQ_ENTRY(PC - 1); - PC += (signed char) GetBYTE(PC) + 1; - tStates += 13; - } - else { - PC++; - tStates += 8; - } - break; - case 0x11: /* LD DE,nnnn */ - tStates += 10; - sim_brk_pend = FALSE; - DE = GetWORD(PC); - PC += 2; - break; - case 0x12: /* LD (DE),A */ - tStates += 7; - CheckBreakByte(DE) - PutBYTE(DE, hreg(AF)); - break; - case 0x13: /* INC DE */ - tStates += 6; - sim_brk_pend = FALSE; - ++DE; - break; - case 0x14: /* INC D */ - tStates += 4; - sim_brk_pend = FALSE; - DE += 0x100; - temp = hreg(DE); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); - break; - case 0x15: /* DEC D */ - tStates += 4; - sim_brk_pend = FALSE; - DE -= 0x100; - temp = hreg(DE); - AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); - break; - case 0x16: /* LD D,nn */ - tStates += 7; - sim_brk_pend = FALSE; - Sethreg(DE, RAM_pp(PC)); - break; - case 0x17: /* RLA */ - tStates += 4; - sim_brk_pend = FALSE; - AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | - (AF & 0xc4) | ((AF >> 15) & 1); - break; - case 0x18: /* JR dd */ - tStates += 12; - sim_brk_pend = FALSE; - checkCPU8080; - PCQ_ENTRY(PC - 1); - PC += (signed char) GetBYTE(PC) + 1; - break; - case 0x19: /* ADD HL,DE */ - tStates += 11; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - DE &= ADDRMASK; - sum = HL + DE; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ DE ^ sum) >> 8]; - HL = sum; - break; - case 0x1a: /* LD A,(DE) */ - tStates += 7; - CheckBreakByte(DE) - Sethreg(AF, GetBYTE(DE)); - break; - case 0x1b: /* DEC DE */ - tStates += 6; - sim_brk_pend = FALSE; - --DE; - break; - case 0x1c: /* INC E */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(DE) + 1; - Setlreg(DE, temp); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); - break; - case 0x1d: /* DEC E */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(DE) - 1; - Setlreg(DE, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); - break; - case 0x1e: /* LD E,nn */ - tStates += 7; - sim_brk_pend = FALSE; - Setlreg(DE, RAM_pp(PC)); - break; - case 0x1f: /* RRA */ - tStates += 4; - sim_brk_pend = FALSE; - AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[hreg(AF)]; - break; - case 0x20: /* JR NZ,dd */ - sim_brk_pend = FALSE; - checkCPU8080; - if (TSTFLAG(Z)) { - PC++; - tStates += 7; - } - else { - PCQ_ENTRY(PC - 1); - PC += (signed char) GetBYTE(PC) + 1; - tStates += 12; - } - break; - case 0x21: /* LD HL,nnnn */ - tStates += 10; - sim_brk_pend = FALSE; - HL = GetWORD(PC); - PC += 2; - break; - case 0x22: /* LD (nnnn),HL */ - tStates += 16; - temp = GetWORD(PC); - CheckBreakWord(temp); - PutWORD(temp, HL); - PC += 2; - break; - case 0x23: /* INC HL */ - tStates += 6; - sim_brk_pend = FALSE; - ++HL; - break; - case 0x24: /* INC H */ - tStates += 4; - sim_brk_pend = FALSE; - HL += 0x100; - temp = hreg(HL); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); - break; - case 0x25: /* DEC H */ - tStates += 4; - sim_brk_pend = FALSE; - HL -= 0x100; - temp = hreg(HL); - AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); - break; - case 0x26: /* LD H,nn */ - tStates += 7; - sim_brk_pend = FALSE; - Sethreg(HL, RAM_pp(PC)); - break; - case 0x27: /* DAA */ - tStates += 4; - sim_brk_pend = FALSE; - acu = hreg(AF); - temp = ldig(acu); - cbits = TSTFLAG(C); - if (TSTFLAG(N)) { /* last operation was a subtract */ - int hd = cbits || acu > 0x99; - if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ - if (temp > 5) { - SETFLAG(H, 0); - } - acu -= 6; - acu &= 0xff; - } - if (hd) { /* adjust high digit */ - acu -= 0x160; - } - } - else { /* last operation was an add */ - if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ - SETFLAG(H, (temp > 9)); - acu += 6; - } - if (cbits || ((acu & 0x1f0) > 0x90)) { /* adjust high digit */ - acu += 0x60; - } - } - AF = (AF & 0x12) | rrdrldTable[acu & 0xff] | (acu >> 8) & 1 | cbits; - break; - case 0x28: /* JR Z,dd */ - sim_brk_pend = FALSE; - checkCPU8080; - if (TSTFLAG(Z)) { - PCQ_ENTRY(PC - 1); - PC += (signed char) GetBYTE(PC) + 1; - tStates += 12; - } - else { - PC++; - tStates += 7; - } - break; - case 0x29: /* ADD HL,HL */ - tStates += 11; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - sum = HL + HL; - AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; - HL = sum; - break; - case 0x2a: /* LD HL,(nnnn) */ - tStates += 16; - temp = GetWORD(PC); - CheckBreakWord(temp); - HL = GetWORD(temp); - PC += 2; - break; - case 0x2b: /* DEC HL */ - tStates += 6; - sim_brk_pend = FALSE; - --HL; - break; - case 0x2c: /* INC L */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(HL) + 1; - Setlreg(HL, temp); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); - break; - case 0x2d: /* DEC L */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(HL) - 1; - Setlreg(HL, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); - break; - case 0x2e: /* LD L,nn */ - tStates += 7; - sim_brk_pend = FALSE; - Setlreg(HL, RAM_pp(PC)); - break; - case 0x2f: /* CPL */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; - break; - case 0x30: /* JR NC,dd */ - sim_brk_pend = FALSE; - checkCPU8080; - if (TSTFLAG(C)) { - PC++; - tStates += 7; - } - else { - PCQ_ENTRY(PC - 1); - PC += (signed char) GetBYTE(PC) + 1; - tStates += 12; - } - break; - case 0x31: /* LD SP,nnnn */ - tStates += 10; - sim_brk_pend = FALSE; - SP = GetWORD(PC); - PC += 2; - break; - case 0x32: /* LD (nnnn),A */ - tStates += 13; - temp = GetWORD(PC); - CheckBreakByte(temp); - PutBYTE(temp, hreg(AF)); - PC += 2; - break; - case 0x33: /* INC SP */ - tStates += 6; - sim_brk_pend = FALSE; - ++SP; - break; - case 0x34: /* INC (HL) */ - tStates += 11; - CheckBreakByte(HL); - temp = GetBYTE(HL) + 1; - PutBYTE(HL, temp); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); - break; - case 0x35: /* DEC (HL) */ - tStates += 11; - CheckBreakByte(HL); - temp = GetBYTE(HL) - 1; - PutBYTE(HL, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); - break; - case 0x36: /* LD (HL),nn */ - tStates += 10; - CheckBreakByte(HL); - PutBYTE(HL, RAM_pp(PC)); - break; - case 0x37: /* SCF */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | 1; - break; - case 0x38: /* JR C,dd */ - sim_brk_pend = FALSE; - checkCPU8080; - if (TSTFLAG(C)) { - PCQ_ENTRY(PC - 1); - PC += (signed char) GetBYTE(PC) + 1; - tStates += 12; - } - else { - PC++; - tStates += 7; - } - break; - case 0x39: /* ADD HL,SP */ - tStates += 11; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - SP &= ADDRMASK; - sum = HL + SP; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ SP ^ sum) >> 8]; - HL = sum; - break; - case 0x3a: /* LD A,(nnnn) */ - tStates += 13; - temp = GetWORD(PC); - CheckBreakByte(temp); - Sethreg(AF, GetBYTE(temp)); - PC += 2; - break; - case 0x3b: /* DEC SP */ - tStates += 6; - sim_brk_pend = FALSE; - --SP; - break; - case 0x3c: /* INC A */ - tStates += 4; - sim_brk_pend = FALSE; - AF += 0x100; - temp = hreg(AF); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); - break; - case 0x3d: /* DEC A */ - tStates += 4; - sim_brk_pend = FALSE; - AF -= 0x100; - temp = hreg(AF); - AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); - break; - case 0x3e: /* LD A,nn */ - tStates += 7; - sim_brk_pend = FALSE; - Sethreg(AF, RAM_pp(PC)); - break; - case 0x3f: /* CCF */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | ((AF & 1) << 4) | (~AF & 1); - break; - case 0x40: /* LD B,B */ - tStates += 4; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x41: /* LD B,C */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & 0xff) | ((BC & 0xff) << 8); - break; - case 0x42: /* LD B,D */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & 0xff) | (DE & ~0xff); - break; - case 0x43: /* LD B,E */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & 0xff) | ((DE & 0xff) << 8); - break; - case 0x44: /* LD B,H */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & 0xff) | (HL & ~0xff); - break; - case 0x45: /* LD B,L */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & 0xff) | ((HL & 0xff) << 8); - break; - case 0x46: /* LD B,(HL) */ - tStates += 7; - CheckBreakByte(HL); - Sethreg(BC, GetBYTE(HL)); - break; - case 0x47: /* LD B,A */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & 0xff) | (AF & ~0xff); - break; - case 0x48: /* LD C,B */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & ~0xff) | ((BC >> 8) & 0xff); - break; - case 0x49: /* LD C,C */ - tStates += 4; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x4a: /* LD C,D */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & ~0xff) | ((DE >> 8) & 0xff); - break; - case 0x4b: /* LD C,E */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & ~0xff) | (DE & 0xff); - break; - case 0x4c: /* LD C,H */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & ~0xff) | ((HL >> 8) & 0xff); - break; - case 0x4d: /* LD C,L */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & ~0xff) | (HL & 0xff); - break; - case 0x4e: /* LD C,(HL) */ - tStates += 7; - CheckBreakByte(HL); - Setlreg(BC, GetBYTE(HL)); - break; - case 0x4f: /* LD C,A */ - tStates += 4; - sim_brk_pend = FALSE; - BC = (BC & ~0xff) | ((AF >> 8) & 0xff); - break; - case 0x50: /* LD D,B */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & 0xff) | (BC & ~0xff); - break; - case 0x51: /* LD D,C */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & 0xff) | ((BC & 0xff) << 8); - break; - case 0x52: /* LD D,D */ - tStates += 4; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x53: /* LD D,E */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & 0xff) | ((DE & 0xff) << 8); - break; - case 0x54: /* LD D,H */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & 0xff) | (HL & ~0xff); - break; - case 0x55: /* LD D,L */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & 0xff) | ((HL & 0xff) << 8); - break; - case 0x56: /* LD D,(HL) */ - tStates += 7; - CheckBreakByte(HL); - Sethreg(DE, GetBYTE(HL)); - break; - case 0x57: /* LD D,A */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & 0xff) | (AF & ~0xff); - break; - case 0x58: /* LD E,B */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & ~0xff) | ((BC >> 8) & 0xff); - break; - case 0x59: /* LD E,C */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & ~0xff) | (BC & 0xff); - break; - case 0x5a: /* LD E,D */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & ~0xff) | ((DE >> 8) & 0xff); - break; - case 0x5b: /* LD E,E */ - tStates += 4; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x5c: /* LD E,H */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & ~0xff) | ((HL >> 8) & 0xff); - break; - case 0x5d: /* LD E,L */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & ~0xff) | (HL & 0xff); - break; - case 0x5e: /* LD E,(HL) */ - tStates += 7; - CheckBreakByte(HL); - Setlreg(DE, GetBYTE(HL)); - break; - case 0x5f: /* LD E,A */ - tStates += 4; - sim_brk_pend = FALSE; - DE = (DE & ~0xff) | ((AF >> 8) & 0xff); - break; - case 0x60: /* LD H,B */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & 0xff) | (BC & ~0xff); - break; - case 0x61: /* LD H,C */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & 0xff) | ((BC & 0xff) << 8); - break; - case 0x62: /* LD H,D */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & 0xff) | (DE & ~0xff); - break; - case 0x63: /* LD H,E */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & 0xff) | ((DE & 0xff) << 8); - break; - case 0x64: /* LD H,H */ - tStates += 4; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x65: /* LD H,L */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & 0xff) | ((HL & 0xff) << 8); - break; - case 0x66: /* LD H,(HL) */ - tStates += 7; - CheckBreakByte(HL); - Sethreg(HL, GetBYTE(HL)); - break; - case 0x67: /* LD H,A */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & 0xff) | (AF & ~0xff); - break; - case 0x68: /* LD L,B */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & ~0xff) | ((BC >> 8) & 0xff); - break; - case 0x69: /* LD L,C */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & ~0xff) | (BC & 0xff); - break; - case 0x6a: /* LD L,D */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & ~0xff) | ((DE >> 8) & 0xff); - break; - case 0x6b: /* LD L,E */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & ~0xff) | (DE & 0xff); - break; - case 0x6c: /* LD L,H */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & ~0xff) | ((HL >> 8) & 0xff); - break; - case 0x6d: /* LD L,L */ - tStates += 4; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x6e: /* LD L,(HL) */ - tStates += 7; - CheckBreakByte(HL); - Setlreg(HL, GetBYTE(HL)); - break; - case 0x6f: /* LD L,A */ - tStates += 4; - sim_brk_pend = FALSE; - HL = (HL & ~0xff) | ((AF >> 8) & 0xff); - break; - case 0x70: /* LD (HL),B */ - tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, hreg(BC)); - break; - case 0x71: /* LD (HL),C */ - tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, lreg(BC)); - break; - case 0x72: /* LD (HL),D */ - tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, hreg(DE)); - break; - case 0x73: /* LD (HL),E */ - tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, lreg(DE)); - break; - case 0x74: /* LD (HL),H */ - tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, hreg(HL)); - break; - case 0x75: /* LD (HL),L */ - tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, lreg(HL)); - break; - case 0x76: /* HALT */ - tStates += 4; - sim_brk_pend = FALSE; - reason = STOP_HALT; - PC--; - goto end_decode; - case 0x77: /* LD (HL),A */ - tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, hreg(AF)); - break; - case 0x78: /* LD A,B */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & 0xff) | (BC & ~0xff); - break; - case 0x79: /* LD A,C */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & 0xff) | ((BC & 0xff) << 8); - break; - case 0x7a: /* LD A,D */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & 0xff) | (DE & ~0xff); - break; - case 0x7b: /* LD A,E */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & 0xff) | ((DE & 0xff) << 8); - break; - case 0x7c: /* LD A,H */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & 0xff) | (HL & ~0xff); - break; - case 0x7d: /* LD A,L */ - tStates += 4; - sim_brk_pend = FALSE; - AF = (AF & 0xff) | ((HL & 0xff) << 8); - break; - case 0x7e: /* LD A,(HL) */ - tStates += 7; - CheckBreakByte(HL); - Sethreg(AF, GetBYTE(HL)); - break; - case 0x7f: /* LD A,A */ - tStates += 4; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x80: /* ADD A,B */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(BC); - acu = hreg(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x81: /* ADD A,C */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(BC); - acu = hreg(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x82: /* ADD A,D */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(DE); - acu = hreg(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x83: /* ADD A,E */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(DE); - acu = hreg(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x84: /* ADD A,H */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(HL); - acu = hreg(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x85: /* ADD A,L */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(HL); - acu = hreg(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x86: /* ADD A,(HL) */ - tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - acu = hreg(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x87: /* ADD A,A */ - tStates += 4; - sim_brk_pend = FALSE; - cbits = 2 * hreg(AF); - AF = cbitsDup8Table[cbits] | (SetPVS(cbits)); - break; - case 0x88: /* ADC A,B */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(BC); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x89: /* ADC A,C */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(BC); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x8a: /* ADC A,D */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(DE); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x8b: /* ADC A,E */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(DE); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x8c: /* ADC A,H */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(HL); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x8d: /* ADC A,L */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(HL); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x8e: /* ADC A,(HL) */ - tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0x8f: /* ADC A,A */ - tStates += 4; - sim_brk_pend = FALSE; - cbits = 2 * hreg(AF) + TSTFLAG(C); - AF = cbitsDup8Table[cbits] | (SetPVS(cbits)); - break; - case 0x90: /* SUB B */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(BC); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x91: /* SUB C */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(BC); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x92: /* SUB D */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(DE); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x93: /* SUB E */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(DE); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x94: /* SUB H */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(HL); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x95: /* SUB L */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(HL); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x96: /* SUB (HL) */ - tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x97: /* SUB A */ - tStates += 4; - sim_brk_pend = FALSE; - AF = cpu_unit.flags & UNIT_CHIP ? 0x42 : 0x46; - break; - case 0x98: /* SBC A,B */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(BC); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x99: /* SBC A,C */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(BC); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x9a: /* SBC A,D */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(DE); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x9b: /* SBC A,E */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(DE); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x9c: /* SBC A,H */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(HL); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x9d: /* SBC A,L */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(HL); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x9e: /* SBC A,(HL) */ - tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0x9f: /* SBC A,A */ - tStates += 4; - sim_brk_pend = FALSE; - cbits = -TSTFLAG(C); - AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPVS(cbits)); - break; - case 0xa0: /* AND B */ - tStates += 4; - sim_brk_pend = FALSE; - AF = andTable[((AF & BC) >> 8) & 0xff]; - break; - case 0xa1: /* AND C */ - tStates += 4; - sim_brk_pend = FALSE; - AF = andTable[((AF >> 8) & BC) & 0xff]; - break; - case 0xa2: /* AND D */ - tStates += 4; - sim_brk_pend = FALSE; - AF = andTable[((AF & DE) >> 8) & 0xff]; - break; - case 0xa3: /* AND E */ - tStates += 4; - sim_brk_pend = FALSE; - AF = andTable[((AF >> 8) & DE) & 0xff]; - break; - case 0xa4: /* AND H */ - tStates += 4; - sim_brk_pend = FALSE; - AF = andTable[((AF & HL) >> 8) & 0xff]; - break; - case 0xa5: /* AND L */ - tStates += 4; - sim_brk_pend = FALSE; - AF = andTable[((AF >> 8) & HL) & 0xff]; - break; - case 0xa6: /* AND (HL) */ - tStates += 7; - CheckBreakByte(HL); - AF = andTable[((AF >> 8) & GetBYTE(HL)) & 0xff]; - break; - case 0xa7: /* AND A */ - tStates += 4; - sim_brk_pend = FALSE; - AF = andTable[(AF >> 8) & 0xff]; - break; - case 0xa8: /* XOR B */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF ^ BC) >> 8) & 0xff]; - break; - case 0xa9: /* XOR C */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) ^ BC) & 0xff]; - break; - case 0xaa: /* XOR D */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF ^ DE) >> 8) & 0xff]; - break; - case 0xab: /* XOR E */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) ^ DE) & 0xff]; - break; - case 0xac: /* XOR H */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF ^ HL) >> 8) & 0xff]; - break; - case 0xad: /* XOR L */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) ^ HL) & 0xff]; - break; - case 0xae: /* XOR (HL) */ - tStates += 7; - CheckBreakByte(HL); - AF = xororTable[((AF >> 8) ^ GetBYTE(HL)) & 0xff]; - break; - case 0xaf: /* XOR A */ - tStates += 4; - sim_brk_pend = FALSE; - AF = 0x44; - break; - case 0xb0: /* OR B */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF | BC) >> 8) & 0xff]; - break; - case 0xb1: /* OR C */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) | BC) & 0xff]; - break; - case 0xb2: /* OR D */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF | DE) >> 8) & 0xff]; - break; - case 0xb3: /* OR E */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) | DE) & 0xff]; - break; - case 0xb4: /* OR H */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF | HL) >> 8) & 0xff]; - break; - case 0xb5: /* OR L */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) | HL) & 0xff]; - break; - case 0xb6: /* OR (HL) */ - tStates += 7; - CheckBreakByte(HL); - AF = xororTable[((AF >> 8) | GetBYTE(HL)) & 0xff]; - break; - case 0xb7: /* OR A */ - tStates += 4; - sim_brk_pend = FALSE; - AF = xororTable[(AF >> 8) & 0xff]; - break; - case 0xb8: /* CP B */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(BC); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; - break; - case 0xb9: /* CP C */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(BC); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; - break; - case 0xba: /* CP D */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(DE); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; - break; - case 0xbb: /* CP E */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(DE); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; - break; - case 0xbc: /* CP H */ - tStates += 4; - sim_brk_pend = FALSE; - temp = hreg(HL); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; - break; - case 0xbd: /* CP L */ - tStates += 4; - sim_brk_pend = FALSE; - temp = lreg(HL); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; - break; - case 0xbe: /* CP (HL) */ - tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; - break; - case 0xbf: /* CP A */ - tStates += 4; - sim_brk_pend = FALSE; - Setlreg(AF, (hreg(AF) & 0x28) | (cpu_unit.flags & UNIT_CHIP ? 0x42 : 0x46)); - break; - case 0xc0: /* RET NZ */ - if (TSTFLAG(Z)) { - sim_brk_pend = FALSE; - tStates += 5; - } - else { - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - break; - case 0xc1: /* POP BC */ - tStates += 10; - CheckBreakWord(SP); - POP(BC); - break; - case 0xc2: /* JP NZ,nnnn */ - sim_brk_pend = FALSE; - JPC(!TSTFLAG(Z)); /* also updates tStates */ - break; - case 0xc3: /* JP nnnn */ - sim_brk_pend = FALSE; - JPC(1); /* also updates tStates */ - break; - case 0xc4: /* CALL NZ,nnnn */ - CALLC(!TSTFLAG(Z)); /* also updates tStates */ - break; - case 0xc5: /* PUSH BC */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(BC); - break; - case 0xc6: /* ADD A,nn */ - tStates += 7; - sim_brk_pend = FALSE; - temp = RAM_pp(PC); - acu = hreg(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0xc7: /* RST 0 */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0; - break; - case 0xc8: /* RET Z */ - if (TSTFLAG(Z)) { - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - else { - sim_brk_pend = FALSE; - tStates += 5; - } - break; - case 0xc9: /* RET */ - tStates += 10; - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - break; - case 0xca: /* JP Z,nnnn */ - sim_brk_pend = FALSE; - JPC(TSTFLAG(Z)); /* also updates tStates */ - break; - case 0xcb: /* CB prefix */ - checkCPU8080; - adr = HL; - switch ((op = GetBYTE(PC)) & 7) { - case 0: - sim_brk_pend = tStateModifier = FALSE; - ++PC; - acu = hreg(BC); - tStates += 8; - break; - case 1: - sim_brk_pend = tStateModifier = FALSE; - ++PC; - acu = lreg(BC); - tStates += 8; - break; - case 2: - sim_brk_pend = tStateModifier = FALSE; - ++PC; - acu = hreg(DE); - tStates += 8; - break; - case 3: - sim_brk_pend = tStateModifier = FALSE; - ++PC; - acu = lreg(DE); - tStates += 8; - break; - case 4: - sim_brk_pend = tStateModifier = FALSE; - ++PC; - acu = hreg(HL); - tStates += 8; - break; - case 5: - sim_brk_pend = tStateModifier = FALSE; - ++PC; - acu = lreg(HL); - tStates += 8; - break; - case 6: - CheckBreakByte(adr); - ++PC; - acu = GetBYTE(adr); - tStateModifier = TRUE; - tStates += 15; - break; - case 7: - sim_brk_pend = tStateModifier = FALSE; - ++PC; - acu = hreg(AF); - tStates += 8; - break; - } - switch (op & 0xc0) { - case 0x00: /* shift/rotate */ - switch (op & 0x38) { - case 0x00: /* RLC */ - temp = (acu << 1) | (acu >> 7); - cbits = temp & 1; - goto cbshflg1; - case 0x08: /* RRC */ - temp = (acu >> 1) | (acu << 7); - cbits = temp & 0x80; - goto cbshflg1; - case 0x10: /* RL */ - temp = (acu << 1) | TSTFLAG(C); - cbits = acu & 0x80; - goto cbshflg1; - case 0x18: /* RR */ - temp = (acu >> 1) | (TSTFLAG(C) << 7); - cbits = acu & 1; - goto cbshflg1; - case 0x20: /* SLA */ - temp = acu << 1; - cbits = acu & 0x80; - goto cbshflg1; - case 0x28: /* SRA */ - temp = (acu >> 1) | (acu & 0x80); - cbits = acu & 1; - goto cbshflg1; - case 0x30: /* SLIA */ - temp = (acu << 1) | 1; - cbits = acu & 0x80; - goto cbshflg1; - case 0x38: /* SRL */ - temp = acu >> 1; - cbits = acu & 1; - cbshflg1: - AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; - } - break; - case 0x40: /* BIT */ - if (tStateModifier) { - tStates -= 3; - } - if (acu & (1 << ((op >> 3) & 7))) { - AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - } - else { - AF = (AF & ~0xfe) | 0x54; - } - if ((op & 7) != 6) { - AF |= (acu & 0x28); - } - temp = acu; - break; - case 0x80: /* RES */ - temp = acu & ~(1 << ((op >> 3) & 7)); - break; - case 0xc0: /* SET */ - temp = acu | (1 << ((op >> 3) & 7)); - break; - } - switch (op & 7) { - case 0: - Sethreg(BC, temp); - break; - case 1: - Setlreg(BC, temp); - break; - case 2: - Sethreg(DE, temp); - break; - case 3: - Setlreg(DE, temp); - break; - case 4: - Sethreg(HL, temp); - break; - case 5: - Setlreg(HL, temp); - break; - case 6: - PutBYTE(adr, temp); - break; - case 7: - Sethreg(AF, temp); - break; - } - break; - case 0xcc: /* CALL Z,nnnn */ - CALLC(TSTFLAG(Z)); /* also updates tStates */ - break; - case 0xcd: /* CALL nnnn */ - CALLC(1); /* also updates tStates */ - break; - case 0xce: /* ADC A,nn */ - tStates += 7; - sim_brk_pend = FALSE; - temp = RAM_pp(PC); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); - break; - case 0xcf: /* RST 8 */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 8; - break; - case 0xd0: /* RET NC */ - if (TSTFLAG(C)) { - sim_brk_pend = FALSE; - tStates += 5; - } - else { - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - break; - case 0xd1: /* POP DE */ - tStates += 10; - CheckBreakWord(SP); - POP(DE); - break; - case 0xd2: /* JP NC,nnnn */ - sim_brk_pend = FALSE; - JPC(!TSTFLAG(C)); /* also updates tStates */ - break; - case 0xd3: /* OUT (nn),A */ - tStates += 11; - sim_brk_pend = FALSE; - out(RAM_pp(PC), hreg(AF)); - break; - case 0xd4: /* CALL NC,nnnn */ - CALLC(!TSTFLAG(C)); /* also updates tStates */ - break; - case 0xd5: /* PUSH DE */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(DE); - break; - case 0xd6: /* SUB nn */ - tStates += 7; - sim_brk_pend = FALSE; - temp = RAM_pp(PC); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0xd7: /* RST 10H */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x10; - break; - case 0xd8: /* RET C */ - if (TSTFLAG(C)) { - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - else { - sim_brk_pend = FALSE; - tStates += 5; - } - break; - case 0xd9: /* EXX */ - tStates += 4; - sim_brk_pend = FALSE; - checkCPU8080; - regs[regs_sel].bc = BC; - regs[regs_sel].de = DE; - regs[regs_sel].hl = HL; - regs_sel = 1 - regs_sel; - BC = regs[regs_sel].bc; - DE = regs[regs_sel].de; - HL = regs[regs_sel].hl; - break; - case 0xda: /* JP C,nnnn */ - sim_brk_pend = FALSE; - JPC(TSTFLAG(C)); /* also updates tStates */ - break; - case 0xdb: /* IN A,(nn) */ - tStates += 11; - sim_brk_pend = FALSE; - Sethreg(AF, in(RAM_pp(PC))); - break; - case 0xdc: /* CALL C,nnnn */ - CALLC(TSTFLAG(C)); /* also updates tStates */ - break; - case 0xdd: /* DD prefix */ - checkCPU8080; - switch (op = RAM_pp(PC)) { - case 0x09: /* ADD IX,BC */ - tStates += 15; - sim_brk_pend = FALSE; - IX &= ADDRMASK; - BC &= ADDRMASK; - sum = IX + BC; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ BC ^ sum) >> 8]; - IX = sum; - break; - case 0x19: /* ADD IX,DE */ - tStates += 15; - sim_brk_pend = FALSE; - IX &= ADDRMASK; - DE &= ADDRMASK; - sum = IX + DE; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ DE ^ sum) >> 8]; - IX = sum; - break; - case 0x21: /* LD IX,nnnn */ - tStates += 14; - sim_brk_pend = FALSE; - IX = GetWORD(PC); - PC += 2; - break; - case 0x22: /* LD (nnnn),IX */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - PutWORD(temp, IX); - PC += 2; - break; - case 0x23: /* INC IX */ - tStates += 10; - sim_brk_pend = FALSE; - ++IX; - break; - case 0x24: /* INC IXH */ - tStates += 9; - sim_brk_pend = FALSE; - IX += 0x100; - AF = (AF & ~0xfe) | incZ80Table[hreg(IX)]; - break; - case 0x25: /* DEC IXH */ - tStates += 9; - sim_brk_pend = FALSE; - IX -= 0x100; - AF = (AF & ~0xfe) | decZ80Table[hreg(IX)]; - break; - case 0x26: /* LD IXH,nn */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IX, RAM_pp(PC)); - break; - case 0x29: /* ADD IX,IX */ - tStates += 15; - sim_brk_pend = FALSE; - IX &= ADDRMASK; - sum = IX + IX; - AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; - IX = sum; - break; - case 0x2a: /* LD IX,(nnnn) */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - IX = GetWORD(temp); - PC += 2; - break; - case 0x2b: /* DEC IX */ - tStates += 10; - sim_brk_pend = FALSE; - --IX; - break; - case 0x2c: /* INC IXL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IX) + 1; - Setlreg(IX, temp); - AF = (AF & ~0xfe) | incZ80Table[temp]; - break; - case 0x2d: /* DEC IXL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IX) - 1; - Setlreg(IX, temp); - AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; - break; - case 0x2e: /* LD IXL,nn */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IX, RAM_pp(PC)); - break; - case 0x34: /* INC (IX+dd) */ - tStates += 23; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr) + 1; - PutBYTE(adr, temp); - AF = (AF & ~0xfe) | incZ80Table[temp]; - break; - case 0x35: /* DEC (IX+dd) */ - tStates += 23; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr) - 1; - PutBYTE(adr, temp); - AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; - break; - case 0x36: /* LD (IX+dd),nn */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, RAM_pp(PC)); - break; - case 0x39: /* ADD IX,SP */ - tStates += 15; - sim_brk_pend = FALSE; - IX &= ADDRMASK; - SP &= ADDRMASK; - sum = IX + SP; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ SP ^ sum) >> 8]; - IX = sum; - break; - case 0x44: /* LD B,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(BC, hreg(IX)); - break; - case 0x45: /* LD B,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(BC, lreg(IX)); - break; - case 0x46: /* LD B,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(BC, GetBYTE(adr)); - break; - case 0x4c: /* LD C,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(BC, hreg(IX)); - break; - case 0x4d: /* LD C,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(BC, lreg(IX)); - break; - case 0x4e: /* LD C,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(BC, GetBYTE(adr)); - break; - case 0x54: /* LD D,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(DE, hreg(IX)); - break; - case 0x55: /* LD D,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(DE, lreg(IX)); - break; - case 0x56: /* LD D,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(DE, GetBYTE(adr)); - break; - case 0x5c: /* LD E,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(DE, hreg(IX)); - break; - case 0x5d: /* LD E,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(DE, lreg(IX)); - break; - case 0x5e: /* LD E,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(DE, GetBYTE(adr)); - break; - case 0x60: /* LD IXH,B */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IX, hreg(BC)); - break; - case 0x61: /* LD IXH,C */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IX, lreg(BC)); - break; - case 0x62: /* LD IXH,D */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IX, hreg(DE)); - break; - case 0x63: /* LD IXH,E */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IX, lreg(DE)); - break; - case 0x64: /* LD IXH,IXH */ - tStates += 9; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x65: /* LD IXH,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IX, lreg(IX)); - break; - case 0x66: /* LD H,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(HL, GetBYTE(adr)); - break; - case 0x67: /* LD IXH,A */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IX, hreg(AF)); - break; - case 0x68: /* LD IXL,B */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IX, hreg(BC)); - break; - case 0x69: /* LD IXL,C */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IX, lreg(BC)); - break; - case 0x6a: /* LD IXL,D */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IX, hreg(DE)); - break; - case 0x6b: /* LD IXL,E */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IX, lreg(DE)); - break; - case 0x6c: /* LD IXL,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IX, hreg(IX)); - break; - case 0x6d: /* LD IXL,IXL */ - tStates += 9; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x6e: /* LD L,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(HL, GetBYTE(adr)); - break; - case 0x6f: /* LD IXL,A */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IX, hreg(AF)); - break; - case 0x70: /* LD (IX+dd),B */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(BC)); - break; - case 0x71: /* LD (IX+dd),C */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(BC)); - break; - case 0x72: /* LD (IX+dd),D */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(DE)); - break; - case 0x73: /* LD (IX+dd),E */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(DE)); - break; - case 0x74: /* LD (IX+dd),H */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(HL)); - break; - case 0x75: /* LD (IX+dd),L */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(HL)); - break; - case 0x77: /* LD (IX+dd),A */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(AF)); - break; - case 0x7c: /* LD A,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(AF, hreg(IX)); - break; - case 0x7d: /* LD A,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(AF, lreg(IX)); - break; - case 0x7e: /* LD A,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(AF, GetBYTE(adr)); - break; - case 0x84: /* ADD A,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - temp = hreg(IX); - acu = hreg(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x85: /* ADD A,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IX); - acu = hreg(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x86: /* ADD A,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x8c: /* ADC A,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - temp = hreg(IX); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x8d: /* ADC A,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IX); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x8e: /* ADC A,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x96: /* SUB (IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); - sum = acu - temp; - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0x94: /* SUB IXH */ - SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ - case 0x9c: /* SBC A,IXH */ - tStates += 9; - sim_brk_pend = FALSE; - temp = hreg(IX); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0x95: /* SUB IXL */ - SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ - case 0x9d: /* SBC A,IXL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IX); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0x9e: /* SBC A,(IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0xa4: /* AND IXH */ - tStates += 9; - sim_brk_pend = FALSE; - AF = andTable[((AF & IX) >> 8) & 0xff]; - break; - case 0xa5: /* AND IXL */ - tStates += 9; - sim_brk_pend = FALSE; - AF = andTable[((AF >> 8) & IX) & 0xff]; - break; - case 0xa6: /* AND (IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - AF = andTable[((AF >> 8) & GetBYTE(adr)) & 0xff]; - break; - case 0xac: /* XOR IXH */ - tStates += 9; - sim_brk_pend = FALSE; - AF = xororTable[((AF ^ IX) >> 8) & 0xff]; - break; - case 0xad: /* XOR IXL */ - tStates += 9; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) ^ IX) & 0xff]; - break; - case 0xae: /* XOR (IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - AF = xororTable[((AF >> 8) ^ GetBYTE(adr)) & 0xff]; - break; - case 0xb4: /* OR IXH */ - tStates += 9; - sim_brk_pend = FALSE; - AF = xororTable[((AF | IX) >> 8) & 0xff]; - break; - case 0xb5: /* OR IXL */ - tStates += 9; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) | IX) & 0xff]; - break; - case 0xb6: /* OR (IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - AF = xororTable[((AF >> 8) | GetBYTE(adr)) & 0xff]; - break; - case 0xbc: /* CP IXH */ - tStates += 9; - sim_brk_pend = FALSE; - temp = hreg(IX); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0xbd: /* CP IXL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IX); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0xbe: /* CP (IX+dd) */ - tStates += 19; - adr = IX + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0xcb: /* CB prefix */ - adr = IX + (signed char) RAM_pp(PC); - switch ((op = GetBYTE(PC)) & 7) { - case 0: - sim_brk_pend = FALSE; - ++PC; - acu = hreg(BC); - break; - case 1: - sim_brk_pend = FALSE; - ++PC; - acu = lreg(BC); - break; - case 2: - sim_brk_pend = FALSE; - ++PC; - acu = hreg(DE); - break; - case 3: - sim_brk_pend = FALSE; - ++PC; - acu = lreg(DE); - break; - case 4: - sim_brk_pend = FALSE; - ++PC; - acu = hreg(HL); - break; - case 5: - sim_brk_pend = FALSE; - ++PC; - acu = lreg(HL); - break; - case 6: - CheckBreakByte(adr); - ++PC; - acu = GetBYTE(adr); - break; - case 7: - sim_brk_pend = FALSE; - ++PC; - acu = hreg(AF); - break; - } - switch (op & 0xc0) { - case 0x00: /* shift/rotate */ - tStates += 23; - switch (op & 0x38) { - case 0x00: /* RLC */ - temp = (acu << 1) | (acu >> 7); - cbits = temp & 1; - goto cbshflg2; - case 0x08: /* RRC */ - temp = (acu >> 1) | (acu << 7); - cbits = temp & 0x80; - goto cbshflg2; - case 0x10: /* RL */ - temp = (acu << 1) | TSTFLAG(C); - cbits = acu & 0x80; - goto cbshflg2; - case 0x18: /* RR */ - temp = (acu >> 1) | (TSTFLAG(C) << 7); - cbits = acu & 1; - goto cbshflg2; - case 0x20: /* SLA */ - temp = acu << 1; - cbits = acu & 0x80; - goto cbshflg2; - case 0x28: /* SRA */ - temp = (acu >> 1) | (acu & 0x80); - cbits = acu & 1; - goto cbshflg2; - case 0x30: /* SLIA */ - temp = (acu << 1) | 1; - cbits = acu & 0x80; - goto cbshflg2; - case 0x38: /* SRL */ - temp = acu >> 1; - cbits = acu & 1; - cbshflg2: - AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; - } - break; - case 0x40: /* BIT */ - tStates += 20; - if (acu & (1 << ((op >> 3) & 7))) { - AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - } - else { - AF = (AF & ~0xfe) | 0x54; - } - if ((op & 7) != 6) { - AF |= (acu & 0x28); - } - temp = acu; - break; - case 0x80: /* RES */ - tStates += 23; - temp = acu & ~(1 << ((op >> 3) & 7)); - break; - case 0xc0: /* SET */ - tStates += 23; - temp = acu | (1 << ((op >> 3) & 7)); - break; - } - switch (op & 7) { - case 0: - Sethreg(BC, temp); - break; - case 1: - Setlreg(BC, temp); - break; - case 2: - Sethreg(DE, temp); - break; - case 3: - Setlreg(DE, temp); - break; - case 4: - Sethreg(HL, temp); - break; - case 5: - Setlreg(HL, temp); - break; - case 6: - PutBYTE(adr, temp); - break; - case 7: - Sethreg(AF, temp); - break; - } - break; - case 0xe1: /* POP IX */ - tStates += 14; - CheckBreakWord(SP); - POP(IX); - break; - case 0xe3: /* EX (SP),IX */ - tStates += 23; - CheckBreakWord(SP); - temp = IX; - POP(IX); - PUSH(temp); - break; - case 0xe5: /* PUSH IX */ - tStates += 15; - CheckBreakWord(SP - 2); - PUSH(IX); - break; - case 0xe9: /* JP (IX) */ - tStates += 8; - sim_brk_pend = FALSE; - PCQ_ENTRY(PC - 2); - PC = IX; - break; - case 0xf9: /* LD SP,IX */ - tStates += 10; - sim_brk_pend = FALSE; - SP = IX; - break; - default: /* ignore DD */ - sim_brk_pend = FALSE; - checkCPUZ80; - PC--; - } - break; - case 0xde: /* SBC A,nn */ - tStates += 7; - sim_brk_pend = FALSE; - temp = RAM_pp(PC); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); - break; - case 0xdf: /* RST 18H */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x18; - break; - case 0xe0: /* RET PO */ - if (TSTFLAG(P)) { - sim_brk_pend = FALSE; - tStates += 5; - } - else { - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - break; - case 0xe1: /* POP HL */ - tStates += 10; - CheckBreakWord(SP); - POP(HL); - break; - case 0xe2: /* JP PO,nnnn */ - sim_brk_pend = FALSE; - JPC(!TSTFLAG(P)); /* also updates tStates */ - break; - case 0xe3: /* EX (SP),HL */ - tStates += 19; - CheckBreakWord(SP); - temp = HL; - POP(HL); - PUSH(temp); - break; - case 0xe4: /* CALL PO,nnnn */ - CALLC(!TSTFLAG(P)); /* also updates tStates */ - break; - case 0xe5: /* PUSH HL */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(HL); - break; - case 0xe6: /* AND nn */ - tStates += 7; - sim_brk_pend = FALSE; - AF = andTable[((AF >> 8) & RAM_pp(PC)) & 0xff]; - break; - case 0xe7: /* RST 20H */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x20; - break; - case 0xe8: /* RET PE */ - if (TSTFLAG(P)) { - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - else { - sim_brk_pend = FALSE; - tStates += 5; - } - break; - case 0xe9: /* JP (HL) */ - tStates += 4; - sim_brk_pend = FALSE; - PCQ_ENTRY(PC - 1); - PC = HL; - break; - case 0xea: /* JP PE,nnnn */ - sim_brk_pend = FALSE; - JPC(TSTFLAG(P)); /* also updates tStates */ - break; - case 0xeb: /* EX DE,HL */ - tStates += 4; - sim_brk_pend = FALSE; - temp = HL; - HL = DE; - DE = temp; - break; - case 0xec: /* CALL PE,nnnn */ - CALLC(TSTFLAG(P)); /* also updates tStates */ - break; - case 0xed: /* ED prefix */ - checkCPU8080; - switch (op = RAM_pp(PC)) { - case 0x40: /* IN B,(C) */ - tStates += 12; - sim_brk_pend = FALSE; - temp = in(lreg(BC)); - Sethreg(BC, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - case 0x41: /* OUT (C),B */ - tStates += 12; - sim_brk_pend = FALSE; - out(lreg(BC), hreg(BC)); - break; - case 0x42: /* SBC HL,BC */ - tStates += 15; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - BC &= ADDRMASK; - sum = HL - BC - TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbits2Z80Table[((HL ^ BC ^ sum) >> 8) & 0x1ff]; - HL = sum; - break; - case 0x43: /* LD (nnnn),BC */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - PutWORD(temp, BC); - PC += 2; - break; - case 0x44: /* NEG */ - case 0x4C: /* NEG, unofficial */ - case 0x54: /* NEG, unofficial */ - case 0x5C: /* NEG, unofficial */ - case 0x64: /* NEG, unofficial */ - case 0x6C: /* NEG, unofficial */ - case 0x74: /* NEG, unofficial */ - case 0x7C: /* NEG, unofficial */ - tStates += 8; - sim_brk_pend = FALSE; - temp = hreg(AF); - AF = ((~(AF & 0xff00) + 1) & 0xff00); /* AF = (-(AF & 0xff00) & 0xff00); */ - AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | negTable[temp]; - break; - case 0x45: /* RETN */ - case 0x55: /* RETN, unofficial */ - case 0x5D: /* RETN, unofficial */ - case 0x65: /* RETN, unofficial */ - case 0x6D: /* RETN, unofficial */ - case 0x75: /* RETN, unofficial */ - case 0x7D: /* RETN, unofficial */ - tStates += 14; - IFF |= IFF >> 1; - CheckBreakWord(SP); - PCQ_ENTRY(PC - 2); - POP(PC); - break; - case 0x46: /* IM 0 */ - tStates += 8; - sim_brk_pend = FALSE; - /* interrupt mode 0 */ - break; - case 0x47: /* LD I,A */ - tStates += 9; - sim_brk_pend = FALSE; - ir = (ir & 0xff) | (AF & ~0xff); - break; - case 0x48: /* IN C,(C) */ - tStates += 12; - sim_brk_pend = FALSE; - temp = in(lreg(BC)); - Setlreg(BC, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - case 0x49: /* OUT (C),C */ - tStates += 12; - sim_brk_pend = FALSE; - out(lreg(BC), lreg(BC)); - break; - case 0x4a: /* ADC HL,BC */ - tStates += 15; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - BC &= ADDRMASK; - sum = HL + BC + TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbitsZ80Table[(HL ^ BC ^ sum) >> 8]; - HL = sum; - break; - case 0x4b: /* LD BC,(nnnn) */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - BC = GetWORD(temp); - PC += 2; - break; - case 0x4d: /* RETI */ - tStates += 14; - IFF |= IFF >> 1; - CheckBreakWord(SP); - PCQ_ENTRY(PC - 2); - POP(PC); - break; - case 0x4f: /* LD R,A */ - tStates += 9; - sim_brk_pend = FALSE; - ir = (ir & ~0xff) | ((AF >> 8) & 0xff); - break; - case 0x50: /* IN D,(C) */ - tStates += 12; - sim_brk_pend = FALSE; - temp = in(lreg(BC)); - Sethreg(DE, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - case 0x51: /* OUT (C),D */ - tStates += 12; - sim_brk_pend = FALSE; - out(lreg(BC), hreg(DE)); - break; - case 0x52: /* SBC HL,DE */ - tStates += 15; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - DE &= ADDRMASK; - sum = HL - DE - TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbits2Z80Table[((HL ^ DE ^ sum) >> 8) & 0x1ff]; - HL = sum; - break; - case 0x53: /* LD (nnnn),DE */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - PutWORD(temp, DE); - PC += 2; - break; - case 0x56: /* IM 1 */ - tStates += 8; - sim_brk_pend = FALSE; - /* interrupt mode 1 */ - break; - case 0x57: /* LD A,I */ - tStates += 9; - sim_brk_pend = FALSE; - AF = (AF & 0x29) | (ir & ~0xff) | ((ir >> 8) & 0x80) | (((ir & ~0xff) == 0) << 6) | ((IFF & 2) << 1); - break; - case 0x58: /* IN E,(C) */ - tStates += 12; - sim_brk_pend = FALSE; - temp = in(lreg(BC)); - Setlreg(DE, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - case 0x59: /* OUT (C),E */ - tStates += 12; - sim_brk_pend = FALSE; - out(lreg(BC), lreg(DE)); - break; - case 0x5a: /* ADC HL,DE */ - tStates += 15; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - DE &= ADDRMASK; - sum = HL + DE + TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbitsZ80Table[(HL ^ DE ^ sum) >> 8]; - HL = sum; - break; - case 0x5b: /* LD DE,(nnnn) */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - DE = GetWORD(temp); - PC += 2; - break; - case 0x5e: /* IM 2 */ - tStates += 8; - sim_brk_pend = FALSE; - /* interrupt mode 2 */ - break; - case 0x5f: /* LD A,R */ - tStates += 9; - sim_brk_pend = FALSE; - AF = (AF & 0x29) | ((ir & 0xff) << 8) | (ir & 0x80) | - (((ir & 0xff) == 0) << 6) | ((IFF & 2) << 1); - break; - case 0x60: /* IN H,(C) */ - tStates += 12; - sim_brk_pend = FALSE; - temp = in(lreg(BC)); - Sethreg(HL, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - case 0x61: /* OUT (C),H */ - tStates += 12; - sim_brk_pend = FALSE; - out(lreg(BC), hreg(HL)); - break; - case 0x62: /* SBC HL,HL */ - tStates += 15; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - sum = HL - HL - TSTFLAG(C); - AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | - cbits2Z80DupTable[(sum >> 8) & 0x1ff]; - HL = sum; - break; - case 0x63: /* LD (nnnn),HL */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - PutWORD(temp, HL); - PC += 2; - break; - case 0x67: /* RRD */ - tStates += 18; - sim_brk_pend = FALSE; - temp = GetBYTE(HL); - acu = hreg(AF); - PutBYTE(HL, hdig(temp) | (ldig(acu) << 4)); - AF = rrdrldTable[(acu & 0xf0) | ldig(temp)] | (AF & 1); - break; - case 0x68: /* IN L,(C) */ - tStates += 12; - sim_brk_pend = FALSE; - temp = in(lreg(BC)); - Setlreg(HL, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - case 0x69: /* OUT (C),L */ - tStates += 12; - sim_brk_pend = FALSE; - out(lreg(BC), lreg(HL)); - break; - case 0x6a: /* ADC HL,HL */ - tStates += 15; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - sum = HL + HL + TSTFLAG(C); - AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | - cbitsZ80DupTable[sum >> 8]; - HL = sum; - break; - case 0x6b: /* LD HL,(nnnn) */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - HL = GetWORD(temp); - PC += 2; - break; - case 0x6f: /* RLD */ - tStates += 18; - sim_brk_pend = FALSE; - temp = GetBYTE(HL); - acu = hreg(AF); - PutBYTE(HL, (ldig(temp) << 4) | ldig(acu)); - AF = rrdrldTable[(acu & 0xf0) | hdig(temp)] | (AF & 1); - break; - case 0x70: /* IN (C) */ - tStates += 12; - sim_brk_pend = FALSE; - temp = in(lreg(BC)); - Setlreg(temp, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - case 0x71: /* OUT (C),0 */ - tStates += 12; - sim_brk_pend = FALSE; - out(lreg(BC), 0); - break; - case 0x72: /* SBC HL,SP */ - tStates += 15; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - SP &= ADDRMASK; - sum = HL - SP - TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbits2Z80Table[((HL ^ SP ^ sum) >> 8) & 0x1ff]; - HL = sum; - break; - case 0x73: /* LD (nnnn),SP */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - PutWORD(temp, SP); - PC += 2; - break; - case 0x78: /* IN A,(C) */ - tStates += 12; - sim_brk_pend = FALSE; - temp = in(lreg(BC)); - Sethreg(AF, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - case 0x79: /* OUT (C),A */ - tStates += 12; - sim_brk_pend = FALSE; - out(lreg(BC), hreg(AF)); - break; - case 0x7a: /* ADC HL,SP */ - tStates += 15; - sim_brk_pend = FALSE; - HL &= ADDRMASK; - SP &= ADDRMASK; - sum = HL + SP + TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbitsZ80Table[(HL ^ SP ^ sum) >> 8]; - HL = sum; - break; - case 0x7b: /* LD SP,(nnnn) */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - SP = GetWORD(temp); - PC += 2; - break; - case 0xa0: /* LDI */ - tStates += 16; - CheckBreakTwoBytes(HL, DE); - acu = RAM_pp(HL); - PutBYTE_pp(DE, acu); - acu += hreg(AF); - AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | - (((--BC & ADDRMASK) != 0) << 2); - break; - case 0xa1: /* CPI */ - tStates += 16; - CheckBreakByte(HL); - acu = hreg(AF); - temp = RAM_pp(HL); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | - ((sum - ((cbits >> 4) & 1)) & 8) | - ((--BC & ADDRMASK) != 0) << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) { - AF &= ~8; - } - break; - case 0xa2: /* INI */ - tStates += 16; - CheckBreakByte(HL); - PutBYTE(HL, in(lreg(BC))); - ++HL; - SETFLAG(N, 1); - SETFLAG(P, (--BC & ADDRMASK) != 0); - break; - case 0xa3: /* OUTI */ - tStates += 16; - CheckBreakByte(HL); - out(lreg(BC), GetBYTE(HL)); - ++HL; - SETFLAG(N, 1); - Sethreg(BC, lreg(BC) - 1); - SETFLAG(Z, lreg(BC) == 0); - break; - case 0xa8: /* LDD */ - tStates += 16; - CheckBreakTwoBytes(HL, DE); - acu = RAM_mm(HL); - PutBYTE_mm(DE, acu); - acu += hreg(AF); - AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | - (((--BC & ADDRMASK) != 0) << 2); - break; - case 0xa9: /* CPD */ - tStates += 16; - CheckBreakByte(HL); - acu = hreg(AF); - temp = RAM_mm(HL); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | - ((sum - ((cbits >> 4) & 1)) & 8) | - ((--BC & ADDRMASK) != 0) << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) { - AF &= ~8; - } - break; - case 0xaa: /* IND */ - tStates += 16; - CheckBreakByte(HL); - PutBYTE(HL, in(lreg(BC))); - --HL; - SETFLAG(N, 1); - Sethreg(BC, lreg(BC) - 1); - SETFLAG(Z, lreg(BC) == 0); - break; - case 0xab: /* OUTD */ - tStates += 16; - CheckBreakByte(HL); - out(lreg(BC), GetBYTE(HL)); - --HL; - SETFLAG(N, 1); - Sethreg(BC, lreg(BC) - 1); - SETFLAG(Z, lreg(BC) == 0); - break; - case 0xb0: /* LDIR */ - tStates -= 5; - acu = hreg(AF); - BC &= ADDRMASK; - do { - tStates += 21; - CheckBreakTwoBytes(HL, DE); - acu = RAM_pp(HL); - PutBYTE_pp(DE, acu); - } while (--BC); - acu += hreg(AF); - AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); - break; - case 0xb1: /* CPIR */ - tStates -= 5; - acu = hreg(AF); - BC &= ADDRMASK; - do { - tStates += 21; - CheckBreakByte(HL); - temp = RAM_pp(HL); - op = --BC != 0; - sum = acu - temp; - } while (op && sum != 0); - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits & 16) >> 4)) & 2) << 4) | - (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | - op << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) { - AF &= ~8; - } - break; - case 0xb2: /* INIR */ - tStates -= 5; - temp = hreg(BC); - do { - tStates += 21; - CheckBreakByte(HL); - PutBYTE(HL, in(lreg(BC))); - ++HL; - } while (--temp); - Sethreg(BC, 0); - SETFLAG(N, 1); - SETFLAG(Z, 1); - break; - case 0xb3: /* OTIR */ - tStates -= 5; - temp = hreg(BC); - do { - tStates += 21; - CheckBreakByte(HL); - out(lreg(BC), GetBYTE(HL)); - ++HL; - } while (--temp); - Sethreg(BC, 0); - SETFLAG(N, 1); - SETFLAG(Z, 1); - break; - case 0xb8: /* LDDR */ - tStates -= 5; - BC &= ADDRMASK; - do { - tStates += 21; - CheckBreakTwoBytes(HL, DE); - acu = RAM_mm(HL); - PutBYTE_mm(DE, acu); - } while (--BC); - acu += hreg(AF); - AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); - break; - case 0xb9: /* CPDR */ - tStates -= 5; - acu = hreg(AF); - BC &= ADDRMASK; - do { - tStates += 21; - CheckBreakByte(HL); - temp = RAM_mm(HL); - op = --BC != 0; - sum = acu - temp; - } while (op && sum != 0); - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits & 16) >> 4)) & 2) << 4) | - (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | - op << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) { - AF &= ~8; - } - break; - case 0xba: /* INDR */ - tStates -= 5; - temp = hreg(BC); - do { - tStates += 21; - CheckBreakByte(HL); - PutBYTE(HL, in(lreg(BC))); - --HL; - } while (--temp); - Sethreg(BC, 0); - SETFLAG(N, 1); - SETFLAG(Z, 1); - break; - case 0xbb: /* OTDR */ - tStates -= 5; - temp = hreg(BC); - do { - tStates += 21; - CheckBreakByte(HL); - out(lreg(BC), GetBYTE(HL)); - --HL; - } while (--temp); - Sethreg(BC, 0); - SETFLAG(N, 1); - SETFLAG(Z, 1); - break; - default: /* ignore ED and following byte */ - sim_brk_pend = FALSE; - checkCPUZ80; - } - break; - case 0xee: /* XOR nn */ - tStates += 7; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) ^ RAM_pp(PC)) & 0xff]; - break; - case 0xef: /* RST 28H */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x28; - break; - case 0xf0: /* RET P */ - if (TSTFLAG(S)) { - sim_brk_pend = FALSE; - tStates += 5; - } - else { - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - break; - case 0xf1: /* POP AF */ - tStates += 10; - CheckBreakWord(SP); - POP(AF); - break; - case 0xf2: /* JP P,nnnn */ - sim_brk_pend = FALSE; - JPC(!TSTFLAG(S)); /* also updates tStates */ - break; - case 0xf3: /* DI */ - tStates += 4; - sim_brk_pend = FALSE; - IFF = 0; - break; - case 0xf4: /* CALL P,nnnn */ - CALLC(!TSTFLAG(S)); /* also updates tStates */ - break; - case 0xf5: /* PUSH AF */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(AF); - break; - case 0xf6: /* OR nn */ - tStates += 7; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) | RAM_pp(PC)) & 0xff]; - break; - case 0xf7: /* RST 30H */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x30; - break; - case 0xf8: /* RET M */ - if (TSTFLAG(S)) { - CheckBreakWord(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - else { - sim_brk_pend = FALSE; - tStates += 5; - } - break; - case 0xf9: /* LD SP,HL */ - tStates += 6; - sim_brk_pend = FALSE; - SP = HL; - break; - case 0xfa: /* JP M,nnnn */ - sim_brk_pend = FALSE; - JPC(TSTFLAG(S)); /* also updates tStates */ - break; - case 0xfb: /* EI */ - tStates += 4; - sim_brk_pend = FALSE; - IFF = 3; - break; - case 0xfc: /* CALL M,nnnn */ - CALLC(TSTFLAG(S)); /* also updates tStates */ - break; - case 0xfd: /* FD prefix */ - checkCPU8080; - switch (op = RAM_pp(PC)) { - case 0x09: /* ADD IY,BC */ - tStates += 15; - sim_brk_pend = FALSE; - IY &= ADDRMASK; - BC &= ADDRMASK; - sum = IY + BC; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ BC ^ sum) >> 8]; - IY = sum; - break; - case 0x19: /* ADD IY,DE */ - tStates += 15; - sim_brk_pend = FALSE; - IY &= ADDRMASK; - DE &= ADDRMASK; - sum = IY + DE; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ DE ^ sum) >> 8]; - IY = sum; - break; - case 0x21: /* LD IY,nnnn */ - tStates += 14; - sim_brk_pend = FALSE; - IY = GetWORD(PC); - PC += 2; - break; - case 0x22: /* LD (nnnn),IY */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - PutWORD(temp, IY); - PC += 2; - break; - case 0x23: /* INC IY */ - tStates += 10; - sim_brk_pend = FALSE; - ++IY; - break; - case 0x24: /* INC IYH */ - tStates += 9; - sim_brk_pend = FALSE; - IY += 0x100; - AF = (AF & ~0xfe) | incZ80Table[hreg(IY)]; - break; - case 0x25: /* DEC IYH */ - tStates += 9; - sim_brk_pend = FALSE; - IY -= 0x100; - AF = (AF & ~0xfe) | decZ80Table[hreg(IY)]; - break; - case 0x26: /* LD IYH,nn */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IY, RAM_pp(PC)); - break; - case 0x29: /* ADD IY,IY */ - tStates += 15; - sim_brk_pend = FALSE; - IY &= ADDRMASK; - sum = IY + IY; - AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; - IY = sum; - break; - case 0x2a: /* LD IY,(nnnn) */ - tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - IY = GetWORD(temp); - PC += 2; - break; - case 0x2b: /* DEC IY */ - tStates += 10; - sim_brk_pend = FALSE; - --IY; - break; - case 0x2c: /* INC IYL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IY) + 1; - Setlreg(IY, temp); - AF = (AF & ~0xfe) | incZ80Table[temp]; - break; - case 0x2d: /* DEC IYL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IY) - 1; - Setlreg(IY, temp); - AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; - break; - case 0x2e: /* LD IYL,nn */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IY, RAM_pp(PC)); - break; - case 0x34: /* INC (IY+dd) */ - tStates += 23; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr) + 1; - PutBYTE(adr, temp); - AF = (AF & ~0xfe) | incZ80Table[temp]; - break; - case 0x35: /* DEC (IY+dd) */ - tStates += 23; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr) - 1; - PutBYTE(adr, temp); - AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; - break; - case 0x36: /* LD (IY+dd),nn */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, RAM_pp(PC)); - break; - case 0x39: /* ADD IY,SP */ - tStates += 15; - sim_brk_pend = FALSE; - IY &= ADDRMASK; - SP &= ADDRMASK; - sum = IY + SP; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ SP ^ sum) >> 8]; - IY = sum; - break; - case 0x44: /* LD B,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(BC, hreg(IY)); - break; - case 0x45: /* LD B,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(BC, lreg(IY)); - break; - case 0x46: /* LD B,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(BC, GetBYTE(adr)); - break; - case 0x4c: /* LD C,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(BC, hreg(IY)); - break; - case 0x4d: /* LD C,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(BC, lreg(IY)); - break; - case 0x4e: /* LD C,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(BC, GetBYTE(adr)); - break; - case 0x54: /* LD D,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(DE, hreg(IY)); - break; - case 0x55: /* LD D,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(DE, lreg(IY)); - break; - case 0x56: /* LD D,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(DE, GetBYTE(adr)); - break; - case 0x5c: /* LD E,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(DE, hreg(IY)); - break; - case 0x5d: /* LD E,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(DE, lreg(IY)); - break; - case 0x5e: /* LD E,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(DE, GetBYTE(adr)); - break; - case 0x60: /* LD IYH,B */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IY, hreg(BC)); - break; - case 0x61: /* LD IYH,C */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IY, lreg(BC)); - break; - case 0x62: /* LD IYH,D */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IY, hreg(DE)); - break; - case 0x63: /* LD IYH,E */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IY, lreg(DE)); - break; - case 0x64: /* LD IYH,IYH */ - tStates += 9; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x65: /* LD IYH,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IY, lreg(IY)); - break; - case 0x66: /* LD H,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(HL, GetBYTE(adr)); - break; - case 0x67: /* LD IYH,A */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(IY, hreg(AF)); - break; - case 0x68: /* LD IYL,B */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IY, hreg(BC)); - break; - case 0x69: /* LD IYL,C */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IY, lreg(BC)); - break; - case 0x6a: /* LD IYL,D */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IY, hreg(DE)); - break; - case 0x6b: /* LD IYL,E */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IY, lreg(DE)); - break; - case 0x6c: /* LD IYL,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IY, hreg(IY)); - break; - case 0x6d: /* LD IYL,IYL */ - tStates += 9; - sim_brk_pend = FALSE; /* nop */ - break; - case 0x6e: /* LD L,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(HL, GetBYTE(adr)); - break; - case 0x6f: /* LD IYL,A */ - tStates += 9; - sim_brk_pend = FALSE; - Setlreg(IY, hreg(AF)); - break; - case 0x70: /* LD (IY+dd),B */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(BC)); - break; - case 0x71: /* LD (IY+dd),C */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(BC)); - break; - case 0x72: /* LD (IY+dd),D */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(DE)); - break; - case 0x73: /* LD (IY+dd),E */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(DE)); - break; - case 0x74: /* LD (IY+dd),H */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(HL)); - break; - case 0x75: /* LD (IY+dd),L */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(HL)); - break; - case 0x77: /* LD (IY+dd),A */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(AF)); - break; - case 0x7c: /* LD A,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(AF, hreg(IY)); - break; - case 0x7d: /* LD A,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - Sethreg(AF, lreg(IY)); - break; - case 0x7e: /* LD A,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(AF, GetBYTE(adr)); - break; - case 0x84: /* ADD A,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - temp = hreg(IY); - acu = hreg(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x85: /* ADD A,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IY); - acu = hreg(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x86: /* ADD A,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x8c: /* ADC A,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - temp = hreg(IY); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x8d: /* ADC A,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IY); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x8e: /* ADC A,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - case 0x96: /* SUB (IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); - sum = acu - temp; - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0x94: /* SUB IYH */ - SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ - case 0x9c: /* SBC A,IYH */ - tStates += 9; - sim_brk_pend = FALSE; - temp = hreg(IY); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0x95: /* SUB IYL */ - SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ - case 0x9d: /* SBC A,IYL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IY); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0x9e: /* SBC A,(IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0xa4: /* AND IYH */ - tStates += 9; - sim_brk_pend = FALSE; - AF = andTable[((AF & IY) >> 8) & 0xff]; - break; - case 0xa5: /* AND IYL */ - tStates += 9; - sim_brk_pend = FALSE; - AF = andTable[((AF >> 8) & IY) & 0xff]; - break; - case 0xa6: /* AND (IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - AF = andTable[((AF >> 8) & GetBYTE(adr)) & 0xff]; - break; - case 0xac: /* XOR IYH */ - tStates += 9; - sim_brk_pend = FALSE; - AF = xororTable[((AF ^ IY) >> 8) & 0xff]; - break; - case 0xad: /* XOR IYL */ - tStates += 9; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) ^ IY) & 0xff]; - break; - case 0xae: /* XOR (IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - AF = xororTable[((AF >> 8) ^ GetBYTE(adr)) & 0xff]; - break; - case 0xb4: /* OR IYH */ - tStates += 9; - sim_brk_pend = FALSE; - AF = xororTable[((AF | IY) >> 8) & 0xff]; - break; - case 0xb5: /* OR IYL */ - tStates += 9; - sim_brk_pend = FALSE; - AF = xororTable[((AF >> 8) | IY) & 0xff]; - break; - case 0xb6: /* OR (IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - AF = xororTable[((AF >> 8) | GetBYTE(adr)) & 0xff]; - break; - case 0xbc: /* CP IYH */ - tStates += 9; - sim_brk_pend = FALSE; - temp = hreg(IY); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0xbd: /* CP IYL */ - tStates += 9; - sim_brk_pend = FALSE; - temp = lreg(IY); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0xbe: /* CP (IY+dd) */ - tStates += 19; - adr = IY + (signed char) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - case 0xcb: /* CB prefix */ - adr = IY + (signed char) RAM_pp(PC); - switch ((op = GetBYTE(PC)) & 7) { - case 0: - sim_brk_pend = FALSE; - ++PC; - acu = hreg(BC); - break; - case 1: - sim_brk_pend = FALSE; - ++PC; - acu = lreg(BC); - break; - case 2: - sim_brk_pend = FALSE; - ++PC; - acu = hreg(DE); - break; - case 3: - sim_brk_pend = FALSE; - ++PC; - acu = lreg(DE); - break; - case 4: - sim_brk_pend = FALSE; - ++PC; - acu = hreg(HL); - break; - case 5: - sim_brk_pend = FALSE; - ++PC; - acu = lreg(HL); - break; - case 6: - CheckBreakByte(adr); - ++PC; - acu = GetBYTE(adr); - break; - case 7: - sim_brk_pend = FALSE; - ++PC; - acu = hreg(AF); - break; - } - switch (op & 0xc0) { - case 0x00: /* shift/rotate */ - tStates += 23; - switch (op & 0x38) { - case 0x00: /* RLC */ - temp = (acu << 1) | (acu >> 7); - cbits = temp & 1; - goto cbshflg3; - case 0x08: /* RRC */ - temp = (acu >> 1) | (acu << 7); - cbits = temp & 0x80; - goto cbshflg3; - case 0x10: /* RL */ - temp = (acu << 1) | TSTFLAG(C); - cbits = acu & 0x80; - goto cbshflg3; - case 0x18: /* RR */ - temp = (acu >> 1) | (TSTFLAG(C) << 7); - cbits = acu & 1; - goto cbshflg3; - case 0x20: /* SLA */ - temp = acu << 1; - cbits = acu & 0x80; - goto cbshflg3; - case 0x28: /* SRA */ - temp = (acu >> 1) | (acu & 0x80); - cbits = acu & 1; - goto cbshflg3; - case 0x30: /* SLIA */ - temp = (acu << 1) | 1; - cbits = acu & 0x80; - goto cbshflg3; - case 0x38: /* SRL */ - temp = acu >> 1; - cbits = acu & 1; - cbshflg3: - AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; - } - break; - case 0x40: /* BIT */ - tStates += 20; - if (acu & (1 << ((op >> 3) & 7))) { - AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - } - else { - AF = (AF & ~0xfe) | 0x54; - } - if ((op & 7) != 6) { - AF |= (acu & 0x28); - } - temp = acu; - break; - case 0x80: /* RES */ - tStates += 23; - temp = acu & ~(1 << ((op >> 3) & 7)); - break; - case 0xc0: /* SET */ - tStates += 23; - temp = acu | (1 << ((op >> 3) & 7)); - break; - } - switch (op & 7) { - case 0: - Sethreg(BC, temp); - break; - case 1: - Setlreg(BC, temp); - break; - case 2: - Sethreg(DE, temp); - break; - case 3: - Setlreg(DE, temp); - break; - case 4: - Sethreg(HL, temp); - break; - case 5: - Setlreg(HL, temp); - break; - case 6: - PutBYTE(adr, temp); - break; - case 7: - Sethreg(AF, temp); - break; - } - break; - case 0xe1: /* POP IY */ - tStates += 14; - CheckBreakWord(SP); - POP(IY); - break; - case 0xe3: /* EX (SP),IY */ - tStates += 23; - CheckBreakWord(SP); - temp = IY; - POP(IY); - PUSH(temp); - break; - case 0xe5: /* PUSH IY */ - tStates += 15; - CheckBreakWord(SP - 2); - PUSH(IY); - break; - case 0xe9: /* JP (IY) */ - tStates += 8; - sim_brk_pend = FALSE; - PCQ_ENTRY(PC - 2); - PC = IY; - break; - case 0xf9: /* LD SP,IY */ - tStates += 10; - sim_brk_pend = FALSE; - SP = IY; - break; - default: /* ignore FD */ - sim_brk_pend = FALSE; - checkCPUZ80; - PC--; - } - break; - case 0xfe: /* CP nn */ - tStates += 7; - sim_brk_pend = FALSE; - temp = RAM_pp(PC); - AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; - break; - case 0xff: /* RST 38H */ - tStates += 11; - CheckBreakWord(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x38; - } - } - end_decode: - pc = PC; - af[af_sel] = AF; - regs[regs_sel].bc = BC; - regs[regs_sel].de = DE; - regs[regs_sel].hl = HL; - ix = IX; - iy = IY; - sp = SP; - - /* simulation halted */ - saved_PC = ((reason == STOP_OPCODE) || (reason == STOP_MEM)) ? PCX : pc; - pcq_r -> qptr = pcq_p; /* update pc q ptr */ - AF_S = af[af_sel]; - BC_S = regs[regs_sel].bc; - DE_S = regs[regs_sel].de; - HL_S = regs[regs_sel].hl; - IX_S = ix; - IY_S = iy; - SP_S = sp; - AF1_S = af[1 - af_sel]; - BC1_S = regs[1 - regs_sel].bc; - DE1_S = regs[1 - regs_sel].de; - HL1_S = regs[1 - regs_sel].hl; - IFF_S = IFF; - IR_S = ir; - executedTStates = tStates; - return reason; -} - -int32 install_bootrom(void) { - int32 i, cnt = 0; - for (i = 0; i < bootrom_size; i++) { - if (M[i + defaultROMLow][0] != (bootrom[i] & 0xff)) { - cnt++; - M[i + defaultROMLow][0] = bootrom[i] & 0xff; - } - } - return cnt; -} - -static int32 lowProtect; -static int32 highProtect; -static int32 isProtected = FALSE; - -void protect(const int32 l, const int32 h) { - isProtected = TRUE; - lowProtect = l; - highProtect = h; -} - -static void resetCell(const int32 address, const int32 bank) { - if (!(isProtected && (bank == 0) && (lowProtect <= address) && (address <= highProtect))) { - M[address][bank] = 0; - } -} - -static void reset_memory(void) { - uint32 i, j; - checkROMBoundaries(); - if (cpu_unit.flags & UNIT_BANKED) { - for (i = 0; i < MAXMEMSIZE; i++) { - for (j = 0; j < MAXBANKS; j++) { - resetCell(i, j); - } - } - } - else if (cpu_unit.flags & UNIT_ROM) { - for (i = 0; i < ROMLow; i++) { - resetCell(i, 0); - } - for (i = ROMHigh + 1; i < MAXMEMSIZE; i++) { - resetCell(i, 0); - } - } - else { - for (i = 0; i < MAXMEMSIZE; i++) { - resetCell(i, 0); - } - } - if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { - install_bootrom(); - } - isProtected = FALSE; -} - -void printROMMessage(const uint32 cntROM) { - if (cntROM) { - printf("Warning: %d bytes written to ROM [%04X - %04X].\n", cntROM, ROMLow, ROMHigh); - } -} - -/* reset routine */ - -t_stat cpu_reset(DEVICE *dptr) { - int32 i; - AF_S = AF1_S = 0; - af_sel = 0; - BC_S = DE_S = HL_S = 0; - regs_sel = 0; - BC1_S = DE1_S = HL1_S = 0; - IR_S = IX_S = IY_S = SP_S = 0; - IFF_S = 3; - bankSelect = 0; - reset_memory(); - sim_brk_types = (SWMASK('E') | SWMASK('M')); - sim_brk_dflt = SWMASK('E'); - for (i = 0; i < PCQ_SIZE; i++) { - pcq[i] = 0; - } - pcq_p = 0; - pcq_r = find_reg("PCQ", NULL, dptr); - if (pcq_r) { - pcq_r -> qptr = 0; - } - else { - return SCPE_IERR; - } - return SCPE_OK; -} - -/* memory examine */ -t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { - *vptr = M[addr & ADDRMASK][(addr >> 16) & BANKMASK]; - return SCPE_OK; -} - -/* memory deposit */ -t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) { - M[addr & ADDRMASK][(addr >> 16) & BANKMASK] = val & 0xff; - return SCPE_OK; -} - -static void checkROMBoundaries(void) { - uint32 temp; - if (ROMLow > ROMHigh) { - printf("ROMLOW [%04X] must be less than or equal to ROMHIGH [%04X]. Values exchanged.\n", - ROMLow, ROMHigh); - temp = ROMLow; - ROMLow = ROMHigh; - ROMHigh = temp; - } - if (cpu_unit.flags & UNIT_ALTAIRROM) { - if (defaultROMLow < ROMLow) { - printf("ROMLOW [%04X] reset to %04X since Altair ROM was desired.\n", ROMLow, defaultROMLow); - ROMLow = defaultROMLow; - } - if (ROMHigh < defaultROMHigh) { - printf("ROMHIGH [%04X] reset to %04X since Altair ROM was desired.\n", ROMHigh, defaultROMHigh); - ROMHigh = defaultROMHigh; - } - } -} - -static t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc) { - checkROMBoundaries(); - return SCPE_OK; -} - -static t_stat cpu_set_norom(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (cpu_unit.flags & UNIT_ALTAIRROM) { - printf("\"SET CPU NOALTAIRROM\" also executed.\n"); - cpu_unit.flags &= ~UNIT_ALTAIRROM; - } - return SCPE_OK; -} - -static t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc) { - install_bootrom(); - if (ROMLow != defaultROMLow) { - printf("\"D ROMLOW %04X\" also executed.\n", defaultROMLow); - ROMLow = defaultROMLow; - } - if (ROMHigh != defaultROMHigh) { - printf("\"D ROMHIGH %04X\" also executed.\n", defaultROMHigh); - ROMHigh = defaultROMHigh; - } - if (!(cpu_unit.flags & UNIT_ROM)) { - printf("\"SET CPU ROM\" also executed.\n"); - cpu_unit.flags |= UNIT_ROM; - } - return SCPE_OK; -} - -static t_stat cpu_set_warnrom(UNIT *uptr, int32 value, char *cptr, void *desc) { - if ((!(cpu_unit.flags & UNIT_ROM)) && (MEMSIZE >= 64*KB)) { - printf("CPU has currently no ROM - no warning to be expected.\n"); - } - return SCPE_OK; -} - -static t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (common > defaultROMLow) { - printf("Warning: COMMON [%04X] must not be greater than %04X. Reset to %04X.\n", - common, defaultROMLow, defaultROMLow); - common = defaultROMLow; - } - if (MEMSIZE != (MAXBANKS * MAXMEMSIZE)) { - previousCapacity = MEMSIZE; - } - MEMSIZE = MAXBANKS * MAXMEMSIZE; - cpu_dev.awidth = 16 + MAXBANKSLOG2; - return SCPE_OK; -} - -static t_stat cpu_set_nonbanked(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (MEMSIZE == (MAXBANKS * MAXMEMSIZE)) { - MEMSIZE = previousCapacity ? previousCapacity : 64*KB; - } - cpu_dev.awidth = 16; - return SCPE_OK; -} - -static t_stat cpu_set_size(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (cpu_unit.flags & UNIT_BANKED) { - printf("\"SET CPU NONBANKED\" also executed.\n"); - cpu_unit.flags &= ~UNIT_BANKED; - } - MEMSIZE = value; - cpu_dev.awidth = 16; - reset_memory(); - return SCPE_OK; -} +/* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) + + Copyright (c) 2002-2004, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license) +*/ + +#include "altairz80_defs.h" + +#if !defined (_WIN32) +#include +#endif + +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_SIZE_LOG2 6 /* log2 of PCQ_SIZE */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY(PC) pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC + +/* simulator stop codes */ +#define STOP_HALT 0 /* HALT */ +#define STOP_IBKPT 1 /* breakpoint (program counter) */ +#define STOP_MEM 2 /* breakpoint (memory access) */ +#define STOP_OPCODE 3 /* unknown 8080 or Z80 instruction */ + +/* two sets of accumulator / flags */ +static uint16 af[2]; +static int af_sel; + +/* two sets of 16-bit registers */ +static struct ddregs { + uint16 bc; + uint16 de; + uint16 hl; +} regs[2]; +static int regs_sel; + +static uint16 ir; +static uint16 ix; +static uint16 iy; +static uint16 sp; +static uint16 pc; +static uint16 IFF; + +#define FLAG_C 1 +#define FLAG_N 2 +#define FLAG_P 4 +#define FLAG_H 16 +#define FLAG_Z 64 +#define FLAG_S 128 + +#define SETFLAG(f,c) AF = (c) ? AF | FLAG_ ## f : AF & ~FLAG_ ## f +#define TSTFLAG(f) ((AF & FLAG_ ## f) != 0) + +#define ldig(x) ((x) & 0xf) +#define hdig(x) (((x) >> 4) & 0xf) +#define lreg(x) ((x) & 0xff) +#define hreg(x) (((x) >> 8) & 0xff) + +#define Setlreg(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) +#define Sethreg(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) + +#define parity(x) parityTable[(x) & 0xff] +/* SetPV and SetPV2 are used to provide correct parity flag semantics for the 8080 in cases + where the Z80 uses the overflow flag +*/ +#define SetPVS(s) ((cpu_unit.flags & UNIT_CHIP) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (parity(s))) +#define SetPV (SetPVS(sum)) +#define SetPV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (parity(temp))) + +/* checkCPU8080 must be invoked whenever a Z80 only instruction is executed */ +#define checkCPU8080 \ + if (((cpu_unit.flags & UNIT_CHIP) == 0) && (cpu_unit.flags & UNIT_OPSTOP)) {\ + reason = STOP_OPCODE; \ + goto end_decode; \ + } + +/* checkCPUZ80 must be invoked whenever a non Z80 instruction is executed */ +#define checkCPUZ80 \ + if (cpu_unit.flags & UNIT_OPSTOP) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ + } + +#define POP(x) { \ + register uint32 y = RAM_pp(SP); \ + x = y + (RAM_pp(SP) << 8); \ +} + +#define JPC(cond) { \ + updateTStates(10); \ + if (cond) { \ + PCQ_ENTRY(PC - 1); \ + PC = GetWORD(PC); \ + } \ + else { \ + PC += 2; \ + } \ +} + +#define CALLC(cond) { \ + if (cond) { \ + register uint32 adrr = GetWORD(PC); \ + CheckBreakWord(SP - 2); \ + PUSH(PC + 2); \ + PCQ_ENTRY(PC - 1); \ + PC = adrr; \ + updateTStates(17); \ + } \ + else { \ + sim_brk_pend = FALSE; \ + PC += 2; \ + updateTStates(10); \ + } \ +} + +extern int32 sim_int_char; +extern int32 sio0s (const int32 port, const int32 io, const int32 data); +extern int32 sio0d (const int32 port, const int32 io, const int32 data); +extern int32 sio1s (const int32 port, const int32 io, const int32 data); +extern int32 sio1d (const int32 port, const int32 io, const int32 data); +extern int32 dsk10 (const int32 port, const int32 io, const int32 data); +extern int32 dsk11 (const int32 port, const int32 io, const int32 data); +extern int32 dsk12 (const int32 port, const int32 io, const int32 data); +extern int32 nulldev (const int32 port, const int32 io, const int32 data); +extern int32 hdsk_io (const int32 port, const int32 io, const int32 data); +extern int32 simh_dev (const int32 port, const int32 io, const int32 data); +extern int32 sr_dev (const int32 port, const int32 io, const int32 data); +extern char messageBuffer[]; +extern void printMessage(void); + +/* function prototypes */ +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); +int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag); + +void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value); +void PutBYTEForced(register uint32 Addr, register uint32 Value); +int32 addressIsInROM(const uint32 Addr); +int32 addressExists(const uint32 Addr); +int32 sim_instr(void); +int32 install_bootrom(void); +void protect(const int32 l, const int32 h); +void printROMMessage(const uint32 cntROM); +uint8 GetBYTEWrapper(register uint32 Addr); +void PutBYTEWrapper(register uint32 Addr, register uint32 Value); +int32 getBankSelect(void); +void setBankSelect(int32 b); +uint32 getCommon(void); +void setCommon(uint32 c); + +#if !defined(ALTAIROPT) +static void warnUnsuccessfulWriteAttempt(const uint32 Addr); +static uint8 warnUnsuccessfulReadAttempt(const uint32 Addr); +static t_stat cpu_set_rom (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_norom (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_altairrom (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_warnrom (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_banked (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_nonbanked (UNIT *uptr, int32 value, char *cptr, void *desc); +#endif + +static t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc); +static void prepareMemoryAccessMessage(t_addr loc); +static void checkROMBoundaries(void); +static void reset_memory(void); +static uint32 in(const uint32 Port); +static void out(const uint32 Port, const uint32 Value); +static uint8 GetBYTE(register uint32 Addr); +static void PutBYTE(register uint32 Addr, register uint32 Value); +static uint16 GetWORD(register uint32 a); +static void PutWORD(register uint32 a, register uint32 v); +static t_bool sim_brk_lookup (const t_addr bloc, const int32 btyp); +static void resetCell(const int32 address, const int32 bank); + +/* CPU data structures + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list +*/ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_ROM + UNIT_ALTAIRROM, MAXMEMSIZE) }; + + int32 PCX; /* external view of PC */ + int32 saved_PC = 0; /* program counter */ +static int32 AF_S; /* AF register */ +static int32 BC_S; /* BC register */ +static int32 DE_S; /* DE register */ +static int32 HL_S; /* HL register */ +static int32 IX_S; /* IX register */ +static int32 IY_S; /* IY register */ +static int32 SP_S; /* SP register */ +static int32 AF1_S; /* alternate AF register */ +static int32 BC1_S; /* alternate BC register */ +static int32 DE1_S; /* alternate DE register */ +static int32 HL1_S; /* alternate HL register */ +static int32 IFF_S; /* interrupt Flip Flop */ +static int32 IR_S; /* interrupt (upper)/refresh (lower) register */ + int32 SR = 0; /* switch register */ + +#if !defined(ALTAIROPT) +static int32 bankSelect = 0; /* determines selected memory bank */ +static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ +#endif + +static uint32 ROMLow = defaultROMLow; /* lowest address of ROM */ +static uint32 ROMHigh = defaultROMHigh; /* highest address of ROM */ +static uint32 previousCapacity= 0; /* safe for previous memory capacity */ +static uint32 clockFrequency = 0; /* in kHz, 0 means as fast as possible */ +static uint32 sliceLength = 10; /* length of time-slice for CPU speed */ + /* adjustment in milliseonds */ +static uint32 executedTStates = 0; /* executed t-states */ +static uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +static int32 pcq_p = 0; /* PC queue ptr */ +static REG *pcq_r = NULL; /* PC queue reg ptr */ + +REG cpu_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (AF, AF_S, 16) }, + { HRDATA (BC, BC_S, 16) }, + { HRDATA (DE, DE_S, 16) }, + { HRDATA (HL, HL_S, 16) }, + { HRDATA (IX, IX_S, 16) }, + { HRDATA (IY, IY_S, 16) }, + { HRDATA (SP, SP_S, 16) }, + { HRDATA (AF1, AF1_S, 16) }, + { HRDATA (BC1, BC1_S, 16) }, + { HRDATA (DE1, DE1_S, 16) }, + { HRDATA (HL1, HL1_S, 16) }, + { GRDATA (IFF, IFF_S, 2, 2, 0) }, + { FLDATA (IR, IR_S, 8) }, + { FLDATA (Z80, cpu_unit.flags, UNIT_V_CHIP), REG_HRO }, + { FLDATA (OPSTOP, cpu_unit.flags, UNIT_V_OPSTOP), REG_HRO }, + { HRDATA (SR, SR, 8) }, + +#if defined(ALTAIROPT) + { HRDATA (ROMLOW, ROMLow, 16), REG_RO }, + { HRDATA (ROMHIGH, ROMHigh, 16), REG_RO }, +#else + { HRDATA (BANK, bankSelect, MAXBANKSLOG2) }, + { HRDATA (COMMON, common, 16) }, + { HRDATA (ROMLOW, ROMLow, 16) }, + { HRDATA (ROMHIGH, ROMHigh, 16) }, +#endif + + { DRDATA (CLOCK, clockFrequency, 32) }, + { DRDATA (SLICE, sliceLength, 16) }, + { DRDATA (TSTATES, executedTStates,32), REG_RO }, + { HRDATA (CAPACITY, cpu_unit.capac, 32), REG_RO }, + { HRDATA (PREVCAP, previousCapacity, 32), REG_RO }, + { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO + REG_CIRC }, + { DRDATA (PCQP, pcq_p, PCQ_SIZE_LOG2), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +static MTAB cpu_mod[] = { + { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL }, + { UNIT_CHIP, 0, "8080", "8080", NULL }, + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + +#if !defined(ALTAIROPT) + { UNIT_BANKED, UNIT_BANKED, "BANKED", "BANKED", &cpu_set_banked }, + { UNIT_BANKED, 0, "NONBANKED", "NONBANKED", &cpu_set_nonbanked }, + { UNIT_ROM, UNIT_ROM, "ROM", "ROM", &cpu_set_rom }, + { UNIT_ROM, 0, "NOROM", "NOROM", &cpu_set_norom }, + { UNIT_ALTAIRROM, UNIT_ALTAIRROM, "ALTAIRROM", "ALTAIRROM", &cpu_set_altairrom }, + { UNIT_ALTAIRROM, 0, "NOALTAIRROM", "NOALTAIRROM", NULL }, + { UNIT_WARNROM, UNIT_WARNROM, "WARNROM", "WARNROM", &cpu_set_warnrom }, + { UNIT_WARNROM, 0, "NOWARNROM", "NOWARNROM", NULL }, +#endif + + { UNIT_MSIZE, 4 * KB, NULL, "4K", &cpu_set_size }, + { UNIT_MSIZE, 8 * KB, NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, 12 * KB, NULL, "12K", &cpu_set_size }, + { UNIT_MSIZE, 16 * KB, NULL, "16K", &cpu_set_size }, + { UNIT_MSIZE, 20 * KB, NULL, "20K", &cpu_set_size }, + { UNIT_MSIZE, 24 * KB, NULL, "24K", &cpu_set_size }, + { UNIT_MSIZE, 28 * KB, NULL, "28K", &cpu_set_size }, + { UNIT_MSIZE, 32 * KB, NULL, "32K", &cpu_set_size }, + { UNIT_MSIZE, 36 * KB, NULL, "36K", &cpu_set_size }, + { UNIT_MSIZE, 40 * KB, NULL, "40K", &cpu_set_size }, + { UNIT_MSIZE, 44 * KB, NULL, "44K", &cpu_set_size }, + { UNIT_MSIZE, 48 * KB, NULL, "48K", &cpu_set_size }, + { UNIT_MSIZE, 52 * KB, NULL, "52K", &cpu_set_size }, + { UNIT_MSIZE, 56 * KB, NULL, "56K", &cpu_set_size }, + { UNIT_MSIZE, 60 * KB, NULL, "60K", &cpu_set_size }, + { UNIT_MSIZE, 64 * KB, NULL, "64K", &cpu_set_size }, + { 0 } }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 16, 16, 1, 16, 8, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL }; + +/* data structure for IN/OUT instructions */ +struct idev { + int32 (*routine)(const int32, const int32, const int32); +}; + +/* This is the I/O configuration table. There are 255 possible + device addresses, if a device is plugged to a port it's routine + address is here, 'nulldev' means no device is available +*/ +static const struct idev dev_table[256] = { + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04 */ + {&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 08 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 10 */ + {&sio0s}, {&sio0d}, {&sio0s}, {&sio0d}, /* 14 */ + {&sio0s}, {&sio0d}, {&nulldev}, {&nulldev}, /* 18 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 28 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 30 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 40 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 44 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 48 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 4C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 50 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 54 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 58 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 5C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 60 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 64 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 68 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 6C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 70 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 74 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 78 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 7C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 80 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 84 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 88 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 8C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 90 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 94 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 98 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 9C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* AC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* BC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* CC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* DC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* EC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */ + {&nulldev}, {&hdsk_io}, {&simh_dev}, {&sr_dev} /* FC */ +}; + +static INLINE void out(const uint32 Port, const uint32 Value) { + dev_table[Port].routine(Port, 1, Value); +} + +static INLINE uint32 in(const uint32 Port) { + return dev_table[Port].routine(Port, 0, 0); +} + +/* the following tables precompute some common subexpressions + parityTable[i] 0..255 (number of 1's in i is odd) ? 0 : 4 + incTable[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4) + decTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2 + cbitsTable[i] 0..511 (i & 0x10) | ((i >> 8) & 1) + cbitsDup8Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | + (((i & 0xff) == 0) << 6) + cbitsDup16Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | (i & 0x28) + cbits2Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | 2 + rrcaTable[i] 0..255 ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) + rraTable[i] 0..255 ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) + addTable[i] 0..511 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) + subTable[i] 0..255 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2 + andTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i] + xororTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i] + rotateShiftTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff] + incZ80Table[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2) + decZ80Table[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2 + cbitsZ80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) + cbitsZ80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | + ((i >> 8) & 1) | (i & 0xa8) + cbits2Z80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 + cbits2Z80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | + (i & 0xa8) + negTable[i] 0..255 (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0) + rrdrldTable[i] 0..255 (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i] + cpTable[i] 0..255 (i & 0x80) | (((i & 0xff) == 0) << 6) +*/ + +/* parityTable[i] = (number of 1's in i is odd) ? 0 : 4, i = 0..255 */ +static const uint8 parityTable[256] = { + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, +}; + +/* incTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4), i = 0..256 */ +static const uint8 incTable[257] = { + 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80 +}; + +/* decTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2, i = 0..255 */ +static const uint8 decTable[256] = { + 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, +}; + +/* cbitsTable[i] = (i & 0x10) | ((i >> 8) & 1), i = 0..511 */ +static const uint8 cbitsTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +}; + +/* cbitsDup8Table[i] = (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | + (((i & 0xff) == 0) << 6), i = 0..511 */ +static const uint16 cbitsDup8Table[512] = { + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, + 0x1818,0x1918,0x1a18,0x1b18,0x1c18,0x1d18,0x1e18,0x1f18, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730, + 0x3838,0x3938,0x3a38,0x3b38,0x3c38,0x3d38,0x3e38,0x3f38, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, + 0x5818,0x5918,0x5a18,0x5b18,0x5c18,0x5d18,0x5e18,0x5f18, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7030,0x7130,0x7230,0x7330,0x7430,0x7530,0x7630,0x7730, + 0x7838,0x7938,0x7a38,0x7b38,0x7c38,0x7d38,0x7e38,0x7f38, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9090,0x9190,0x9290,0x9390,0x9490,0x9590,0x9690,0x9790, + 0x9898,0x9998,0x9a98,0x9b98,0x9c98,0x9d98,0x9e98,0x9f98, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0b0,0xb1b0,0xb2b0,0xb3b0,0xb4b0,0xb5b0,0xb6b0,0xb7b0, + 0xb8b8,0xb9b8,0xbab8,0xbbb8,0xbcb8,0xbdb8,0xbeb8,0xbfb8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd090,0xd190,0xd290,0xd390,0xd490,0xd590,0xd690,0xd790, + 0xd898,0xd998,0xda98,0xdb98,0xdc98,0xdd98,0xde98,0xdf98, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0b0,0xf1b0,0xf2b0,0xf3b0,0xf4b0,0xf5b0,0xf6b0,0xf7b0, + 0xf8b8,0xf9b8,0xfab8,0xfbb8,0xfcb8,0xfdb8,0xfeb8,0xffb8, + 0x0041,0x0101,0x0201,0x0301,0x0401,0x0501,0x0601,0x0701, + 0x0809,0x0909,0x0a09,0x0b09,0x0c09,0x0d09,0x0e09,0x0f09, + 0x1011,0x1111,0x1211,0x1311,0x1411,0x1511,0x1611,0x1711, + 0x1819,0x1919,0x1a19,0x1b19,0x1c19,0x1d19,0x1e19,0x1f19, + 0x2021,0x2121,0x2221,0x2321,0x2421,0x2521,0x2621,0x2721, + 0x2829,0x2929,0x2a29,0x2b29,0x2c29,0x2d29,0x2e29,0x2f29, + 0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731, + 0x3839,0x3939,0x3a39,0x3b39,0x3c39,0x3d39,0x3e39,0x3f39, + 0x4001,0x4101,0x4201,0x4301,0x4401,0x4501,0x4601,0x4701, + 0x4809,0x4909,0x4a09,0x4b09,0x4c09,0x4d09,0x4e09,0x4f09, + 0x5011,0x5111,0x5211,0x5311,0x5411,0x5511,0x5611,0x5711, + 0x5819,0x5919,0x5a19,0x5b19,0x5c19,0x5d19,0x5e19,0x5f19, + 0x6021,0x6121,0x6221,0x6321,0x6421,0x6521,0x6621,0x6721, + 0x6829,0x6929,0x6a29,0x6b29,0x6c29,0x6d29,0x6e29,0x6f29, + 0x7031,0x7131,0x7231,0x7331,0x7431,0x7531,0x7631,0x7731, + 0x7839,0x7939,0x7a39,0x7b39,0x7c39,0x7d39,0x7e39,0x7f39, + 0x8081,0x8181,0x8281,0x8381,0x8481,0x8581,0x8681,0x8781, + 0x8889,0x8989,0x8a89,0x8b89,0x8c89,0x8d89,0x8e89,0x8f89, + 0x9091,0x9191,0x9291,0x9391,0x9491,0x9591,0x9691,0x9791, + 0x9899,0x9999,0x9a99,0x9b99,0x9c99,0x9d99,0x9e99,0x9f99, + 0xa0a1,0xa1a1,0xa2a1,0xa3a1,0xa4a1,0xa5a1,0xa6a1,0xa7a1, + 0xa8a9,0xa9a9,0xaaa9,0xaba9,0xaca9,0xada9,0xaea9,0xafa9, + 0xb0b1,0xb1b1,0xb2b1,0xb3b1,0xb4b1,0xb5b1,0xb6b1,0xb7b1, + 0xb8b9,0xb9b9,0xbab9,0xbbb9,0xbcb9,0xbdb9,0xbeb9,0xbfb9, + 0xc081,0xc181,0xc281,0xc381,0xc481,0xc581,0xc681,0xc781, + 0xc889,0xc989,0xca89,0xcb89,0xcc89,0xcd89,0xce89,0xcf89, + 0xd091,0xd191,0xd291,0xd391,0xd491,0xd591,0xd691,0xd791, + 0xd899,0xd999,0xda99,0xdb99,0xdc99,0xdd99,0xde99,0xdf99, + 0xe0a1,0xe1a1,0xe2a1,0xe3a1,0xe4a1,0xe5a1,0xe6a1,0xe7a1, + 0xe8a9,0xe9a9,0xeaa9,0xeba9,0xeca9,0xeda9,0xeea9,0xefa9, + 0xf0b1,0xf1b1,0xf2b1,0xf3b1,0xf4b1,0xf5b1,0xf6b1,0xf7b1, + 0xf8b9,0xf9b9,0xfab9,0xfbb9,0xfcb9,0xfdb9,0xfeb9,0xffb9, +}; + +/* cbitsDup16Table[i] = (i & 0x10) | ((i >> 8) & 1) | (i & 0x28), i = 0..511 */ +static const uint8 cbitsDup16Table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, +}; + +/* cbits2Table[i] = (i & 0x10) | ((i >> 8) & 1) | 2, i = 0..511 */ +static const uint8 cbits2Table[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* rrcaTable[i] = ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ +static const uint16 rrcaTable[256] = { + 0x0000,0x8001,0x0100,0x8101,0x0200,0x8201,0x0300,0x8301, + 0x0400,0x8401,0x0500,0x8501,0x0600,0x8601,0x0700,0x8701, + 0x0808,0x8809,0x0908,0x8909,0x0a08,0x8a09,0x0b08,0x8b09, + 0x0c08,0x8c09,0x0d08,0x8d09,0x0e08,0x8e09,0x0f08,0x8f09, + 0x1000,0x9001,0x1100,0x9101,0x1200,0x9201,0x1300,0x9301, + 0x1400,0x9401,0x1500,0x9501,0x1600,0x9601,0x1700,0x9701, + 0x1808,0x9809,0x1908,0x9909,0x1a08,0x9a09,0x1b08,0x9b09, + 0x1c08,0x9c09,0x1d08,0x9d09,0x1e08,0x9e09,0x1f08,0x9f09, + 0x2020,0xa021,0x2120,0xa121,0x2220,0xa221,0x2320,0xa321, + 0x2420,0xa421,0x2520,0xa521,0x2620,0xa621,0x2720,0xa721, + 0x2828,0xa829,0x2928,0xa929,0x2a28,0xaa29,0x2b28,0xab29, + 0x2c28,0xac29,0x2d28,0xad29,0x2e28,0xae29,0x2f28,0xaf29, + 0x3020,0xb021,0x3120,0xb121,0x3220,0xb221,0x3320,0xb321, + 0x3420,0xb421,0x3520,0xb521,0x3620,0xb621,0x3720,0xb721, + 0x3828,0xb829,0x3928,0xb929,0x3a28,0xba29,0x3b28,0xbb29, + 0x3c28,0xbc29,0x3d28,0xbd29,0x3e28,0xbe29,0x3f28,0xbf29, + 0x4000,0xc001,0x4100,0xc101,0x4200,0xc201,0x4300,0xc301, + 0x4400,0xc401,0x4500,0xc501,0x4600,0xc601,0x4700,0xc701, + 0x4808,0xc809,0x4908,0xc909,0x4a08,0xca09,0x4b08,0xcb09, + 0x4c08,0xcc09,0x4d08,0xcd09,0x4e08,0xce09,0x4f08,0xcf09, + 0x5000,0xd001,0x5100,0xd101,0x5200,0xd201,0x5300,0xd301, + 0x5400,0xd401,0x5500,0xd501,0x5600,0xd601,0x5700,0xd701, + 0x5808,0xd809,0x5908,0xd909,0x5a08,0xda09,0x5b08,0xdb09, + 0x5c08,0xdc09,0x5d08,0xdd09,0x5e08,0xde09,0x5f08,0xdf09, + 0x6020,0xe021,0x6120,0xe121,0x6220,0xe221,0x6320,0xe321, + 0x6420,0xe421,0x6520,0xe521,0x6620,0xe621,0x6720,0xe721, + 0x6828,0xe829,0x6928,0xe929,0x6a28,0xea29,0x6b28,0xeb29, + 0x6c28,0xec29,0x6d28,0xed29,0x6e28,0xee29,0x6f28,0xef29, + 0x7020,0xf021,0x7120,0xf121,0x7220,0xf221,0x7320,0xf321, + 0x7420,0xf421,0x7520,0xf521,0x7620,0xf621,0x7720,0xf721, + 0x7828,0xf829,0x7928,0xf929,0x7a28,0xfa29,0x7b28,0xfb29, + 0x7c28,0xfc29,0x7d28,0xfd29,0x7e28,0xfe29,0x7f28,0xff29, +}; + +/* rraTable[i] = ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ +static const uint16 rraTable[256] = { + 0x0000,0x0001,0x0100,0x0101,0x0200,0x0201,0x0300,0x0301, + 0x0400,0x0401,0x0500,0x0501,0x0600,0x0601,0x0700,0x0701, + 0x0808,0x0809,0x0908,0x0909,0x0a08,0x0a09,0x0b08,0x0b09, + 0x0c08,0x0c09,0x0d08,0x0d09,0x0e08,0x0e09,0x0f08,0x0f09, + 0x1000,0x1001,0x1100,0x1101,0x1200,0x1201,0x1300,0x1301, + 0x1400,0x1401,0x1500,0x1501,0x1600,0x1601,0x1700,0x1701, + 0x1808,0x1809,0x1908,0x1909,0x1a08,0x1a09,0x1b08,0x1b09, + 0x1c08,0x1c09,0x1d08,0x1d09,0x1e08,0x1e09,0x1f08,0x1f09, + 0x2020,0x2021,0x2120,0x2121,0x2220,0x2221,0x2320,0x2321, + 0x2420,0x2421,0x2520,0x2521,0x2620,0x2621,0x2720,0x2721, + 0x2828,0x2829,0x2928,0x2929,0x2a28,0x2a29,0x2b28,0x2b29, + 0x2c28,0x2c29,0x2d28,0x2d29,0x2e28,0x2e29,0x2f28,0x2f29, + 0x3020,0x3021,0x3120,0x3121,0x3220,0x3221,0x3320,0x3321, + 0x3420,0x3421,0x3520,0x3521,0x3620,0x3621,0x3720,0x3721, + 0x3828,0x3829,0x3928,0x3929,0x3a28,0x3a29,0x3b28,0x3b29, + 0x3c28,0x3c29,0x3d28,0x3d29,0x3e28,0x3e29,0x3f28,0x3f29, + 0x4000,0x4001,0x4100,0x4101,0x4200,0x4201,0x4300,0x4301, + 0x4400,0x4401,0x4500,0x4501,0x4600,0x4601,0x4700,0x4701, + 0x4808,0x4809,0x4908,0x4909,0x4a08,0x4a09,0x4b08,0x4b09, + 0x4c08,0x4c09,0x4d08,0x4d09,0x4e08,0x4e09,0x4f08,0x4f09, + 0x5000,0x5001,0x5100,0x5101,0x5200,0x5201,0x5300,0x5301, + 0x5400,0x5401,0x5500,0x5501,0x5600,0x5601,0x5700,0x5701, + 0x5808,0x5809,0x5908,0x5909,0x5a08,0x5a09,0x5b08,0x5b09, + 0x5c08,0x5c09,0x5d08,0x5d09,0x5e08,0x5e09,0x5f08,0x5f09, + 0x6020,0x6021,0x6120,0x6121,0x6220,0x6221,0x6320,0x6321, + 0x6420,0x6421,0x6520,0x6521,0x6620,0x6621,0x6720,0x6721, + 0x6828,0x6829,0x6928,0x6929,0x6a28,0x6a29,0x6b28,0x6b29, + 0x6c28,0x6c29,0x6d28,0x6d29,0x6e28,0x6e29,0x6f28,0x6f29, + 0x7020,0x7021,0x7120,0x7121,0x7220,0x7221,0x7320,0x7321, + 0x7420,0x7421,0x7520,0x7521,0x7620,0x7621,0x7720,0x7721, + 0x7828,0x7829,0x7928,0x7929,0x7a28,0x7a29,0x7b28,0x7b29, + 0x7c28,0x7c29,0x7d28,0x7d29,0x7e28,0x7e29,0x7f28,0x7f29, +}; + +/* addTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6), i = 0..511 */ +static const uint16 addTable[512] = { + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, + 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, + 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, + 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, + 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, + 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, + 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, + 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, + 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, + 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, + 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, + 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, + 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, +}; + +/* subTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2, i = 0..255 */ +static const uint16 subTable[256] = { + 0x0042,0x0102,0x0202,0x0302,0x0402,0x0502,0x0602,0x0702, + 0x080a,0x090a,0x0a0a,0x0b0a,0x0c0a,0x0d0a,0x0e0a,0x0f0a, + 0x1002,0x1102,0x1202,0x1302,0x1402,0x1502,0x1602,0x1702, + 0x180a,0x190a,0x1a0a,0x1b0a,0x1c0a,0x1d0a,0x1e0a,0x1f0a, + 0x2022,0x2122,0x2222,0x2322,0x2422,0x2522,0x2622,0x2722, + 0x282a,0x292a,0x2a2a,0x2b2a,0x2c2a,0x2d2a,0x2e2a,0x2f2a, + 0x3022,0x3122,0x3222,0x3322,0x3422,0x3522,0x3622,0x3722, + 0x382a,0x392a,0x3a2a,0x3b2a,0x3c2a,0x3d2a,0x3e2a,0x3f2a, + 0x4002,0x4102,0x4202,0x4302,0x4402,0x4502,0x4602,0x4702, + 0x480a,0x490a,0x4a0a,0x4b0a,0x4c0a,0x4d0a,0x4e0a,0x4f0a, + 0x5002,0x5102,0x5202,0x5302,0x5402,0x5502,0x5602,0x5702, + 0x580a,0x590a,0x5a0a,0x5b0a,0x5c0a,0x5d0a,0x5e0a,0x5f0a, + 0x6022,0x6122,0x6222,0x6322,0x6422,0x6522,0x6622,0x6722, + 0x682a,0x692a,0x6a2a,0x6b2a,0x6c2a,0x6d2a,0x6e2a,0x6f2a, + 0x7022,0x7122,0x7222,0x7322,0x7422,0x7522,0x7622,0x7722, + 0x782a,0x792a,0x7a2a,0x7b2a,0x7c2a,0x7d2a,0x7e2a,0x7f2a, + 0x8082,0x8182,0x8282,0x8382,0x8482,0x8582,0x8682,0x8782, + 0x888a,0x898a,0x8a8a,0x8b8a,0x8c8a,0x8d8a,0x8e8a,0x8f8a, + 0x9082,0x9182,0x9282,0x9382,0x9482,0x9582,0x9682,0x9782, + 0x988a,0x998a,0x9a8a,0x9b8a,0x9c8a,0x9d8a,0x9e8a,0x9f8a, + 0xa0a2,0xa1a2,0xa2a2,0xa3a2,0xa4a2,0xa5a2,0xa6a2,0xa7a2, + 0xa8aa,0xa9aa,0xaaaa,0xabaa,0xacaa,0xadaa,0xaeaa,0xafaa, + 0xb0a2,0xb1a2,0xb2a2,0xb3a2,0xb4a2,0xb5a2,0xb6a2,0xb7a2, + 0xb8aa,0xb9aa,0xbaaa,0xbbaa,0xbcaa,0xbdaa,0xbeaa,0xbfaa, + 0xc082,0xc182,0xc282,0xc382,0xc482,0xc582,0xc682,0xc782, + 0xc88a,0xc98a,0xca8a,0xcb8a,0xcc8a,0xcd8a,0xce8a,0xcf8a, + 0xd082,0xd182,0xd282,0xd382,0xd482,0xd582,0xd682,0xd782, + 0xd88a,0xd98a,0xda8a,0xdb8a,0xdc8a,0xdd8a,0xde8a,0xdf8a, + 0xe0a2,0xe1a2,0xe2a2,0xe3a2,0xe4a2,0xe5a2,0xe6a2,0xe7a2, + 0xe8aa,0xe9aa,0xeaaa,0xebaa,0xecaa,0xedaa,0xeeaa,0xefaa, + 0xf0a2,0xf1a2,0xf2a2,0xf3a2,0xf4a2,0xf5a2,0xf6a2,0xf7a2, + 0xf8aa,0xf9aa,0xfaaa,0xfbaa,0xfcaa,0xfdaa,0xfeaa,0xffaa, +}; + +/* andTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i], i = 0..255 */ +static const uint16 andTable[256] = { + 0x0054,0x0110,0x0210,0x0314,0x0410,0x0514,0x0614,0x0710, + 0x0818,0x091c,0x0a1c,0x0b18,0x0c1c,0x0d18,0x0e18,0x0f1c, + 0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,0x1610,0x1714, + 0x181c,0x1918,0x1a18,0x1b1c,0x1c18,0x1d1c,0x1e1c,0x1f18, + 0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,0x2630,0x2734, + 0x283c,0x2938,0x2a38,0x2b3c,0x2c38,0x2d3c,0x2e3c,0x2f38, + 0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,0x3634,0x3730, + 0x3838,0x393c,0x3a3c,0x3b38,0x3c3c,0x3d38,0x3e38,0x3f3c, + 0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,0x4610,0x4714, + 0x481c,0x4918,0x4a18,0x4b1c,0x4c18,0x4d1c,0x4e1c,0x4f18, + 0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,0x5614,0x5710, + 0x5818,0x591c,0x5a1c,0x5b18,0x5c1c,0x5d18,0x5e18,0x5f1c, + 0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,0x6634,0x6730, + 0x6838,0x693c,0x6a3c,0x6b38,0x6c3c,0x6d38,0x6e38,0x6f3c, + 0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,0x7630,0x7734, + 0x783c,0x7938,0x7a38,0x7b3c,0x7c38,0x7d3c,0x7e3c,0x7f38, + 0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,0x8690,0x8794, + 0x889c,0x8998,0x8a98,0x8b9c,0x8c98,0x8d9c,0x8e9c,0x8f98, + 0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,0x9694,0x9790, + 0x9898,0x999c,0x9a9c,0x9b98,0x9c9c,0x9d98,0x9e98,0x9f9c, + 0xa0b4,0xa1b0,0xa2b0,0xa3b4,0xa4b0,0xa5b4,0xa6b4,0xa7b0, + 0xa8b8,0xa9bc,0xaabc,0xabb8,0xacbc,0xadb8,0xaeb8,0xafbc, + 0xb0b0,0xb1b4,0xb2b4,0xb3b0,0xb4b4,0xb5b0,0xb6b0,0xb7b4, + 0xb8bc,0xb9b8,0xbab8,0xbbbc,0xbcb8,0xbdbc,0xbebc,0xbfb8, + 0xc094,0xc190,0xc290,0xc394,0xc490,0xc594,0xc694,0xc790, + 0xc898,0xc99c,0xca9c,0xcb98,0xcc9c,0xcd98,0xce98,0xcf9c, + 0xd090,0xd194,0xd294,0xd390,0xd494,0xd590,0xd690,0xd794, + 0xd89c,0xd998,0xda98,0xdb9c,0xdc98,0xdd9c,0xde9c,0xdf98, + 0xe0b0,0xe1b4,0xe2b4,0xe3b0,0xe4b4,0xe5b0,0xe6b0,0xe7b4, + 0xe8bc,0xe9b8,0xeab8,0xebbc,0xecb8,0xedbc,0xeebc,0xefb8, + 0xf0b4,0xf1b0,0xf2b0,0xf3b4,0xf4b0,0xf5b4,0xf6b4,0xf7b0, + 0xf8b8,0xf9bc,0xfabc,0xfbb8,0xfcbc,0xfdb8,0xfeb8,0xffbc, +}; + +/* xororTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i], i = 0..255 */ +static const uint16 xororTable[256] = { + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, + 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, + 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, + 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, + 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, + 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, + 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, + 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, + 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, + 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, + 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, + 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, + 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, +}; + +/* rotateShiftTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff], i = 0..255 */ +static const uint8 rotateShiftTable[256] = { + 68, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, + 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, + 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, + 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, + 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, + 4, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, + 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, + 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, + 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, + 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, + 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, + 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, + 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, + 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, + 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, + 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, +}; + +/* incZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2), i = 0..256 */ +static const uint8 incZ80Table[257] = { + 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 148,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80, +}; + +/* decZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2, i = 0..255 */ +static const uint8 decZ80Table[256] = { + 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 62, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, +}; + +/* cbitsZ80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1), i = 0..511 */ +static const uint8 cbitsZ80Table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +}; + +/* cbitsZ80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | + ((i >> 8) & 1) | (i & 0xa8), i = 0..511 */ +static const uint8 cbitsZ80DupTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, + 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, + 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, + 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, + 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, + 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, + 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, + 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, + 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, + 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, + 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, + 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, + 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, + 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, + 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, + 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, + 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, + 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, + 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, + 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, + 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, + 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, + 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, +}; + +/* cbits2Z80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2, i = 0..511 */ +static const uint8 cbits2Z80Table[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* cbits2Z80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | + (i & 0xa8), i = 0..511 */ +static const uint8 cbits2Z80DupTable[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, + 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, + 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, + 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, + 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, + 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, + 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, + 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, + 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, + 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, + 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, + 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, + 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, + 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, + 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, + 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, + 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, + 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, + 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, + 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, + 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, + 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, + 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, + 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, + 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, + 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, + 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, +}; + +/* negTable[i] = (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0), i = 0..255 */ +static const uint8 negTable[256] = { + 2,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 7,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* rrdrldTable[i] = (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i], i = 0..255 */ +static const uint16 rrdrldTable[256] = { + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, + 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, + 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, + 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, + 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, + 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, + 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, + 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, + 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, + 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, + 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, + 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, + 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, +}; + +/* cpTable[i] = (i & 0x80) | (((i & 0xff) == 0) << 6), i = 0..255 */ +static const uint8 cpTable[256] = { + 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +}; + +/* remove comments to generate table contents +static void altairz80_init(void); +void (*sim_vm_init) (void) = &altairz80_init; +static void altairz80_init(void) { +*/ +/* parityTable */ +/* + uint32 i, v; + for (i = 0; i < 256; i++) { + v = ((i & 1) + ((i & 2) >> 1) + ((i & 4) >> 2) + ((i & 8) >> 3) + + ((i & 16) >> 4) + ((i & 32) >> 5) + ((i & 64) >> 6) + ((i & 128) >> 7)) % 2 ? 0 : 4; + printf("%1d,", v); + if ( ((i+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* incTable */ +/* + uint32 temp, v; + for (temp = 0; temp <= 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4); + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* decTable */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | 2; + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbitsTable */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | ((cbits >> 8) & 1); + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbitsDup8Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | ((cbits >> 8) & 1) | ((cbits & 0xff) << 8) | (cbits & 0xa8) | (((cbits & 0xff) == 0) << 6); + printf("0x%04x,", v); + if ( ((cbits+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* cbitsDup16Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | ((cbits >> 8) & 1) | (cbits & 0x28); + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbits2Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | ((cbits >> 8) & 1) | 2; + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* rrcaTable */ +/* + uint32 temp, sum, v; + for (temp = 0; temp < 256; temp++) { + sum = temp >> 1; + v = ((temp & 1) << 15) | (sum << 8) | (sum & 0x28) | (temp & 1); + printf("0x%04x,", v); + if ( ((temp+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* rraTable */ +/* + uint32 temp, sum, v; + for (temp = 0; temp < 256; temp++) { + sum = temp >> 1; + v = (sum << 8) | (sum & 0x28) | (temp & 1); + printf("0x%04x,", v); + if ( ((temp+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* addTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 512; sum++) { + v = ((sum & 0xff) << 8) | (sum & 0xa8) | (((sum & 0xff) == 0) << 6); + printf("0x%04x,", v); + if ( ((sum+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* subTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 256; sum++) { + v = ((sum & 0xff) << 8) | (sum & 0xa8) | (((sum & 0xff) == 0) << 6) | 2; + printf("0x%04x,", v); + if ( ((sum+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* andTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 256; sum++) { + v = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | parityTable[sum]; + printf("0x%04x,", v); + if ( ((sum+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* xororTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 256; sum++) { + v = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | parityTable[sum]; + printf("0x%04x,", v); + if ( ((sum+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* rotateShiftTable */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | parity(temp); + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* incZ80Table */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | ((temp == 0x80) << 2); + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* decZ80Table */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | ((temp == 0x7f) << 2) | 2; + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbitsZ80Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbitsZ80DupTable */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1) | (cbits & 0xa8); + printf("%3d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbits2Z80Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1); + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbits2Z80DupTable */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1) | + (cbits & 0xa8); + printf("%3d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* negTable */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (((temp & 0x0f) != 0) << 4) | ((temp == 0x80) << 2) | 2 | (temp != 0); + printf("%2d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* rrdrldTable */ +/* + uint32 acu, v; + for (acu = 0; acu < 256; acu++) { + v = (acu << 8) | (acu & 0xa8) | (((acu & 0xff) == 0) << 6) | parityTable[acu]; + printf("0x%04x,", v); + if ( ((acu+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* cpTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 256; sum++) { + v = (sum & 0x80) | (((sum & 0xff) == 0) << 6); + printf("%3d,", v); + if ( ((sum+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* remove comments to generate table contents +} +*/ + +/* Memory management. Two options available: + 1) All features (ROM checking, ROM boundaries definable at run time, banked memory) + 2) Bare bones (faster, no checking, no banked memory) - define ALTAIROPT +*/ + +static int32 lowProtect; +static int32 highProtect; +static int32 isProtected = FALSE; + +void protect(const int32 l, const int32 h) { + isProtected = TRUE; + lowProtect = l; + highProtect = h; +} + +#if defined(ALTAIROPT) + +static uint8 M[MAXMEMSIZE]; /* RAM which is present */ + +/* determine whether Addr points to Read Only Memory */ +INLINE int32 addressIsInROM(const uint32 Addr) { + return FALSE; +} + +/* determine whether Addr points to a valid memory address */ +INLINE int32 addressExists(const uint32 Addr) { + return TRUE; +} + +#if defined(ALTAIROPTMACRO) + +#define GetBYTE(Addr) M[(Addr) & ADDRMASK] + +#define PutBYTE(Addr, Value) M[(Addr) & ADDRMASK] = Value; + +#define PutWORD(Addr, Value) \ + M[(Addr) & ADDRMASK] = Value; \ + M[((Addr) + 1) & ADDRMASK] = Value >> 8; + +#else + +static INLINE uint8 GetBYTE(register uint32 Addr) { + return M[Addr & ADDRMASK]; +} + +static INLINE void PutBYTE(register uint32 Addr, register uint32 Value) { + M[Addr & ADDRMASK] = Value; +} + +static INLINE void PutWORD(register uint32 Addr, register uint32 Value) { + M[Addr & ADDRMASK] = Value; + M[(Addr + 1) & ADDRMASK] = Value >> 8; +} + +#endif + +INLINE void PutBYTEForced(register uint32 Addr, register uint32 Value) { + M[Addr & ADDRMASK] = Value; +} + +void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value) { + M[Addr & ADDRMASK] = Value; +} + +int32 install_bootrom(void) { + extern int32 bootrom[bootrom_size]; + int32 i, cnt = 0; + for (i = 0; i < bootrom_size; i++) { + if (M[i + defaultROMLow] != (bootrom[i] & 0xff)) { + cnt++; + M[i + defaultROMLow] = bootrom[i] & 0xff; + } + } + return cnt; +} + +static void resetCell(const int32 address, const int32 bank) { + if (!(isProtected && (lowProtect <= address) && (address <= highProtect))) { + M[address] = 0; + } +} + +/* memory examine */ +t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { + *vptr = M[addr & ADDRMASK]; + return SCPE_OK; +} + +/* memory deposit */ +t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) { + M[addr & ADDRMASK] = val & 0xff; + return SCPE_OK; +} + +int32 getBankSelect(void) { + return 0; +} + +void setBankSelect(int32 b) { +} + +uint32 getCommon(void) { + return 0; +} + +void setCommon(uint32 c) { +} + +#else + +static uint8 M[MAXMEMSIZE][MAXBANKS]; /* RAM which is present */ + +static void warnUnsuccessfulWriteAttempt(const uint32 Addr) { + if (cpu_unit.flags & UNIT_WARNROM) { + if (addressIsInROM(Addr)) { + message2("Attempt to write to ROM " AddressFormat ".", Addr); + } + else { + message2("Attempt to write to non existing memory " AddressFormat ".", Addr); + } + } +} + +static uint8 warnUnsuccessfulReadAttempt(const uint32 Addr) { + if (cpu_unit.flags & UNIT_WARNROM) { + message2("Attempt to read from non existing memory " AddressFormat ".", Addr); + } + return 0xff; +} + +/* determine whether Addr points to Read Only Memory */ +int32 addressIsInROM(const uint32 Addr) { + uint32 addr = Addr & ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + return (cpu_unit.flags & UNIT_ROM) && ( /* must have ROM enabled */ + /* in banked case we have standard Altair ROM */ + ((cpu_unit.flags & UNIT_BANKED) && (defaultROMLow <= addr)) || + /* in non-banked case we check the bounds of the ROM */ + (((cpu_unit.flags & UNIT_BANKED) == 0) && (ROMLow <= addr) && (addr <= ROMHigh))); +} + +/* determine whether Addr points to a valid memory address */ +int32 addressExists(const uint32 Addr) { + uint32 addr = Addr & ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + return (cpu_unit.flags & UNIT_BANKED) || (addr < MEMSIZE) || + ( ((cpu_unit.flags & UNIT_BANKED) == 0) && (cpu_unit.flags & UNIT_ROM) + && (ROMLow <= addr) && (addr <= ROMHigh) ); +} + +static INLINE uint8 GetBYTE(register uint32 Addr) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if (cpu_unit.flags & UNIT_BANKED) { /* banked memory case */ + /* if Addr below "common" take from selected bank, otherwise from bank 0 */ + return Addr < common ? M[Addr][bankSelect] : M[Addr][0]; + } + else { /* non-banked memory case */ + return ((Addr < MEMSIZE) || + ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= Addr) && (Addr <= ROMHigh) )) ? + M[Addr][0] : warnUnsuccessfulReadAttempt(Addr); + } +} + +static INLINE void PutBYTE(register uint32 Addr, register uint32 Value) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if (cpu_unit.flags & UNIT_BANKED) { + if (Addr < common) { + M[Addr][bankSelect] = Value; + } + else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + M[Addr][0] = Value; + } + else { + warnUnsuccessfulWriteAttempt(Addr); + } + } + else { + if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + M[Addr][0] = Value; + } + else { + warnUnsuccessfulWriteAttempt(Addr); + } + } +} + +static INLINE void PutWORD(register uint32 Addr, register uint32 Value) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if (cpu_unit.flags & UNIT_BANKED) { + if (Addr < common) { + M[Addr][bankSelect] = Value; + } + else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + M[Addr][0] = Value; + } + else { + warnUnsuccessfulWriteAttempt(Addr); + } + Addr = (Addr + 1) & ADDRMASK; + if (Addr < common) { + M[Addr][bankSelect] = Value >> 8; + } + else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + M[Addr][0] = Value >> 8; + } + else { + warnUnsuccessfulWriteAttempt(Addr); + } + } + else { + if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + M[Addr][0] = Value; + } + else { + warnUnsuccessfulWriteAttempt(Addr); + } + Addr = (Addr + 1) & ADDRMASK; + if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + M[Addr][0] = Value >> 8; + } + else { + warnUnsuccessfulWriteAttempt(Addr); + } + } +} + +void PutBYTEForced(register uint32 Addr, register uint32 Value) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if ((cpu_unit.flags & UNIT_BANKED) && (Addr < common)) { + M[Addr][bankSelect] = Value; + } + else { + M[Addr][0] = Value; + } +} + +void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value) { + M[Addr & ADDRMASK][Bank & BANKMASK] = Value; +} + +int32 install_bootrom(void) { + extern int32 bootrom[bootrom_size]; + int32 i, cnt = 0; + for (i = 0; i < bootrom_size; i++) { + if (M[i + defaultROMLow][0] != (bootrom[i] & 0xff)) { + cnt++; + M[i + defaultROMLow][0] = bootrom[i] & 0xff; + } + } + return cnt; +} + +static void resetCell(const int32 address, const int32 bank) { + if (!(isProtected && (bank == 0) && (lowProtect <= address) && (address <= highProtect))) { + M[address][bank] = 0; + } +} + +/* memory examine */ +t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { + *vptr = M[addr & ADDRMASK][(addr >> 16) & BANKMASK]; + return SCPE_OK; +} + +/* memory deposit */ +t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) { + M[addr & ADDRMASK][(addr >> 16) & BANKMASK] = val & 0xff; + return SCPE_OK; +} + +int32 getBankSelect(void) { + return bankSelect; +} + +void setBankSelect(int32 b) { + bankSelect = b; +} + +uint32 getCommon(void) { + return common; +} + +void setCommon(uint32 c) { + common = c; +} + +#endif + +uint8 GetBYTEWrapper(register uint32 Addr) { /* make sure that non-inlined version exists */ + return GetBYTE(Addr); +} + +void PutBYTEWrapper(register uint32 Addr, register uint32 Value) { + PutBYTE(Addr, Value); +} + +#define RAM_mm(a) GetBYTE(a--) +#define RAM_pp(a) GetBYTE(a++) + +#define PutBYTE_pp(a,v) PutBYTE(a++, v) +#define PutBYTE_mm(a,v) PutBYTE(a--, v) +#define mm_PutBYTE(a,v) PutBYTE(--a, v) + +static INLINE uint16 GetWORD(register uint32 a) { + return GetBYTE(a) | (GetBYTE(a + 1) << 8); +} + +#define MASK_BRK (TRUE + 1) + +/* this is a modified version of sim_brk_test with two differences: + 1) is does not set sim_brk_pend to FALSE (this if left to the instruction decode) + 2) it returns MASK_BRK if a breakpoint is found but should be ignored +*/ +static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) { + extern t_bool sim_brk_pend; + extern t_addr sim_brk_ploc; + extern char *sim_brk_act; + BRKTAB *bp; + if ((bp = sim_brk_fnd (loc)) && /* entry in table? */ + (btyp & bp -> typ) && /* type match? */ + (!sim_brk_pend || (loc != sim_brk_ploc)) && /* new location? */ + (--(bp -> cnt) <= 0)) { /* count reach 0? */ + bp -> cnt = 0; /* reset count */ + sim_brk_ploc = loc; /* save location */ + sim_brk_act = bp -> act; /* set up actions */ + sim_brk_pend = TRUE; /* don't do twice */ + return TRUE; + } + return (sim_brk_pend && (loc == sim_brk_ploc)) ? MASK_BRK : FALSE; +} + +static void prepareMemoryAccessMessage(t_addr loc) { + extern char memoryAccessMessage[]; + sprintf(memoryAccessMessage, "Memory access breakpoint [%04xh]", loc); +} + +#define PUSH(x) { \ + mm_PutBYTE(SP, (x) >> 8); \ + mm_PutBYTE(SP, x); \ +} + +#define CheckBreakByte(a) \ + if (sim_brk_summ && sim_brk_test(a, SWMASK('M'))) { \ + reason = STOP_MEM; \ + prepareMemoryAccessMessage(a); \ + goto end_decode; \ + } + +#define CheckBreakTwoBytesExtended(a1, a2, iCode) \ + if (sim_brk_summ) { \ + br1 = sim_brk_lookup(a1, SWMASK('M')); \ + br2 = br1 ? FALSE : sim_brk_lookup(a2, SWMASK('M')); \ + if ((br1 == MASK_BRK) || (br2 == MASK_BRK)) { \ + sim_brk_pend = FALSE; \ + } \ + else if (br1 || br2) { \ + reason = STOP_MEM; \ + if (br1) { \ + prepareMemoryAccessMessage(a1); \ + } \ + else { \ + prepareMemoryAccessMessage(a2); \ + } \ + iCode; \ + goto end_decode; \ + } \ + else { \ + sim_brk_pend = FALSE; \ + } \ + } + +#define CheckBreakTwoBytes(a1, a2) CheckBreakTwoBytesExtended(a1, a2,;) + +#define CheckBreakWord(a) CheckBreakTwoBytes(a, (a + 1)) + +#define updateTStates(n) \ + tStates += n; \ + if (sim_step) { \ + if (sim_switches & SWMASK ('T')) { sim_step -= n; } else { sim_step--; } \ + if (sim_step <= 0) { reason = SCPE_STOP; goto end_decode; } \ + } + +int32 sim_instr (void) { + extern int32 sim_switches; + extern int32 sim_step; + extern int32 sim_interval; + extern t_bool sim_brk_pend; + extern int32 timerInterrupt; + extern int32 timerInterruptHandler; + extern uint32 sim_os_msec(void); + extern t_bool rtc_avail; + extern int32 sim_brk_summ; + int32 reason = 0; + register uint32 specialProcessing; + register uint32 AF; + register uint32 BC; + register uint32 DE; + register uint32 HL; + register uint32 PC; + register uint32 SP; + register uint32 IX; + register uint32 IY; + register uint32 temp = 0; + register uint32 acu = 0; + register uint32 sum; + register uint32 cbits; + register uint32 op; + register uint32 adr; + /* tStates contains the number of t-states executed. One t-state is executed + in one microsecond on a 1MHz CPU. tStates is used for real-time simulations. */ + register uint32 tStates; + uint32 tStatesInSlice; /* number of t-states in 10 mSec time-slice */ + uint32 startTime; + int32 br1, br2, tStateModifier = FALSE; + + sim_cancel_step (); + pc = saved_PC & ADDRMASK; /* load local PC */ + af[af_sel] = AF_S; + regs[regs_sel].bc = BC_S; + regs[regs_sel].de = DE_S; + regs[regs_sel].hl = HL_S; + ix = IX_S; + iy = IY_S; + sp = SP_S; + af[1 - af_sel] = AF1_S; + regs[1 - regs_sel].bc = BC1_S; + regs[1 - regs_sel].de = DE1_S; + regs[1 - regs_sel].hl = HL1_S; + IFF = IFF_S; + ir = IR_S; + + AF = af[af_sel]; + BC = regs[regs_sel].bc; + DE = regs[regs_sel].de; + HL = regs[regs_sel].hl; + PC = pc; + SP = sp; + IX = ix; + IY = iy; + specialProcessing = clockFrequency | timerInterrupt | sim_brk_summ; + tStates = 0; + if (rtc_avail) { + startTime = sim_os_msec(); + tStatesInSlice = sliceLength*clockFrequency; + } + else { /* make sure that sim_os_msec() is not called later */ + clockFrequency = startTime = tStatesInSlice = 0; + } + + /* main instruction fetch/decode loop */ + while (TRUE) { /* loop until halted */ + if (sim_interval <= 0) { /* check clock queue */ + if ( (reason = sim_process_event()) ) { + break; + } + else { + specialProcessing = clockFrequency | timerInterrupt | sim_brk_summ; + } + } + + if (specialProcessing) { /* quick check for special processing */ + if (clockFrequency && (tStates >= tStatesInSlice)) { + /* clockFrequency != 0 implies that real time clock is available */ + startTime += sliceLength; + tStates -= tStatesInSlice; +#if defined (_WIN32) + while (sim_os_msec() <= startTime) {} /* poor man's sleep */ +#else + { + uint32 now; + if (startTime > (now = sim_os_msec())) { + usleep(1000 * (startTime - now)); + } + } +#endif + } + + if (timerInterrupt && (IFF & 1)) { + timerInterrupt = FALSE; + specialProcessing = clockFrequency | sim_brk_summ; + IFF = 0; /* disable interrupts */ + CheckBreakTwoBytesExtended(SP - 2, SP - 1, (timerInterrupt = TRUE, IFF |= 1)); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = timerInterruptHandler & ADDRMASK; + } + + if (sim_brk_summ && (sim_brk_lookup(PC, SWMASK('E')) == TRUE)) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + } + + PCX = PC; + sim_interval--; + + /* make sure that each instructions properly sets sim_brk_pend: + 1) Either directly to FALSE if no memory access takes place or + 2) through a call to a Check... routine + */ + switch(RAM_pp(PC)) { + case 0x00: /* NOP */ + updateTStates(4); + sim_brk_pend = FALSE; + break; + case 0x01: /* LD BC,nnnn */ + updateTStates(10); + sim_brk_pend = FALSE; + BC = GetWORD(PC); + PC += 2; + break; + case 0x02: /* LD (BC),A */ + updateTStates(7); + CheckBreakByte(BC) + PutBYTE(BC, hreg(AF)); + break; + case 0x03: /* INC BC */ + updateTStates(6); + sim_brk_pend = FALSE; + ++BC; + break; + case 0x04: /* INC B */ + updateTStates(4); + sim_brk_pend = FALSE; + BC += 0x100; + temp = hreg(BC); + AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); /* SetPV2 uses temp */ + break; + case 0x05: /* DEC B */ + updateTStates(4); + sim_brk_pend = FALSE; + BC -= 0x100; + temp = hreg(BC); + AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); /* SetPV2 uses temp */ + break; + case 0x06: /* LD B,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + Sethreg(BC, RAM_pp(PC)); + break; + case 0x07: /* RLCA */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + case 0x08: /* EX AF,AF' */ + updateTStates(4); + sim_brk_pend = FALSE; + checkCPU8080; + af[af_sel] = AF; + af_sel = 1 - af_sel; + AF = af[af_sel]; + break; + case 0x09: /* ADD HL,BC */ + updateTStates(11); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ BC ^ sum) >> 8]; + HL = sum; + break; + case 0x0a: /* LD A,(BC) */ + updateTStates(7); + CheckBreakByte(BC) + Sethreg(AF, GetBYTE(BC)); + break; + case 0x0b: /* DEC BC */ + updateTStates(6); + sim_brk_pend = FALSE; + --BC; + break; + case 0x0c: /* INC C */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(BC) + 1; + Setlreg(BC, temp); + AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); + break; + case 0x0d: /* DEC C */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(BC) - 1; + Setlreg(BC, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); + break; + case 0x0e: /* LD C,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + Setlreg(BC, RAM_pp(PC)); + break; + case 0x0f: /* RRCA */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & 0xc4) | rrcaTable[hreg(AF)]; + break; + case 0x10: /* DJNZ dd */ + sim_brk_pend = FALSE; + checkCPU8080; + if ((BC -= 0x100) & 0xff00) { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + updateTStates(13); + } + else { + PC++; + updateTStates(8); + } + break; + case 0x11: /* LD DE,nnnn */ + updateTStates(10); + sim_brk_pend = FALSE; + DE = GetWORD(PC); + PC += 2; + break; + case 0x12: /* LD (DE),A */ + updateTStates(7); + CheckBreakByte(DE) + PutBYTE(DE, hreg(AF)); + break; + case 0x13: /* INC DE */ + updateTStates(6); + sim_brk_pend = FALSE; + ++DE; + break; + case 0x14: /* INC D */ + updateTStates(4); + sim_brk_pend = FALSE; + DE += 0x100; + temp = hreg(DE); + AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); /* SetPV2 uses temp */ + break; + case 0x15: /* DEC D */ + updateTStates(4); + sim_brk_pend = FALSE; + DE -= 0x100; + temp = hreg(DE); + AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); /* SetPV2 uses temp */ + break; + case 0x16: /* LD D,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + Sethreg(DE, RAM_pp(PC)); + break; + case 0x17: /* RLA */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + case 0x18: /* JR dd */ + updateTStates(12); + sim_brk_pend = FALSE; + checkCPU8080; + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + break; + case 0x19: /* ADD HL,DE */ + updateTStates(11); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ DE ^ sum) >> 8]; + HL = sum; + break; + case 0x1a: /* LD A,(DE) */ + updateTStates(7); + CheckBreakByte(DE) + Sethreg(AF, GetBYTE(DE)); + break; + case 0x1b: /* DEC DE */ + updateTStates(6); + sim_brk_pend = FALSE; + --DE; + break; + case 0x1c: /* INC E */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(DE) + 1; + Setlreg(DE, temp); + AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); + break; + case 0x1d: /* DEC E */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(DE) - 1; + Setlreg(DE, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); + break; + case 0x1e: /* LD E,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + Setlreg(DE, RAM_pp(PC)); + break; + case 0x1f: /* RRA */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[hreg(AF)]; + break; + case 0x20: /* JR NZ,dd */ + sim_brk_pend = FALSE; + checkCPU8080; + if (TSTFLAG(Z)) { + PC++; + updateTStates(7); + } + else { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + updateTStates(12); + } + break; + case 0x21: /* LD HL,nnnn */ + updateTStates(10); + sim_brk_pend = FALSE; + HL = GetWORD(PC); + PC += 2; + break; + case 0x22: /* LD (nnnn),HL */ + updateTStates(16); + temp = GetWORD(PC); + CheckBreakWord(temp); + PutWORD(temp, HL); + PC += 2; + break; + case 0x23: /* INC HL */ + updateTStates(6); + sim_brk_pend = FALSE; + ++HL; + break; + case 0x24: /* INC H */ + updateTStates(4); + sim_brk_pend = FALSE; + HL += 0x100; + temp = hreg(HL); + AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); /* SetPV2 uses temp */ + break; + case 0x25: /* DEC H */ + updateTStates(4); + sim_brk_pend = FALSE; + HL -= 0x100; + temp = hreg(HL); + AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); /* SetPV2 uses temp */ + break; + case 0x26: /* LD H,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + Sethreg(HL, RAM_pp(PC)); + break; + case 0x27: /* DAA */ + updateTStates(4); + sim_brk_pend = FALSE; + acu = hreg(AF); + temp = ldig(acu); + cbits = TSTFLAG(C); + if (TSTFLAG(N)) { /* last operation was a subtract */ + int hd = cbits || acu > 0x99; + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + if (temp > 5) { + SETFLAG(H, 0); + } + acu -= 6; + acu &= 0xff; + } + if (hd) { /* adjust high digit */ + acu -= 0x160; + } + } + else { /* last operation was an add */ + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + SETFLAG(H, (temp > 9)); + acu += 6; + } + if (cbits || ((acu & 0x1f0) > 0x90)) { /* adjust high digit */ + acu += 0x60; + } + } + AF = (AF & 0x12) | rrdrldTable[acu & 0xff] | ((acu >> 8) & 1) | cbits; + break; + case 0x28: /* JR Z,dd */ + sim_brk_pend = FALSE; + checkCPU8080; + if (TSTFLAG(Z)) { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + updateTStates(12); + } + else { + PC++; + updateTStates(7); + } + break; + case 0x29: /* ADD HL,HL */ + updateTStates(11); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + sum = HL + HL; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + HL = sum; + break; + case 0x2a: /* LD HL,(nnnn) */ + updateTStates(16); + temp = GetWORD(PC); + CheckBreakWord(temp); + HL = GetWORD(temp); + PC += 2; + break; + case 0x2b: /* DEC HL */ + updateTStates(6); + sim_brk_pend = FALSE; + --HL; + break; + case 0x2c: /* INC L */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(HL) + 1; + Setlreg(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); + break; + case 0x2d: /* DEC L */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(HL) - 1; + Setlreg(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); + break; + case 0x2e: /* LD L,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + Setlreg(HL, RAM_pp(PC)); + break; + case 0x2f: /* CPL */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; + break; + case 0x30: /* JR NC,dd */ + sim_brk_pend = FALSE; + checkCPU8080; + if (TSTFLAG(C)) { + PC++; + updateTStates(7); + } + else { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + updateTStates(12); + } + break; + case 0x31: /* LD SP,nnnn */ + updateTStates(10); + sim_brk_pend = FALSE; + SP = GetWORD(PC); + PC += 2; + break; + case 0x32: /* LD (nnnn),A */ + updateTStates(13); + temp = GetWORD(PC); + CheckBreakByte(temp); + PutBYTE(temp, hreg(AF)); + PC += 2; + break; + case 0x33: /* INC SP */ + updateTStates(6); + sim_brk_pend = FALSE; + ++SP; + break; + case 0x34: /* INC (HL) */ + updateTStates(11); + CheckBreakByte(HL); + temp = GetBYTE(HL) + 1; + PutBYTE(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); + break; + case 0x35: /* DEC (HL) */ + updateTStates(11); + CheckBreakByte(HL); + temp = GetBYTE(HL) - 1; + PutBYTE(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); + break; + case 0x36: /* LD (HL),nn */ + updateTStates(10); + CheckBreakByte(HL); + PutBYTE(HL, RAM_pp(PC)); + break; + case 0x37: /* SCF */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | 1; + break; + case 0x38: /* JR C,dd */ + sim_brk_pend = FALSE; + checkCPU8080; + if (TSTFLAG(C)) { + PCQ_ENTRY(PC - 1); + PC += (signed char) GetBYTE(PC) + 1; + updateTStates(12); + } + else { + PC++; + updateTStates(7); + } + break; + case 0x39: /* ADD HL,SP */ + updateTStates(11); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ SP ^ sum) >> 8]; + HL = sum; + break; + case 0x3a: /* LD A,(nnnn) */ + updateTStates(13); + temp = GetWORD(PC); + CheckBreakByte(temp); + Sethreg(AF, GetBYTE(temp)); + PC += 2; + break; + case 0x3b: /* DEC SP */ + updateTStates(6); + sim_brk_pend = FALSE; + --SP; + break; + case 0x3c: /* INC A */ + updateTStates(4); + sim_brk_pend = FALSE; + AF += 0x100; + temp = hreg(AF); + AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); /* SetPV2 uses temp */ + break; + case 0x3d: /* DEC A */ + updateTStates(4); + sim_brk_pend = FALSE; + AF -= 0x100; + temp = hreg(AF); + AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); /* SetPV2 uses temp */ + break; + case 0x3e: /* LD A,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + Sethreg(AF, RAM_pp(PC)); + break; + case 0x3f: /* CCF */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | ((AF & 1) << 4) | (~AF & 1); + break; + case 0x40: /* LD B,B */ + updateTStates(4); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x41: /* LD B,C */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & 0xff) | ((BC & 0xff) << 8); + break; + case 0x42: /* LD B,D */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & 0xff) | (DE & ~0xff); + break; + case 0x43: /* LD B,E */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & 0xff) | ((DE & 0xff) << 8); + break; + case 0x44: /* LD B,H */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & 0xff) | (HL & ~0xff); + break; + case 0x45: /* LD B,L */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & 0xff) | ((HL & 0xff) << 8); + break; + case 0x46: /* LD B,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + Sethreg(BC, GetBYTE(HL)); + break; + case 0x47: /* LD B,A */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & 0xff) | (AF & ~0xff); + break; + case 0x48: /* LD C,B */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & ~0xff) | ((BC >> 8) & 0xff); + break; + case 0x49: /* LD C,C */ + updateTStates(4); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x4a: /* LD C,D */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & ~0xff) | ((DE >> 8) & 0xff); + break; + case 0x4b: /* LD C,E */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & ~0xff) | (DE & 0xff); + break; + case 0x4c: /* LD C,H */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & ~0xff) | ((HL >> 8) & 0xff); + break; + case 0x4d: /* LD C,L */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & ~0xff) | (HL & 0xff); + break; + case 0x4e: /* LD C,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + Setlreg(BC, GetBYTE(HL)); + break; + case 0x4f: /* LD C,A */ + updateTStates(4); + sim_brk_pend = FALSE; + BC = (BC & ~0xff) | ((AF >> 8) & 0xff); + break; + case 0x50: /* LD D,B */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & 0xff) | (BC & ~0xff); + break; + case 0x51: /* LD D,C */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & 0xff) | ((BC & 0xff) << 8); + break; + case 0x52: /* LD D,D */ + updateTStates(4); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x53: /* LD D,E */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & 0xff) | ((DE & 0xff) << 8); + break; + case 0x54: /* LD D,H */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & 0xff) | (HL & ~0xff); + break; + case 0x55: /* LD D,L */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & 0xff) | ((HL & 0xff) << 8); + break; + case 0x56: /* LD D,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + Sethreg(DE, GetBYTE(HL)); + break; + case 0x57: /* LD D,A */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & 0xff) | (AF & ~0xff); + break; + case 0x58: /* LD E,B */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & ~0xff) | ((BC >> 8) & 0xff); + break; + case 0x59: /* LD E,C */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & ~0xff) | (BC & 0xff); + break; + case 0x5a: /* LD E,D */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & ~0xff) | ((DE >> 8) & 0xff); + break; + case 0x5b: /* LD E,E */ + updateTStates(4); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x5c: /* LD E,H */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & ~0xff) | ((HL >> 8) & 0xff); + break; + case 0x5d: /* LD E,L */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & ~0xff) | (HL & 0xff); + break; + case 0x5e: /* LD E,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + Setlreg(DE, GetBYTE(HL)); + break; + case 0x5f: /* LD E,A */ + updateTStates(4); + sim_brk_pend = FALSE; + DE = (DE & ~0xff) | ((AF >> 8) & 0xff); + break; + case 0x60: /* LD H,B */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & 0xff) | (BC & ~0xff); + break; + case 0x61: /* LD H,C */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & 0xff) | ((BC & 0xff) << 8); + break; + case 0x62: /* LD H,D */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & 0xff) | (DE & ~0xff); + break; + case 0x63: /* LD H,E */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & 0xff) | ((DE & 0xff) << 8); + break; + case 0x64: /* LD H,H */ + updateTStates(4); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x65: /* LD H,L */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & 0xff) | ((HL & 0xff) << 8); + break; + case 0x66: /* LD H,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + Sethreg(HL, GetBYTE(HL)); + break; + case 0x67: /* LD H,A */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & 0xff) | (AF & ~0xff); + break; + case 0x68: /* LD L,B */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & ~0xff) | ((BC >> 8) & 0xff); + break; + case 0x69: /* LD L,C */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & ~0xff) | (BC & 0xff); + break; + case 0x6a: /* LD L,D */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & ~0xff) | ((DE >> 8) & 0xff); + break; + case 0x6b: /* LD L,E */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & ~0xff) | (DE & 0xff); + break; + case 0x6c: /* LD L,H */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & ~0xff) | ((HL >> 8) & 0xff); + break; + case 0x6d: /* LD L,L */ + updateTStates(4); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x6e: /* LD L,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + Setlreg(HL, GetBYTE(HL)); + break; + case 0x6f: /* LD L,A */ + updateTStates(4); + sim_brk_pend = FALSE; + HL = (HL & ~0xff) | ((AF >> 8) & 0xff); + break; + case 0x70: /* LD (HL),B */ + updateTStates(7); + CheckBreakByte(HL); + PutBYTE(HL, hreg(BC)); + break; + case 0x71: /* LD (HL),C */ + updateTStates(7); + CheckBreakByte(HL); + PutBYTE(HL, lreg(BC)); + break; + case 0x72: /* LD (HL),D */ + updateTStates(7); + CheckBreakByte(HL); + PutBYTE(HL, hreg(DE)); + break; + case 0x73: /* LD (HL),E */ + updateTStates(7); + CheckBreakByte(HL); + PutBYTE(HL, lreg(DE)); + break; + case 0x74: /* LD (HL),H */ + updateTStates(7); + CheckBreakByte(HL); + PutBYTE(HL, hreg(HL)); + break; + case 0x75: /* LD (HL),L */ + updateTStates(7); + CheckBreakByte(HL); + PutBYTE(HL, lreg(HL)); + break; + case 0x76: /* HALT */ + updateTStates(4); + sim_brk_pend = FALSE; + reason = STOP_HALT; + PC--; + goto end_decode; + case 0x77: /* LD (HL),A */ + updateTStates(7); + CheckBreakByte(HL); + PutBYTE(HL, hreg(AF)); + break; + case 0x78: /* LD A,B */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & 0xff) | (BC & ~0xff); + break; + case 0x79: /* LD A,C */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & 0xff) | ((BC & 0xff) << 8); + break; + case 0x7a: /* LD A,D */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & 0xff) | (DE & ~0xff); + break; + case 0x7b: /* LD A,E */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & 0xff) | ((DE & 0xff) << 8); + break; + case 0x7c: /* LD A,H */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & 0xff) | (HL & ~0xff); + break; + case 0x7d: /* LD A,L */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = (AF & 0xff) | ((HL & 0xff) << 8); + break; + case 0x7e: /* LD A,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + Sethreg(AF, GetBYTE(HL)); + break; + case 0x7f: /* LD A,A */ + updateTStates(4); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x80: /* ADD A,B */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(BC); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x81: /* ADD A,C */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(BC); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x82: /* ADD A,D */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(DE); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x83: /* ADD A,E */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(DE); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x84: /* ADD A,H */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(HL); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x85: /* ADD A,L */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(HL); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x86: /* ADD A,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + temp = GetBYTE(HL); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x87: /* ADD A,A */ + updateTStates(4); + sim_brk_pend = FALSE; + cbits = 2 * hreg(AF); + AF = cbitsDup8Table[cbits] | (SetPVS(cbits)); + break; + case 0x88: /* ADC A,B */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(BC); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x89: /* ADC A,C */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(BC); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x8a: /* ADC A,D */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(DE); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x8b: /* ADC A,E */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(DE); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x8c: /* ADC A,H */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(HL); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x8d: /* ADC A,L */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(HL); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x8e: /* ADC A,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + temp = GetBYTE(HL); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0x8f: /* ADC A,A */ + updateTStates(4); + sim_brk_pend = FALSE; + cbits = 2 * hreg(AF) + TSTFLAG(C); + AF = cbitsDup8Table[cbits] | (SetPVS(cbits)); + break; + case 0x90: /* SUB B */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(BC); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x91: /* SUB C */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(BC); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x92: /* SUB D */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(DE); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x93: /* SUB E */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(DE); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x94: /* SUB H */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(HL); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x95: /* SUB L */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(HL); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x96: /* SUB (HL) */ + updateTStates(7); + CheckBreakByte(HL); + temp = GetBYTE(HL); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x97: /* SUB A */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = cpu_unit.flags & UNIT_CHIP ? 0x42 : 0x46; + break; + case 0x98: /* SBC A,B */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(BC); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x99: /* SBC A,C */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(BC); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x9a: /* SBC A,D */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(DE); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x9b: /* SBC A,E */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(DE); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x9c: /* SBC A,H */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(HL); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x9d: /* SBC A,L */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(HL); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x9e: /* SBC A,(HL) */ + updateTStates(7); + CheckBreakByte(HL); + temp = GetBYTE(HL); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0x9f: /* SBC A,A */ + updateTStates(4); + sim_brk_pend = FALSE; + cbits = -TSTFLAG(C); + AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPVS(cbits)); + break; + case 0xa0: /* AND B */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = andTable[((AF & BC) >> 8) & 0xff]; + break; + case 0xa1: /* AND C */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = andTable[((AF >> 8) & BC) & 0xff]; + break; + case 0xa2: /* AND D */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = andTable[((AF & DE) >> 8) & 0xff]; + break; + case 0xa3: /* AND E */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = andTable[((AF >> 8) & DE) & 0xff]; + break; + case 0xa4: /* AND H */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = andTable[((AF & HL) >> 8) & 0xff]; + break; + case 0xa5: /* AND L */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = andTable[((AF >> 8) & HL) & 0xff]; + break; + case 0xa6: /* AND (HL) */ + updateTStates(7); + CheckBreakByte(HL); + AF = andTable[((AF >> 8) & GetBYTE(HL)) & 0xff]; + break; + case 0xa7: /* AND A */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = andTable[(AF >> 8) & 0xff]; + break; + case 0xa8: /* XOR B */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF ^ BC) >> 8) & 0xff]; + break; + case 0xa9: /* XOR C */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) ^ BC) & 0xff]; + break; + case 0xaa: /* XOR D */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF ^ DE) >> 8) & 0xff]; + break; + case 0xab: /* XOR E */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) ^ DE) & 0xff]; + break; + case 0xac: /* XOR H */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF ^ HL) >> 8) & 0xff]; + break; + case 0xad: /* XOR L */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) ^ HL) & 0xff]; + break; + case 0xae: /* XOR (HL) */ + updateTStates(7); + CheckBreakByte(HL); + AF = xororTable[((AF >> 8) ^ GetBYTE(HL)) & 0xff]; + break; + case 0xaf: /* XOR A */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = 0x44; + break; + case 0xb0: /* OR B */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF | BC) >> 8) & 0xff]; + break; + case 0xb1: /* OR C */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) | BC) & 0xff]; + break; + case 0xb2: /* OR D */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF | DE) >> 8) & 0xff]; + break; + case 0xb3: /* OR E */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) | DE) & 0xff]; + break; + case 0xb4: /* OR H */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF | HL) >> 8) & 0xff]; + break; + case 0xb5: /* OR L */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) | HL) & 0xff]; + break; + case 0xb6: /* OR (HL) */ + updateTStates(7); + CheckBreakByte(HL); + AF = xororTable[((AF >> 8) | GetBYTE(HL)) & 0xff]; + break; + case 0xb7: /* OR A */ + updateTStates(4); + sim_brk_pend = FALSE; + AF = xororTable[(AF >> 8) & 0xff]; + break; + case 0xb8: /* CP B */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SetPV) | cbits2Table[cbits & 0x1ff]; + break; + case 0xb9: /* CP C */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SetPV) | cbits2Table[cbits & 0x1ff]; + break; + case 0xba: /* CP D */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SetPV) | cbits2Table[cbits & 0x1ff]; + break; + case 0xbb: /* CP E */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SetPV) | cbits2Table[cbits & 0x1ff]; + break; + case 0xbc: /* CP H */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = hreg(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SetPV) | cbits2Table[cbits & 0x1ff]; + break; + case 0xbd: /* CP L */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = lreg(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SetPV) | cbits2Table[cbits & 0x1ff]; + break; + case 0xbe: /* CP (HL) */ + updateTStates(7); + CheckBreakByte(HL); + temp = GetBYTE(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SetPV) | cbits2Table[cbits & 0x1ff]; + break; + case 0xbf: /* CP A */ + updateTStates(4); + sim_brk_pend = FALSE; + Setlreg(AF, (hreg(AF) & 0x28) | (cpu_unit.flags & UNIT_CHIP ? 0x42 : 0x46)); + break; + case 0xc0: /* RET NZ */ + if (TSTFLAG(Z)) { + sim_brk_pend = FALSE; + updateTStates(5); + } + else { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + updateTStates(11); + } + break; + case 0xc1: /* POP BC */ + updateTStates(10); + CheckBreakWord(SP); + POP(BC); + break; + case 0xc2: /* JP NZ,nnnn */ + sim_brk_pend = FALSE; + JPC(!TSTFLAG(Z)); /* also updates tStates */ + break; + case 0xc3: /* JP nnnn */ + sim_brk_pend = FALSE; + JPC(1); /* also updates tStates */ + break; + case 0xc4: /* CALL NZ,nnnn */ + CALLC(!TSTFLAG(Z)); /* also updates tStates */ + break; + case 0xc5: /* PUSH BC */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(BC); + break; + case 0xc6: /* ADD A,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + temp = RAM_pp(PC); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0xc7: /* RST 0 */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = 0; + break; + case 0xc8: /* RET Z */ + if (TSTFLAG(Z)) { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + updateTStates(11); + } + else { + sim_brk_pend = FALSE; + updateTStates(5); + } + break; + case 0xc9: /* RET */ + updateTStates(10); + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + break; + case 0xca: /* JP Z,nnnn */ + sim_brk_pend = FALSE; + JPC(TSTFLAG(Z)); /* also updates tStates */ + break; + case 0xcb: /* CB prefix */ + checkCPU8080; + adr = HL; + switch ((op = GetBYTE(PC)) & 7) { + case 0: + sim_brk_pend = tStateModifier = FALSE; + ++PC; + acu = hreg(BC); + updateTStates(8); + break; + case 1: + sim_brk_pend = tStateModifier = FALSE; + ++PC; + acu = lreg(BC); + updateTStates(8); + break; + case 2: + sim_brk_pend = tStateModifier = FALSE; + ++PC; + acu = hreg(DE); + updateTStates(8); + break; + case 3: + sim_brk_pend = tStateModifier = FALSE; + ++PC; + acu = lreg(DE); + updateTStates(8); + break; + case 4: + sim_brk_pend = tStateModifier = FALSE; + ++PC; + acu = hreg(HL); + updateTStates(8); + break; + case 5: + sim_brk_pend = tStateModifier = FALSE; + ++PC; + acu = lreg(HL); + updateTStates(8); + break; + case 6: + CheckBreakByte(adr); + ++PC; + acu = GetBYTE(adr); + tStateModifier = TRUE; + updateTStates(15); + break; + case 7: + sim_brk_pend = tStateModifier = FALSE; + ++PC; + acu = hreg(AF); + updateTStates(8); + break; + } + switch (op & 0xc0) { + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg1; + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg1; + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg1; + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg1; + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg1; + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg1; + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg1; + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg1: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + case 0x40: /* BIT */ + if (tStateModifier) { + tStates -= 3; + } + if (acu & (1 << ((op >> 3) & 7))) { + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + } + else { + AF = (AF & ~0xfe) | 0x54; + } + if ((op & 7) != 6) { + AF |= (acu & 0x28); + } + temp = acu; + break; + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + case 0: + Sethreg(BC, temp); + break; + case 1: + Setlreg(BC, temp); + break; + case 2: + Sethreg(DE, temp); + break; + case 3: + Setlreg(DE, temp); + break; + case 4: + Sethreg(HL, temp); + break; + case 5: + Setlreg(HL, temp); + break; + case 6: + PutBYTE(adr, temp); + break; + case 7: + Sethreg(AF, temp); + break; + } + break; + case 0xcc: /* CALL Z,nnnn */ + CALLC(TSTFLAG(Z)); /* also updates tStates */ + break; + case 0xcd: /* CALL nnnn */ + CALLC(1); /* also updates tStates */ + break; + case 0xce: /* ADC A,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + temp = RAM_pp(PC); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + break; + case 0xcf: /* RST 8 */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = 8; + break; + case 0xd0: /* RET NC */ + if (TSTFLAG(C)) { + sim_brk_pend = FALSE; + updateTStates(5); + } + else { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + updateTStates(11); + } + break; + case 0xd1: /* POP DE */ + updateTStates(10); + CheckBreakWord(SP); + POP(DE); + break; + case 0xd2: /* JP NC,nnnn */ + sim_brk_pend = FALSE; + JPC(!TSTFLAG(C)); /* also updates tStates */ + break; + case 0xd3: /* OUT (nn),A */ + updateTStates(11); + sim_brk_pend = FALSE; + out(RAM_pp(PC), hreg(AF)); + break; + case 0xd4: /* CALL NC,nnnn */ + CALLC(!TSTFLAG(C)); /* also updates tStates */ + break; + case 0xd5: /* PUSH DE */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(DE); + break; + case 0xd6: /* SUB nn */ + updateTStates(7); + sim_brk_pend = FALSE; + temp = RAM_pp(PC); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0xd7: /* RST 10H */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = 0x10; + break; + case 0xd8: /* RET C */ + if (TSTFLAG(C)) { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + updateTStates(11); + } + else { + sim_brk_pend = FALSE; + updateTStates(5); + } + break; + case 0xd9: /* EXX */ + updateTStates(4); + sim_brk_pend = FALSE; + checkCPU8080; + regs[regs_sel].bc = BC; + regs[regs_sel].de = DE; + regs[regs_sel].hl = HL; + regs_sel = 1 - regs_sel; + BC = regs[regs_sel].bc; + DE = regs[regs_sel].de; + HL = regs[regs_sel].hl; + break; + case 0xda: /* JP C,nnnn */ + sim_brk_pend = FALSE; + JPC(TSTFLAG(C)); /* also updates tStates */ + break; + case 0xdb: /* IN A,(nn) */ + updateTStates(11); + sim_brk_pend = FALSE; + Sethreg(AF, in(RAM_pp(PC))); + break; + case 0xdc: /* CALL C,nnnn */ + CALLC(TSTFLAG(C)); /* also updates tStates */ + break; + case 0xdd: /* DD prefix */ + checkCPU8080; + switch (op = RAM_pp(PC)) { + case 0x09: /* ADD IX,BC */ + updateTStates(15); + sim_brk_pend = FALSE; + IX &= ADDRMASK; + BC &= ADDRMASK; + sum = IX + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ BC ^ sum) >> 8]; + IX = sum; + break; + case 0x19: /* ADD IX,DE */ + updateTStates(15); + sim_brk_pend = FALSE; + IX &= ADDRMASK; + DE &= ADDRMASK; + sum = IX + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ DE ^ sum) >> 8]; + IX = sum; + break; + case 0x21: /* LD IX,nnnn */ + updateTStates(14); + sim_brk_pend = FALSE; + IX = GetWORD(PC); + PC += 2; + break; + case 0x22: /* LD (nnnn),IX */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + PutWORD(temp, IX); + PC += 2; + break; + case 0x23: /* INC IX */ + updateTStates(10); + sim_brk_pend = FALSE; + ++IX; + break; + case 0x24: /* INC IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + IX += 0x100; + AF = (AF & ~0xfe) | incZ80Table[hreg(IX)]; + break; + case 0x25: /* DEC IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + IX -= 0x100; + AF = (AF & ~0xfe) | decZ80Table[hreg(IX)]; + break; + case 0x26: /* LD IXH,nn */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IX, RAM_pp(PC)); + break; + case 0x29: /* ADD IX,IX */ + updateTStates(15); + sim_brk_pend = FALSE; + IX &= ADDRMASK; + sum = IX + IX; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + IX = sum; + break; + case 0x2a: /* LD IX,(nnnn) */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + IX = GetWORD(temp); + PC += 2; + break; + case 0x2b: /* DEC IX */ + updateTStates(10); + sim_brk_pend = FALSE; + --IX; + break; + case 0x2c: /* INC IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IX) + 1; + Setlreg(IX, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + case 0x2d: /* DEC IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IX) - 1; + Setlreg(IX, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + case 0x2e: /* LD IXL,nn */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IX, RAM_pp(PC)); + break; + case 0x34: /* INC (IX+dd) */ + updateTStates(23); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr) + 1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + case 0x35: /* DEC (IX+dd) */ + updateTStates(23); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr) - 1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + case 0x36: /* LD (IX+dd),nn */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, RAM_pp(PC)); + break; + case 0x39: /* ADD IX,SP */ + updateTStates(15); + sim_brk_pend = FALSE; + IX &= ADDRMASK; + SP &= ADDRMASK; + sum = IX + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ SP ^ sum) >> 8]; + IX = sum; + break; + case 0x44: /* LD B,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(BC, hreg(IX)); + break; + case 0x45: /* LD B,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(BC, lreg(IX)); + break; + case 0x46: /* LD B,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Sethreg(BC, GetBYTE(adr)); + break; + case 0x4c: /* LD C,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(BC, hreg(IX)); + break; + case 0x4d: /* LD C,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(BC, lreg(IX)); + break; + case 0x4e: /* LD C,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Setlreg(BC, GetBYTE(adr)); + break; + case 0x54: /* LD D,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(DE, hreg(IX)); + break; + case 0x55: /* LD D,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(DE, lreg(IX)); + break; + case 0x56: /* LD D,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Sethreg(DE, GetBYTE(adr)); + break; + case 0x5c: /* LD E,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(DE, hreg(IX)); + break; + case 0x5d: /* LD E,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(DE, lreg(IX)); + break; + case 0x5e: /* LD E,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Setlreg(DE, GetBYTE(adr)); + break; + case 0x60: /* LD IXH,B */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IX, hreg(BC)); + break; + case 0x61: /* LD IXH,C */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IX, lreg(BC)); + break; + case 0x62: /* LD IXH,D */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IX, hreg(DE)); + break; + case 0x63: /* LD IXH,E */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IX, lreg(DE)); + break; + case 0x64: /* LD IXH,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x65: /* LD IXH,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IX, lreg(IX)); + break; + case 0x66: /* LD H,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Sethreg(HL, GetBYTE(adr)); + break; + case 0x67: /* LD IXH,A */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IX, hreg(AF)); + break; + case 0x68: /* LD IXL,B */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IX, hreg(BC)); + break; + case 0x69: /* LD IXL,C */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IX, lreg(BC)); + break; + case 0x6a: /* LD IXL,D */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IX, hreg(DE)); + break; + case 0x6b: /* LD IXL,E */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IX, lreg(DE)); + break; + case 0x6c: /* LD IXL,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IX, hreg(IX)); + break; + case 0x6d: /* LD IXL,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x6e: /* LD L,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Setlreg(HL, GetBYTE(adr)); + break; + case 0x6f: /* LD IXL,A */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IX, hreg(AF)); + break; + case 0x70: /* LD (IX+dd),B */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, hreg(BC)); + break; + case 0x71: /* LD (IX+dd),C */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, lreg(BC)); + break; + case 0x72: /* LD (IX+dd),D */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, hreg(DE)); + break; + case 0x73: /* LD (IX+dd),E */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, lreg(DE)); + break; + case 0x74: /* LD (IX+dd),H */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, hreg(HL)); + break; + case 0x75: /* LD (IX+dd),L */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, lreg(HL)); + break; + case 0x77: /* LD (IX+dd),A */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, hreg(AF)); + break; + case 0x7c: /* LD A,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(AF, hreg(IX)); + break; + case 0x7d: /* LD A,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(AF, lreg(IX)); + break; + case 0x7e: /* LD A,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Sethreg(AF, GetBYTE(adr)); + break; + case 0x84: /* ADD A,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = hreg(IX); + acu = hreg(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x85: /* ADD A,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IX); + acu = hreg(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x86: /* ADD A,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x8c: /* ADC A,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = hreg(IX); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x8d: /* ADC A,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IX); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x8e: /* ADC A,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x96: /* SUB (IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu - temp; + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0x94: /* SUB IXH */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + case 0x9c: /* SBC A,IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = hreg(IX); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0x95: /* SUB IXL */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + case 0x9d: /* SBC A,IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IX); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0x9e: /* SBC A,(IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0xa4: /* AND IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = andTable[((AF & IX) >> 8) & 0xff]; + break; + case 0xa5: /* AND IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = andTable[((AF >> 8) & IX) & 0xff]; + break; + case 0xa6: /* AND (IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + AF = andTable[((AF >> 8) & GetBYTE(adr)) & 0xff]; + break; + case 0xac: /* XOR IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = xororTable[((AF ^ IX) >> 8) & 0xff]; + break; + case 0xad: /* XOR IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) ^ IX) & 0xff]; + break; + case 0xae: /* XOR (IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + AF = xororTable[((AF >> 8) ^ GetBYTE(adr)) & 0xff]; + break; + case 0xb4: /* OR IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = xororTable[((AF | IX) >> 8) & 0xff]; + break; + case 0xb5: /* OR IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) | IX) & 0xff]; + break; + case 0xb6: /* OR (IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + AF = xororTable[((AF >> 8) | GetBYTE(adr)) & 0xff]; + break; + case 0xbc: /* CP IXH */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = hreg(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0xbd: /* CP IXL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0xbe: /* CP (IX+dd) */ + updateTStates(19); + adr = IX + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0xcb: /* CB prefix */ + adr = IX + (signed char) RAM_pp(PC); + switch ((op = GetBYTE(PC)) & 7) { + case 0: + sim_brk_pend = FALSE; + ++PC; + acu = hreg(BC); + break; + case 1: + sim_brk_pend = FALSE; + ++PC; + acu = lreg(BC); + break; + case 2: + sim_brk_pend = FALSE; + ++PC; + acu = hreg(DE); + break; + case 3: + sim_brk_pend = FALSE; + ++PC; + acu = lreg(DE); + break; + case 4: + sim_brk_pend = FALSE; + ++PC; + acu = hreg(HL); + break; + case 5: + sim_brk_pend = FALSE; + ++PC; + acu = lreg(HL); + break; + case 6: + CheckBreakByte(adr); + ++PC; + acu = GetBYTE(adr); + break; + case 7: + sim_brk_pend = FALSE; + ++PC; + acu = hreg(AF); + break; + } + switch (op & 0xc0) { + case 0x00: /* shift/rotate */ + updateTStates(23); + switch (op & 0x38) { + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg2; + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg2; + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg2; + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg2; + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg2; + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg2; + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg2; + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg2: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + case 0x40: /* BIT */ + updateTStates(20); + if (acu & (1 << ((op >> 3) & 7))) { + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + } + else { + AF = (AF & ~0xfe) | 0x54; + } + if ((op & 7) != 6) { + AF |= (acu & 0x28); + } + temp = acu; + break; + case 0x80: /* RES */ + updateTStates(23); + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + case 0xc0: /* SET */ + updateTStates(23); + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + case 0: + Sethreg(BC, temp); + break; + case 1: + Setlreg(BC, temp); + break; + case 2: + Sethreg(DE, temp); + break; + case 3: + Setlreg(DE, temp); + break; + case 4: + Sethreg(HL, temp); + break; + case 5: + Setlreg(HL, temp); + break; + case 6: + PutBYTE(adr, temp); + break; + case 7: + Sethreg(AF, temp); + break; + } + break; + case 0xe1: /* POP IX */ + updateTStates(14); + CheckBreakWord(SP); + POP(IX); + break; + case 0xe3: /* EX (SP),IX */ + updateTStates(23); + CheckBreakWord(SP); + temp = IX; + POP(IX); + PUSH(temp); + break; + case 0xe5: /* PUSH IX */ + updateTStates(15); + CheckBreakWord(SP - 2); + PUSH(IX); + break; + case 0xe9: /* JP (IX) */ + updateTStates(8); + sim_brk_pend = FALSE; + PCQ_ENTRY(PC - 2); + PC = IX; + break; + case 0xf9: /* LD SP,IX */ + updateTStates(10); + sim_brk_pend = FALSE; + SP = IX; + break; + default: /* ignore DD */ + sim_brk_pend = FALSE; + checkCPUZ80; + PC--; + } + break; + case 0xde: /* SBC A,nn */ + updateTStates(7); + sim_brk_pend = FALSE; + temp = RAM_pp(PC); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + break; + case 0xdf: /* RST 18H */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = 0x18; + break; + case 0xe0: /* RET PO */ + if (TSTFLAG(P)) { + sim_brk_pend = FALSE; + updateTStates(5); + } + else { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + updateTStates(11); + } + break; + case 0xe1: /* POP HL */ + updateTStates(10); + CheckBreakWord(SP); + POP(HL); + break; + case 0xe2: /* JP PO,nnnn */ + sim_brk_pend = FALSE; + JPC(!TSTFLAG(P)); /* also updates tStates */ + break; + case 0xe3: /* EX (SP),HL */ + updateTStates(19); + CheckBreakWord(SP); + temp = HL; + POP(HL); + PUSH(temp); + break; + case 0xe4: /* CALL PO,nnnn */ + CALLC(!TSTFLAG(P)); /* also updates tStates */ + break; + case 0xe5: /* PUSH HL */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(HL); + break; + case 0xe6: /* AND nn */ + updateTStates(7); + sim_brk_pend = FALSE; + AF = andTable[((AF >> 8) & RAM_pp(PC)) & 0xff]; + break; + case 0xe7: /* RST 20H */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = 0x20; + break; + case 0xe8: /* RET PE */ + if (TSTFLAG(P)) { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + updateTStates(11); + } + else { + sim_brk_pend = FALSE; + updateTStates(5); + } + break; + case 0xe9: /* JP (HL) */ + updateTStates(4); + sim_brk_pend = FALSE; + PCQ_ENTRY(PC - 1); + PC = HL; + break; + case 0xea: /* JP PE,nnnn */ + sim_brk_pend = FALSE; + JPC(TSTFLAG(P)); /* also updates tStates */ + break; + case 0xeb: /* EX DE,HL */ + updateTStates(4); + sim_brk_pend = FALSE; + temp = HL; + HL = DE; + DE = temp; + break; + case 0xec: /* CALL PE,nnnn */ + CALLC(TSTFLAG(P)); /* also updates tStates */ + break; + case 0xed: /* ED prefix */ + checkCPU8080; + switch (op = RAM_pp(PC)) { + case 0x40: /* IN B,(C) */ + updateTStates(12); + sim_brk_pend = FALSE; + temp = in(lreg(BC)); + Sethreg(BC, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + case 0x41: /* OUT (C),B */ + updateTStates(12); + sim_brk_pend = FALSE; + out(lreg(BC), hreg(BC)); + break; + case 0x42: /* SBC HL,BC */ + updateTStates(15); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL - BC - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ BC ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + case 0x43: /* LD (nnnn),BC */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + PutWORD(temp, BC); + PC += 2; + break; + case 0x44: /* NEG */ + case 0x4C: /* NEG, unofficial */ + case 0x54: /* NEG, unofficial */ + case 0x5C: /* NEG, unofficial */ + case 0x64: /* NEG, unofficial */ + case 0x6C: /* NEG, unofficial */ + case 0x74: /* NEG, unofficial */ + case 0x7C: /* NEG, unofficial */ + updateTStates(8); + sim_brk_pend = FALSE; + temp = hreg(AF); + AF = ((~(AF & 0xff00) + 1) & 0xff00); /* AF = (-(AF & 0xff00) & 0xff00); */ + AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | negTable[temp]; + break; + case 0x45: /* RETN */ + case 0x55: /* RETN, unofficial */ + case 0x5D: /* RETN, unofficial */ + case 0x65: /* RETN, unofficial */ + case 0x6D: /* RETN, unofficial */ + case 0x75: /* RETN, unofficial */ + case 0x7D: /* RETN, unofficial */ + updateTStates(14); + IFF |= IFF >> 1; + CheckBreakWord(SP); + PCQ_ENTRY(PC - 2); + POP(PC); + break; + case 0x46: /* IM 0 */ + updateTStates(8); + sim_brk_pend = FALSE; + /* interrupt mode 0 */ + break; + case 0x47: /* LD I,A */ + updateTStates(9); + sim_brk_pend = FALSE; + ir = (ir & 0xff) | (AF & ~0xff); + break; + case 0x48: /* IN C,(C) */ + updateTStates(12); + sim_brk_pend = FALSE; + temp = in(lreg(BC)); + Setlreg(BC, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + case 0x49: /* OUT (C),C */ + updateTStates(12); + sim_brk_pend = FALSE; + out(lreg(BC), lreg(BC)); + break; + case 0x4a: /* ADC HL,BC */ + updateTStates(15); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL + BC + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ BC ^ sum) >> 8]; + HL = sum; + break; + case 0x4b: /* LD BC,(nnnn) */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + BC = GetWORD(temp); + PC += 2; + break; + case 0x4d: /* RETI */ + updateTStates(14); + IFF |= IFF >> 1; + CheckBreakWord(SP); + PCQ_ENTRY(PC - 2); + POP(PC); + break; + case 0x4f: /* LD R,A */ + updateTStates(9); + sim_brk_pend = FALSE; + ir = (ir & ~0xff) | ((AF >> 8) & 0xff); + break; + case 0x50: /* IN D,(C) */ + updateTStates(12); + sim_brk_pend = FALSE; + temp = in(lreg(BC)); + Sethreg(DE, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + case 0x51: /* OUT (C),D */ + updateTStates(12); + sim_brk_pend = FALSE; + out(lreg(BC), hreg(DE)); + break; + case 0x52: /* SBC HL,DE */ + updateTStates(15); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL - DE - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ DE ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + case 0x53: /* LD (nnnn),DE */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + PutWORD(temp, DE); + PC += 2; + break; + case 0x56: /* IM 1 */ + updateTStates(8); + sim_brk_pend = FALSE; + /* interrupt mode 1 */ + break; + case 0x57: /* LD A,I */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = (AF & 0x29) | (ir & ~0xff) | ((ir >> 8) & 0x80) | (((ir & ~0xff) == 0) << 6) | ((IFF & 2) << 1); + break; + case 0x58: /* IN E,(C) */ + updateTStates(12); + sim_brk_pend = FALSE; + temp = in(lreg(BC)); + Setlreg(DE, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + case 0x59: /* OUT (C),E */ + updateTStates(12); + sim_brk_pend = FALSE; + out(lreg(BC), lreg(DE)); + break; + case 0x5a: /* ADC HL,DE */ + updateTStates(15); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL + DE + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ DE ^ sum) >> 8]; + HL = sum; + break; + case 0x5b: /* LD DE,(nnnn) */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + DE = GetWORD(temp); + PC += 2; + break; + case 0x5e: /* IM 2 */ + updateTStates(8); + sim_brk_pend = FALSE; + /* interrupt mode 2 */ + break; + case 0x5f: /* LD A,R */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = (AF & 0x29) | ((ir & 0xff) << 8) | (ir & 0x80) | + (((ir & 0xff) == 0) << 6) | ((IFF & 2) << 1); + break; + case 0x60: /* IN H,(C) */ + updateTStates(12); + sim_brk_pend = FALSE; + temp = in(lreg(BC)); + Sethreg(HL, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + case 0x61: /* OUT (C),H */ + updateTStates(12); + sim_brk_pend = FALSE; + out(lreg(BC), hreg(HL)); + break; + case 0x62: /* SBC HL,HL */ + updateTStates(15); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + sum = HL - HL - TSTFLAG(C); + AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80DupTable[(sum >> 8) & 0x1ff]; + HL = sum; + break; + case 0x63: /* LD (nnnn),HL */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + PutWORD(temp, HL); + PC += 2; + break; + case 0x67: /* RRD */ + updateTStates(18); + sim_brk_pend = FALSE; + temp = GetBYTE(HL); + acu = hreg(AF); + PutBYTE(HL, hdig(temp) | (ldig(acu) << 4)); + AF = rrdrldTable[(acu & 0xf0) | ldig(temp)] | (AF & 1); + break; + case 0x68: /* IN L,(C) */ + updateTStates(12); + sim_brk_pend = FALSE; + temp = in(lreg(BC)); + Setlreg(HL, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + case 0x69: /* OUT (C),L */ + updateTStates(12); + sim_brk_pend = FALSE; + out(lreg(BC), lreg(HL)); + break; + case 0x6a: /* ADC HL,HL */ + updateTStates(15); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + sum = HL + HL + TSTFLAG(C); + AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80DupTable[sum >> 8]; + HL = sum; + break; + case 0x6b: /* LD HL,(nnnn) */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + HL = GetWORD(temp); + PC += 2; + break; + case 0x6f: /* RLD */ + updateTStates(18); + sim_brk_pend = FALSE; + temp = GetBYTE(HL); + acu = hreg(AF); + PutBYTE(HL, (ldig(temp) << 4) | ldig(acu)); + AF = rrdrldTable[(acu & 0xf0) | hdig(temp)] | (AF & 1); + break; + case 0x70: /* IN (C) */ + updateTStates(12); + sim_brk_pend = FALSE; + temp = in(lreg(BC)); + Setlreg(temp, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + case 0x71: /* OUT (C),0 */ + updateTStates(12); + sim_brk_pend = FALSE; + out(lreg(BC), 0); + break; + case 0x72: /* SBC HL,SP */ + updateTStates(15); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL - SP - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ SP ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + case 0x73: /* LD (nnnn),SP */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + PutWORD(temp, SP); + PC += 2; + break; + case 0x78: /* IN A,(C) */ + updateTStates(12); + sim_brk_pend = FALSE; + temp = in(lreg(BC)); + Sethreg(AF, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + case 0x79: /* OUT (C),A */ + updateTStates(12); + sim_brk_pend = FALSE; + out(lreg(BC), hreg(AF)); + break; + case 0x7a: /* ADC HL,SP */ + updateTStates(15); + sim_brk_pend = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL + SP + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ SP ^ sum) >> 8]; + HL = sum; + break; + case 0x7b: /* LD SP,(nnnn) */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + SP = GetWORD(temp); + PC += 2; + break; + case 0xa0: /* LDI */ + updateTStates(16); + CheckBreakTwoBytes(HL, DE); + acu = RAM_pp(HL); + PutBYTE_pp(DE, acu); + acu += hreg(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & ADDRMASK) != 0) << 2); + break; + case 0xa1: /* CPI */ + updateTStates(16); + CheckBreakByte(HL); + acu = hreg(AF); + temp = RAM_pp(HL); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | + ((sum - ((cbits >> 4) & 1)) & 8) | + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) { + AF &= ~8; + } + break; + case 0xa2: /* INI */ + updateTStates(16); + CheckBreakByte(HL); + PutBYTE(HL, in(lreg(BC))); + ++HL; + SETFLAG(N, 1); + SETFLAG(P, (--BC & ADDRMASK) != 0); + break; + case 0xa3: /* OUTI */ + updateTStates(16); + CheckBreakByte(HL); + out(lreg(BC), GetBYTE(HL)); + ++HL; + SETFLAG(N, 1); + Sethreg(BC, lreg(BC) - 1); + SETFLAG(Z, lreg(BC) == 0); + break; + case 0xa8: /* LDD */ + updateTStates(16); + CheckBreakTwoBytes(HL, DE); + acu = RAM_mm(HL); + PutBYTE_mm(DE, acu); + acu += hreg(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & ADDRMASK) != 0) << 2); + break; + case 0xa9: /* CPD */ + updateTStates(16); + CheckBreakByte(HL); + acu = hreg(AF); + temp = RAM_mm(HL); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | + ((sum - ((cbits >> 4) & 1)) & 8) | + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) { + AF &= ~8; + } + break; + case 0xaa: /* IND */ + updateTStates(16); + CheckBreakByte(HL); + PutBYTE(HL, in(lreg(BC))); + --HL; + SETFLAG(N, 1); + Sethreg(BC, lreg(BC) - 1); + SETFLAG(Z, lreg(BC) == 0); + break; + case 0xab: /* OUTD */ + updateTStates(16); + CheckBreakByte(HL); + out(lreg(BC), GetBYTE(HL)); + --HL; + SETFLAG(N, 1); + Sethreg(BC, lreg(BC) - 1); + SETFLAG(Z, lreg(BC) == 0); + break; + case 0xb0: /* LDIR */ + tStates -= 5; + acu = hreg(AF); + BC &= ADDRMASK; + do { + updateTStates(21); + CheckBreakTwoBytes(HL, DE); + acu = RAM_pp(HL); + PutBYTE_pp(DE, acu); + } while (--BC); + acu += hreg(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + case 0xb1: /* CPIR */ + tStates -= 5; + acu = hreg(AF); + BC &= ADDRMASK; + do { + updateTStates(21); + CheckBreakByte(HL); + temp = RAM_pp(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) { + AF &= ~8; + } + break; + case 0xb2: /* INIR */ + tStates -= 5; + temp = hreg(BC); + do { + updateTStates(21); + CheckBreakByte(HL); + PutBYTE(HL, in(lreg(BC))); + ++HL; + } while (--temp); + Sethreg(BC, 0); + SETFLAG(N, 1); + SETFLAG(Z, 1); + break; + case 0xb3: /* OTIR */ + tStates -= 5; + temp = hreg(BC); + do { + updateTStates(21); + CheckBreakByte(HL); + out(lreg(BC), GetBYTE(HL)); + ++HL; + } while (--temp); + Sethreg(BC, 0); + SETFLAG(N, 1); + SETFLAG(Z, 1); + break; + case 0xb8: /* LDDR */ + tStates -= 5; + BC &= ADDRMASK; + do { + updateTStates(21); + CheckBreakTwoBytes(HL, DE); + acu = RAM_mm(HL); + PutBYTE_mm(DE, acu); + } while (--BC); + acu += hreg(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + case 0xb9: /* CPDR */ + tStates -= 5; + acu = hreg(AF); + BC &= ADDRMASK; + do { + updateTStates(21); + CheckBreakByte(HL); + temp = RAM_mm(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) { + AF &= ~8; + } + break; + case 0xba: /* INDR */ + tStates -= 5; + temp = hreg(BC); + do { + updateTStates(21); + CheckBreakByte(HL); + PutBYTE(HL, in(lreg(BC))); + --HL; + } while (--temp); + Sethreg(BC, 0); + SETFLAG(N, 1); + SETFLAG(Z, 1); + break; + case 0xbb: /* OTDR */ + tStates -= 5; + temp = hreg(BC); + do { + updateTStates(21); + CheckBreakByte(HL); + out(lreg(BC), GetBYTE(HL)); + --HL; + } while (--temp); + Sethreg(BC, 0); + SETFLAG(N, 1); + SETFLAG(Z, 1); + break; + default: /* ignore ED and following byte */ + sim_brk_pend = FALSE; + checkCPUZ80; + } + break; + case 0xee: /* XOR nn */ + updateTStates(7); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) ^ RAM_pp(PC)) & 0xff]; + break; + case 0xef: /* RST 28H */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = 0x28; + break; + case 0xf0: /* RET P */ + if (TSTFLAG(S)) { + sim_brk_pend = FALSE; + updateTStates(5); + } + else { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + updateTStates(11); + } + break; + case 0xf1: /* POP AF */ + updateTStates(10); + CheckBreakWord(SP); + POP(AF); + break; + case 0xf2: /* JP P,nnnn */ + sim_brk_pend = FALSE; + JPC(!TSTFLAG(S)); /* also updates tStates */ + break; + case 0xf3: /* DI */ + updateTStates(4); + sim_brk_pend = FALSE; + IFF = 0; + break; + case 0xf4: /* CALL P,nnnn */ + CALLC(!TSTFLAG(S)); /* also updates tStates */ + break; + case 0xf5: /* PUSH AF */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(AF); + break; + case 0xf6: /* OR nn */ + updateTStates(7); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) | RAM_pp(PC)) & 0xff]; + break; + case 0xf7: /* RST 30H */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = 0x30; + break; + case 0xf8: /* RET M */ + if (TSTFLAG(S)) { + CheckBreakWord(SP); + PCQ_ENTRY(PC - 1); + POP(PC); + updateTStates(11); + } + else { + sim_brk_pend = FALSE; + updateTStates(5); + } + break; + case 0xf9: /* LD SP,HL */ + updateTStates(6); + sim_brk_pend = FALSE; + SP = HL; + break; + case 0xfa: /* JP M,nnnn */ + sim_brk_pend = FALSE; + JPC(TSTFLAG(S)); /* also updates tStates */ + break; + case 0xfb: /* EI */ + updateTStates(4); + sim_brk_pend = FALSE; + IFF = 3; + break; + case 0xfc: /* CALL M,nnnn */ + CALLC(TSTFLAG(S)); /* also updates tStates */ + break; + case 0xfd: /* FD prefix */ + checkCPU8080; + switch (op = RAM_pp(PC)) { + case 0x09: /* ADD IY,BC */ + updateTStates(15); + sim_brk_pend = FALSE; + IY &= ADDRMASK; + BC &= ADDRMASK; + sum = IY + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ BC ^ sum) >> 8]; + IY = sum; + break; + case 0x19: /* ADD IY,DE */ + updateTStates(15); + sim_brk_pend = FALSE; + IY &= ADDRMASK; + DE &= ADDRMASK; + sum = IY + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ DE ^ sum) >> 8]; + IY = sum; + break; + case 0x21: /* LD IY,nnnn */ + updateTStates(14); + sim_brk_pend = FALSE; + IY = GetWORD(PC); + PC += 2; + break; + case 0x22: /* LD (nnnn),IY */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + PutWORD(temp, IY); + PC += 2; + break; + case 0x23: /* INC IY */ + updateTStates(10); + sim_brk_pend = FALSE; + ++IY; + break; + case 0x24: /* INC IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + IY += 0x100; + AF = (AF & ~0xfe) | incZ80Table[hreg(IY)]; + break; + case 0x25: /* DEC IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + IY -= 0x100; + AF = (AF & ~0xfe) | decZ80Table[hreg(IY)]; + break; + case 0x26: /* LD IYH,nn */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IY, RAM_pp(PC)); + break; + case 0x29: /* ADD IY,IY */ + updateTStates(15); + sim_brk_pend = FALSE; + IY &= ADDRMASK; + sum = IY + IY; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + IY = sum; + break; + case 0x2a: /* LD IY,(nnnn) */ + updateTStates(20); + temp = GetWORD(PC); + CheckBreakWord(temp); + IY = GetWORD(temp); + PC += 2; + break; + case 0x2b: /* DEC IY */ + updateTStates(10); + sim_brk_pend = FALSE; + --IY; + break; + case 0x2c: /* INC IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IY) + 1; + Setlreg(IY, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + case 0x2d: /* DEC IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IY) - 1; + Setlreg(IY, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + case 0x2e: /* LD IYL,nn */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IY, RAM_pp(PC)); + break; + case 0x34: /* INC (IY+dd) */ + updateTStates(23); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr) + 1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + case 0x35: /* DEC (IY+dd) */ + updateTStates(23); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr) - 1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + case 0x36: /* LD (IY+dd),nn */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, RAM_pp(PC)); + break; + case 0x39: /* ADD IY,SP */ + updateTStates(15); + sim_brk_pend = FALSE; + IY &= ADDRMASK; + SP &= ADDRMASK; + sum = IY + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ SP ^ sum) >> 8]; + IY = sum; + break; + case 0x44: /* LD B,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(BC, hreg(IY)); + break; + case 0x45: /* LD B,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(BC, lreg(IY)); + break; + case 0x46: /* LD B,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Sethreg(BC, GetBYTE(adr)); + break; + case 0x4c: /* LD C,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(BC, hreg(IY)); + break; + case 0x4d: /* LD C,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(BC, lreg(IY)); + break; + case 0x4e: /* LD C,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Setlreg(BC, GetBYTE(adr)); + break; + case 0x54: /* LD D,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(DE, hreg(IY)); + break; + case 0x55: /* LD D,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(DE, lreg(IY)); + break; + case 0x56: /* LD D,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Sethreg(DE, GetBYTE(adr)); + break; + case 0x5c: /* LD E,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(DE, hreg(IY)); + break; + case 0x5d: /* LD E,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(DE, lreg(IY)); + break; + case 0x5e: /* LD E,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Setlreg(DE, GetBYTE(adr)); + break; + case 0x60: /* LD IYH,B */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IY, hreg(BC)); + break; + case 0x61: /* LD IYH,C */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IY, lreg(BC)); + break; + case 0x62: /* LD IYH,D */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IY, hreg(DE)); + break; + case 0x63: /* LD IYH,E */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IY, lreg(DE)); + break; + case 0x64: /* LD IYH,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x65: /* LD IYH,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IY, lreg(IY)); + break; + case 0x66: /* LD H,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Sethreg(HL, GetBYTE(adr)); + break; + case 0x67: /* LD IYH,A */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(IY, hreg(AF)); + break; + case 0x68: /* LD IYL,B */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IY, hreg(BC)); + break; + case 0x69: /* LD IYL,C */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IY, lreg(BC)); + break; + case 0x6a: /* LD IYL,D */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IY, hreg(DE)); + break; + case 0x6b: /* LD IYL,E */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IY, lreg(DE)); + break; + case 0x6c: /* LD IYL,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IY, hreg(IY)); + break; + case 0x6d: /* LD IYL,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; /* nop */ + break; + case 0x6e: /* LD L,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Setlreg(HL, GetBYTE(adr)); + break; + case 0x6f: /* LD IYL,A */ + updateTStates(9); + sim_brk_pend = FALSE; + Setlreg(IY, hreg(AF)); + break; + case 0x70: /* LD (IY+dd),B */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, hreg(BC)); + break; + case 0x71: /* LD (IY+dd),C */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, lreg(BC)); + break; + case 0x72: /* LD (IY+dd),D */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, hreg(DE)); + break; + case 0x73: /* LD (IY+dd),E */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, lreg(DE)); + break; + case 0x74: /* LD (IY+dd),H */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, hreg(HL)); + break; + case 0x75: /* LD (IY+dd),L */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, lreg(HL)); + break; + case 0x77: /* LD (IY+dd),A */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + PutBYTE(adr, hreg(AF)); + break; + case 0x7c: /* LD A,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(AF, hreg(IY)); + break; + case 0x7d: /* LD A,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + Sethreg(AF, lreg(IY)); + break; + case 0x7e: /* LD A,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + Sethreg(AF, GetBYTE(adr)); + break; + case 0x84: /* ADD A,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = hreg(IY); + acu = hreg(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x85: /* ADD A,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IY); + acu = hreg(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x86: /* ADD A,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x8c: /* ADC A,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = hreg(IY); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x8d: /* ADC A,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IY); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x8e: /* ADC A,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + case 0x96: /* SUB (IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu - temp; + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0x94: /* SUB IYH */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + case 0x9c: /* SBC A,IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = hreg(IY); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0x95: /* SUB IYL */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + case 0x9d: /* SBC A,IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IY); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0x9e: /* SBC A,(IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0xa4: /* AND IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = andTable[((AF & IY) >> 8) & 0xff]; + break; + case 0xa5: /* AND IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = andTable[((AF >> 8) & IY) & 0xff]; + break; + case 0xa6: /* AND (IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + AF = andTable[((AF >> 8) & GetBYTE(adr)) & 0xff]; + break; + case 0xac: /* XOR IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = xororTable[((AF ^ IY) >> 8) & 0xff]; + break; + case 0xad: /* XOR IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) ^ IY) & 0xff]; + break; + case 0xae: /* XOR (IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + AF = xororTable[((AF >> 8) ^ GetBYTE(adr)) & 0xff]; + break; + case 0xb4: /* OR IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = xororTable[((AF | IY) >> 8) & 0xff]; + break; + case 0xb5: /* OR IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + AF = xororTable[((AF >> 8) | IY) & 0xff]; + break; + case 0xb6: /* OR (IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + AF = xororTable[((AF >> 8) | GetBYTE(adr)) & 0xff]; + break; + case 0xbc: /* CP IYH */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = hreg(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0xbd: /* CP IYL */ + updateTStates(9); + sim_brk_pend = FALSE; + temp = lreg(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0xbe: /* CP (IY+dd) */ + updateTStates(19); + adr = IY + (signed char) RAM_pp(PC); + CheckBreakByte(adr); + temp = GetBYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + case 0xcb: /* CB prefix */ + adr = IY + (signed char) RAM_pp(PC); + switch ((op = GetBYTE(PC)) & 7) { + case 0: + sim_brk_pend = FALSE; + ++PC; + acu = hreg(BC); + break; + case 1: + sim_brk_pend = FALSE; + ++PC; + acu = lreg(BC); + break; + case 2: + sim_brk_pend = FALSE; + ++PC; + acu = hreg(DE); + break; + case 3: + sim_brk_pend = FALSE; + ++PC; + acu = lreg(DE); + break; + case 4: + sim_brk_pend = FALSE; + ++PC; + acu = hreg(HL); + break; + case 5: + sim_brk_pend = FALSE; + ++PC; + acu = lreg(HL); + break; + case 6: + CheckBreakByte(adr); + ++PC; + acu = GetBYTE(adr); + break; + case 7: + sim_brk_pend = FALSE; + ++PC; + acu = hreg(AF); + break; + } + switch (op & 0xc0) { + case 0x00: /* shift/rotate */ + updateTStates(23); + switch (op & 0x38) { + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg3; + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg3; + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg3; + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg3; + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg3; + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg3; + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg3; + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg3: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + case 0x40: /* BIT */ + updateTStates(20); + if (acu & (1 << ((op >> 3) & 7))) { + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + } + else { + AF = (AF & ~0xfe) | 0x54; + } + if ((op & 7) != 6) { + AF |= (acu & 0x28); + } + temp = acu; + break; + case 0x80: /* RES */ + updateTStates(23); + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + case 0xc0: /* SET */ + updateTStates(23); + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + case 0: + Sethreg(BC, temp); + break; + case 1: + Setlreg(BC, temp); + break; + case 2: + Sethreg(DE, temp); + break; + case 3: + Setlreg(DE, temp); + break; + case 4: + Sethreg(HL, temp); + break; + case 5: + Setlreg(HL, temp); + break; + case 6: + PutBYTE(adr, temp); + break; + case 7: + Sethreg(AF, temp); + break; + } + break; + case 0xe1: /* POP IY */ + updateTStates(14); + CheckBreakWord(SP); + POP(IY); + break; + case 0xe3: /* EX (SP),IY */ + updateTStates(23); + CheckBreakWord(SP); + temp = IY; + POP(IY); + PUSH(temp); + break; + case 0xe5: /* PUSH IY */ + updateTStates(15); + CheckBreakWord(SP - 2); + PUSH(IY); + break; + case 0xe9: /* JP (IY) */ + updateTStates(8); + sim_brk_pend = FALSE; + PCQ_ENTRY(PC - 2); + PC = IY; + break; + case 0xf9: /* LD SP,IY */ + updateTStates(10); + sim_brk_pend = FALSE; + SP = IY; + break; + default: /* ignore FD */ + sim_brk_pend = FALSE; + checkCPUZ80; + PC--; + } + break; + case 0xfe: /* CP nn */ + updateTStates(7); + sim_brk_pend = FALSE; + temp = RAM_pp(PC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SetPV) | cbits2Table[cbits & 0x1ff]; + break; + case 0xff: /* RST 38H */ + updateTStates(11); + CheckBreakWord(SP - 2); + PUSH(PC); + PCQ_ENTRY(PC - 1); + PC = 0x38; + } + } + end_decode: + pc = PC; + af[af_sel] = AF; + regs[regs_sel].bc = BC; + regs[regs_sel].de = DE; + regs[regs_sel].hl = HL; + ix = IX; + iy = IY; + sp = SP; + + /* simulation halted */ + saved_PC = ((reason == STOP_OPCODE) || (reason == STOP_MEM)) ? PCX : pc; + pcq_r -> qptr = pcq_p; /* update pc q ptr */ + AF_S = af[af_sel]; + BC_S = regs[regs_sel].bc; + DE_S = regs[regs_sel].de; + HL_S = regs[regs_sel].hl; + IX_S = ix; + IY_S = iy; + SP_S = sp; + AF1_S = af[1 - af_sel]; + BC1_S = regs[1 - regs_sel].bc; + DE1_S = regs[1 - regs_sel].de; + HL1_S = regs[1 - regs_sel].hl; + IFF_S = IFF; + IR_S = ir; + executedTStates = tStates; + return reason; +} + +static void reset_memory(void) { + uint32 i, j; + checkROMBoundaries(); + if (cpu_unit.flags & UNIT_BANKED) { + for (i = 0; i < MAXMEMSIZE; i++) { + for (j = 0; j < MAXBANKS; j++) { + resetCell(i, j); + } + } + } + else if (cpu_unit.flags & UNIT_ROM) { + for (i = 0; i < ROMLow; i++) { + resetCell(i, 0); + } + for (i = ROMHigh + 1; i < MAXMEMSIZE; i++) { + resetCell(i, 0); + } + } + else { + for (i = 0; i < MAXMEMSIZE; i++) { + resetCell(i, 0); + } + } + if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { + install_bootrom(); + } + isProtected = FALSE; +} + +void printROMMessage(const uint32 cntROM) { + if (cntROM) { + printf("Warning: %d bytes written to ROM [%04X - %04X].\n", cntROM, ROMLow, ROMHigh); + } +} + +/* reset routine */ + +t_stat cpu_reset(DEVICE *dptr) { + extern int32 sim_brk_types, sim_brk_dflt; /* breakpoint info */ + int32 i; + AF_S = AF1_S = 0; + af_sel = 0; + BC_S = DE_S = HL_S = 0; + regs_sel = 0; + BC1_S = DE1_S = HL1_S = 0; + IR_S = IX_S = IY_S = SP_S = 0; + IFF_S = 3; + setBankSelect(0); + reset_memory(); + sim_brk_types = (SWMASK('E') | SWMASK('M')); + sim_brk_dflt = SWMASK('E'); + for (i = 0; i < PCQ_SIZE; i++) { + pcq[i] = 0; + } + pcq_p = 0; + pcq_r = find_reg("PCQ", NULL, dptr); + if (pcq_r) { + pcq_r -> qptr = 0; + } + else { + return SCPE_IERR; + } + return SCPE_OK; +} + +static void checkROMBoundaries(void) { + uint32 temp; + if (ROMLow > ROMHigh) { + printf("ROMLOW [%04X] must be less than or equal to ROMHIGH [%04X]. Values exchanged.\n", + ROMLow, ROMHigh); + temp = ROMLow; + ROMLow = ROMHigh; + ROMHigh = temp; + } + if (cpu_unit.flags & UNIT_ALTAIRROM) { + if (defaultROMLow < ROMLow) { + printf("ROMLOW [%04X] reset to %04X since Altair ROM was desired.\n", ROMLow, defaultROMLow); + ROMLow = defaultROMLow; + } + if (ROMHigh < defaultROMHigh) { + printf("ROMHIGH [%04X] reset to %04X since Altair ROM was desired.\n", ROMHigh, defaultROMHigh); + ROMHigh = defaultROMHigh; + } + } +} + +#if !defined(ALTAIROPT) +static t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc) { + checkROMBoundaries(); + return SCPE_OK; +} + +static t_stat cpu_set_norom(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (cpu_unit.flags & UNIT_ALTAIRROM) { + printf("\"SET CPU NOALTAIRROM\" also executed.\n"); + cpu_unit.flags &= ~UNIT_ALTAIRROM; + } + return SCPE_OK; +} + +static t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc) { + install_bootrom(); + if (ROMLow != defaultROMLow) { + printf("\"D ROMLOW %04X\" also executed.\n", defaultROMLow); + ROMLow = defaultROMLow; + } + if (ROMHigh != defaultROMHigh) { + printf("\"D ROMHIGH %04X\" also executed.\n", defaultROMHigh); + ROMHigh = defaultROMHigh; + } + if (!(cpu_unit.flags & UNIT_ROM)) { + printf("\"SET CPU ROM\" also executed.\n"); + cpu_unit.flags |= UNIT_ROM; + } + return SCPE_OK; +} + +static t_stat cpu_set_warnrom(UNIT *uptr, int32 value, char *cptr, void *desc) { + if ((!(cpu_unit.flags & UNIT_ROM)) && (MEMSIZE >= 64*KB)) { + printf("CPU has currently no ROM - no warning to be expected.\n"); + } + return SCPE_OK; +} + +static t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (common > defaultROMLow) { + printf("Warning: COMMON [%04X] must not be greater than %04X. Reset to %04X.\n", + common, defaultROMLow, defaultROMLow); + common = defaultROMLow; + } + if (MEMSIZE != (MAXBANKS * MAXMEMSIZE)) { + previousCapacity = MEMSIZE; + } + MEMSIZE = MAXBANKS * MAXMEMSIZE; + cpu_dev.awidth = 16 + MAXBANKSLOG2; + return SCPE_OK; +} + +static t_stat cpu_set_nonbanked(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (MEMSIZE == (MAXBANKS * MAXMEMSIZE)) { + MEMSIZE = previousCapacity ? previousCapacity : 64*KB; + } + cpu_dev.awidth = 16; + return SCPE_OK; +} +#endif + +static t_stat cpu_set_size(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (cpu_unit.flags & UNIT_BANKED) { + printf("\"SET CPU NONBANKED\" also executed.\n"); + cpu_unit.flags &= ~UNIT_BANKED; + } + MEMSIZE = value; + cpu_dev.awidth = 16; + reset_memory(); + return SCPE_OK; +} + +/* This is the binary loader. The input file is considered to be + a string of literal bytes with no format special format. The + load starts at the current value of the PC. ROM/NOROM and + ALTAIRROM/NOALTAIRROM settings are ignored. +*/ + +int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { + int32 i, addr = 0, cnt = 0, org, cntROM = 0, cntNonExist = 0; + t_addr j, lo, hi; + char *result; + t_stat status; + if (flag) { + result = get_range(NULL, cptr, &lo, &hi, 16, ADDRMASK, 0); + if (result == NULL) { + return SCPE_ARG; + } + for (j = lo; j <= hi; j++) { + if (putc(GetBYTE(j), fileref) == EOF) { + return SCPE_IOERR; + } + } + printf("%d byte%s dumped [%x - %x].\n", hi + 1 - lo, hi == lo ? "" : "s", lo, hi); + } + else { + if (*cptr == 0) { + addr = saved_PC; + } + else { + addr = get_uint(cptr, 16, ADDRMASK, &status); + if (status != SCPE_OK) { + return status; + } + } + org = addr; + while ((addr < MAXMEMSIZE) && ((i = getc(fileref)) != EOF)) { + PutBYTEForced(addr, i); + if (addressIsInROM(addr)) { + cntROM++; + } + if (!addressExists(addr)) { + cntNonExist++; + } + addr++; + cnt++; + } /* end while */ + printf("%d bytes [%d page%s] loaded at %x.\n", cnt, (cnt + 255) >> 8, + ((cnt + 255) >> 8) == 1 ? "" : "s", org); + printROMMessage(cntROM); + if (cntNonExist) { + printf("Warning: %d bytes written to non-existing memory (for this configuration).\n", cntNonExist); + } + } + return SCPE_OK; +} diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h index fe5cbc83..793407db 100644 --- a/AltairZ80/altairZ80_defs.h +++ b/AltairZ80/altairZ80_defs.h @@ -1,90 +1,86 @@ -/* altairz80_defs.h: MITS Altair simulator definitions - - Copyright (c) 2002-2003, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. - - Based on work by Charles E Owen (c) 1997 -*/ - -#include "sim_defs.h" /* simulator definitions */ - -#define MAXMEMSIZE 65536 /* maximum memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ -#define bootrom_size 256 /* size of boot rom */ -#define MAXBANKS 8 /* max number of memory banks */ -#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ -#define BANKMASK (MAXBANKS-1) /* bank mask */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define KB 1024 /* kilo byte */ -#define defaultROMLow 0xff00 /* default for lowest addres of ROM */ -#define defaultROMHigh 0xffff /* default for highest addres of ROM */ - -#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ -#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */ -#define unitNoOffset1 0x37 /* LD A, */ -#define unitNoOffset2 0xb4 /* LD a,80h | */ - -#define UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on nvalid operation */ -#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) -#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 CPU */ -#define UNIT_CHIP (1 << UNIT_V_CHIP) -#define UNIT_V_MSIZE (UNIT_V_UF+2) /* memory size */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_V_BANKED (UNIT_V_UF+3) /* banked memory is used */ -#define UNIT_BANKED (1 << UNIT_V_BANKED) -#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */ -#define UNIT_ROM (1 << UNIT_V_ROM) -#define UNIT_V_ALTAIRROM (UNIT_V_UF+5) /* ALTAIR ROM exists */ -#define UNIT_ALTAIRROM (1 << UNIT_V_ALTAIRROM) -#define UNIT_V_WARNROM (UNIT_V_UF+6) /* warn if ROM is written to */ -#define UNIT_WARNROM (1 << UNIT_V_WARNROM) - -#define AddressFormat "[%04xh]" -#define PCformat "\n" AddressFormat " " -#define message1(p1) \ - sprintf(messageBuffer,PCformat p1,PCX); printMessage() -#define message2(p1,p2) \ - sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage() -#define message3(p1,p2,p3) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage() -#define message4(p1,p2,p3,p4) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage() -#define message5(p1,p2,p3,p4,p5) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5); printMessage() -#define message6(p1,p2,p3,p4,p5,p6) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5,p6); printMessage() - -/* The Default is to use "inline". In this case the wrapper functions for - GetBYTE and PutBYTE need to be created. Otherwise they are not needed - and the calls map to the original functions. */ -#ifdef NO_INLINE -#define INLINE -#define GetBYTEWrapper GetBYTE -#define PutBYTEWrapper PutBYTE -#else -#if defined(__DECC) && defined(VMS) -#define INLINE __inline -#else -#define INLINE inline -#endif -#endif +/* altairz80_defs.h: MITS Altair simulator definitions + + Copyright (c) 2002-2004, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 +*/ + +#include "sim_defs.h" /* simulator definitions */ + +#define MAXMEMSIZE 65536 /* maximum memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ +#define bootrom_size 256 /* size of boot rom */ +#define MAXBANKS 8 /* max number of memory banks */ +#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ +#define BANKMASK (MAXBANKS-1) /* bank mask */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define KB 1024 /* kilo byte */ +#define defaultROMLow 0xff00 /* default for lowest addres of ROM */ +#define defaultROMHigh 0xffff /* default for highest addres of ROM */ + +#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ +#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */ +#define unitNoOffset1 0x37 /* LD A, */ +#define unitNoOffset2 0xb4 /* LD a,80h | */ + +#define UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on nvalid operation */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 CPU */ +#define UNIT_CHIP (1 << UNIT_V_CHIP) +#define UNIT_V_MSIZE (UNIT_V_UF+2) /* memory size */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define UNIT_V_BANKED (UNIT_V_UF+3) /* banked memory is used */ +#define UNIT_BANKED (1 << UNIT_V_BANKED) +#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */ +#define UNIT_ROM (1 << UNIT_V_ROM) +#define UNIT_V_ALTAIRROM (UNIT_V_UF+5) /* ALTAIR ROM exists */ +#define UNIT_ALTAIRROM (1 << UNIT_V_ALTAIRROM) +#define UNIT_V_WARNROM (UNIT_V_UF+6) /* warn if ROM is written to */ +#define UNIT_WARNROM (1 << UNIT_V_WARNROM) + +#define AddressFormat "[%04xh]" +#define PCformat "\n" AddressFormat " " +#define message1(p1) \ + sprintf(messageBuffer,PCformat p1,PCX); printMessage() +#define message2(p1,p2) \ + sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage() +#define message3(p1,p2,p3) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage() +#define message4(p1,p2,p3,p4) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage() +#define message5(p1,p2,p3,p4,p5) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5); printMessage() +#define message6(p1,p2,p3,p4,p5,p6) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5,p6); printMessage() + +/* The Default is to use "inline". */ +#if defined(NO_INLINE) +#define INLINE +#else +#if defined(__DECC) && defined(VMS) +#define INLINE __inline +#else +#define INLINE inline +#endif +#endif diff --git a/AltairZ80/altairZ80_dsk.c b/AltairZ80/altairZ80_dsk.c index 8856e9cd..fe450daa 100644 --- a/AltairZ80/altairZ80_dsk.c +++ b/AltairZ80/altairZ80_dsk.c @@ -1,6 +1,6 @@ /* altairz80_dsk.c: MITS Altair 88-DISK Simulator - Copyright (c) 2002-2003, Peter Schorn + Copyright (c) 2002-2004, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -142,7 +142,6 @@ static char* selectInOut(const int32 io); extern int32 PCX; extern int32 saved_PC; extern FILE *sim_log; -extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value); extern void printMessage(void); extern char messageBuffer[]; extern int32 install_bootrom(void); @@ -251,7 +250,9 @@ DEVICE dsk_dev = { "DSK", dsk_unit, dsk_reg, dsk_mod, 8, 10, 31, 1, 8, 8, NULL, NULL, &dsk_reset, - &dsk_boot, NULL, NULL, NULL, 0, NULL, NULL }; + &dsk_boot, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL }; static void resetDSKWarningFlags(void) { int32 i; @@ -351,7 +352,7 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if (hasVerbose() && (warnDSK10 < warnLevelDSK)) { warnDSK10++; -/*01*/ message1("Attempt of IN 0x08 on unattached disk - ignored.\n"); +/*01*/ message1("Attempt of IN 0x08 on unattached disk - ignored."); } return 0xff; /* no drive selected - can do nothing */ } @@ -363,14 +364,14 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { writebuf(); } if (trace_flag & TRACE_IN_OUT) { - message2("OUT 0x08: %x\n", data); + message2("OUT 0x08: %x", data); } current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */ current_disk_flags = (dsk_dev.units + current_disk) -> flags; if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */ if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) { warnAttached[current_disk]++; -/*02*/message2("Attempt to select unattached DSK%d - ignored.\n", current_disk); +/*02*/message2("Attempt to select unattached DSK%d - ignored.", current_disk); } current_disk = NUM_OF_DSK; } @@ -390,7 +391,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if (hasVerbose() && (warnDSK11 < warnLevelDSK)) { warnDSK11++; -/*03*/message2("Attempt of %s 0x09 on unattached disk - ignored.\n", selectInOut(io)); +/*03*/message2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io)); } return 0; /* no drive selected - can do nothing */ } @@ -400,10 +401,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { in9_count++; if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2 * DSK_SECT) && (!in9_message)) { in9_message = TRUE; - message2("Looping on sector find %d.\n", current_disk); + message2("Looping on sector find %d.", current_disk); } if (trace_flag & TRACE_IN_OUT) { - message1("IN 0x09\n"); + message1("IN 0x09"); } if (dirty) {/* implies that current_disk < NUM_OF_DSK */ writebuf(); @@ -425,12 +426,12 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { /* drive functions */ if (trace_flag & TRACE_IN_OUT) { - message2("OUT 0x09: %x\n", data); + message2("OUT 0x09: %x", data); } if (data & 0x01) { /* step head in */ if (trace_flag & TRACE_TRACK_STUCK) { if (current_track[current_disk] == (tracks[current_disk] - 1)) { - message2("Unnecessary step in for disk %d\n", current_disk); + message2("Unnecessary step in for disk %d", current_disk); } } current_track[current_disk]++; @@ -447,7 +448,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { if (data & 0x02) { /* step head out */ if (trace_flag & TRACE_TRACK_STUCK) { if (current_track[current_disk] == 0) { - message2("Unnecessary step out for disk %d\n", current_disk); + message2("Unnecessary step out for disk %d", current_disk); } } current_track[current_disk]--; @@ -501,7 +502,7 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if (hasVerbose() && (warnDSK12 < warnLevelDSK)) { warnDSK12++; -/*04*/message2("Attempt of %s 0x0a on unattached disk - ignored.\n", selectInOut(io)); +/*04*/message2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io)); } return 0; } @@ -513,7 +514,7 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { if (current_byte[current_disk] >= DSK_SECTSIZE) { /* physically read the sector */ if (trace_flag & TRACE_READ_WRITE) { - message4("IN 0x0a (READ) D%d T%d S%d\n", current_disk, current_track[current_disk], current_sector[current_disk]); + message4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); } for (i = 0; i < DSK_SECTSIZE; i++) { dskbuf[i] = 0; @@ -547,21 +548,21 @@ static void writebuf(void) { uptr = dsk_dev.units + current_disk; if (((uptr -> flags) & UNIT_DSKWLK) == 0) { /* write enabled */ if (trace_flag & TRACE_READ_WRITE) { - message4("OUT 0x0a (WRITE) D%d T%d S%d\n", current_disk, current_track[current_disk], current_sector[current_disk]); + message4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); } if (dskseek(uptr)) { - message4("fseek failed D%d T%d S%d\n", current_disk, current_track[current_disk], current_sector[current_disk]); + message4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); } rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); if (rtn != 1) { - message4("fwrite failed T%d S%d Return=%d\n", current_track[current_disk], current_sector[current_disk], rtn); + message4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn); } } else if ( ((uptr -> flags) & UNIT_DSK_VERBOSE) && (warnLock[current_disk] < warnLevelDSK) ) { /* write locked - print warning message if required */ warnLock[current_disk]++; /*05*/ - message2("Attempt to write to locked DSK%d - ignored.\n", current_disk); + message2("Attempt to write to locked DSK%d - ignored.", current_disk); } current_flag[current_disk] &= 0xfe; /* ENWD off */ current_byte[current_disk] = 0xff; diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c index e640e5df..fb041050 100644 --- a/AltairZ80/altairZ80_sio.c +++ b/AltairZ80/altairZ80_sio.c @@ -1,6 +1,6 @@ /* altairz80_sio: MITS Altair serial I/O card - Copyright (c) 2002-2003, Peter Schorn + Copyright (c) 2002-2004, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -112,6 +112,9 @@ extern t_stat sim_cancel(UNIT *uptr); extern t_stat sim_poll_kbd(void); extern t_stat sim_putchar(int32 out); extern t_stat attach_unit(UNIT *uptr, char *cptr); +extern int32 getBankSelect(void); +extern void setBankSelect(int32 b); +extern uint32 getCommon(void); extern t_bool rtc_avail; extern FILE *sim_log; extern int32 PCX; @@ -119,8 +122,6 @@ extern int32 sim_switches; extern uint32 sim_os_msec(void); extern const char *scp_error_messages[]; extern int32 SR; -extern int32 bankSelect; -extern int32 common; extern uint8 GetBYTEWrapper(register uint32 Addr); extern UNIT cpu_unit; @@ -184,7 +185,7 @@ static SIO_TERMINAL sio_terminals[Terminals] = {0, 0, 0x16, 0x17, 0x00}, {0, 0, 0x18, 0x19, 0x00} }; static TMLN TerminalLines[Terminals] = { {0} }; /* four terminals */ -static TMXR altairTMXR = {Terminals, 0, 0 }; /* mux descriptor */ +static TMXR altairTMXR = {Terminals, 0, 0, TerminalLines}; /* mux descriptor */ static UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; @@ -220,7 +221,9 @@ DEVICE sio_dev = { "SIO", &sio_unit, sio_reg, sio_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &sio_reset, - NULL, &sio_attach, &sio_detach, NULL, 0, NULL, NULL }; + NULL, &sio_attach, &sio_detach, + NULL, 0, 0, + NULL, NULL, NULL }; static UNIT ptr_unit = { UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0), KBD_POLL_WAIT }; @@ -235,7 +238,9 @@ DEVICE ptr_dev = { "PTR", &ptr_unit, ptr_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - NULL, NULL, NULL, NULL, 0, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL }; static UNIT ptp_unit = { UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT }; @@ -250,7 +255,9 @@ DEVICE ptp_dev = { "PTP", &ptp_unit, ptp_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, - NULL, NULL, NULL, NULL, 0, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL }; /* Synthetic device SIMH for communication between Altair and SIMH environment using port 0xfe */ @@ -301,14 +308,24 @@ DEVICE simh_device = { "SIMH", &simh_unit, simh_reg, simh_mod, 1, 10, 31, 1, 16, 4, NULL, NULL, &simh_dev_reset, - NULL, NULL, NULL, NULL, 0, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL }; char messageBuffer[256]; void printMessage(void) { printf(messageBuffer); +#if defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__) +/* need to make sure that carriage return is executed - ttrunstate() of scp_tty.c + has disabled \n translation */ + printf("\r\n"); +#else + printf("\n"); +#endif if (sim_log) { fprintf(sim_log, messageBuffer); + fprintf(sim_log,"\n"); } } @@ -325,10 +342,6 @@ static t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { } static t_stat sio_attach(UNIT *uptr, char *cptr) { - int32 i; - for (i = 0; i < Terminals; i++) { - altairTMXR.ldsc[i] = &TerminalLines[i]; - } reset_sio_terminals(FALSE); return tmxr_attach(&altairTMXR, uptr, cptr); /* attach mux */ } @@ -362,7 +375,7 @@ static t_stat sio_svc(UNIT *uptr) { } temp = tmxr_poll_conn(&altairTMXR); /* poll connection */ if (temp >= 0) { - altairTMXR.ldsc[temp] -> rcve = 1; /* enable receive */ + TerminalLines[temp].rcve = 1; /* enable receive */ } tmxr_poll_rx(&altairTMXR); /* poll input */ tmxr_poll_tx(&altairTMXR); /* poll output */ @@ -385,8 +398,8 @@ static t_stat sio_reset(DEVICE *dptr) { resetSIOWarningFlags(); if (sio_unit.flags & UNIT_ATT) { for (i = 0; i < Terminals; i++) { - if (altairTMXR.ldsc[i] -> conn > 0) { - tmxr_reset_ln(altairTMXR.ldsc[i]); + if (TerminalLines[i].conn > 0) { + tmxr_reset_ln(&TerminalLines[i]); } } reset_sio_terminals(FALSE); @@ -442,9 +455,9 @@ int32 sio0s(const int32 port, const int32 io, const int32 data) { if (io == 0) { /* IN */ if (sio_unit.flags & UNIT_ATT) { sio_terminals[ti].status = - (((tmxr_rqln(altairTMXR.ldsc[ti]) > 0 ? 0x01 : 0) | + (((tmxr_rqln(&TerminalLines[ti]) > 0 ? 0x01 : 0) | /* read possible if character available */ - ((altairTMXR.ldsc[ti] -> conn) && (altairTMXR.ldsc[ti] -> xmte) ? 0x02 : 0x00))); + ((TerminalLines[ti].conn) && (TerminalLines[ti].xmte) ? 0x02 : 0x00))); /* write possible if connected and transmit enabled */ } return sio_terminals[ti].status; @@ -475,7 +488,7 @@ int32 sio0d(const int32 port, const int32 io, const int32 data) { } if (io == 0) { /* IN */ if (sio_unit.flags & UNIT_ATT) { - sio_terminals[ti].data = tmxr_getc_ln(altairTMXR.ldsc[ti]) & 0xff; + sio_terminals[ti].data = tmxr_getc_ln(&TerminalLines[ti]) & 0xff; } sio_terminals[ti].status &= 0xfe; if (sio_unit.flags & UNIT_BS) { @@ -493,7 +506,7 @@ int32 sio0d(const int32 port, const int32 io, const int32 data) { else { /* OUT */ int32 d = sio_unit.flags & UNIT_ANSI ? data & 0x7f : data; if (sio_unit.flags & UNIT_ATT) { - tmxr_putc_ln(altairTMXR.ldsc[ti], d); + tmxr_putc_ln(&TerminalLines[ti], d); /* status ignored */ } else { sim_putchar(d); @@ -511,7 +524,7 @@ int32 sio1s(const int32 port, const int32 io, const int32 data) { if ((ptr_unit.flags & UNIT_ATT) == 0) { if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*06*/ message1("Attempt to test status of unattached PTR. 0x02 returned.\n"); +/*06*/ message1("Attempt to test status of unattached PTR. 0x02 returned."); } return 0x02; } @@ -536,14 +549,14 @@ int32 sio1d(const int32 port, const int32 io, const int32 data) { if (ptr_unit.u3) { /* no more data available */ if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnPTREOF < warnLevelSIO)) { warnPTREOF++; -/*07*/ message1("PTR attempted to read past EOF. 0x00 returned.\n"); +/*07*/ message1("PTR attempted to read past EOF. 0x00 returned."); } return 0; } if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */ if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*08*/ message1("Attempt to read from unattached PTR. 0x00 returned.\n"); +/*08*/ message1("Attempt to read from unattached PTR. 0x00 returned."); } return 0; } @@ -560,7 +573,7 @@ int32 sio1d(const int32 port, const int32 io, const int32 data) { } /* else ignore data */ else if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTP < warnLevelSIO)) { warnUnattachedPTP++; -/*09*/message2("Attempt to output '0x%02x' to unattached PTP - ignored.\n", data); +/*09*/message2("Attempt to output '0x%02x' to unattached PTP - ignored.", data); } ptp_unit.pos++; return 0; /* ignored since OUT */ @@ -571,10 +584,10 @@ int32 nulldev(const int32 port, const int32 io, const int32 data) { if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) { warnUnassignedPort++; if (io == 0) { - message2("Unassigned IN(%2xh) - ignored.\n", port); + message2("Unassigned IN(%2xh) - ignored.", port); } else { - message3("Unassigned OUT(%2xh) -> %2xh - ignored.\n", port, data); + message3("Unassigned OUT(%2xh) -> %2xh - ignored.", port, data); } } return io == 0 ? 0xff : 0; @@ -739,7 +752,7 @@ static void attachCPM(UNIT *uptr) { } lastCPMStatus = attach_unit(uptr, cpmCommandLine); if ((lastCPMStatus != SCPE_OK) && (simh_unit.flags & UNIT_SIMH_VERBOSE)) { - message3("Cannot open '%s' (%s).\n", cpmCommandLine, scp_error_messages[lastCPMStatus - SCPE_BASE]); + message3("Cannot open '%s' (%s).", cpmCommandLine, scp_error_messages[lastCPMStatus - SCPE_BASE]); } } @@ -862,7 +875,7 @@ static int32 simh_in(const int32 port) { break; case getBankSelectCmd: if (cpu_unit.flags & UNIT_BANKED) { - result = bankSelect; + result = getBankSelect(); } else { result = 0; @@ -874,11 +887,11 @@ static int32 simh_in(const int32 port) { break; case getCommonCmd: if (getCommonPos == 0) { - result = common & 0xff; + result = getCommon() & 0xff; getCommonPos = 1; } else { - result = (common >> 8) & 0xff; + result = (getCommon() >> 8) & 0xff; getCommonPos = lastCommand = 0; } break; @@ -898,7 +911,7 @@ static int32 simh_in(const int32 port) { break; default: if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - message2("Unnecessary IN from SIMH pseudo device on port %03xh ignored.\n", + message2("Unnecessary IN from SIMH pseudo device on port %03xh ignored.", port); } result = lastCommand = 0; @@ -933,7 +946,7 @@ static int32 simh_out(const int32 port, const int32 data) { break; case setBankSelectCmd: if (cpu_unit.flags & UNIT_BANKED) { - bankSelect = data & BANKMASK; + setBankSelect(data & BANKMASK); } else if (simh_unit.flags & UNIT_SIMH_VERBOSE) { message2("Set selected bank to %i ignored for non-banked memory.", data & 3); @@ -965,7 +978,7 @@ static int32 simh_out(const int32 port, const int32 data) { switch(data) { case printTimeCmd: /* print time */ if (rtc_avail) { - message2("Current time in milliseconds = %d.\n", sim_os_msec()); + message2("Current time in milliseconds = %d.", sim_os_msec()); } else { warnNoRealTimeClock(); @@ -977,7 +990,7 @@ static int32 simh_out(const int32 port, const int32 data) { markTime[markTimeSP++] = sim_os_msec(); } else { - message1("Timer stack overflow.\n"); + message1("Timer stack overflow."); } } else { @@ -988,10 +1001,10 @@ static int32 simh_out(const int32 port, const int32 data) { if (rtc_avail) { if (markTimeSP > 0) { uint32 delta = sim_os_msec() - markTime[--markTimeSP]; - message2("Timer stopped. Elapsed time in milliseconds = %d.\n", delta); + message2("Timer stopped. Elapsed time in milliseconds = %d.", delta); } else { - message1("No timer active.\n"); + message1("No timer active."); } } else { @@ -1044,10 +1057,10 @@ static int32 simh_out(const int32 port, const int32 data) { if (rtc_avail) { if (markTimeSP > 0) { uint32 delta = sim_os_msec() - markTime[markTimeSP - 1]; - message2("Timer running. Elapsed in milliseconds = %d.\n", delta); + message2("Timer running. Elapsed in milliseconds = %d.", delta); } else { - message1("No timer active.\n"); + message1("No timer active."); } } else { @@ -1091,7 +1104,7 @@ static int32 simh_out(const int32 port, const int32 data) { break; default: if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - message3("Unknown command (%i) to SIMH pseudo device on port %03xh ignored.\n", + message3("Unknown command (%i) to SIMH pseudo device on port %03xh ignored.", data, port); } } diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c index 9cc29210..51bdb4b9 100644 --- a/AltairZ80/altairZ80_sys.c +++ b/AltairZ80/altairZ80_sys.c @@ -1,782 +1,719 @@ -/* altairz80_sys.c: MITS Altair system interface - - Copyright (c) 2002-2003, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. - - Based on work by Charles E Owen (c) 1997 - Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) -*/ - -#include -#include "altairz80_defs.h" - -extern DEVICE cpu_dev; -extern DEVICE dsk_dev; -extern DEVICE hdsk_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern DEVICE sio_dev; -extern DEVICE simh_device; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern int32 saved_PC; -extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value); -extern void PutBYTEForced(register uint32 Addr, register uint32 Value); -extern uint8 GetBYTEWrapper(register uint32 Addr); -extern int32 addressIsInROM(const uint32 Addr); -extern int32 addressExists(const uint32 Addr); -extern void printROMMessage(const uint32 cntROM); - -int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag); -int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); -static int32 checkbase(char ch, const char *numString); -static int32 numok(char ch, const char **numString, const int32 minvalue, - const int32 maxvalue, const int32 requireSign, int32 *result); -static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, int32 *at, - int32 *hat, int32 *dollar); -static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]); -int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); -static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr); -static int32 checkXY(const char xy); - -/* SCP data structures - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax number of words needed for examine - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "Altair 8800 (Z80)"; -REG *sim_PC = &cpu_reg[0]; -int32 sim_emax = 4; -DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL }; - -char memoryAccessMessage[80]; -const char *sim_stop_messages[] = { - "HALT instruction", - "Breakpoint", - memoryAccessMessage, - "Invalid Opcode" }; - -static char *const Mnemonics8080[] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */ - "DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ - "DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ - "DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ - "DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ - "DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ - "DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ - "DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ - "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */ - "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */ - "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */ - "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ - "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ - "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ - "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ - "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ - "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ - "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ - "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ - "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ - "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ - "ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */ - "CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */ - "RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */ - "RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ - "RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */ - "RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */ - "RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */ - "RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */ - "RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */ - "RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */ - }; - -static char *const MnemonicsZ80[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ - "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ - "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ - "JR $h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ - "JR NZ,$h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", /* 20-27 */ - "JR Z,$h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", /* 28-2f */ - "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", /* 30-37 */ - "JR C,$h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", /* 40-47 */ - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", /* 48-4f */ - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", /* 50-57 */ - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", /* 58-5f */ - "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", /* 60-67 */ - "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", /* 68-6f */ - "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", /* 70-77 */ - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", /* 78-7f */ - "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", /* 80-87 */ - "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 90-97 */ - "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", /* 98-9f */ - "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* a0-a7 */ - "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* a8-af */ - "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* b0-b7 */ - "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* b8-bf */ - "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c0-c7 */ - "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ - "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ - "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ - "RET PO", "POP HL", "JP PO,#h", "EX (SP),HL", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", /* e0-e7 */ - "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ - "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ - "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ -}; - -static char *const MnemonicsCB[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 00-07 */ - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 08-0f */ - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 10-17 */ - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 18-1f */ - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 20-27 */ - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 28-2f */ - "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 30-37 */ - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 38-3f */ - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", /* 40-47 */ - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", /* 48-4f */ - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", /* 50-57 */ - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", /* 58-5f */ - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", /* 60-67 */ - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", /* 68-6f */ - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", /* 70-77 */ - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", /* 78-7f */ - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", /* 80-87 */ - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", /* 88-8f */ - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", /* 90-97 */ - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", /* 98-9f */ - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", /* a0-a7 */ - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", /* a8-af */ - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", /* b0-b7 */ - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", /* b8-bf */ - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", /* c0-c7 */ - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", /* c8-cf */ - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", /* d0-d7 */ - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", /* d8-df */ - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", /* e0-e7 */ - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", /* e8-ef */ - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", /* f0-f7 */ - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" /* f8-ff */ -}; - -static char *const MnemonicsED[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", /* 00-07 */ - "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", /* 08-0f */ - "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", /* 10-17 */ - "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", /* 18-1f */ - "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", /* 20-27 */ - "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", /* 28-2f */ - "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", /* 30-37 */ - "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", /* 38-3f */ - "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", /* 40-47 */ - "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", /* 48-4f */ - "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", /* 50-57 */ - "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", /* 58-5f */ - "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", /* 60-67 */ - "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", /* 68-6f */ - "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", /* 70-77 */ - "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", /* 78-7f */ - "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", /* 80-87 */ - "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", /* 88-8f */ - "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", /* 90-97 */ - "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", /* 98-9f */ - "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", /* a0-a7 */ - "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", /* a8-af */ - "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", /* b0-b7 */ - "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", /* b8-bf */ - "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", /* c0-c7 */ - "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", /* c8-cf */ - "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", /* d0-d7 */ - "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", /* d8-df */ - "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", /* e0-e7 */ - "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", /* e8-ef */ - "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", /* f0-f7 */ - "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" /* f8-ff */ -}; - -static char *const MnemonicsXX[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ - "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ - "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ - "JR $h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ - "JR NZ,$h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%H", "DEC I%H", "LD I%H,*h", "DAA", /* 20-27 */ - "JR Z,$h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%L", "DEC I%L", "LD I%L,*h", "CPL", /* 28-2f */ - "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", /* 30-37 */ - "JR C,$h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%H", "LD B,I%L", "LD B,(I%+^h)", "LD B,A", /* 40-47 */ - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%H", "LD C,I%L", "LD C,(I%+^h)", "LD C,A", /* 48-4f */ - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%H", "LD D,I%L", "LD D,(I%+^h)", "LD D,A", /* 50-57 */ - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%H", "LD E,I%L", "LD E,(I%+^h)", "LD E,A", /* 58-5f */ - "LD I%H,B", "LD I%H,C", "LD I%H,D", "LD I%H,E", "LD I%H,I%H", "LD I%H,I%L", "LD H,(I%+^h)", "LD I%H,A", /* 60-67 */ - "LD I%L,B", "LD I%L,C", "LD I%L,D", "LD I%L,E", "LD I%L,I%H", "LD I%L,I%L", "LD L,(I%+^h)", "LD I%L,A", /* 68-6f */ - "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", /* 70-77 */ - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%H", "LD A,I%L", "LD A,(I%+^h)", "LD A,A", /* 78-7f */ - "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,I%H", "ADD A,I%L", "ADD A,(I%+^h)", "ADD A,A", /* 80-87 */ - "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,I%H", "ADC A,I%L", "ADC A,(I%+^h)", "ADC A,A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%H", "SUB I%L", "SUB (I%+^h)", "SUB A", /* 90-97 */ - "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,I%H", "SBC A,I%L", "SBC A,(I%+^h)", "SBC A,A", /* 98-9f */ - "AND B", "AND C", "AND D", "AND E", "AND I%H", "AND I%L", "AND (I%+^h)", "AND A", /* a0-a7 */ - "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%H", "XOR I%L", "XOR (I%+^h)", "XOR A", /* a8-af */ - "OR B", "OR C", "OR D", "OR E", "OR I%H", "OR I%L", "OR (I%+^h)", "OR A", /* b0-b7 */ - "CP B", "CP C", "CP D", "CP E", "CP I%H", "CP I%L", "CP (I%+^h)", "CP A", /* b8-bf */ - "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c8-cf */ - "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ - "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ - "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ - "RET PO", "POP I%", "JP PO,#h", "EX (SP),I%", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", /* e0-e7 */ - "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ - "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ - "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ -}; - -static char *const MnemonicsXCB[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", /* 00-07 */ - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", /* 08-0f */ - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", /* 10-17 */ - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", /* 18-1f */ - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", /* 20-27 */ - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", /* 28-2f */ - "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", /* 30-37 */ - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", /* 38-3f */ - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", /* 40-47 */ - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", /* 48-4f */ - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", /* 50-57 */ - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", /* 58-5f */ - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", /* 60-67 */ - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", /* 68-6f */ - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", /* 70-77 */ - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", /* 78-7f */ - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", /* 80-87 */ - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", /* 88-8f */ - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", /* 90-97 */ - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", /* 98-9f */ - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", /* a0-a7 */ - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", /* a8-af */ - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", /* b0-b7 */ - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", /* b8-bf */ - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", /* c0-c7 */ - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", /* c8-cf */ - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", /* d0-d7 */ - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", /* d8-df */ - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", /* e0-e7 */ - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", /* e8-ef */ - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", /* f0-f7 */ - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */ -}; - -/* symbolic disassembler - - Inputs: - *val = instructions to disassemble - useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used - addr = current PC - Outputs: - *S = output text - - DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997 - You are not allowed to distribute this software - commercially. - -*/ - -static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr) { - char R[128], H[10], C = '\0', *T, *P; - uint8 J = 0, Offset = 0; - uint16 B = 0; - - if (useZ80Mnemonics) { - switch(val[B]) { - case 0xcb: - B++; - T = MnemonicsCB[val[B++]]; - break; - case 0xed: - B++; - T = MnemonicsED[val[B++]]; - break; - case 0xdd: - case 0xfd: - C = (val[B++] == 0xdd) ? 'X' : 'Y'; - if (val[B] == 0xcb) { - B++; - Offset = val[B++]; - J = 1; - T = MnemonicsXCB[val[B++]]; - } - else { - T = MnemonicsXX[val[B++]]; - } - break; - default: - T = MnemonicsZ80[val[B++]]; - } - } - else { - T = Mnemonics8080[val[B++]]; - } - - if (P = strchr(T, '^')) { - strncpy(R, T, P - T); - R[P - T] = '\0'; - sprintf(H, "%02X", val[B++]); - strcat(R, H); - strcat(R, P + 1); - } - else { - strcpy(R, T); - } - if (P = strchr(R, '%')) { - *P = C; - if (P = strchr(P + 1, '%')) { - *P = C; - } - } - - if(P = strchr(R, '*')) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - sprintf(H, "%02X", val[B++]); - strcat(S, H); - strcat(S, P + 1); - } - else if (P = strchr(R, '@')) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - if(!J) { - Offset = val[B++]; - } - strcat(S, Offset & 0x80 ? "-" : "+"); - J = Offset & 0x80 ? 256 - Offset : Offset; - sprintf(H, "%02X", J); - strcat(S, H); - strcat(S, P + 1); - } - else if (P = strchr(R, '$')) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - Offset = val[B++]; - sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)); - strcat(S, H); - strcat(S, P + 1); - } - else if (P = strchr(R, '#')) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - sprintf(H, "%04X", val[B] + 256 * val[B + 1]); - strcat(S, H); - strcat(S, P + 1); - B += 2; - } - else { - strcpy(S, R); - } - return(B); -} - -/* symbolic output - - Inputs: - *of = output stream - addr = current PC - *val = pointer to values - *uptr = pointer to unit - sw = switches - Outputs: - status = error code -*/ - -int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { - char disasm[128]; - int32 ch = val[0] & 0x7f; - if (sw & (SWMASK('A') | SWMASK('C'))) { - fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch); - return SCPE_OK; - } - if (!(sw & SWMASK('M'))) { - return SCPE_ARG; - } - ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr); - fprintf(of, "%s", disasm); - return 1 - ch; /* need to return additional bytes */ -} - -/* numString checks determines the base of the number (ch, *numString) - and returns FALSE if the number is bad */ -static int32 checkbase(char ch, const char *numString) { - int32 decimal = (ch <= '9'); - if (toupper(ch) == 'H') { - return FALSE; - } - while (isxdigit(ch = *numString++)) { - if (ch > '9') { - decimal = FALSE; - } - } - return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE); -} - -static int32 numok(char ch, const char **numString, const int32 minvalue, - const int32 maxvalue, const int32 requireSign, int32 *result) { - int32 sign = 1, value = 0, base; - if (requireSign) { - if (ch == '+') { - ch = *(*numString)++; - } - else if (ch == '-') { - sign = -1; - ch = *(*numString)++; - } - else { - return FALSE; - } - } - if (!(base = checkbase(ch, *numString))) { - return FALSE; - } - while (isxdigit(ch)) { - value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10)); - ch = *(*numString)++; - } - if (toupper(ch) != 'H') { - (*numString)--; - } - *result = value * sign; - return (minvalue <= value) && (value <= maxvalue); -} - -static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, - int32 *at, int32 *hat, int32 *dollar) { - char pat = *pattern++; - char inp = *input++; - while ((pat) && (inp)) { - switch(pat) { - case '_': /* patterns containting '_' should never match */ - return FALSE; - case ',': - if (inp == ' ') { - inp = *input++; - continue; - } /* otherwise fall through */ - case ' ': - if (inp != pat) { - return FALSE; - } - pat = *pattern++; - inp = *input++; - while (inp == ' ') { - inp = *input++; - } - continue; - case '%': - inp = toupper(inp); - if ((inp == 'X') || (inp == 'Y')) { - if (*xyFirst) { /* make sure that second '%' corresponds to first */ - if (*xyFirst == inp) { - *xy = inp; - } - else { - return FALSE; - } - } - else { /* take note of first '%' for later */ - *xyFirst = inp; - *xy = inp; - } - } - else { - return FALSE; - } - break; - case '#': - if (numok(inp, &input, 0, 65535, FALSE, number)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - case '*': - if (numok(inp, &input, 0, 255, FALSE, star)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - case '@': - if (numok(inp, &input, -128, 65535, TRUE, at)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - case '$': - if (numok(inp, &input, 0, 65535, FALSE, dollar)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - case '^': - if (numok(inp, &input, 0, 255, FALSE, hat)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - default: - if (toupper(pat) != toupper(inp)) { - return FALSE; - } - } - pat = *pattern++; - inp = *input++; - } - while (inp == ' ') { - inp = *input++; - } - return (pat == 0) && (inp == 0); -} - -static INLINE int32 checkXY(const char xy) { - return xy == 'X' ? 0xdd : 0xfd; /* else is 'Y' */ -} - -static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]) { - char xyFirst = 0, xy; - int32 op, number, star, at, hat, dollar; - for (op = 0; op < 256; op++) { - number = star = at = dollar = -129; - if (match(Mnemonics[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - val[0] = op; - if (number >= 0) { - val[1] = (0xff) & number; - val[2] = (0xff) & (number >> 8); - return -2; /* two additional bytes returned */ - } - else if (star >= 0) { - val[1] = (0xff) & star; - return -1; /* one additional byte returned */ - } - else if (at > -129) { - if ((-128 <= at) && (at <= 127)) { - val[1] = (int8)(at); - return -1; /* one additional byte returned */ - } - else { - return SCPE_ARG; - } - } - else if (dollar >= 0) { - dollar -= addr + 2; /* relative translation */ - if ((-128 <= dollar) && (dollar <= 127)) { - val[1] = (int8)(dollar); - return -1; /* one additional byte returned */ - } - else { - return SCPE_ARG; - } - } - else { - return SCPE_OK; - } - } - } - if (Mnemonics == Mnemonics8080) { - return SCPE_ARG; - } - - for (op = 0; op < 256; op++) { - if (match(MnemonicsCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - val[0] = 0xcb; - val[1] = op; - return -1; /* one additional byte returned */ - } - } - - for (op = 0; op < 256; op++) { - number = -1; - if (match(MnemonicsED[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - val[0] = 0xed; - val[1] = op; - if (number >= 0) { - val[2] = (0xff) & number; - val[3] = (0xff) & (number >> 8); - return -3; /* three additional bytes returned */ - } - else { - return -1; /* one additional byte returned */ - } - } - } - - for (op = 0; op < 256; op++) { - number = star = hat = -1; - xy = 0; - if (match(MnemonicsXX[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - /* all matches must have contained a '%' character */ - if (!(val[0] = checkXY(xy))) { - return SCPE_ARG; - } - val[1] = op; - if (number >= 0) { - val[2] = (0xff) & number; - val[3] = (0xff) & (number >> 8); - return -3; /* three additional bytes returned */ - } - else if ((star >= 0) && (hat >= 0)) { - val[2] = (0xff) & hat; - val[3] = (0xff) & star; - return -3; /* three additional bytes returned */ - } - else if (star >= 0) { - val[2] = (0xff) & star; - return -2; /* two additional bytes returned */ - } - else if (hat >= 0) { - val[2] = (0xff) & hat; - return -2; /* two additional bytes returned */ - } - else { - return -1; /* one additional byte returned */ - } - } - } - - for (op = 0; op < 256; op++) { - at = -129; - xy = 0; - if (match(MnemonicsXCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - /* all matches must have contained a '%' character */ - if (!(val[0] = checkXY(xy))) { - return SCPE_ARG; - } - val[1] = 0xcb; - if (at > -129) { - val[2] = (int8) (at); - } - else { - printf("Offset expected.\n"); - return SCPE_ARG; - } - val[3] = op; - return -3; /* three additional bytes returned */ - } - } - 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 -*/ -int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) { - while (isspace(*cptr)) cptr++; /* absorb spaces */ - if ((sw & (SWMASK('A') | SWMASK('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) { - return SCPE_ARG; /* must have one char */ - } - val[0] = (uint32) cptr[0]; - return SCPE_OK; - } - return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080); -} - - -/* This is the binary loader. The input file is considered to be - a string of literal bytes with no format special format. The - load starts at the current value of the PC. ROM/NOROM and - ALTAIRROM/NOALTAIRROM settings are ignored. -*/ - -int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { - int32 i, addr = 0, cnt = 0, org, cntROM = 0, cntNonExist = 0; - t_addr j, lo, hi; - char *result; - t_stat status; - if (flag) { - result = get_range(cptr, &lo, &hi, 16, ADDRMASK, 0); - if (result == NULL) { - return SCPE_ARG; - } - for (j = lo; j <= hi; j++) { - if (putc(GetBYTEWrapper(j), fileref) == EOF) { - return SCPE_IOERR; - } - } - printf("%d bytes dumped [%x - %x].\n", hi + 1 - lo, lo, hi); - } - else { - if (*cptr == 0) { - addr = saved_PC; - } - else { - addr = get_uint(cptr, 16, ADDRMASK, &status); - if (status != SCPE_OK) { - return status; - } - } - org = addr; - while ((addr < MAXMEMSIZE) && ((i = getc(fileref)) != EOF)) { - PutBYTEForced(addr, i); - if (addressIsInROM(addr)) { - cntROM++; - } - if (!addressExists(addr)) { - cntNonExist++; - } - addr++; - cnt++; - } /* end while */ - printf("%d bytes [%d page%s] loaded at %x.\n", cnt, (cnt + 255) >> 8, - ((cnt + 255) >> 8) == 1 ? "" : "s", org); - printROMMessage(cntROM); - if (cntNonExist) { - printf("Warning: %d bytes written to non-existing memory (for this configuration).\n", cntNonExist); - } - } - return SCPE_OK; -} +/* altairz80_sys.c: MITS Altair system interface + + Copyright (c) 2002-2004, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) +*/ + +#include +#include "altairz80_defs.h" + +extern DEVICE cpu_dev; +extern DEVICE dsk_dev; +extern DEVICE hdsk_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern DEVICE sio_dev; +extern DEVICE simh_device; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern int32 saved_PC; + +int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); +static int32 checkbase(char ch, const char *numString); +static int32 numok(char ch, const char **numString, const int32 minvalue, + const int32 maxvalue, const int32 requireSign, int32 *result); +static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, int32 *at, + int32 *hat, int32 *dollar); +static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]); +int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); +static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr); +static int32 checkXY(const char xy); + +/* SCP data structures + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "Altair 8800 (Z80)"; +REG *sim_PC = &cpu_reg[0]; +int32 sim_emax = 4; +DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL }; + +char memoryAccessMessage[80]; +const char *sim_stop_messages[] = { + "HALT instruction", + "Breakpoint", + memoryAccessMessage, + "Invalid Opcode" }; + +static char *const Mnemonics8080[] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */ + "DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ + "DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ + "DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ + "DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ + "DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ + "DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ + "DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ + "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */ + "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */ + "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */ + "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ + "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ + "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ + "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ + "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ + "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ + "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ + "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ + "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ + "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ + "ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */ + "CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */ + "RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */ + "RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ + "RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */ + "RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */ + "RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */ + "RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */ + "RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */ + "RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */ + }; + +static char *const MnemonicsZ80[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ + "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ + "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ + "JR $h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ + "JR NZ,$h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", /* 20-27 */ + "JR Z,$h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", /* 28-2f */ + "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", /* 30-37 */ + "JR C,$h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", /* 40-47 */ + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", /* 48-4f */ + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", /* 50-57 */ + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", /* 58-5f */ + "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", /* 60-67 */ + "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", /* 68-6f */ + "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", /* 70-77 */ + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", /* 78-7f */ + "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", /* 80-87 */ + "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 90-97 */ + "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", /* 98-9f */ + "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* a0-a7 */ + "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* a8-af */ + "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* b0-b7 */ + "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* b8-bf */ + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c0-c7 */ + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ + "RET PO", "POP HL", "JP PO,#h", "EX (SP),HL", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", /* e0-e7 */ + "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ + "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ +}; + +static char *const MnemonicsCB[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 00-07 */ + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 08-0f */ + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 10-17 */ + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 18-1f */ + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 20-27 */ + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 28-2f */ + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 30-37 */ + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 38-3f */ + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", /* 40-47 */ + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", /* 48-4f */ + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", /* 50-57 */ + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", /* 58-5f */ + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", /* 60-67 */ + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", /* 68-6f */ + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", /* 70-77 */ + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", /* 78-7f */ + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", /* 80-87 */ + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", /* 88-8f */ + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", /* 90-97 */ + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", /* 98-9f */ + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", /* a0-a7 */ + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", /* a8-af */ + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", /* b0-b7 */ + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", /* b8-bf */ + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", /* c0-c7 */ + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", /* c8-cf */ + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", /* d0-d7 */ + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", /* d8-df */ + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", /* e0-e7 */ + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", /* e8-ef */ + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", /* f0-f7 */ + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" /* f8-ff */ +}; + +static char *const MnemonicsED[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", /* 00-07 */ + "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", /* 08-0f */ + "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", /* 10-17 */ + "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", /* 18-1f */ + "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", /* 20-27 */ + "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", /* 28-2f */ + "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", /* 30-37 */ + "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", /* 38-3f */ + "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", /* 40-47 */ + "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", /* 48-4f */ + "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", /* 50-57 */ + "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", /* 58-5f */ + "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", /* 60-67 */ + "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", /* 68-6f */ + "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", /* 70-77 */ + "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", /* 78-7f */ + "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", /* 80-87 */ + "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", /* 88-8f */ + "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", /* 90-97 */ + "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", /* 98-9f */ + "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", /* a0-a7 */ + "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", /* a8-af */ + "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", /* b0-b7 */ + "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", /* b8-bf */ + "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", /* c0-c7 */ + "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", /* c8-cf */ + "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", /* d0-d7 */ + "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", /* d8-df */ + "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", /* e0-e7 */ + "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", /* e8-ef */ + "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", /* f0-f7 */ + "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" /* f8-ff */ +}; + +static char *const MnemonicsXX[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ + "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ + "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ + "JR $h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ + "JR NZ,$h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%H", "DEC I%H", "LD I%H,*h", "DAA", /* 20-27 */ + "JR Z,$h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%L", "DEC I%L", "LD I%L,*h", "CPL", /* 28-2f */ + "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", /* 30-37 */ + "JR C,$h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%H", "LD B,I%L", "LD B,(I%+^h)", "LD B,A", /* 40-47 */ + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%H", "LD C,I%L", "LD C,(I%+^h)", "LD C,A", /* 48-4f */ + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%H", "LD D,I%L", "LD D,(I%+^h)", "LD D,A", /* 50-57 */ + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%H", "LD E,I%L", "LD E,(I%+^h)", "LD E,A", /* 58-5f */ + "LD I%H,B", "LD I%H,C", "LD I%H,D", "LD I%H,E", "LD I%H,I%H", "LD I%H,I%L", "LD H,(I%+^h)", "LD I%H,A", /* 60-67 */ + "LD I%L,B", "LD I%L,C", "LD I%L,D", "LD I%L,E", "LD I%L,I%H", "LD I%L,I%L", "LD L,(I%+^h)", "LD I%L,A", /* 68-6f */ + "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", /* 70-77 */ + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%H", "LD A,I%L", "LD A,(I%+^h)", "LD A,A", /* 78-7f */ + "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,I%H", "ADD A,I%L", "ADD A,(I%+^h)", "ADD A,A", /* 80-87 */ + "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,I%H", "ADC A,I%L", "ADC A,(I%+^h)", "ADC A,A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%H", "SUB I%L", "SUB (I%+^h)", "SUB A", /* 90-97 */ + "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,I%H", "SBC A,I%L", "SBC A,(I%+^h)", "SBC A,A", /* 98-9f */ + "AND B", "AND C", "AND D", "AND E", "AND I%H", "AND I%L", "AND (I%+^h)", "AND A", /* a0-a7 */ + "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%H", "XOR I%L", "XOR (I%+^h)", "XOR A", /* a8-af */ + "OR B", "OR C", "OR D", "OR E", "OR I%H", "OR I%L", "OR (I%+^h)", "OR A", /* b0-b7 */ + "CP B", "CP C", "CP D", "CP E", "CP I%H", "CP I%L", "CP (I%+^h)", "CP A", /* b8-bf */ + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c8-cf */ + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ + "RET PO", "POP I%", "JP PO,#h", "EX (SP),I%", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", /* e0-e7 */ + "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ + "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ +}; + +static char *const MnemonicsXCB[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", /* 00-07 */ + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", /* 08-0f */ + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", /* 10-17 */ + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", /* 18-1f */ + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", /* 20-27 */ + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", /* 28-2f */ + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", /* 30-37 */ + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", /* 38-3f */ + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", /* 40-47 */ + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", /* 48-4f */ + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", /* 50-57 */ + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", /* 58-5f */ + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", /* 60-67 */ + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", /* 68-6f */ + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", /* 70-77 */ + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", /* 78-7f */ + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", /* 80-87 */ + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", /* 88-8f */ + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", /* 90-97 */ + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", /* 98-9f */ + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", /* a0-a7 */ + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", /* a8-af */ + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", /* b0-b7 */ + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", /* b8-bf */ + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", /* c0-c7 */ + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", /* c8-cf */ + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", /* d0-d7 */ + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", /* d8-df */ + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", /* e0-e7 */ + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", /* e8-ef */ + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", /* f0-f7 */ + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */ +}; + +/* symbolic disassembler + + Inputs: + *val = instructions to disassemble + useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used + addr = current PC + Outputs: + *S = output text + + DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997 + You are not allowed to distribute this software + commercially. + +*/ + +static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr) { + char R[128], H[10], C = '\0', *T, *P; + uint8 J = 0, Offset = 0; + uint16 B = 0; + + if (useZ80Mnemonics) { + switch(val[B]) { + case 0xcb: + B++; + T = MnemonicsCB[val[B++]]; + break; + case 0xed: + B++; + T = MnemonicsED[val[B++]]; + break; + case 0xdd: + case 0xfd: + C = (val[B++] == 0xdd) ? 'X' : 'Y'; + if (val[B] == 0xcb) { + B++; + Offset = val[B++]; + J = 1; + T = MnemonicsXCB[val[B++]]; + } + else { + T = MnemonicsXX[val[B++]]; + } + break; + default: + T = MnemonicsZ80[val[B++]]; + } + } + else { + T = Mnemonics8080[val[B++]]; + } + + if ( (P = strchr(T, '^')) ) { + strncpy(R, T, P - T); + R[P - T] = '\0'; + sprintf(H, "%02X", val[B++]); + strcat(R, H); + strcat(R, P + 1); + } + else { + strcpy(R, T); + } + if ( (P = strchr(R, '%')) ) { + *P = C; + if ( (P = strchr(P + 1, '%')) ) { + *P = C; + } + } + + if( (P = strchr(R, '*')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + sprintf(H, "%02X", val[B++]); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '@')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + if(!J) { + Offset = val[B++]; + } + strcat(S, Offset & 0x80 ? "-" : "+"); + J = Offset & 0x80 ? 256 - Offset : Offset; + sprintf(H, "%02X", J); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '$')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + Offset = val[B++]; + sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '#')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + sprintf(H, "%04X", val[B] + 256 * val[B + 1]); + strcat(S, H); + strcat(S, P + 1); + B += 2; + } + else { + strcpy(S, R); + } + return(B); +} + +/* symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { + char disasm[128]; + int32 ch = val[0] & 0x7f; + if (sw & (SWMASK('A') | SWMASK('C'))) { + fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch); + return SCPE_OK; + } + if (!(sw & SWMASK('M'))) { + return SCPE_ARG; + } + ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr); + fprintf(of, "%s", disasm); + return 1 - ch; /* need to return additional bytes */ +} + +/* numString checks determines the base of the number (ch, *numString) + and returns FALSE if the number is bad */ +static int32 checkbase(char ch, const char *numString) { + int32 decimal = (ch <= '9'); + if (toupper(ch) == 'H') { + return FALSE; + } + while (isxdigit(ch = *numString++)) { + if (ch > '9') { + decimal = FALSE; + } + } + return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE); +} + +static int32 numok(char ch, const char **numString, const int32 minvalue, + const int32 maxvalue, const int32 requireSign, int32 *result) { + int32 sign = 1, value = 0, base; + if (requireSign) { + if (ch == '+') { + ch = *(*numString)++; + } + else if (ch == '-') { + sign = -1; + ch = *(*numString)++; + } + else { + return FALSE; + } + } + if (!(base = checkbase(ch, *numString))) { + return FALSE; + } + while (isxdigit(ch)) { + value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10)); + ch = *(*numString)++; + } + if (toupper(ch) != 'H') { + (*numString)--; + } + *result = value * sign; + return (minvalue <= value) && (value <= maxvalue); +} + +static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, + int32 *at, int32 *hat, int32 *dollar) { + char pat = *pattern++; + char inp = *input++; + while ((pat) && (inp)) { + switch(pat) { + case '_': /* patterns containting '_' should never match */ + return FALSE; + case ',': + if (inp == ' ') { + inp = *input++; + continue; + } /* otherwise fall through */ + case ' ': + if (inp != pat) { + return FALSE; + } + pat = *pattern++; + inp = *input++; + while (inp == ' ') { + inp = *input++; + } + continue; + case '%': + inp = toupper(inp); + if ((inp == 'X') || (inp == 'Y')) { + if (*xyFirst) { /* make sure that second '%' corresponds to first */ + if (*xyFirst == inp) { + *xy = inp; + } + else { + return FALSE; + } + } + else { /* take note of first '%' for later */ + *xyFirst = inp; + *xy = inp; + } + } + else { + return FALSE; + } + break; + case '#': + if (numok(inp, &input, 0, 65535, FALSE, number)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '*': + if (numok(inp, &input, 0, 255, FALSE, star)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '@': + if (numok(inp, &input, -128, 65535, TRUE, at)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '$': + if (numok(inp, &input, 0, 65535, FALSE, dollar)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '^': + if (numok(inp, &input, 0, 255, FALSE, hat)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + default: + if (toupper(pat) != toupper(inp)) { + return FALSE; + } + } + pat = *pattern++; + inp = *input++; + } + while (inp == ' ') { + inp = *input++; + } + return (pat == 0) && (inp == 0); +} + +static INLINE int32 checkXY(const char xy) { + return xy == 'X' ? 0xdd : 0xfd; /* else is 'Y' */ +} + +static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]) { + char xyFirst = 0, xy; + int32 op, number, star, at, hat, dollar; + for (op = 0; op < 256; op++) { + number = star = at = dollar = -129; + if (match(Mnemonics[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = op; + if (number >= 0) { + val[1] = (0xff) & number; + val[2] = (0xff) & (number >> 8); + return -2; /* two additional bytes returned */ + } + else if (star >= 0) { + val[1] = (0xff) & star; + return -1; /* one additional byte returned */ + } + else if (at > -129) { + if ((-128 <= at) && (at <= 127)) { + val[1] = (int8)(at); + return -1; /* one additional byte returned */ + } + else { + return SCPE_ARG; + } + } + else if (dollar >= 0) { + dollar -= addr + 2; /* relative translation */ + if ((-128 <= dollar) && (dollar <= 127)) { + val[1] = (int8)(dollar); + return -1; /* one additional byte returned */ + } + else { + return SCPE_ARG; + } + } + else { + return SCPE_OK; + } + } + } + if (Mnemonics == Mnemonics8080) { + return SCPE_ARG; + } + + for (op = 0; op < 256; op++) { + if (match(MnemonicsCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = 0xcb; + val[1] = op; + return -1; /* one additional byte returned */ + } + } + + for (op = 0; op < 256; op++) { + number = -1; + if (match(MnemonicsED[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = 0xed; + val[1] = op; + if (number >= 0) { + val[2] = (0xff) & number; + val[3] = (0xff) & (number >> 8); + return -3; /* three additional bytes returned */ + } + else { + return -1; /* one additional byte returned */ + } + } + } + + for (op = 0; op < 256; op++) { + number = star = hat = -1; + xy = 0; + if (match(MnemonicsXX[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + /* all matches must have contained a '%' character */ + if (!(val[0] = checkXY(xy))) { + return SCPE_ARG; + } + val[1] = op; + if (number >= 0) { + val[2] = (0xff) & number; + val[3] = (0xff) & (number >> 8); + return -3; /* three additional bytes returned */ + } + else if ((star >= 0) && (hat >= 0)) { + val[2] = (0xff) & hat; + val[3] = (0xff) & star; + return -3; /* three additional bytes returned */ + } + else if (star >= 0) { + val[2] = (0xff) & star; + return -2; /* two additional bytes returned */ + } + else if (hat >= 0) { + val[2] = (0xff) & hat; + return -2; /* two additional bytes returned */ + } + else { + return -1; /* one additional byte returned */ + } + } + } + + for (op = 0; op < 256; op++) { + at = -129; + xy = 0; + if (match(MnemonicsXCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + /* all matches must have contained a '%' character */ + if (!(val[0] = checkXY(xy))) { + return SCPE_ARG; + } + val[1] = 0xcb; + if (at > -129) { + val[2] = (int8) (at); + } + else { + printf("Offset expected.\n"); + return SCPE_ARG; + } + val[3] = op; + return -3; /* three additional bytes returned */ + } + } + 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 +*/ +int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) { + while (isspace(*cptr)) cptr++; /* absorb spaces */ + if ((sw & (SWMASK('A') | SWMASK('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) { + return SCPE_ARG; /* must have one char */ + } + val[0] = (uint32) cptr[0]; + return SCPE_OK; + } + return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080); +} diff --git a/AltairZ80/altairz80_doc.txt b/AltairZ80/altairz80_doc.txt new file mode 100644 index 00000000..388cdaa2 --- /dev/null +++ b/AltairZ80/altairz80_doc.txt @@ -0,0 +1,972 @@ +To: Users +From: Peter Schorn +Subj: AltairZ80 Simulator Usage +Date: 15-Feb-2004 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Copyright (c) 2002-2004, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + +This memorandum documents the Altair 8800 Simulator with Z80 support. + +1. Simulator Files + +sim/scp.h + sim_console.h + sim_defs.h + sim_fio.h + sim_rev.h + sim_sock.h + sim_timer.h + sim_tmxr.h + scp.c + sim_console.c + sim_fio.c + sim_sock.c + sim_timer.c + sim_tmxr.c + +sim/AltairZ80/altairz80_defs.h + altairz80_cpu.c + altairz80_dsk.c + altairz80_hdsk.c + altairz80_sio.c + altairz80_sys.c + + +2. Revision History + +- 26-Jan-2004, Peter Schorn (added support for t-state stepping) +- 25-Feb-2003, Peter Schorn (added support for real time simulation) +- 9-Oct-2002, Peter Schorn (added support for simulated hard disk) +- 28-Sep-2002, Peter Schorn (number of tracks per disk can be configured) +- 19-Sep-2002, Peter Schorn (added WARNROM feature) +- 31-Aug-2002, Peter Schorn (added extended ROM features suggested + by Scott LaBombard) +- 4-May-2002, Peter Schorn (added description of MP/M II sample software) +- 28-Apr-2002, Peter Schorn (added periodic timer interrupts and three + additional consoles) +- 15-Apr-2002, Peter Schorn (added memory breakpoint) +- 7-Apr-2002, Peter Schorn (added ROM / NOROM switch) +Original version of this document written by Charles E Owen + + +3. Background. + + The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800 was +announced on the January 1975 cover of Popular Electronics, which boasted +you could buy and build this powerful computer kit for only $397. The kit +consisted at that time of only the parts to build a case, power supply, +card cage (18 slots), CPU card, and memory card with 256 *bytes* of memory. +Still, thousands were ordered within the first few months after the +announcement, starting the personal computer revolution as we know it +today. + + Many laugh at the small size of the that first kit, noting there were no +peripherals and the 256 byte memory size. But the computer was an open +system, and by 1977 MITS and many other small startups had added many +expansion cards to make the Altair quite a respectable little computer. The +"Altair Bus" that made this possible was soon called the S-100 Bus, later +adopted as an industry standard, and eventually became the IEE-696 Bus. + + +4. Hardware + + We are simulating a fairly "loaded" Altair 8800 from about 1977, with the +following configuration: + + device simulates + name(s) + + CPU Altair 8800 with Intel 8080 CPU board, 62KB + of RAM, 2K of EPROM with start boot ROM. + SIO MITS 88-2SIO Dual Serial Interface Board. Port 1 + is assumed to be connected to a serial "glass + TTY" that is your terminal running the Simulator. + PTR Paper Tape Reader attached to port 2 of the 2SIO board. + PTP Paper Tape Punch attached to port 2 of the + 2SIO board. This also doubles as a printer port. + DSK MITS 88-DISK Floppy Disk controller with up + to eight drives. + + +4.1 CPU + + We have 2 CPU options that were not present on the original machine but +are useful in the simulator. We also allow you to select memory sizes, but +be aware that some sample software requires the full 64K (i.e. CP/M) and +the MITS Disk Basic and Altair DOS require about a minimum of 24K. + + SET CPU 8080 Simulates the 8080 CPU (normal) + SET CPU Z80 Simulates the Z80 CPU. Note that some software (e.g. most + original Altair software such as 4K Basic) requires an 8080 CPU and + will not or not properly run on a Z80. This is mainly due to the use + of the parity flag on the 8080 which has not always the same + semantics on the Z80. + + SET CPU ITRAP Causes the simulator to halt if an invalid opcode + is detected (depending on the chosen CPU). + SET CPU NOITRAP Does not stop on an invalid Opcode. This is + how the real 8080 works. + + SET CPU 4K + SET CPU 8K + SET CPU 12K + SET CPU 16K + ...... (in 4K steps) + SET CPU 64K All these set various CPU memory configurations. + + SET CPU BANKED Enables the banked memory support. The simulated memory + has eight banks with address range 0..'common' (see registers below) + and a common area from 'common' to 0xfff which is common to all + banks. The currently active bank is determined by register 'bank' + (see below). You can only switch to banked memory if the memory + is set to 64K. The banked memory is used by CP/M 3. + + SET CPU NONBANKED Disables banked memory support. + + SET CPU ROM Enables the ROM from address 'ROMLOW' to 'ROMHIGH' + (see below under CPU Registers) and prevents write access + to these locations. This is the default setting. + + SET CPU NOROM Disables the ROM. + + SET CPU ALTAIRROM Enables the slightly modified but downwards compatible + Altair boot ROM at addresses 0FF00 to 0FFFF. This is the default. + + SET CPU NOALTAIRROM Disables standard Altair ROM behavior. + + SET CPU WARNROM Enables warning messages to be printed when the CPU + attempts to write into ROM or into non-existing memory. Also prints + a warning message if the CPU attempts to read from non-existing + memory. + + SET CPU NOWARNROM Suppreses all warning message of "WARNROM". Note that + some software tries on purpose to write to ROM in order to detect + the available RAM. + + The BOOT EPROM card starts at address 0FF00 if it has been enabled by +'SET CPU ALTAIRROM'. Jumping to this address will boot drive 0 of the +floppy controller (CPU must be set to ROM or equivalent code must be +present). If no valid bootable software is present there the machine +crashes. This is historically accurate behavior. + + The real 8080, on receiving a HLT (Halt) instruction, freezes the +processor and only an interrupt or CPU hardware reset will restore it. The +simulator is alot nicer, it will halt but send you back to the simulator +command line. + +CPU Registers include the following: + + Name Size Comment + + PC 16 The Program Counter + AF 16 The accumulator and the flag register + F = S Z - AC - P/V N C + S = Sign flag. + Z = Zero Flag. + AC = Auxillary Carry flag. + P/V = Parity flag on 8080 + Parity / Overflow flag on Z80 + - = not used (undefined) + N = Internal sign flag + C = Carry flag. + BC 16 The BC register pair. + Register B is the high 8 bits, C is the lower 8 bits + DE 16 The DE register pair. + Register D is the high 8 bits, E is the lower 8 bits. + HL 16 The HL register pair. + Register H is the high 8 bits, L is the lower 8 bits. + AF1 16 The alternate AF register (on Z80 only) + BC1 16 The alternate BC register (on Z80 only) + DE1 16 The alternate DE register (on Z80 only) + HL1 16 The alternate HL register (on Z80 only) + IX 16 The IX index register (on Z80 only) + IY 16 The IY index register (on Z80 only) + IFF 8 Interrupt flag (on Z80 only) + INT 8 Interrupt register (on Z80 only) + + SR 16 The front panel switches (use D SR 8 for 4k Basic). + WRU 8 The interrupt character. This starts as 5 + (ctrl-E) but some Altair software uses this + keystroke so best to change this to something + exotic such as 035 (which is Ctl-]). + + BANK 3 The currently active memory bank (if banked memory + is activated - see memory options above) + COMMON 16 The starting address of common memory. Originally set + to 0xc000 (note this setting must agree with the + value supplied to GENCPM for CP/M 3 system generation) + ROMLOW 16 The starting address of the ROM. Default is 0FF00. + ROMHIGH 16 The final address of the ROM. Default is 0FFFF. + CLOCK 32 The clock speed of the simulated CPU in kHz or 0 to run + at maximum speed. To set the clock speed for a typical + 4 MHz Z80 CPU, use D CLOCK 4000. The CP/M utility SPEED + measures the clock speed of the simulated CPU. + + +4.2 The Serial I/O Card (2SIO) + + This simple programmed I/O device provides 2 serial ports to the outside +world, which could be hardware jumpered to support RS-232 plugs or a TTY +current loop interface. The standard I/O addresses assigned by MITS was +10-11 (hex) for the first port, and 12-13 (hex) for the second. We follow +this standard in the Simulator. + + The simulator directs I/O to/from the first port to the screen. The +second port reads from an attachable "tape reader" file on input, and +writes to an attachable "punch file" on output. These files are considered +a simple stream of 8-bit bytes. + + The SIO can be configured in SIMH with the following commands: + + SET SIO TTY Bit 8 is set to zero on console output + SET SIO ANSI Bit 8 is not touched on console output + + SET SIO ALL Console input support lower- and upper case + SET SIO UPPER Console input is transformed to upper case characters only + (This feature is useful for most Altair software) + + SET SIO BS Map the delete character to backspace + SET SIO DEL Map the backspace character to delete + + SET SIO QUIET Do not print warning messages + SET SIO VERBOSE Print warning messages (useful for debugging) + The register SIOWL determines how often the same warning + is displayed. The default is 3. + + You can also attach the SIO to a port: + + ATTACH SIO 23 Console IO goes via a Telnet connection on port 23 + DETACH SIO Console IO goes via the regular SIMH console + + +4.3 The SIMH pseudo device + + The SIMH pseudo device facilitates the communication between the +simulated ALTAIR and the simulator environment. This device defines a +number of (most R/O) registers (see source code) which are primarily useful +for debugging purposes. + + The SIMH pseudo device can be configured with + + SET SIMH QUIET Do not print warning messages + SET SIMH VERBOSE Print warning messages (useful for debugging) + + SET SIMH TIMERON Start periodic timer interrupts + SET SIMH TIMEROFF Stop the periodic timer interrupts + + The following variables determine the behavior of the timer: + + TIMD This is the delay between consecutive interrupts in milliseconds. + Use D TIMD 20 for a 50 Hz clock. + TIMH This is the address of the interrupt handler to call for a + timer interrupt. + + +4.4 The 88-DISK controller. + + The MITS 88-DISK is a simple programmed I/O interface to the MITS 8-inch +floppy drive, which was basically a Pertec FD-400 with a power supply and +buffer board builtin. The controller supports neither interrupts nor DMA, +so floppy access required the sustained attention of the CPU. The standard +I/O addresses were 8, 9, and 0A (hex), and we follow the standard. Details +on controlling this hardware are in the altair_dsk.c source file. + + The only difference is that the simulated disks may be larger than the +original ones: The original disk had 77 tracks while the simulated disks +support up to 254 tracks (only relevant for CP/M). You can change the +number of tracks per disk by setting the appropriate value in TRACKS[..]. +For example "D TRACKS[0] 77" sets the number of tracks for disk 0 to the +original number of 77. The command "D TRACKS[0-7] 77" changes the highest +track number for all disks to 77. + + For debugging purposes you can set the trace level of some disk I/O +functions. To do so the following bits in TRACE (a register of the disk) +have been defined with the following meaning: + + 1 Trace all IN and OUT instructions on the disk ports 8 and 9 + 2 Trace all read and writes to full sectors on the disk + 4 Print a message whenever an unnecessary step-in or step out of the + disk head occurs (often an indication of an infinite loop) + 8 Print a message whenever the disk head appears to be waiting for a + sector which does not show up (often an indication of an infinite + loop) + +For example the command "D TRACE 10" will trace options 2+8 from above. + + The DSK device can be configured with + + SET DSK QUIET Do not print warning messages for disk + SET DSK VERBOSE Print warning messages for disk + (useful for debugging) + The register DSKWL determines how often the + same warning is displayed. The default is 3. + + SET DSK WRITEENABLED Allow write operations for disk + SET DSK LOCKED Disk is locked, i.e. no write operations + will be allowed. + + +4.5 The simulated hard disk + + In order to increase the available storage capacity, the simulator +features 8 simulated hard disks with a capacity of 8MB (HDSK0 to HDSK7). +Currently only CP/M supports two hard disks as devices I: and J:. + + For debugging purposes one can set the trace flag by executing the +command "D HDTRACE 1". The default for "HDTRACE" is 0 (no trace). + + The HDSK device can be configured with + + SET HDSK QUIET Do not print warning messages for hard disk + SET HDSK VERBOSE Print warning messages for hard disk + (useful for debugging) + + SET HDSK WRITEENABLED Allow write operations for hard disk + SET HDSK LOCKED Hard disk is locked, i.e. no + write operations will be allowed. + + +5. Sample Software + + Running an Altair in 1977 you would be running either MITS Disk Extended +BASIC, or the brand new and sexy CP/M Operating System from Digital +Research. Or possibly, you ordered Altair DOS back when it was promised in +1975, and are still waiting for it to be delivered in early 1977. + + We have samples of all three for you to check out. We can't go into the +details of how they work, but we'll give you a few hints. + + +5.1 CP/M Version 2.2 + + This version is my own port of the standard CP/M to the Altair. There +were some "official" versions but I don't have them. None were endorsed or +sold by MITS to my knowledge, however. + + To boot CP/M: + + sim> attach dsk cpm2.dsk + sim> boot dsk + + CP/M feels like DOS, sort of. DIR will work. I have included all the +standard CP/M utilities, plus a few common public-domain ones. I also +include the sources to the customized BIOS and some other small programs. +TYPE will print an ASCII file. DUMP will dump a binary one. LS is a +better DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" +them to binary format (.COM). ED is a simple editor, #A command will bring +the source file to the buffer, T command will "type" lines, L will move +lines, E exits the editor. 20L20T will move down 20 lines, and type 20. +Very DECish. DDT is the debugger, DO is a batch-type command processor. A +sample batch file that will assemble and write out the bootable CP/M image +(on drive A) is "SYSCPM2.SUB". To run it, type "DO SYSCPM2". + + In order to efficiently transfer files into the CP/M environment use the +included program R . If you have a file named foo.ext in the +current directory (i.e. the directory where SIMH is), executing R FOO.EXT +under CP/M will transfer the file onto the CP/M disk. Transferring a file +from the CP/M environment to the SIMH environment is accomplished by +W for text files or by W B for binary files. +The simplest way for transferring multiple files is to create a ".SUB" +batch file which contains the necessary R resp. W commands. + + If you need more storage space you can use a simulated hard disk on +drives I: and J:. To use do "attach HDSK0 hdi.dsk" and issue the +"XFORMAT I:" resp. "XFORMAT J:" command from CP/M do initialize the disk +to an empty state. + +The disk "cpm2.dsk" contains the following files: +Name Ext Size Comment +ASM .COM 8K ; CP/M assembler +BDOS .MAC 68K ; Basic Disk Operating System assembler source code +BOOT .COM 1K ; transfer control to boot ROM +BOOT .MAC 2K ; source for BOOT.COM +BOOTGEN .COM 2K ; put a program on the boot sectors +CBIOSX .MAC 48K ; CP/M 2 BIOS source for Altair +CCP .MAC 26K ; Console Command Processor assembler source code +COPY .COM 2K ; copy disks +CPMBOOT .COM 12K ; CP/M operating system +CPU .COM 2K ; get and set the CPU type (8080 or Z80) +CPU .MAC 2K ; source for CPU.COM +CREF80 .COM 4K ; cross reference utility +DDT .COM 6K ; 8080 debugger +DDTZ .COM 10K ; Z80 debugger +DIF .COM 4K ; determine differences between two files +DO .COM 2K ; batch processing +DSKBOOT .MAC 8K ; source for boot ROM +DUMP .COM 2K ; hex dump a file +ED .COM 8K ; line editor +ELIZA .BAS 10K ; Eliza game in Basic +EX8080 .COM 12K ; exercise 8080 instruction set +EXZ80N .COM 12K ; exercise Z80 instruction set, No undefined status bits +EXZ80U .COM 12K ; exercise Z80 instruction set, Undefined status bits +EXZ80 .MAC 54K ; source for EX8080.COM, EXZ80N.COM, EXZ80U.COM +EX .SUB 2K ; benchmark execution of EX8080.COM, EXZ80N.COM, EXZ80U.COM +FORMAT .COM 2K ; format disks +GO .COM 0K ; start the currently loaded program at 100H +HDSKBOOT.MAC 6K ; boot code for hard disk +L80 .COM 12K ; Microsoft linker +LADDER .COM 40K ; game +LADDER .DAT 2K ; high score file for LADDER.COM +LIB80 .COM 6K ; library utility +LOAD .COM 2K ; load hex files +LS .COM 4K ; directory utility +LU .COM 20K ; library utility +M80 .COM 20K ; Microsoft macro assembler +MBASIC .COM 24K ; Microsoft Basic interpreter +MC .SUB 2K ; assemble and link an assembler program +MCC .SUB 2K ; read, assemble and link an assembler program +MCCL .SUB 2K ; assemble, link and produce listing +MEMCFG .LIB 2K ; defines the memory configuration +MOVER .MAC 2K ; moves operating system in place +OTHELLO .COM 12K ; Othello (Reversi) game +PIP .COM 8K ; Peripheral Interchange Program +PRELIM .COM 2K ; preliminary CPU tests +PRELIM .MAC 6K ; source code for PRELIM.COM +R .COM 4K ; read files from SIMH environment +RSETSIMH.COM 2K ; reset SIMH interface +RSETSIMH.MAC 2K ; assembler source for RSETSIMH.COM +SHOWSEC .COM 3K ; show sectors on a disk +SID .COM 8K ; debugger for 8080 +SPEED .COM 2K ; utility to measure the clock speed of the simulated CPU +STAT .COM 6K ; provide information about currently logged disks +SURVEY .COM 2K ; system survey +SURVEY .MAC 16K ; assembler source for SURVEY.COM +SYSCOPY .COM 2K ; copy system tracks between disks +SYSCPM2 .SUB 2K ; create CP/M 2 on drive A: +TIMER .COM 2K ; perform various timer operations +TIMER .MAC 2K ; source code for TIMER.COM +UNCR .COM 8K ; un-crunch utility +UNERA .COM 2K ; un-erase a file +UNERA .MAC 16K ; source for UNERA.COM +USQ .COM 2K ; un-squeeze utility +W .COM 4K ; write files to SIMH environment +WM .COM 12K ; word master screen editor +WM .HLP 3K ; help file for WM.COM +WORM .COM 4K ; worm game for VT100 terminal +XFORMAT .COM 2K ; initialise a drive (floppy or hard disk) +XSUB .COM 2K ; support for DO.COM +ZAP .COM 10K ; SuperZap 5.2 disk editor configured for VT100 +ZSID .COM 10K ; debugger for Z80 +ZTRAN4 .COM 4K ; translate 8080 mnemonics into Z80 equivalents + + +5.2 CP/M Version 3 with banked memory + + CP/M 3 is the successor to CP/M 2.2. A customised BIOS (BIOS3.MAC) is +included to facilitate modification if so desired. The defaults supplied in +GENCPM.DAT for system generation can be used. BOOTGEN.COM is used to place +the CP/M loader (LDR.COM) on the boot tracks of a disk. + + Running CP/M 3 with banked memory: + sim> attach dsk cpm3.dsk + sim> reset cpu + sim> set cpu banked + sim> set cpu itrap + sim> boot dsk + + Executing "DO SYSCPM3" will re-generate the banked version of CP/M 3. You +can boot CP/M 3 with or without a Z80 CPU. The Z80 CPU is needed for both +sysgens due to the use of BOOTGEN.COM which requires it. + +The disk "cpm3.dsk" contains the following files: +ASM .COM 8K ; CP/M assembler +ASSIGN .SYS 2K +BDOS3 .SPR 10K +BIOS3 .MAC 28K ; CP/M 3 BIOS source for Altair SIMH +BIOS3 .SPR 4K +BNKBDOS3.SPR 14K +BNKBIOS3.SPR 4K +BOOT .COM 2K ; transfer control to boot ROM +BOOTGEN .COM 2K ; put a program on the boot sectors +CCP .COM 4K +COPYSYS .COM 2K +CPM3 .SYS 18K +CPMLDR .MAC 38K ; CP/M 3 loader assembler source +DATE .COM 4K ; date utility +DDT .COM 6K ; 8080 debugger +DDTZ .COM 10K ; Z80 debugger +DEFS .LIB 2K ; include file for BIOS3.MAC to create banked CP/M 3 +DEVICE .COM 8K +DIF .COM 4K ; determine differences between two files +DIR .COM 16K ; directory utility +DO .COM 6K ; batch processing +DUMP .COM 2K +ED .COM 10K +ERASE .COM 4K +GENCOM .COM 16K +GENCPM .COM 22K +GENCPM .DAT 4K ; CP/M generation information for banked version +GENCPMNB.DAT 4K ; CP/M generation information for non-banked version +GET .COM 8K +HELP .COM 8K ; help utility +HELP .HLP 62K ; help files +HEXCOM .CPM 2K +HIST .UTL 2K +INITDIR .COM 32K +L80 .COM 12K ; Microsoft linker +LDR .COM 4K ; CP/M loader with optimised loader BIOS +LDRBIOS3.MAC 14K ; optimised (for space) loader BIOS +LIB .COM 8K ; Digital Research librarian +LINK .COM 16K ; Digital Research linker +LOAD .COM 2K +M80 .COM 20K ; Microsoft macro assembler +MC .SUB 2K ; assemble and link an assmbler program +MCC .SUB 2K ; read, assemble and link an assembler program +PATCH .COM 4K +PIP .COM 10K ; Peripheral Interchange Program +PROFILE .SUB 2K ; commands to be executed at start up +PUT .COM 8K +R .COM 4K ; read files from SIMH environment +RENAME .COM 4K +RESBDOS3.SPR 2K +RMAC .COM 14K ; Digital Research macro assembler +RSETSIMH.COM 2K ; reset SIMH interface +SAVE .COM 2K +SCB .MAC 2K +SET .COM 12K +SETDEF .COM 6K +SHOW .COM 10K +SHOWSEC .COM 4K ; show sectors on a disk +SID .COM 8K ; 8080 debugger +SYSCOPY .COM 2K ; copy system tracks between disks +SYSCPM3 .SUB 2K ; create banked CP/M 3 system +TRACE .UTL 2K +TSHOW .COM 2K ; show split time +TSTART .COM 2K ; create timer and start it +TSTOP .COM 2K ; show final time and stop timer +TYPE .COM 4K +UNERA .COM 2K ; un-erase a file +W .COM 4K ; write files to SIMH environment +XREF .COM 16K ; cross reference utility +ZSID .COM 10K ; Z80 debugger + + +5.3 MP/M II with banked memory + + MP/M II is an acronym for MultiProgramming Monitor Control Program for +Microprocessors. It is a multiuser operating system for an eight bit +microcomputer. MP/M II supports multiprogramming at each terminal. This +version supports four terminals available via Telnet. To boot: + + sim> attach dsk mpm.dsk + sim> set cpu itrap + sim> set cpu z80 + sim> set cpu rom + sim> set cpu banked + sim> attach sio 23 + sim> d common b000 + sim> boot dsk + + Now connect a Telnet session to the simulator and type "MPM" at the "A>" +prompt. Now you can connect up to three additional terminals via Telnet to +the Altair running MP/M II. To re-generate the system perform "DO SYSMPM" +in the CP/M environment (not possible under MP/M since XSUB is needed). + +The disk "mpm.dsk" contains the following files: +Name Ext Size Comment +ABORT .PRL 2K ; abort a process +ABORT .RSP 2K +ASM .PRL 10K ; MP/M assembler +BNKBDOS .SPR 12K ; banked BDOS +BNKXDOS .SPR 2K ; banked XDOS +BNKXIOS .SPR 4K ; banked XIOS +BOOTGEN .COM 2K ; copy an executable to the boot section +CONSOLE .PRL 2K ; print console number +CPM .COM 2K ; return to CP/M +CPM .MAC 2K ; source for CPM.COM +DDT .COM 6K ; MP/M DDT +DDT2 .COM 6K ; CP/M DDT +DDTZ .COM 10K ; CP/M DDT with Z80 support +DIF .COM 4K ; difference between two files +DIR .PRL 2K ; directory command +DO .COM 2K ; CP/M submit +DSKRESET.PRL 2K ; disk reset command +DUMP .MAC 6K ; source for DUMP.PRL +DUMP .PRL 2K ; dump command +ED .PRL 10K ; MP/M line editor +ERA .PRL 2K ; erase command +ERAQ .PRL 4K ; erase comand (verbose) +GENHEX .COM 2K +GENMOD .COM 2K +GENSYS .COM 10K +L80 .COM 12K ; Microsoft linker +LDRBIOS .MAC 14K ; loader BIOS +LIB .COM 8K ; library utility +LINK .COM 16K ; linker +LOAD .COM 2K ; loader +M80 .COM 20K ; Microsoft macro assembler +MC .SUB 2K ; assemble and link an assmbler program +MCC .SUB 2K ; read, assemble and link an assembler program +MPM .COM 8K ; start MP/M II +MPM .SYS 26K ; MP/M system file +MPMD .LIB 2K ; define a banked system +MPMLDR .COM 6K ; MP/M loader without LDRBIOS +MPMSTAT .BRS 6K ; status of MP/M system +MPMSTAT .PRL 6K +MPMSTAT .RSP 2K +MPMXIOS .MAC 26K ; XIOS for MP/M +PIP .PRL 10K ; MP/M peripheral interchange program +PIP2 .COM 8K ; CP/M peripheral interchange program +PRINTER .PRL 2K +PRLCOM .PRL 4K +R .COM 4K ; read a file from the SIMH environment +RDT .PRL 8K ; debugger for page relocatable programs +REN .PRL 4K ; rename a file +RESBDOS .SPR 4K ; non-banked BDOS +RMAC .COM 14K ; Digital Research macro assembler +RSETSIMH.COM 2K ; reset SIMH interface +SCHED .BRS 2K ; schedule a job +SCHED .PRL 4K +SCHED .RSP 2K +SDIR .PRL 18K ; fancy directory command +SET .PRL 8K ; set parameters +SHOW .PRL 8K ; show status of disks +SPOOL .BRS 4K ; spool utility +SPOOL .PRL 4K +SPOOL .RSP 2K +STAT .COM 6K ; CP/M stat command +STAT .PRL 10K ; MP/M stat command +STOPSPLR.PRL 2K ; stop spooler +SUBMIT .PRL 6K ; MP/M submit +SYSCOPY .COM 2K ; copy system tracks +SYSMPM .SUB 2K ; do a system generation +SYSTEM .DAT 2K ; default values for system generation +TMP .SPR 2K +TOD .PRL 4K ; time of day +TSHOW .COM 2K ; show split time +TSTART .COM 2K ; create timer and start it +TSTOP .COM 2K ; show final time and stop timer +TYPE .PRL 2K ; type a file on the screen +USER .PRL 2K ; set user area +W .COM 4K ; write a file to SIMH environment +XDOS .SPR 10K ; XDOS +XREF .COM 16K ; cross reference utility +XSUB .COM 2K ; for CP/M DO + + +5.4 CP/M application software + + There is also a small collection of sample application software +containing the following items: + +- SPL: a Small Programming Language with a suite of sample programs +- PROLOGZ: a Prolog interpreter written in SPL with sources +- PASCFORM: a Pascal pretty printer written in Pascal +- Pascal MT+: Pascal language system needed to compile PASCFORM + +The sample software comes on "app.dsk" and to use it do + + sim> attach dsk1 app.dsk + +before booting CP/M. + +The disk "app.dsk" contains the following files: +Name Ext Size Comment +BOOTGEN .COM 2K +BOOTGEN .SPL 6K ; SPL source for BOOTGEN.COM +C .SUB 2K ; batch file for compiling an SPL source file +CALC .PRO 4K ; Prolog demo program: Calculator +CC .SUB 2K ; compile an SPL source which is on the underlying + file system +DECLARAT. 12K ; common include file, SPL source +DIF .COM 4K +DIF .SPL 10K ; SPL source for DIF.COM +EDIT .SPL 10K ; screen editor for PROLOGZ, SPL source +FAMILY .PRO 4K ; Prolog demo program: Family relations +INTEGER .PRO 2K ; Prolog demo program: Integer arithmetic +KNAKE .PRO 2K ; Prolog demo program: Logic puzzle +LINKMT .COM 12K ; Pascal MT+ 5.5 linker +MAIN .SPL 14K ; main module for PROLOGZ, SPL source +MOVE .MAC 4K ; helper functions for PROLOGZ in assembler +MTERRS .TXT 6K ; Pascal MT+ error messages +MTPLUS .000 14K ; Pascal MT+ 5.5 compiler file +MTPLUS .001 12K ; Pascal MT+ 5.5 compiler file +MTPLUS .002 8K ; Pascal MT+ 5.5 compiler file +MTPLUS .003 8K ; Pascal MT+ 5.5 compiler file +MTPLUS .004 18K ; Pascal MT+ 5.5 compiler file +MTPLUS .005 8K ; Pascal MT+ 5.5 compiler file +MTPLUS .006 6K ; Pascal MT+ 5.5 compiler file +MTPLUS .COM 36K ; Pascal MT+ 5.5 compiler +PASCFORM.COM 36K ; Pascal formatter +PASCFORM.PAS 54K ; Pascal formatter source code +PASCFORM.SUB 2K ; create Pascal formatter +PASLIB .ERL 24K ; Pascal MT+ 5.5 run time library +PINST .COM 4K ; terminal installation program for PROLOGZ +PINST .SPL 16K ; terminal installation program for PROLOGZ, + SPL source +PROLOGZ .COM 18K ; PROLOGZ interpreter and screen editor +PROLOGZ .SPL 2K ; PROLOGZ main program, SPL source +PROLOGZ .TXT 40K ; PROLOGZ documentation in German +PROVE .SPL 16K ; backtrack theorem prover for PROLOGZ, SPL source +PZCLEAN .SUB 2K ; PROLOGZ: remove all created ".rel" and ".lst" files +PZLINK .SUB 2K ; PROLOGZ: create PINST, PROLOGZ and personalise the + serial number +PZMAKE .SUB 2K ; PROLOGZ: compiles the sources (you can ignore + any compiler errors) +QUEEN .PRO 2K ; Prolog demo program: N-queens problem +READ .COM 4K +READ .SPL 10K ; SPL source for R.COM +SHOWSEC .COM 4K +SHOWSEC .SPL 6K ; SPL source for SHOWSEC.COM +SPEED .COM 2K ; utility to measure the clock speed of the simulated CPU +SPEED .SPL 2K ; SPL source for SPEED.COM, requires SWLIB.MAC +SPL .COM 38K ; the SPL compiler itself +SPL .TXT 56K ; SPL language and compiler documentation in German +SPLERROR.DAT 12K ; error messages of the compiler (in German) +SPLIB .REL 6K ; SPL runtime library +STDIO . 2K ; include file for SPL programs +SWLIB .MAC 2K ; assembler utility routines needed by SPEED.SPL +SYSCOPY .COM 2K +SYSCOPY .SPL 6K ; SPL source for SYSCOPY.COM +TERMBDOS.SPL 2K ; terminal interface to CP/M for PROLOGZ, SPL source +UTIL .SPL 18K ; utility functions for PROLOGZ, SPL source +WRITE .COM 4K +WRITE .SPL 8K ; SPL source for W.COM +XFORMAT .COM 2K +XFORMAT .SPL 6K ; SPL source for XFORMAT.COM + + +5.5 MITS Disk Extended BASIC Version 4.1 + + This was the commonly used software for serious users of the Altair +computer. It is a powerful (but slow) BASIC with some extended commands to +allow it to access and manage the disk. There was no operating system it +ran under. To boot: + + sim> set cpu 8080 ;Z80 will not work + sim> attach dsk mbasic.dsk + sim> set sio upper + sim> go ff00 + + MEMORY SIZE? [return] + LINEPRINTER? [C return] + HIGHEST DISK NUMBER? [0 return] (0 here = 1 drive system) + NUMBER OF FILES? [3 return] + NUMBER OF RANDOM FILES? [2 return] + + 44041 BYTES FREE + ALTAIR BASIC REV. 4.1 + [DISK EXTENDED VERSION] + COPYRIGHT 1977 BY MITS INC. + OK + [MOUNT 0] + OK + [FILES] + + +5.6 Altair DOS Version 1.0 + + This was long promised but not delivered until it was almost irrelevant. +A short attempted tour will reveal it to be a dog, far inferior to CP/M. To +boot: + + sim> d tracks[0-7] 77 ;set to Altair settings + sim> set cpu altairrom + sim> attach dsk altdos.dsk + sim> set sio upper + sim> go ff00 + + MEMORY SIZE? [return] + INTERRUPTS? N [return] + HIGHEST DISK NUMBER? [0 return] (3 here = 4 drive system) + HOW MANY DISK FILES? [3 return] + HOW MANY RANDOM FILES? [2 return] + + 056449 BYTES AVAILABLE + DOS MONITOR VER 1.0 + COPYRIGHT 1977 BY MITS INC + .[MNT 0] + + .[DIR 0] + + +5.7 Altair Basic 3.2 (4k) + + In order to run the famous 4k Basic, use the following commands (the +trick is to get the Switch Register right). + + sim> set cpu 8080 ;note 4k Basic will not run on a Z80 CPU + sim> set sio upper ;4k Basic does not like lower case letters as input + sim> set sio ansi ;4k Basic produces 8-bit output, strip to seven bits + sim> d sr 8 ;good setting for the Switch Register + sim> load 4kbas.bin 0 ;load it at 0 + sim> go 0 ;and start it + MEMORY SIZE? [return] + TERMINAL WIDTH? [return] + WANT SIN? [Y] + + 61911 BYTES FREE + + BASIC VERSION 3.2 + [4K VERSION] + + OK + + +5.8 Altair 8k Basic + Running 8k Basic follows the procedure for 4k Basic. + + sim> set cpu 8080 ;note 8k Basic will not run on a Z80 CPU + sim> set sio upper ;8k Basic does not like lower case letters as input + sim> set sio ansi ;8k Basic produces 8-bit output, strip to seven bits + sim> d sr 8 ;good setting for the Switch Register + sim> load 8kbas.bin 0 ;load it at 0 + sim> go 0 ;and start it + MEMORY SIZE? [A] + + WRITTEN FOR ROYALTIES BY MICRO-SOFT + + MEMORY SIZE? [return] + TERMINAL WIDTH? [return] + WANT SIN-COS-TAN-ATN? [Y] + + 58756 BYTES FREE + ALTAIR BASIC REV. 4.0 + [EIGHT-K VERSION] + COPYRIGHT 1976 BY MITS INC. + OK + + +5.9 Altair Basic 4.0 + + Execute the following commands to run Altair Extended Basic: + + sim> set sio upper ;Extended Basic does not like lower case letters as input + sim> set sio ansi ;Extended Basic produces 8-bit output, strip to seven bits + sim> d sr 8 ;good setting for the Switch Register + sim> load exbas.bin 0 ;load it at 0 + sim> go 0 ;and start it + 16384 Bytes loaded at 0. + + MEMORY SIZE? [return] + WANT SIN-COS-TAN-ATN? [Y] + + 50606 BYTES FREE + ALTAIR BASIC REV. 4.0 + [EXTENDED VERSION] + COPYRIGHT 1977 BY MITS INC. + OK + + +5.10 Altair Disk Extended Basic Version 300-5-C + + This version of Basic was provided by Scott LaBombard. To execute use the +following commands: + + sim> d tracks[0-7] 77 ;set to Altair settings + sim> at dsk extbas5.dsk + sim> g 0 + + MEMORY SIZE? [return] + LINEPRINTER? [C] + HIGHEST DISK NUMBER? [0] + HOW MANY FILES? [3] + HOW MANY RANDOM FILES? [3] + + 42082 BYTES FREE + + ALTAIR DISK EXTENDED BASIC + VERSION 300-5-C [01NOV78] + COPYRIGHT 1978 BY MITS INC. + + OK + + +6. Special simulator features + + +6.1 Memory access breakpoints + + In addition to the regular SIMH features such as PC queue, breakpoints +etc., this simulator supports memory access breakpoints. A memory access +breakpoint is triggered when a pre-defined memory location is accessed +(read, write or update). To set a memory location breakpoint enter + +sim> break -m + + Execution will stop whenever an operation accesses . Note that +a memory access breakpoint is not triggered by fetching code from memory +(this is the job of regular breakpoints). This feature has been implemented +by using the typing facility of the SIMH breakpoints. + + +6.2 T-state stepping + + The SIMH step command supports the "-t" modifier to allow steppping for +a predefined number of t-states. For example + +sim> step -t 1000 + +will cause the simulated CPU to execute 1000 t-states (note that the shortest +instruction will have 4 t-states). On the other hand, the command + +sim> step 1000 + +will cause the simulated CPU to execute 1000 instructions. + + +7. Brief summary of all major changes to the original Altair simulator +- Full support for Z80. CP/M software requiring a Z80 CPU now runs + properly. DDTZ and PROLOGZ are included for demonstration purposes. +- Added banked memory support. +- PC queue implemented. +- Full assembler and dis-assembler support for Z80 and 8080 mnemonics. + Depending on the current setting of the CPU, the appropriate mnemonics + are used. +- The BOOT ROM was changed to fully load the software from disk. The + original code basically loaded a copy of itself from the disk and + executed it. +- ROM and memory size settings are now fully honored. This means that you + cannot write into the ROM or outside the defined RAM (e.g. when the RAM size + was truncated with the SET CPU commands). This feature allows programs which + check for the size of available RAM to run properly (e.g. 4k Basic). In + addition one can enable and disable the ROM which is useful in special cases + (e.g. when testing a new version of the ROM). +- The console can also be used via Telnet. This is useful when a terminal is + needed which supports cursor control such as a VT100. PROLOGZ for example + has a built-in screen editor which works under Telnet. +- Simplified file exchange for CP/M. Using the READ program under CP/M one + can easily import files into CP/M from the regular file system. Note that PIP + does not work properly on non-text files on PTR. +- The WRITE program can be used to transfer files from the CP/M environment to + the regular environment (binary or ASCII transfer). +- The last character read from PTR is always Control-Z (the EOF character for + CP/M). This makes sure that PIP (Peripheral Interchange Program on CP/M) will + terminate properly. +- Fixed a bug in the BIOS warm boot routine which caused CP/M to crash. +- Modified the BIOS for CP/M to support 8 disks. +- Added CP/M 3 banked version as sample software +- Changed from octal to hex +- Made the DSK and SIO device more robust (previously malicious code could + crash the simulator) +- Added memory access break points +- Added periodic timer interrupts (useful for MP/M) +- Added additional consoles (useful for MP/M) +- Added MP/M II banked version as sample software diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index 9794098b..bb1d0d01 100644 --- a/AltairZ80/altairz80_hdsk.c +++ b/AltairZ80/altairz80_hdsk.c @@ -1,6 +1,6 @@ /* altairz80_hdsk.c: simulated hard disk device to increase capacity - Copyright (c) 2002-2003, Peter Schorn + Copyright (c) 2002-2004, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -111,7 +111,9 @@ DEVICE hdsk_dev = { "HDSK", hdsk_unit, hdsk_reg, hdsk_mod, 8, 10, 31, 1, 8, 8, NULL, NULL, NULL, - &hdsk_boot, NULL, NULL, NULL, 0, NULL, NULL }; + &hdsk_boot, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL }; static t_stat hdsk_svc(UNIT *uptr) { return SCPE_OK; @@ -224,34 +226,34 @@ static int32 checkParameters(void) { int32 currentFlag; if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { if (hdsk_hasVerbose()) { - message2("HDSK%d does not exist, will use HDSK0 instead.\n", selectedDisk); + message2("HDSK%d does not exist, will use HDSK0 instead.", selectedDisk); } selectedDisk = 0; } currentFlag = (hdsk_dev.units + selectedDisk) -> flags; if ((currentFlag & UNIT_ATT) == 0) { if (currentFlag & UNIT_HDSK_VERBOSE) { - message2("HDSK%d is not attached.\n", selectedDisk); + message2("HDSK%d is not attached.", selectedDisk); } return FALSE; /* cannot read or write */ } if ((selectedSector < 0) || (selectedSector >= HDSK_SECTORS_PER_TRACK)) { if (currentFlag & UNIT_HDSK_VERBOSE) { - message4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.\n", + message4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.", selectedDisk, selectedSector, HDSK_SECTORS_PER_TRACK); } selectedSector = 0; } if ((selectedTrack < 0) || (selectedTrack >= HDS_MAX_TRACKS)) { if (currentFlag & UNIT_HDSK_VERBOSE) { - message4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.\n", + message4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.", selectedDisk, selectedTrack, HDS_MAX_TRACKS); } selectedTrack = 0; } selectedDMA &= ADDRMASK; if (hdskTrace) { - message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x\n", + message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x", (hdskLastCommand == hdsk_read) ? "Read" : "Write", selectedDisk, selectedSector, selectedTrack, selectedDMA); } @@ -263,7 +265,7 @@ static int32 doSeek(void) { if (fseek(uptr -> fileref, HDSK_TRACK_SIZE * selectedTrack + HDSK_SECTOR_SIZE * selectedSector, SEEK_SET)) { if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - message4("Could not access HDSK%d Sector=%02d Track=%04d.\n", + message4("Could not access HDSK%d Sector=%02d Track=%04d.", selectedDisk, selectedSector, selectedTrack); } return CPM_ERROR; @@ -285,7 +287,7 @@ static int32 doRead(void) { hdskbuf[i] = CPM_EMPTY; } if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - message4("Could not read HDSK%d Sector=%02d Track=%04d.\n", + message4("Could not read HDSK%d Sector=%02d Track=%04d.", selectedDisk, selectedSector, selectedTrack); } return CPM_OK; /* allows the creation of empty hard disks */ @@ -309,7 +311,7 @@ static int32 doWrite(void) { } if (fwrite(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - message4("Could not write HDSK%d Sector=%02d Track=%04d.\n", + message4("Could not write HDSK%d Sector=%02d Track=%04d.", selectedDisk, selectedSector, selectedTrack); } return CPM_ERROR; @@ -317,7 +319,7 @@ static int32 doWrite(void) { } else { if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - message4("Could not write to locked HDSK%d Sector=%02d Track=%04d.\n", + message4("Could not write to locked HDSK%d Sector=%02d Track=%04d.", selectedDisk, selectedSector, selectedTrack); } return CPM_ERROR; @@ -334,7 +336,7 @@ static int32 hdsk_in(const int32 port) { return result; } else if (hdsk_hasVerbose()) { - message4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).\n", + message4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).", port, hdskLastCommand, hdskCommandPosition); } return CPM_OK; diff --git a/GRI/gri_cpu.c b/GRI/gri_cpu.c index f6166100..06987a36 100644 --- a/GRI/gri_cpu.c +++ b/GRI/gri_cpu.c @@ -1,6 +1,6 @@ /* gri_cpu.c: GRI-909 CPU simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/GRI/gri_defs.h b/GRI/gri_defs.h index 2888bed1..1764237c 100644 --- a/GRI/gri_defs.h +++ b/GRI/gri_defs.h @@ -1,6 +1,6 @@ /* gri_defs.h: GRI-909 simulator definitions - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/GRI/gri_doc.txt b/GRI/gri_doc.txt index aeab0072..c7fbfc13 100644 --- a/GRI/gri_doc.txt +++ b/GRI/gri_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: GRI-909 Simulator Usage -Date: 20-Apr-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,13 +36,19 @@ This memorandum documents the GRI-909 simulator. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c + sim_timer.c sim_tmxr.c sim/gri/ gri_defs.h diff --git a/GRI/gri_sys.c b/GRI/gri_sys.c index 6bde9909..9bd8a41c 100644 --- a/GRI/gri_sys.c +++ b/GRI/gri_sys.c @@ -1,6 +1,6 @@ /* gri_sys.c: GRI-909 simulator interface - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/H316/h316_cpu.c b/H316/h316_cpu.c index 997d5794..2a03a039 100644 --- a/H316/h316_cpu.c +++ b/H316/h316_cpu.c @@ -25,6 +25,7 @@ cpu H316/H516 CPU + 04-Jan-04 RMS Removed unnecessary compare 31-Dec-03 RMS Fixed bug in cpu_set_hist 24-Oct-03 RMS Added DMA/DMC support, instruction history 30-Dec-01 RMS Added old PC queue @@ -1317,7 +1318,7 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ } /* end for */ if (dibp->chan) { /* DMA/DMC? */ chan = dibp->chan - 1; - if ((chan >= 0) && (chan < DMC_V_DMC1) && (chan >= dma_nch)) { + if ((chan < DMC_V_DMC1) && (chan >= dma_nch)) { printf ("%s configured for DMA channel %d\n", sim_dname (dptr), chan + 1); if (sim_log) fprintf (sim_log, "%s configured for DMA channel %d\n", sim_dname (dptr), chan + 1); diff --git a/H316/h316_defs.h b/H316/h316_defs.h index d1593b0f..c70ec1d5 100644 --- a/H316/h316_defs.h +++ b/H316/h316_defs.h @@ -1,6 +1,6 @@ /* h316_defs.h: Honeywell 316/516 simulator definitions - Copyright (c) 1999-2003, Robert M. Supnik + Copyright (c) 1999-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/H316/h316_doc.txt b/H316/h316_doc.txt index 5954577b..6bf32676 100644 --- a/H316/h316_doc.txt +++ b/H316/h316_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: H316 Simulator Usage -Date: 15-Nov-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -38,15 +38,21 @@ This memorandum documents the Honeywell 316/516 simulator. The H316 requires the following files: -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/h316/ h316_defs.h diff --git a/H316/h316_dp.c b/H316/h316_dp.c index 7f865c76..fe943062 100644 --- a/H316/h316_dp.c +++ b/H316/h316_dp.c @@ -1,6 +1,6 @@ /* h316_dp.c: Honeywell 4623, 4651, 4720 disk simulator - Copyright (c) 2003, Robert M. Supnik + Copyright (c) 2003-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/H316/h316_fhd.c b/H316/h316_fhd.c index b264e5e1..921a295f 100644 --- a/H316/h316_fhd.c +++ b/H316/h316_fhd.c @@ -1,6 +1,6 @@ /* h316_fhd.c: H316/516 fixed head simulator - Copyright (c) 2003, Robert M. Supnik + Copyright (c) 2003-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ fhd 516-4400 fixed head disk + 04-Jan-04 RMS Changed sim_fsize calling sequence + These head-per-track devices are buffered in memory, to minimize overhead. */ @@ -402,14 +404,17 @@ t_stat fhd_attach (UNIT *uptr, char *cptr) { uint32 sz, sf; uint32 ds_bytes = FH_WDPSF * sizeof (int16); +t_stat r; -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) { +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) { sf = (sz + ds_bytes - 1) / ds_bytes; if (sf >= FH_NUMSF) sf = FH_NUMSF - 1; uptr->flags = (uptr->flags & ~UNIT_SF) | (sf << UNIT_V_SF); } uptr->capac = UNIT_GETSF (uptr->flags) * FH_WDPSF; -return attach_unit (uptr, cptr); +return SCPE_OK; } /* Set size routine */ diff --git a/H316/h316_lp.c b/H316/h316_lp.c index 44b0c956..3f2faa3c 100644 --- a/H316/h316_lp.c +++ b/H316/h316_lp.c @@ -1,6 +1,6 @@ /* h316_lp.c: Honeywell 316/516 line printer - Copyright (c) 1999-2003, Robert M. Supnik + Copyright (c) 1999-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/H316/h316_mt.c b/H316/h316_mt.c index 3bf7dced..ed904de9 100644 --- a/H316/h316_mt.c +++ b/H316/h316_mt.c @@ -1,6 +1,6 @@ /* h316_mt.c: H316/516 magnetic tape simulator - Copyright (c) 2003, Robert M. Supnik + Copyright (c) 2003-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/H316/h316_stddev.c b/H316/h316_stddev.c index ebdaf590..51737f4c 100644 --- a/H316/h316_stddev.c +++ b/H316/h316_stddev.c @@ -1,6 +1,6 @@ /* h316_stddev.c: Honeywell 316/516 standard devices - Copyright (c) 1999-2003, Robert M. Supnik + Copyright (c) 1999-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/H316/h316_sys.c b/H316/h316_sys.c index 0c3c6502..a15eb970 100644 --- a/H316/h316_sys.c +++ b/H316/h316_sys.c @@ -1,6 +1,6 @@ /* h316_sys.c: Honeywell 316/516 simulator interface - Copyright (c) 1999-2003, Robert M Supnik + Copyright (c) 1999-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index b28972c4..efadef53 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -1,6 +1,6 @@ /* hp2100_cpu.c: HP 2100 CPU simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index 3c7940df..142da0e0 100644 --- a/HP2100/hp2100_defs.h +++ b/HP2100/hp2100_defs.h @@ -1,6 +1,6 @@ /* hp2100_defs.h: HP 2100 simulator definitions - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_doc.txt b/HP2100/hp2100_doc.txt index b6440a10..4e1c57ee 100644 --- a/HP2100/hp2100_doc.txt +++ b/HP2100/hp2100_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: HP2100 Simulator Usage -Date: 15-Jul-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2002, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,15 +36,21 @@ This memorandum documents the HP 2100 simulator. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/hp2100/ hp2100_defs.h @@ -450,7 +456,13 @@ automatically to upper case. In 7B mode, input and output characters are masked to 7 bits. In 8B mode, characters are not modified. The default mode is UC. In addition, each line supports the DATASET option. DATASET, when set, enables modem control. The default settings are UC -mode and DATASET disabled. +mode and DATASET disabled. Finally, each line supports output logging. +The SET MUXLn LOG command enables logging on a line: + + SET MUXLn LOG=filename log output of line n to filename + +The SET MUXLn NOLOG command disables logging and closes the open log +file, if any. The modem controls model a simplified Bell 103A dataset with just four lines: data terminal ready and request to send from the computer to the diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index 64a7ad0b..8a1d1424 100644 --- a/HP2100/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -1,6 +1,6 @@ /* hp2100_dp.c: HP 2100 12557A/13210A disk simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index 47edee33..f11dab05 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -1,6 +1,6 @@ /* hp2100_dq.c: HP 2100 12565A disk simulator - Copyright (c) 1993-2003, Bill McDermith + Copyright (c) 1993-2004, Bill McDermith Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c index d72d743e..7326fb1a 100644 --- a/HP2100/hp2100_dr.c +++ b/HP2100/hp2100_dr.c @@ -1,6 +1,6 @@ /* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_fp.c b/HP2100/hp2100_fp.c index 365413b8..70a8027b 100644 --- a/HP2100/hp2100_fp.c +++ b/HP2100/hp2100_fp.c @@ -1,6 +1,6 @@ /* hp2100_fp.c: HP 2100 floating point instructions - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 49568518..af3086e1 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -1,6 +1,6 @@ /* hp2100_ipl.c: HP 2000 interprocessor link simulator - Copyright (c) 2002-2003, Robert M Supnik + Copyright (c) 2002-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_lps.c b/HP2100/hp2100_lps.c index cca3e6ed..005bb19c 100644 --- a/HP2100/hp2100_lps.c +++ b/HP2100/hp2100_lps.c @@ -1,6 +1,6 @@ /* hp2100_lps.c: HP 2100 12653A line printer simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_lpt.c b/HP2100/hp2100_lpt.c index bd7bba70..9644f596 100644 --- a/HP2100/hp2100_lpt.c +++ b/HP2100/hp2100_lpt.c @@ -1,6 +1,6 @@ /* hp2100_lpt.c: HP 2100 12845A line printer simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index e607cc88..825b4dd1 100644 --- a/HP2100/hp2100_ms.c +++ b/HP2100/hp2100_ms.c @@ -1,6 +1,6 @@ /* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index 56ddc636..dc9163ff 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -1,6 +1,6 @@ /* hp2100_mt.c: HP 2100 12559A magnetic tape simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index 4647462a..1c06839e 100644 --- a/HP2100/hp2100_mux.c +++ b/HP2100/hp2100_mux.c @@ -1,6 +1,6 @@ /* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator - Copyright (c) 2002-2003, Robert M Supnik + Copyright (c) 2002-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ mux,muxl,muxc 12920A terminal multiplexor + 05-Jan-04 RMS Revised for tmxr library changes 21-Dec-03 RMS Added invalid character screening for TSB (from Mike Gemeny) 09-May-03 RMS Added network device flag 01-Nov-02 RMS Added 7B/8B support @@ -152,7 +153,7 @@ uint32 muxc_chan = 0; /* ctrl chan */ uint32 muxc_scan = 0; /* ctrl scan */ TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */ -TMXR mux_desc = { MUX_LINES, 0, 0, NULL }; /* mux descriptor */ +TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc }; /* mux descriptor */ DEVICE muxl_dev, muxu_dev, muxc_dev; int32 muxlio (int32 inst, int32 IR, int32 dat); @@ -268,6 +269,10 @@ MTAB muxl_mod[] = { { UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", NULL }, { UNIT_MDM, 0, "no dataset", "NODATASET", NULL }, { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", + &tmxr_set_log, &tmxr_show_log, &mux_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", + &tmxr_set_nolog, NULL, &mux_desc }, { MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, { 0 } }; @@ -433,7 +438,7 @@ case ioOTX: /* output */ (muxc_ota[ln] & ~OTC_C1) | (dat & OTC_C1); if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ (old & DTR) && !(muxc_ota[ln] & DTR)) { /* DTR drop? */ - tmxr_msg (mux_ldsc[ln].conn, "\r\nLine hangup\r\n"); + tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n"); tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ muxc_lia[ln] = 0; } /* dataset off */ } /* end update */ @@ -645,9 +650,7 @@ if (muxu_unit.flags & UNIT_ATT) { /* master att? */ t = sim_rtcn_init (muxu_unit.wait, TMR_MUX); sim_activate (&muxu_unit, t); } } /* activate */ else sim_cancel (&muxu_unit); /* else stop */ -for (i = 0; i < MUX_LINES; i++) { - mux_desc.ldsc[i] = &mux_ldsc[i]; - mux_reset_ln (i); } +for (i = 0; i < MUX_LINES; i++) mux_reset_ln (i); return SCPE_OK; } diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index f0fce56a..d820eacf 100644 --- a/HP2100/hp2100_sys.c +++ b/HP2100/hp2100_sys.c @@ -1,6 +1,6 @@ /* hp2100_sys.c: HP 2100 simulator interface - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index 666c2b50..4a7b7d59 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -1,6 +1,6 @@ /* i1401_cd.c: IBM 1402 card reader/punch - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index bee63ac9..93372cc3 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -1,6 +1,6 @@ /* i1401_cpu.c: IBM 1401 CPU simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_dat.h b/I1401/i1401_dat.h index 02e6ac00..1c4c6422 100644 --- a/I1401/i1401_dat.h +++ b/I1401/i1401_dat.h @@ -1,6 +1,6 @@ /* i1401_dat.h: IBM 1401 character conversion tables - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_defs.h b/I1401/i1401_defs.h index a93427fb..76801e1a 100644 --- a/I1401/i1401_defs.h +++ b/I1401/i1401_defs.h @@ -1,6 +1,6 @@ /* i1401_defs.h: IBM 1401 simulator definitions - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_doc.txt b/I1401/i1401_doc.txt index 83d4b9d0..053175db 100644 --- a/I1401/i1401_doc.txt +++ b/I1401/i1401_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: IBM 1401 Simulator Usage -Date: 15-Jul-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,15 +36,21 @@ This memorandum documents the IBM 1401 simulator. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/i1401/ i1401_defs.h diff --git a/I1401/i1401_dp.c b/I1401/i1401_dp.c index 1e2a0686..5d53300a 100644 --- a/I1401/i1401_dp.c +++ b/I1401/i1401_dp.c @@ -1,6 +1,6 @@ /* i1401_dp.c: IBM 1311 disk simulator - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c index 5e8c5691..e5428b44 100644 --- a/I1401/i1401_iq.c +++ b/I1401/i1401_iq.c @@ -1,6 +1,6 @@ /* i1401_iq.c: IBM 1407 inquiry terminal - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_lp.c b/I1401/i1401_lp.c index 696b6f32..606a3a7e 100644 --- a/I1401/i1401_lp.c +++ b/I1401/i1401_lp.c @@ -1,6 +1,6 @@ /* i1401_lp.c: IBM 1403 line printer simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_mt.c b/I1401/i1401_mt.c index d5888b8b..0c5bc222 100644 --- a/I1401/i1401_mt.c +++ b/I1401/i1401_mt.c @@ -1,6 +1,6 @@ /* i1401_mt.c: IBM 1401 magnetic tape simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1401/i1401_sys.c b/I1401/i1401_sys.c index 27e61090..9ee07af2 100644 --- a/I1401/i1401_sys.c +++ b/I1401/i1401_sys.c @@ -1,6 +1,6 @@ /* i1401_sys.c: IBM 1401 simulator interface - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c index 4c3ecb86..1bd6116f 100644 --- a/I1620/i1620_cd.c +++ b/I1620/i1620_cd.c @@ -1,6 +1,6 @@ /* i1620_cd.c: IBM 1622 card reader/punch - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_cpu.c b/I1620/i1620_cpu.c index 3a8a718f..e615e2d6 100644 --- a/I1620/i1620_cpu.c +++ b/I1620/i1620_cpu.c @@ -1,6 +1,6 @@ /* i1620_cpu.c: IBM 1620 CPU simulator - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ This CPU module incorporates code and comments from the 1620 simulator by Geoff Kuenning, with his permission. + 26-Mar-04 RMS Fixed warnings with -std=c99 02-Nov-03 RMS Fixed bug in branch digit (found by Dave Babcock) 21-Aug-03 RMS Fixed bug in immediate index add (found by Michael Short) 25-Apr-03 RMS Changed t_addr to uint32 throughout @@ -153,15 +154,15 @@ t_stat xor_field (uint32 d, uint32 s); t_stat com_field (uint32 d, uint32 s); void upd_ind (void); -extern tty (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern dp (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern btp (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern btr (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1); extern t_stat fp_add (uint32 d, uint32 s, t_bool sub); extern t_stat fp_mul (uint32 d, uint32 s); diff --git a/I1620/i1620_defs.h b/I1620/i1620_defs.h index b07cde33..0c817e44 100644 --- a/I1620/i1620_defs.h +++ b/I1620/i1620_defs.h @@ -1,6 +1,6 @@ /* i1620_defs.h: IBM 1620 simulator definitions - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_doc.txt b/I1620/i1620_doc.txt index 2f408e54..37b24a91 100644 --- a/I1620/i1620_doc.txt +++ b/I1620/i1620_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: IBM 1620 Simulator Usage -Date: 15-Apr-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,13 +36,19 @@ Geoff Kuenning's 1620 simulator, which is used by permission. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c + sim_timer.c sim_tmxr.c sim/i1620/ i1620_defs.h diff --git a/I1620/i1620_dp.c b/I1620/i1620_dp.c index 10f2a16c..6a2da846 100644 --- a/I1620/i1620_dp.c +++ b/I1620/i1620_dp.c @@ -1,6 +1,6 @@ /* i1620_dp.c: IBM 1311 disk simulator - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_fp.c b/I1620/i1620_fp.c index 0cb54a96..f1035749 100644 --- a/I1620/i1620_fp.c +++ b/I1620/i1620_fp.c @@ -1,6 +1,6 @@ /* i1620_fp.c: IBM 1620 floating point simulator - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_lp.c b/I1620/i1620_lp.c index 3ad1e1c4..908f20fc 100644 --- a/I1620/i1620_lp.c +++ b/I1620/i1620_lp.c @@ -1,6 +1,6 @@ /* i1620_lp.c: IBM 1443 line printer simulator - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_pt.c b/I1620/i1620_pt.c index 2f213077..9617c173 100644 --- a/I1620/i1620_pt.c +++ b/I1620/i1620_pt.c @@ -1,6 +1,6 @@ /* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator - Copyright (c) 2002-2003, Robert M Supnik + Copyright (c) 2002-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_sys.c b/I1620/i1620_sys.c index 43951d1d..09b95a63 100644 --- a/I1620/i1620_sys.c +++ b/I1620/i1620_sys.c @@ -1,6 +1,6 @@ /* i1620_sys.c: IBM 1620 simulator interface - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_tty.c b/I1620/i1620_tty.c index 47f20906..d2d3bbc1 100644 --- a/I1620/i1620_tty.c +++ b/I1620/i1620_tty.c @@ -1,6 +1,6 @@ /* i1620_tty.c: IBM 1620 typewriter - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Ibm1130/ibm1130_cpu.c b/Ibm1130/ibm1130_cpu.c index 5f3add4b..c5e92479 100644 --- a/Ibm1130/ibm1130_cpu.c +++ b/Ibm1130/ibm1130_cpu.c @@ -141,7 +141,7 @@ extern CTAB *sim_vm_cmd; #define MAX_EXTRA_COMMANDS 10 CTAB x_cmds[MAX_EXTRA_COMMANDS]; -#ifdef WIN32 +#ifdef _WIN32 # define CRLF "\r\n" #else # define CRLF "\n" @@ -1160,7 +1160,7 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) { if (addr < MEMSIZE) { - M[addr] = val & 0xFFFF; + M[addr] = (uint16) (val & 0xFFFF); return SCPE_OK; } return SCPE_NXM; @@ -1476,7 +1476,7 @@ static t_stat cpu_attach (UNIT *uptr, char *cptr) PSYMENTRY n, prv, s; FILE *fd; - unlink(cptr); // delete old log file, if present + remove(cptr); // delete old log file, if present new_log = TRUE; log_fac = sim_switches & SWMASK ('F'); // display the FAC and the ACC/EXT as fixed point. @@ -1565,16 +1565,16 @@ static void trace_instruction (void) fac = 1.f; } else { - if ((sign = mant & 0x80000000)) + if ((sign = mant & 0x80000000) != 0) mant = -mant; fac = (float) mant * ((float) 1./ (float) (unsigned long) 0x80000000); } sprintf(fltstr, "%c%.5f ", sign ? '-' : ' ', fac); if (BETWEEN(M[3], 0x300, MEMSIZE-128)) { - exp = (M[M[3]+125] & 0xFF) - 128; + exp = (short) ((M[M[3]+125] & 0xFF) - 128); mant = (M[M[3]+126] << 8) | ((M[M[3]+127] >> 8) & 0xFF); - if ((sign = (mant & 0x00800000))) + if ((sign = (mant & 0x00800000)) != 0) mant = (-mant) & 0x00FFFFFF; fac = (float) mant * ((float) 1. / (float) 0x00800000); @@ -1660,7 +1660,7 @@ void debug_print (char *fmt, ...) } } -#ifdef WIN32 +#ifdef _WIN32 #include #endif @@ -1668,7 +1668,7 @@ void debug_print (char *fmt, ...) static t_stat view_cmd (int flag, char *cptr) { -#ifdef WIN32 +#ifdef _WIN32 char cmdline[256]; sprintf(cmdline, "notepad %s", cptr); @@ -1713,7 +1713,7 @@ static void cgi_clockfail (void) // cgi_start_timer - OS dependent routine to set things up so that // cgi_timeout() will be called after cgi_maxsec seconds. -#if defined(WIN32) +#if defined(_WIN32) static DWORD WINAPI cgi_timer_thread (LPVOID arg) { Sleep(cgi_maxsec*1000); // timer thread -- wait, then call timeout routine diff --git a/Ibm1130/ibm1130_cr.c b/Ibm1130/ibm1130_cr.c index a1da52db..ad90ebb6 100644 --- a/Ibm1130/ibm1130_cr.c +++ b/Ibm1130/ibm1130_cr.c @@ -1,6 +1,10 @@ #include "ibm1130_defs.h" #include "ibm1130_fmt.h" +#ifdef _WIN32 +# include // Microsoft puts definition of mktemp into io.h rather than stdlib.h +#endif + /* ibm1130_cr.c: IBM 1130 1442 Card Reader simulator Based on the SIMH package written by Robert M Supnik @@ -1187,7 +1191,7 @@ static void checkdeck (void) static t_bool nextdeck (void) { - char buf[200], tmpbuf[200], *fname, *tn, *c, quote, *mode; + char buf[200], tmpbuf[200], *fname, *c, quote, *mode; int code; long fpos; @@ -1204,7 +1208,7 @@ static t_bool nextdeck (void) cr_unit.fileref = NULL; if (cr_unit.flags & UNIT_SCRATCH) { - unlink(tempfile); + remove(tempfile); CLRBIT(cr_unit.flags, UNIT_SCRATCH); } } @@ -1229,8 +1233,39 @@ static t_bool nextdeck (void) } if (buf[0] == '!') { /* literal text line, make a temporary file */ - if (*tempfile == '\0') { - if ((tn = tempnam(".", "1130")) == NULL) { + +#if defined (__GNUC__) && !defined (_WIN32) // GCC complains about mktemp & always provides mkstemp + + if (*tempfile == '\0') { // first time, open guaranteed-unique file + int fh; + + strcpy(tempfile, "tempXXXXXX"); // get modifiable copy of name template + + if ((fh = mkstemp(tempfile)) == -1) { // open file. Actual name is set by side effect + printf("Cannot create temporary deck file\n"); + break_simulation(STOP_DECK_BREAK); + return 0; + } + // get FILE * from the file handle + if ((cr_unit.fileref = fdopen(fh, "w+b")) == NULL) { + printf("Cannot use temporary deck file %s\n", tempfile); + break_simulation(STOP_DECK_BREAK); + return 0; + } + } + else { // on later opens, just reuse the old name + if ((cr_unit.fileref = fopen(tempfile, "w+b")) == NULL) { + printf("Cannot create temporary file %s\n", tempfile); + break_simulation(STOP_DECK_BREAK); + return 0; + } + } +#else // ANSI standard C always provides mktemp + + if (*tempfile == '\0') { // first time, construct unique name + char *tn; + + if ((tn = mktemp("crXXXXXX")) == NULL) { printf("Cannot create temporary card file name\n"); break_simulation(STOP_DECK_BREAK); return 0; @@ -1238,12 +1273,13 @@ static t_bool nextdeck (void) strcpy(tempfile, tn); strcat(tempfile, ".tmp"); } - - if ((cr_unit.fileref = fopen(tempfile, "wb+")) == NULL) { + // (re)create file + if ((cr_unit.fileref = fopen(tempfile, "w+b")) == NULL) { printf("Cannot create temporary file %s\n", tempfile); break_simulation(STOP_DECK_BREAK); return 0; } +#endif SETBIT(cr_unit.flags, UNIT_SCRATCH); @@ -1560,7 +1596,7 @@ t_stat cr_detach (UNIT *uptr) fclose(cr_unit.fileref); if (cr_unit.flags & UNIT_SCRATCH) { - unlink(tempfile); + remove(tempfile); CLRBIT(cr_unit.flags, UNIT_SCRATCH); } @@ -1677,7 +1713,7 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) { char msg[80]; int ch; - int16 wd; + uint16 wd; t_bool lastcard; switch (func) { @@ -1763,7 +1799,7 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) cp_unit.COLUMN = 81; } else if (cp_unit.COLUMN < 80) { - wd = ReadW(addr); /* store one word to punch buffer */ + wd = (uint16) ReadW(addr); /* store one word to punch buffer */ punchstation[cp_unit.COLUMN] = wd & 0xFFF0; if (wd & 0x0008) /* mark this as last column to be punched */ SETBIT(cp_unit.flags, UNIT_LASTPUNCH); @@ -2052,8 +2088,7 @@ char response_byte; static DWORD CALLBACK pcr_thread (LPVOID arg) { - DWORD event; - long nrcvd, nread; + DWORD event, nrcvd, nread; HANDLE objs[4]; BOOL pick_queued = FALSE, reset_queued = FALSE; @@ -2172,10 +2207,10 @@ static DWORD CALLBACK pcr_thread (LPVOID arg) printf((nrcvd <= 0) ? "PCR: NO RESP!\n" : "PCR: GOT %d BYTES\n", nrcvd); if (nrcvd > 0) { - pcr_nleft -= nrcvd; + pcr_nleft -= (int) nrcvd; begin_pcr_critical_section(); - pcr_nready += nrcvd; + pcr_nready += (int) nrcvd; end_pcr_critical_section(); } @@ -2210,7 +2245,7 @@ static char lastcmd = '?'; static void pcr_cmd (char cmd) { - long nwrite, nrcvd; + DWORD nwrite, nrcvd; if (cmd != '\0') { if (cr_unit.flags & UNIT_DEBUG && (cmd != 'S' || cmd != lastcmd)) @@ -2231,7 +2266,7 @@ static void pcr_cmd (char cmd) static BOOL pcr_handle_status_byte (char byte) { - long nrcvd; + DWORD nrcvd; static char prev_status = '?'; BOOL show; @@ -2276,7 +2311,7 @@ static void pcr_set_dsw_from_status (BOOL post_pick) static BOOL pcr_handle_byte (char byte) { - long nrcvd; + DWORD nrcvd; GetOverlappedResult(hpcr, &ovRd, &nrcvd, TRUE); diff --git a/Ibm1130/ibm1130_defs.h b/Ibm1130/ibm1130_defs.h index 5c5ef1fc..20a8f247 100644 --- a/Ibm1130/ibm1130_defs.h +++ b/Ibm1130/ibm1130_defs.h @@ -15,6 +15,7 @@ #include "sim_defs.h" /* main SIMH defns (include path should include .., or make a copy) */ #include #include +#include #if defined(VMS) # include /* to pick up 'unlink' */ @@ -23,7 +24,7 @@ #define MIN(a,b) (((a) <= (b)) ? (a) : (b)) #define MAX(a,b) (((a) >= (b)) ? (a) : (b)) -#ifndef WIN32 +#ifndef _WIN32 int strnicmp (char *a, char *b, int n); int strcmpi (char *a, char *b); #endif diff --git a/Ibm1130/ibm1130_disk.c b/Ibm1130/ibm1130_disk.c index 7b5c99f6..fd293041 100644 --- a/Ibm1130/ibm1130_disk.c +++ b/Ibm1130/ibm1130_disk.c @@ -347,7 +347,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) uptr->CYL = 0; } - dsk_sec[drv] = (dsk_sec[drv] + 1) % 4; /* advance the "next sector" count every time */ + dsk_sec[drv] = (int16) ((dsk_sec[drv] + 1) % 4); /* advance the "next sector" count every time */ ACC = dsk_dsw[drv] | dsk_sec[drv]; if (modify & 0x01) { /* reset interrupts */ @@ -474,7 +474,7 @@ t_stat dsk_reset (DEVICE *dptr) uptr->CYL = 0; uptr->FUNC = DSK_FUNC_IDLE; - dsk_dsw[drv] = (uptr->flags & UNIT_ATT) ? DSK_DSW_CARRIAGE_HOME : 0; + dsk_dsw[drv] = (int16) ((uptr->flags & UNIT_ATT) ? DSK_DSW_CARRIAGE_HOME : 0); } calc_ints(); diff --git a/Ibm1130/ibm1130_fmt.c b/Ibm1130/ibm1130_fmt.c index 6a9ea5fe..1d501009 100644 --- a/Ibm1130/ibm1130_fmt.c +++ b/Ibm1130/ibm1130_fmt.c @@ -104,7 +104,7 @@ char cX; // character to test iO = 0; // init output position iT = 0; // init tab stop - while (cX = *(p_szInbuf + iI)) // while there are characters + while ((cX = *(p_szInbuf + iI)) != 0) // while there are characters { if (cX == '\t') // q. tab character? { // a. yes .. @@ -227,7 +227,7 @@ char *EditToFortran(char* p_pszEdit) // convert line to 1130 assembler char pszLine[MAXLINE]; // source line char* pszWork; // work pointer size_t iI; // work integer -char bContinue; // true if continue +int bContinue; // true if continue if (p_pszEdit == NULL) // q. null request? return FMSG; // a. yes .. return display message diff --git a/Ibm1130/ibm1130_gdu.c b/Ibm1130/ibm1130_gdu.c index b95732e1..293f5223 100644 --- a/Ibm1130/ibm1130_gdu.c +++ b/Ibm1130/ibm1130_gdu.c @@ -169,7 +169,7 @@ void xio_2250_display (int32 addr, int32 func, int32 modify) WriteW(addr+3, gdu_y & 0x7FF); WriteW(addr+4, gdu_fkey); WriteW(addr+5, gdu_akey); - gdu_ar = addr+6; /* this alters the channel address register? */ + gdu_ar = (int16) (addr+6); /* this alters the channel address register? */ clear_interrupts(); /* read status clears the interrupts */ break; @@ -182,7 +182,7 @@ void xio_2250_display (int32 addr, int32 func, int32 modify) set_indicators((ReadW(addr) << 16) | ReadW(addr+1)); } else { - gdu_ar = addr; + gdu_ar = (int16) addr; gdu_fkey = 0; gdu_akey = 0; clear_interrupts(); @@ -273,7 +273,7 @@ static int32 read_gduword (void) int32 w; w = M[gdu_ar++ & mem_mask]; - gdu_dsw = (gdu_dsw & ~GDU_DSW_ADDR_DISP) | ((gdu_ar - gdu_instaddr) & GDU_DSW_ADDR_DISP); + gdu_dsw = (int16) ((gdu_dsw & ~GDU_DSW_ADDR_DISP) | ((gdu_ar - gdu_instaddr) & GDU_DSW_ADDR_DISP)); return w; } @@ -387,8 +387,8 @@ static void draw (int32 newx, int32 newy, t_bool beam) #endif } - gdu_x = newx; - gdu_y = newy; + gdu_x = (int16) newx; + gdu_y = (int16) newy; } static void generate_image (void) @@ -419,7 +419,7 @@ static void generate_image (void) case 0: // short branch case 1: gdu_revert = gdu_ar; // save revert address & get new address - gdu_ar = read_gduword() & 0x1FFF; + gdu_ar = (int16) (read_gduword() & 0x1FFF); if (gdu_dsw & GDU_DSW_CHARACTER_MODE) { draw_characters(); // in character mode this means we are at character data gdu_ar = gdu_revert; @@ -443,7 +443,7 @@ static void generate_image (void) if (instr & 0x0080) // indirect new_addr = M[new_addr & mem_mask]; - gdu_ar = new_addr; + gdu_ar = (int16) new_addr; if (gdu_dsw & GDU_DSW_CHARACTER_MODE) { draw_characters(); @@ -600,9 +600,9 @@ static void draw_characters (void) case 7: // new line gdu_x = 0; - gdu_y -= ci->dy; + gdu_y -= (int16) ci->dy; if (gdu_y < 0 && last_abs) - gdu_y = 1024 - ci->dy; // this is a guess + gdu_y = (int16) (1024 - ci->dy); // this is a guess break; } } @@ -631,7 +631,7 @@ static void draw_characters (void) gdu_x += ci->dx; if (gdu_x > 1023 && last_abs) { // line wrap gdu_x = 0; - gdu_y -= ci->dy; + gdu_y -= (int16) ci->dy; } } } while ((w & 0x0080) == 0); // repeat until we hit revert bit @@ -645,7 +645,7 @@ static void draw_characters (void) /******* PLATFORM SPECIFIC CODE ***********************************************************/ -#ifdef WIN32 +#ifdef _WIN32 #include #include @@ -1114,5 +1114,5 @@ static void ShowPenHit (int x, int y) } #endif -#endif // WIN32 defined +#endif // _WIN32 defined #endif // GUI_SUPPORT defined diff --git a/Ibm1130/ibm1130_gui.c b/Ibm1130/ibm1130_gui.c index 01d1d04d..9ae67c35 100644 --- a/Ibm1130/ibm1130_gui.c +++ b/Ibm1130/ibm1130_gui.c @@ -126,8 +126,8 @@ void scp_panic (char *msg) exit(1); } -#ifdef WIN32 - /* only WIN32 is defined right now */ +#ifdef _WIN32 + /* only _WIN32 is defined right now */ #include @@ -1463,7 +1463,7 @@ static void tear_printer (void) // if (! stuff_and_wait("detach cr", 1000, 0)) // detach the card reader so they can edit the deck file // return; - unlink(filename); // delete the file + remove(filename); // delete the file sprintf(cmd, "attach prt \"%s\"", filename); // reattach stuff_cmd(cmd); @@ -1634,5 +1634,5 @@ void remark_cmd (char *remark) } } -#endif // WIN32 defined +#endif // _WIN32 defined #endif // GUI_SUPPORT defined diff --git a/Ibm1130/ibm1130_prt.c b/Ibm1130/ibm1130_prt.c index 4f7dfa40..f5eabfa1 100644 --- a/Ibm1130/ibm1130_prt.c +++ b/Ibm1130/ibm1130_prt.c @@ -264,7 +264,7 @@ static void flush_prt_line (FILE *fd, int spacemode, t_bool phys_flush) if (spacemode && ! maxnp) { // spacing only if (prt_row == 0 && prt_nnl) { -#ifdef WIN32 +#ifdef _WIN32 if (! cgi) putc('\r', fd); // DOS/Windows: end with cr/lf #endif @@ -283,7 +283,7 @@ static void flush_prt_line (FILE *fd, int spacemode, t_bool phys_flush) if (prt_nnl) { // there are queued newlines // if we spaced to top of form, don't emit formfeed. We'd only ever emit the formfeed if we skipped via control tape channels // if (prt_row == 0 && prt_nnl) { // we spaced to top of form -//#ifdef WIN32 +//#ifdef _WIN32 // if (! cgi) // putc('\r', fd); // DOS/Windows: end with cr/lf //#endif @@ -293,7 +293,7 @@ static void flush_prt_line (FILE *fd, int spacemode, t_bool phys_flush) // } // else { while (prt_nnl > 0) { // spit out queued newlines -#ifdef WIN32 +#ifdef _WIN32 if (! cgi) putc('\r', fd); // DOS/Windows: end with cr/lf #endif @@ -347,7 +347,7 @@ void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify) switch (func) { case XIO_READ: - M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8; + M[iocc_addr & mem_mask] = (uint16) (codewheel1132[prt_nchar].ebcdic << 8); if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */ prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; @@ -631,7 +631,7 @@ static t_stat delete_cmd (int flag, char *cptr) if (*gbuf == 0) return SCPE_2FARG; if (*cptr != 0) return SCPE_2MARG; /* now eol? */ - status = unlink(gbuf); /* delete the file */ + status = remove(gbuf); /* delete the file */ if (status != 0 && errno != ENOENT) /* print message if failed and file exists */ perror(gbuf); @@ -745,7 +745,7 @@ static t_stat prt_attach (UNIT *uptr, char *cptr) reset_prt_line(); if (IS_1132(uptr)) { - PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]); + PRT_DSW = (uint16) ((PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row])); if (IS_ONLINE(uptr)) CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY); diff --git a/Ibm1130/ibm1130_stddev.c b/Ibm1130/ibm1130_stddev.c index 98bc8a86..73ccfccb 100644 --- a/Ibm1130/ibm1130_stddev.c +++ b/Ibm1130/ibm1130_stddev.c @@ -125,8 +125,8 @@ static unsigned char conout_map[256]; /* 1130 console code to ASCII translation static unsigned char conin_map[256]; /* input mapping */ static int curcol = 0; /* current typewriter element column, leftmost = 0 */ static int maxcol = 0; /* highest curcol seen in this output line */ -static char black_ribbon[30]; /* output escape sequence for black ribbon shift */ -static char red_ribbon[30]; /* output escape sequence for red ribbon shift */ +static unsigned char black_ribbon[30]; /* output escape sequence for black ribbon shift */ +static unsigned char red_ribbon[30]; /* output escape sequence for red ribbon shift */ static OS_MAP os_buf[MAX_OUTPUT_COLUMNS]; /* current typewriter output line, holds character struck in each column */ static OS_MAP os_map[MAX_OS_MAPPINGS]; /* overstrike mapping entries */ @@ -800,8 +800,8 @@ static void set_default_mapping (int32 flags) reset_mapping(); - strcpy(black_ribbon, "\033[30m"); - strcpy(red_ribbon, "\033[31m"); + strcpy((char *) black_ribbon, "\033[30m"); + strcpy((char *) red_ribbon, "\033[31m"); switch (flags & CSET_MASK) { case CSET_1130: @@ -850,10 +850,10 @@ static t_stat map_conout_character (int ch) int i, cmp; if (ch == (COUT_IS_CTRL|COUT_CTRL_BLACK)) - return (tto_unit.flags & ENABLE_ANSI) ? sim_putstr(black_ribbon) : SCPE_OK; + return (tto_unit.flags & ENABLE_ANSI) ? sim_putstr((char *) black_ribbon) : SCPE_OK; if (ch == (COUT_IS_CTRL|COUT_CTRL_RED)) - return (tto_unit.flags & ENABLE_ANSI) ? sim_putstr(red_ribbon) : SCPE_OK; + return (tto_unit.flags & ENABLE_ANSI) ? sim_putstr((char *) red_ribbon) : SCPE_OK; if ((ch = conout_map[ch & 0xFF]) == 0) ch = '?'; // unknown character? print ? @@ -1088,7 +1088,7 @@ static void read_map_file (FILE *fd) static char * get_num_char (char **pc, unsigned char *out, int ndigits, int base, char *errmsg) { - unsigned char ch = 0, digit; + int ch = 0, digit; char *c = *pc; while (--ndigits >= 0) { /* collect specified number of digits */ @@ -1108,7 +1108,7 @@ static char * get_num_char (char **pc, unsigned char *out, int ndigits, int base c++; } - *out = ch; /* return parsed character */ + *out = (unsigned char) ch; /* return parsed character */ *pc = c-1; /* make input pointer point to last character seen */ return NULL; /* no error */ } @@ -1119,9 +1119,10 @@ static char * get_num_char (char **pc, unsigned char *out, int ndigits, int base * error encountered. *pc is advanced to next whitespace or whatever followed input. */ -static char * get_characters (char **pc, char *outstr, int nmax, int *nout) +static char * get_characters (char **pc, unsigned char *outstr, int nmax, int *nout) { - char *c = *pc, *out = outstr, *errstr; + char *c = *pc, *errstr; + unsigned char *out = outstr; while (*c && *c <= ' ') /* skip leading whitespace */ c++; @@ -1181,7 +1182,7 @@ static char * get_characters (char **pc, char *outstr, int nmax, int *nout) else if (BETWEEN(*c, 'A', 'Z') || BETWEEN(*c, 'a', 'z')) return "invalid \\ escape"; /* other \x letters are bad */ else { - *out++ = *c; /* otherwise, accept \x as literal character x */ + *out++ = (unsigned char) *c;/* otherwise, accept \x as literal character x */ } break; } @@ -1189,18 +1190,18 @@ static char * get_characters (char **pc, char *outstr, int nmax, int *nout) else if (*c == '^') { /* control character */ c++; if (BETWEEN(*c, 'A', 'Z')) /* convert alpha, e.g. A -> 1 */ - *out++ = *c - 'A' + 1; + *out++ = (unsigned char) (*c - 'A' + 1); else if (BETWEEN(*c, 'a', 'z')) - *out++ = *c - 'z' + 1; + *out++ = (unsigned char) (*c - 'z' + 1); else /* non alpha is bad */ return "invalid control letter"; } else if (str_match(c, "IGNORE")) { /* magic word: a character that will never be output */ - *out++ = IGNR_; + *out++ = (unsigned char) IGNR_; c += 6; } else { - *out++ = *c; /* save literal character */ + *out++ = (unsigned char) *c; /* save literal character */ } c++; @@ -1219,7 +1220,8 @@ static char * get_characters (char **pc, char *outstr, int nmax, int *nout) static char * handle_map_ansi_definition (char **pc) { - char *outstr, *errmsg; + unsigned char *outstr; + char *errmsg; int n; if (str_match(*pc, "black")) { /* find which string we're setting */ diff --git a/Ibm1130/ibm1130_sys.c b/Ibm1130/ibm1130_sys.c index 6ddf2dac..ccc1b8aa 100644 --- a/Ibm1130/ibm1130_sys.c +++ b/Ibm1130/ibm1130_sys.c @@ -442,7 +442,7 @@ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) return SCPE_ARG; } -#ifndef WIN32 +#ifndef _WIN32 int strnicmp (char *a, char *b, int n) { diff --git a/Interdata/id16_cpu.c b/Interdata/id16_cpu.c index 3bdc7fd8..5ad6bca3 100644 --- a/Interdata/id16_cpu.c +++ b/Interdata/id16_cpu.c @@ -1,6 +1,6 @@ /* id16_cpu.c: Interdata 16b CPU simulator - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id16_dboot.c b/Interdata/id16_dboot.c index edbc9c0a..ad6170f2 100644 --- a/Interdata/id16_dboot.c +++ b/Interdata/id16_dboot.c @@ -1,6 +1,6 @@ /* id16_dboot.c: Interdata 16b simulator disk bootstrap - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id16_sys.c b/Interdata/id16_sys.c index be300924..b707524e 100644 --- a/Interdata/id16_sys.c +++ b/Interdata/id16_sys.c @@ -1,6 +1,6 @@ /* id16_sys.c: Interdata 16b simulator interface - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 26-Mar-04 RMS Fixed warning with -std=c99 27-Feb-03 RMS Added relative addressing support */ @@ -47,7 +48,7 @@ extern uint16 *M; t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val, t_bool cf); t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val, t_bool cf); extern t_stat lp_load (FILE *fileref, char *cptr, char *fnam); -extern pt_dump (FILE *of, char *cptr, char *fnam); +extern t_stat pt_dump (FILE *of, char *cptr, char *fnam); /* SCP data structures and interface routines diff --git a/Interdata/id32_cpu.c b/Interdata/id32_cpu.c index 530e695d..9d05ab9d 100644 --- a/Interdata/id32_cpu.c +++ b/Interdata/id32_cpu.c @@ -25,6 +25,7 @@ cpu Interdata 32b CPU + 25-Jan-04 RMS Revised for device debug support 31-Dec-03 RMS Fixed bug in cpu_set_hist 22-Sep-03 RMS Added additional instruction decode types Added instruction history @@ -191,6 +192,11 @@ struct InstHistory { #define ABS(x) (((x) & SIGN32)? NEG (x): (x)) #define DNEG(x,y) y = NEG (y); \ x = (~(x) + (y == 0)) & DMASK32 + +/* Logging */ + +#define LOG_CPU_I 0x0001 /* intr/exception */ +#define LOG_CPU_C 0x0002 /* context change */ uint32 GREG[16 * NRSETS] = { 0 }; /* general registers */ uint32 *M = NULL; /* memory */ @@ -219,7 +225,6 @@ REG *pcq_r = NULL; /* PC queue reg ptr */ uint32 dec_flgs = 0; /* decode flags */ uint32 fp_in_hwre = 0; /* ucode vs hwre fp */ uint32 pawidth = PAWIDTH32; /* addr mask */ -uint32 cpu_log = 0; /* debug logging */ uint32 hst_p = 0; /* history pointer */ uint32 hst_lnt = 0; /* history length */ struct InstHistory *hst = NULL; /* instruction history */ @@ -231,7 +236,7 @@ extern int32 sim_interval; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern UNIT pic_unit, lfc_unit, pas_unit; /* timers */ -extern FILE *sim_log; +extern FILE *sim_deb; uint32 ReadB (uint32 loc, uint32 rel); uint32 ReadH (uint32 loc, uint32 rel); @@ -538,7 +543,6 @@ REG cpu_reg[] = { { BRDATA (PCQ, pcq, 16, 20, PCQ_SIZE), REG_RO+REG_CIRC }, { HRDATA (PCQP, pcq_p, 6), REG_HRO }, { HRDATA (WRU, sim_int_char, 8) }, - { HRDATA (DBGLOG, cpu_log, 16), REG_HIDDEN }, { HRDATA (BLKIOD, blk_io.dfl, 16), REG_HRO }, { HRDATA (BLKIOC, blk_io.cur, 20), REG_HRO }, { HRDATA (BLKIOE, blk_io.end, 20), REG_HRO }, @@ -561,12 +565,18 @@ MTAB cpu_mod[] = { &cpu_set_hist, &cpu_show_hist }, { 0 } }; +DEBTAB cpu_deb[] = { + { "INTEXC", LOG_CPU_I }, + { "CONTEXT", LOG_CPU_C }, + { NULL, 0 } }; + DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 16, 20, 1, 16, 8, &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL, - &cpu_dib, 0 }; + &cpu_dib, DEV_DEBUG, 0, + cpu_deb, NULL, NULL }; t_stat sim_instr (void) { @@ -1307,7 +1317,7 @@ case 0xE1: /* SVC - RX */ R[14] = t; /* old PSW */ R[15] = PC; /* old PC */ PC = ReadH (SVNPC + r1 + r1, P); /* new PC */ - if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log, + if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) fprintf (sim_deb, ">>SVC: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", pcq[pcq_p], t, PC, PSW); break; @@ -1341,7 +1351,7 @@ case 0xE3: /* SCP - RXH */ case 0x18: /* LPSWR - RR */ PCQ_ENTRY; /* effective branch */ PC = R[(r2 + 1) & 0xF] & VAMASK; /* new PC (old reg set) */ - if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log, + if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) fprintf (sim_deb, ">>LPSWR: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", pcq[pcq_p], BUILD_PSW (cc), PC, opnd); cc = newPSW (opnd); /* new PSW */ @@ -1351,7 +1361,7 @@ case 0x18: /* LPSWR - RR */ case 0xC2: /* LPSW - RXF */ PCQ_ENTRY; /* effective branch */ PC = ReadF ((ea + 4) & VAMASK, VR) & VAMASK; /* new PC */ - if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log, + if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) fprintf (sim_deb, ">>LPSW: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", pcq[pcq_p], BUILD_PSW (cc), PC, opnd); cc = newPSW (opnd); /* new PSW */ @@ -1587,7 +1597,7 @@ if (cpu_unit.flags & UNIT_832) { /* 8/32? */ R[15] = oldPC; } /* PC to new 15 */ else { GREG[14] = oldPSW; /* 7/32, PSW to set 0 14 */ GREG[15] = oldPC; } /* PC to set 0 15 */ -if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log, +if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) fprintf (sim_deb, ">>Exc %X: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", loc, oldPC, oldPSW, PC, PSW | cc | flg); return cc | flg; /* return CC */ @@ -1672,7 +1682,7 @@ newPSW (0x2800); /* new PSW */ R[0] = oldPSW; /* save old PSW */ R[1] = PC; /* save PC */ R[2] = dev; /* set dev # */ -if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log, +if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) fprintf (sim_deb, ">>Int %X: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", dev, PC, oldPSW, vec, 0x2800); if (DEV_ACC (dev)) { /* dev exist? */ diff --git a/Interdata/id32_dboot.c b/Interdata/id32_dboot.c index 69215974..951dbd43 100644 --- a/Interdata/id32_dboot.c +++ b/Interdata/id32_dboot.c @@ -1,6 +1,6 @@ /* id32_dboot.c: Interdata 32b simulator disk bootstrap - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id32_sys.c b/Interdata/id32_sys.c index 40ba1399..f1a04fec 100644 --- a/Interdata/id32_sys.c +++ b/Interdata/id32_sys.c @@ -1,6 +1,6 @@ /* id32_sys.c: Interdata 32b simulator interface - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id_defs.h b/Interdata/id_defs.h index 886ec740..6968559e 100644 --- a/Interdata/id_defs.h +++ b/Interdata/id_defs.h @@ -1,6 +1,6 @@ /* id_defs.h: Interdata 16b/32b simulator definitions - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ The author gratefully acknowledges the help of Carl Friend and Al Kossow, who provided key documents about the Interdata product line. + 25-Jan-04 RMS Removed local logging support 22-Sep-03 RMS Added additional instruction decode types 21-Jun-03 RMS Changed subroutine argument for ARM compiler conflict 25-Apr-03 RMS Revised for extended file support @@ -457,17 +458,6 @@ typedef struct interdib DIB; #define MIN(x,y) (((x) < (y))? (x): (y)) #define MAX(x,y) (((x) > (y))? (x): (y)) -/* Logging */ - -#define LOG_CPU_I 0x0001 /* instructions */ -#define LOG_CPU_C 0x0002 /* context change */ -#define LOG_DP 0x0010 -#define LOG_IDC 0x0020 -#define LOG_MT 0x0040 -#define LOG_FD 0x0080 - -#define DBG_LOG(x) (sim_log && (cpu_log & (x))) - /* Function prototypes */ int32 int_chg (uint32 irq, int32 dat, int32 armdis); diff --git a/Interdata/id_doc.txt b/Interdata/id_doc.txt index 4507e6d2..96c6efc8 100644 --- a/Interdata/id_doc.txt +++ b/Interdata/id_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: Interdata 16b/32b Simulator Usage -Date: 15-Jul-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,15 +36,21 @@ This memorandum documents the Interdata 16b and 32b simulators. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/interdata/ id_defs.h @@ -596,7 +602,13 @@ automatically to upper case. In 7B mode, input and output characters are masked to 7 bits. In 8B mode, characters are not modified. The default mode is UC. Each line (each unit of PASL) can also be set for modem control with the command SET PASLn DATASET. The defaults are 7b mode -and DATASET disabled. +and DATASET disabled. Finally, each line supports output logging. +The SET PASLn LOG command enables logging on a line: + + SET PASLn LOG=filename log output of line n to filename + +The SET PASLn NOLOG command disables logging and closes the open log +file, if any. Once PAS is attached and the simulator is running, the terminals listen for connections on the specified port. They assume that the incoming diff --git a/Interdata/id_dp.c b/Interdata/id_dp.c index ea7ab2e3..224957d4 100644 --- a/Interdata/id_dp.c +++ b/Interdata/id_dp.c @@ -1,6 +1,6 @@ /* id_dp.c: Interdata 2.5MB/10MB cartridge disk simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ dp M46-421 2.5MB/10MB cartridge disk + 25-Jan-04 RMS Revised for device debug support 25-Apr-03 RMS Revised for extended file support 16-Feb-03 RMS Fixed read to test transfer ok before selch operation */ @@ -136,7 +137,7 @@ static struct drvtyp drv_tab[] = { { 0 } }; extern uint32 int_req[INTSZ], int_enb[INTSZ]; -extern FILE *sim_log; +extern FILE *sim_deb; uint8 dpxb[DP_NUMBY]; /* xfer buffer */ uint32 dp_bptr = 0; /* buffer ptr */ @@ -152,7 +153,6 @@ uint32 dpd_arm[DP_NUMDR] = { 0 }; /* drives armed */ int32 dp_stime = 100; /* seek latency */ int32 dp_rtime = 100; /* rotate latency */ int32 dp_wtime = 1; /* word time */ -uint32 dp_log = 0; /* debug log */ uint8 dp_tplte[(2 * DP_NUMDR) + 2]; /* fix/rmv + ctrl + end */ DEVICE dp_dev; @@ -213,7 +213,6 @@ REG dp_reg[] = { DP_NUMDR, REG_RO) }, { URDATA (CAPAC, dp_unit[0].capac, 10, T_ADDR_W, 0, DP_NUMDR, PV_LEFT | REG_HRO) }, - { FLDATA (LOG, dp_log, 0), REG_HIDDEN }, { HRDATA (DEVNO, dp_dib.dno, 8), REG_HRO }, { HRDATA (SELCH, dp_dib.sch, 2), REG_HRO }, { NULL } }; @@ -246,7 +245,7 @@ DEVICE dp_dev = { DP_NUMDR, 16, 24, 1, 16, 8, NULL, NULL, &dp_reset, &id_dboot, &dp_attach, &dp_detach, - &dp_dib, DEV_DISABLE }; + &dp_dib, DEV_DISABLE | DEV_DEBUG }; /* Controller: IO routine */ @@ -266,7 +265,7 @@ case IO_RD: /* read data */ else dp_sta = dp_sta | STA_BSY; /* xfr? set busy */ return dp_db; /* return data */ case IO_WD: /* write data */ - if (sim_log && dp_log) fprintf (sim_log, + if (DEBUG_PRS (dp_dev)) fprintf (sim_deb, ">>DPC WD = %02X, STA = %02X\n", dat, dp_sta); if (dp_sta & STC_IDL) dp_hdsc = dat & HS_MASK; /* idle? hdsc */ else { /* data xfer */ @@ -278,7 +277,7 @@ case IO_SS: /* status */ if (t & SETC_EX) t = t | STA_EX; /* test for EX */ return t; case IO_OC: /* command */ - if (sim_log && dp_log) fprintf (sim_log, + if (DEBUG_PRS (dp_dev)) fprintf (sim_deb, ">>DPC OC = %02X, STA = %02X\n", dat, dp_sta); f = dat & CMC_MASK; /* get cmd */ if (f & CMC_CLR) { /* clear? */ @@ -315,7 +314,7 @@ case IO_ADR: /* select */ if (dp_sta & STC_IDL) dp_svun = dev; /* idle? save unit */ return BY; /* byte only */ case IO_WD: /* write data */ - if (sim_log && dp_log) fprintf (sim_log, + if (DEBUG_PRS (dp_dev)) fprintf (sim_deb, ">>DP%d WD = %02X, STA = %02X\n", u, dat, dp_sta); if (GET_DTYPE (uptr->flags) == TYPE_2315) /* 2.5MB drive? */ dp_cyl = dat & 0xFF; /* cyl is 8b */ @@ -330,7 +329,7 @@ case IO_SS: /* status */ if (t & SETD_EX) t = t | STA_EX; /* test for ex */ return t; case IO_OC: /* command */ - if (sim_log && dp_log) fprintf (sim_log, + if (DEBUG_PRS (dp_dev)) fprintf (sim_deb, ">>DP%d OC = %02X, STA = %02X\n", u, dat, dp_sta); dpd_arm[u] = int_chg (v_DPC + u + 1, dat, dpd_arm[u]); if (dat & CMD_SK) t = dp_cyl; /* seek? get cyl */ diff --git a/Interdata/id_fd.c b/Interdata/id_fd.c index 63d38104..3c06a519 100644 --- a/Interdata/id_fd.c +++ b/Interdata/id_fd.c @@ -1,6 +1,6 @@ /* id_fd.c: Interdata floppy disk simulator - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id_fp.c b/Interdata/id_fp.c index 24136f72..2aa7b28c 100644 --- a/Interdata/id_fp.c +++ b/Interdata/id_fp.c @@ -1,6 +1,6 @@ /* id_fp.c: Interdata floating point instructions - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id_idc.c b/Interdata/id_idc.c index 97f40bb7..39b563ee 100644 --- a/Interdata/id_idc.c +++ b/Interdata/id_idc.c @@ -1,6 +1,6 @@ /* id_idc.c: Interdata MSM/IDC disk controller simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id_io.c b/Interdata/id_io.c index c16ede55..2c58f51d 100644 --- a/Interdata/id_io.c +++ b/Interdata/id_io.c @@ -1,6 +1,6 @@ /* id_io.c: Interdata CPU-independent I/O routines - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id_lp.c b/Interdata/id_lp.c index da118ebf..6364b9dc 100644 --- a/Interdata/id_lp.c +++ b/Interdata/id_lp.c @@ -1,6 +1,6 @@ /* id_lp.c: Interdata line printer - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id_mt.c b/Interdata/id_mt.c index 61d671f7..a205f999 100644 --- a/Interdata/id_mt.c +++ b/Interdata/id_mt.c @@ -1,6 +1,6 @@ /* id_mt.c: Interdata magnetic tape simulator - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id_pas.c b/Interdata/id_pas.c index 03591711..87cf25f1 100644 --- a/Interdata/id_pas.c +++ b/Interdata/id_pas.c @@ -1,6 +1,6 @@ /* id_pas.c: Interdata programmable async line adapter simulator - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ pas Programmable asynchronous line adapter(s) + 05-Jan-04 RMS Revised for tmxr library changes 09-May-03 RMS Added network device flag This module implements up to 32 individual serial interfaces, representing @@ -100,7 +101,7 @@ uint32 pas_tps = 50; /* polls/second */ uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */ TMLN pas_ldsc[PAS_LINES] = { 0 }; /* line descriptors */ -TMXR pas_desc = { 8, 0, 0, &pas_ldsc[0], NULL }; /* mux descriptor */ +TMXR pas_desc = { 8, 0, 0, pas_ldsc }; /* mux descriptor */ #define PAS_ENAB pas_desc.lines uint32 pas (uint32 dev, uint32 op, uint32 dat); @@ -145,16 +146,16 @@ REG pas_reg[] = { MTAB pas_mod[] = { { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES", - &pas_vlines, NULL, &pas_nlreg }, + &pas_vlines, NULL, &pas_nlreg }, { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &pas_desc }, + &tmxr_dscln, NULL, &pas_desc }, { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &pas_summ }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &pas_show, NULL }, + NULL, &pas_show, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &pas_show, NULL }, + NULL, &pas_show, NULL }, { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE pas_dev = { @@ -212,6 +213,10 @@ MTAB pasl_mod[] = { { UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", NULL }, { UNIT_MDM, 0, "no dataset", "NODATASET", NULL }, { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", + &tmxr_set_log, &tmxr_show_log, &pas_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", + &tmxr_set_nolog, NULL, &pas_desc }, { 0 } }; REG pasl_reg[] = { @@ -270,7 +275,7 @@ case IO_OC: /* command */ if ((pas_cmd[ln] & CMD_DTR) && (pas_sta[ln] & STA_RING)) pas_sta[ln] = pas_sta[ln] & ~(STA_CROF | STA_RING); if (old_cmd & ~pas_cmd[ln] & CMD_DTR) { - tmxr_msg (pas_ldsc[ln].conn, "\r\nLine hangup\r\n"); + tmxr_linemsg (&pas_ldsc[ln], "\r\nLine hangup\r\n"); tmxr_reset_ln (&pas_ldsc[ln]); /* reset line */ pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */ if (pas_rarm[ln]) SET_INT (v_PAS + ln + ln); } } @@ -424,9 +429,7 @@ if (pas_unit.flags & UNIT_ATT) { /* master att? */ t = sim_rtcn_init (pas_unit.wait, TMR_PAS); sim_activate (&pas_unit, t); } } /* activate */ else sim_cancel (&pas_unit); /* else stop */ -for (i = 0; i < PAS_LINES; i++) { - pas_desc.ldsc[i] = &pas_ldsc[i]; - pas_reset_ln (i); } +for (i = 0; i < PAS_LINES; i++) pas_reset_ln (i); return SCPE_OK; } @@ -501,7 +504,7 @@ if (newln < PAS_ENAB) { return SCPE_OK; for (i = newln; i < PAS_ENAB; i++) { if (pas_ldsc[i].conn) { - tmxr_msg (pas_ldsc[i].conn, "\r\nOperator disconnected line\r\n"); + tmxr_linemsg (&pas_ldsc[i], "\r\nOperator disconnected line\r\n"); tmxr_reset_ln (&pas_ldsc[i]); } /* reset line */ pasl_unit[i].flags = pasl_unit[i].flags | UNIT_DIS; pas_reset_ln (i); } diff --git a/Interdata/id_pt.c b/Interdata/id_pt.c index 8a499e6a..0339ac30 100644 --- a/Interdata/id_pt.c +++ b/Interdata/id_pt.c @@ -1,6 +1,6 @@ /* id_pt.c: Interdata paper tape reader - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -332,7 +332,7 @@ char *tptr; extern DEVICE cpu_dev; if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; -tptr = get_range (cptr, &lo, &hi, cpu_dev.aradix, 0xFFFF, 0); +tptr = get_range (NULL, cptr, &lo, &hi, cpu_dev.aradix, 0xFFFF, 0); if ((tptr == NULL) || (lo < INTSVT)) return SCPE_ARG; if (*tptr != 0) return SCPE_2MARG; for (i = lo, cs = 0; i <= hi; i++) cs = cs ^ IOReadB (i); diff --git a/Interdata/id_tt.c b/Interdata/id_tt.c index 6e0cb3a4..0a284813 100644 --- a/Interdata/id_tt.c +++ b/Interdata/id_tt.c @@ -1,6 +1,6 @@ /* id_tt.c: Interdata teletype - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Interdata/id_uvc.c b/Interdata/id_uvc.c index 24dcd7cf..de84c613 100644 --- a/Interdata/id_uvc.c +++ b/Interdata/id_uvc.c @@ -1,6 +1,6 @@ /* id_uvc.c: Interdata universal clock - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/LGP/lgp_cpu.c b/LGP/lgp_cpu.c new file mode 100644 index 00000000..a8c4a5dd --- /dev/null +++ b/LGP/lgp_cpu.c @@ -0,0 +1,689 @@ +/* lgp_cpu.c: LGP CPU simulator + + Copyright (c) 2004, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 LGP-30 [LGP-21] CPU + + The system state for the LGP-30 [LGP-21] is: + + A<0:31> accumulator + C<0:11> counter (PC) + OVF overflow flag [LGP-21 only] + + The LGP-30 [LGP-21] has just one instruction format: + + 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |S| |opcode | | operand address | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + LGP-30 instructions: + + <0,12:15> operation + + 0 stop + 1 A <- M[ea] + 2 M[ea] <- A + 3 M[ea] <- C + 1 + 4 input + 5 A <- A / M[ea] + 6 A <- A * M[ea], low result + 7 A <- A * M[ea], high result + 8 output + 9 A <- A & M[ea] + A C <- ea + B C <- ea if A < 0 + -B C <- ea if (A < 0) || T-switch set + C M[ea] <- A + D M[ea] <- A, A <- 0 + E A <- A + M[ea] + F A <- A - M[ea] + + LGP-21 instructions: + + <0,12:15> operation + + 0 stop; sense and skip + -0 stop; sense overflow and skip + 1 A <- M[ea] + 2 M[ea] <- A + 3 M[ea] <- C + 1 + 4 6b input + -4 4b input + 5 A <- A / M[ea] + 6 A <- A * M[ea], low result + 7 A <- A * M[ea], high result + 8 6b output + -8 4b output + 9 A <- A & M[ea] + A C <- ea + B C <- ea if A < 0 + -B C <- ea if (A < 0) || T-switch set + C M[ea] <- A + D M[ea] <- A, A <- 0 + E A <- A + M[ea] + F A <- A - M[ea] + + The LGP-30 [LGP-21] has 4096 32b words of memory. The low order + bit is always read and stored as 0. The LGP-30 uses a drum for + memory, with 64 tracks of 64 words. The LGP-21 uses a disk for + memory, with 32 tracks of 128 words. +*/ + +/* This routine is the instruction decode routine for the LGP-30 + [LGP-21]. 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: + + STOP instruction + breakpoint encountered + overflow [LGP-30] + I/O error in I/O simulator + + 2. Interrupts. There are no interrupts. + + 3. Non-existent memory. All of memory always exists. + + 4. Adding I/O devices. The LGP-30 could not support additional + I/O devices. The LGP-21 could but none are known. +*/ + +#include "lgp_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] = (PC - 1) & AMASK; +#define M16 0xFFFF +#define M32 0xFFFFFFFF +#define NEG(x) ((~(x) + 1) & DMASK) +#define ABS(x) (((x) & SIGN)? NEG (x): (x)) + +uint32 M[MEMSIZE] = { 0 }; /* memory */ +uint32 PC = 0; /* counter */ +uint32 A = 0; /* accumulator */ +uint32 IR = 0; /* instr register */ +uint32 OVF = 0; /* overflow indicator */ +uint32 t_switch = 0; /* transfer switch */ +uint32 bp32 = 0; /* BP32 switch */ +uint32 bp16 = 0; /* BP16 switch */ +uint32 bp8 = 0; /* BP8 switch */ +uint32 bp4 = 0; /* BP4 switch */ +uint32 inp_strt = 0; /* input started */ +uint32 inp_done = 0; /* input done */ +uint32 out_strt = 0; /* output started */ +uint32 out_done = 0; /* output done */ +uint32 lgp21_sov = 0; /* LGP-21 sense pending */ +int32 delay = 0; +int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ + +extern int32 sim_interval; +extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern int32 sim_step; + +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_model (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_30opt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_30opt_i (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_30opt_o (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_fill (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_exec (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_one_inst (uint32 opc, uint32 ir); +uint32 Mul64 (uint32 a, uint32 b, uint32 *low); +t_bool Div32 (uint32 dvd, uint32 dvr, uint32 *q); +uint32 I_delay (uint32 opc, uint32 ea, uint32 op); +uint32 shift_in (uint32 a, uint32 dat, uint32 sh4); + +extern t_stat op_p (uint32 dev, uint32 ch); +extern t_stat op_i (uint32 dev, uint32 ch, uint32 sh4); + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list +*/ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_IN4B+UNIT_TTSS_D, MEMSIZE) }; + +REG cpu_reg[] = { + { DRDATA (C, PC, 12), REG_VMAD }, + { HRDATA (A, A, 32), REG_VMIO }, + { HRDATA (IR, IR, 32), REG_VMIO }, + { FLDATA (OVF, OVF, 0) }, + { FLDATA (TSW, t_switch, 0) }, + { FLDATA (BP32, bp32, 0) }, + { FLDATA (BP16, bp16, 0) }, + { FLDATA (BP8, bp8, 0) }, + { FLDATA (BP4, bp4, 0) }, + { FLDATA (INPST, inp_strt, 0) }, + { FLDATA (INPDN, inp_done, 0) }, + { FLDATA (OUTST, out_strt, 0) }, + { FLDATA (OUTDN, out_done, 0) }, + { DRDATA (DELAY, delay, 7) }, + { BRDATA (CQ, pcq, 16, 12, PCQ_SIZE), REG_RO + REG_CIRC }, + { HRDATA (CQP, pcq_p, 6), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB cpu_mod[] = { + { UNIT_LGP21, UNIT_LGP21, "LGP-21", "LGP21", &cpu_set_model, &cpu_show_model }, + { UNIT_LGP21, 0, "LGP-30", "LGP30", &cpu_set_model, &cpu_show_model }, + { UNIT_TTSS_D, UNIT_TTSS_D, 0, "TRACK" }, + { UNIT_TTSS_D, 0, 0, "NORMAL" }, + { UNIT_LGPH_D, UNIT_LGPH_D, 0, "LGPHEX" }, + { UNIT_LGPH_D, 0, 0, "STANDARDHEX" }, + { UNIT_MANI, UNIT_MANI, NULL, "MANUAL" }, + { UNIT_MANI, 0, NULL, "TAPE" }, + { UNIT_IN4B, UNIT_IN4B, NULL, "4B", &cpu_set_30opt }, + { UNIT_IN4B, 0, NULL, "6B", &cpu_set_30opt }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "INPUT", &cpu_set_30opt_i }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "OUTPUT", &cpu_set_30opt_o }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "EXECUTE", &cpu_set_exec }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "FILL", &cpu_set_fill }, + { 0 } }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 10, 12, 1, 16, 32, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL }; + +/* Timing tables */ + +/* Optimization minima and maxima + Z B Y R I D N M P E U T H C A S */ + +static const int32 min_30[16] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; +static const int32 max_30[16] = { + 7, 7, 7, 7, 7, 5, 8, 6, 7, 7, 0, 0, 7, 7, 7, 7 }; +static const int32 min_21[16] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; +static const int32 max_21[16] = { + 0, 16, 16, 16, 0, 58, 81, 79, 0, 16, 0, 0, 16, 16, 16, 16 }; + +static const uint32 log_to_phys_30[NSC_30] = { /* drum interlace chart */ + 0, 57, 50, 43, 36, 29, 22, 15, 8 , + 1, 58, 51, 44, 37, 30, 23, 16, 9 , + 2, 59, 52, 45, 38, 31, 24, 17, 10, + 3, 60, 53, 46, 39, 32, 25, 18, 11, + 4, 61, 54, 47, 40, 33, 26, 19, 12, + 5, 62, 55, 48, 41, 32, 27, 20, 13, + 6, 63, 56, 49, 42, 33, 28, 21, 14, + 7 }; + +static const uint32 log_to_phys_21[NSC_21] = { /* disk interlace chart */ + 0, 64, 57, 121, 50, 114, 43, 107, 36, 100, 29, 93, 22, 86, 15, 79, 8, 72, + 1, 65, 58, 122, 51, 115, 44, 108, 37, 101, 30, 94, 23, 87, 16, 80, 9, 73, + 2, 66, 59, 123, 52, 116, 45, 109, 38, 102, 31, 95, 24, 88, 17, 81, 10, 74, + 3, 67, 60, 124, 53, 117, 46, 110, 39, 103, 32, 96, 25, 89, 18, 82, 11, 75, + 4, 68, 61, 125, 54, 118, 47, 111, 40, 104, 33, 97, 26, 90, 19, 83, 12, 76, + 5, 69, 62, 126, 55, 119, 48, 112, 41, 105, 34, 98, 27, 91, 20, 84, 12, 77, + 6, 70, 63, 127, 56, 120, 49, 113, 42, 106, 35, 99, 28, 92, 21, 85, 13, 78, + 7, 71 }; + +t_stat sim_instr (void) +{ +t_stat r = 0; +uint32 oPC; + +/* Restore register state */ + +PC = PC & AMASK; /* mask PC */ +sim_cancel_step (); /* defang SCP step */ +if (lgp21_sov) { /* stop sense pending? */ + lgp21_sov = 0; + if (!OVF) PC = (PC + 1) & AMASK; /* ovf off? skip */ + else OVF = 0; } /* on? reset */ + +/* Main instruction fetch/decode loop */ + +do { if (sim_interval <= 0) { /* check clock queue */ + if (r = sim_process_event ()) break; } + + if (delay > 0) { /* delay to next instr */ + delay = delay - 1; /* count down delay */ + sim_interval = sim_interval - 1; + continue; } /* skip execution */ + + if (sim_brk_summ && /* breakpoint? */ + sim_brk_test (PC, SWMASK ('E'))) { + r = STOP_IBKPT; /* stop simulation */ + break; } + + IR = Read (oPC = PC); /* get instruction */ + PC = (PC + 1) & AMASK; /* increment PC */ + sim_interval = sim_interval - 1; + + if (r = cpu_one_inst (oPC, IR)) { /* one instr; error? */ + if (r == STOP_STALL) { /* stall? */ + PC = oPC; /* back up PC */ + delay = r = 0; } /* no delay */ + else break; } + + if (sim_step && (--sim_step <= 0)) /* do step count */ + r = SCPE_STOP; + + } while (r == 0); /* loop until halted */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ +return r; +} + +/* Execute one instruction */ + +t_stat cpu_one_inst (uint32 opc, uint32 ir) +{ +uint32 ea, op, dat, res, dev, sh4, ch; +t_bool ovf_this_cycle = FALSE; +t_stat reason = 0; + +op = I_GETOP (ir); /* opcode */ +ea = I_GETEA (ir); /* address */ +switch (op) { /* case on opcode */ + +/* Loads, stores, transfers instructions */ + +case OP_B: /* bring */ + A = Read (ea); /* A <- M[ea] */ + delay = I_delay (opc, ea, op); + break; + +case OP_H: /* hold */ + Write (ea, A); /* M[ea] <- A */ + delay = I_delay (opc, ea, op); + break; + +case OP_C: /* clear */ + Write (ea, A); /* M[ea] <- A */ + A = 0; /* A <- 0 */ + delay = I_delay (opc, ea, op); + break; + +case OP_Y: /* store address */ + dat = Read (ea); /* get operand */ + dat = (dat & ~I_EA) | (A & I_EA); /* merge address */ + Write (ea, dat); + delay = I_delay (opc, ea, op); + break; + +case OP_R: /* return address */ + dat = Read (ea); /* get operand */ + dat = (dat & ~I_EA) | (((PC + 1) & AMASK) << I_V_EA); + Write (ea, dat); + delay = I_delay (opc, ea, op); + break; + +case OP_U: /* uncond transfer */ + PCQ_ENTRY; + PC = ea; /* transfer */ + delay = I_delay (opc, ea, op); + break; + +case OP_T: /* conditional transfer */ + if ((A & SIGN) || /* A < 0 or */ + ((ir & SIGN) && t_switch)) { /* -T and Tswitch set? */ + PCQ_ENTRY; + PC = ea; } /* transfer */ + delay = I_delay (opc, ea, op); + break; + +/* Arithmetic and logical instructions */ + +case OP_A: /* add */ + dat = Read (ea); /* get operand */ + res = (A + dat) & DMASK; /* add */ + if ((~A ^ dat) & (dat ^ res) & SIGN) /* calc overflow */ + ovf_this_cycle = TRUE; + A = res; /* save result */ + delay = I_delay (opc, ea, op); + break; + +case OP_S: /* sub */ + dat = Read (ea); /* get operand */ + res = (A - dat) & DMASK; /* subtract */ + if ((A ^ dat) & (~dat ^ res) & SIGN) /* calc overflow */ + ovf_this_cycle = TRUE; + A = res; + delay = I_delay (opc, ea, op); + break; + +case OP_M: /* multiply high */ + dat = Read (ea); /* get operand */ + A = (Mul64 (A, dat, NULL) << 1) & DMASK; /* multiply */ + delay = I_delay (opc, ea, op); + break; + +case OP_N: /* multiply low */ + dat = Read (ea); /* get operand */ + Mul64 (A, dat, &res); /* multiply */ + A = res; /* keep low result */ + delay = I_delay (opc, ea, op); /* total delay */ + break; + +case OP_D: /* divide */ + dat = Read (ea); /* get operand */ + if (Div32 (A, dat, &A)) ovf_this_cycle = TRUE; /* divide; overflow? */ + delay = I_delay (opc, ea, op); + break; + +case OP_E: /* extract */ + dat = Read (ea); /* get operand */ + A = A & dat; /* and */ + delay = I_delay (opc, ea, op); + break; + +/* IO instructions */ + +case OP_P: /* output */ + if (Q_LGP21) { /* LGP-21 */ + ch = A >> 26; /* char, 6b */ + if (ir & SIGN) ch = (ch & 0x3C) | 2; /* 4b? convert */ + dev = I_GETTK (ir); } /* device select */ + else { /* LGP-30 */ + ch = I_GETTK (ir); /* char, always 6b */ + dev = Q_OUTPT? DEV_PT: DEV_TT; } /* device select */ + reason = op_p (dev & DEV_MASK, ch); /* output */ + delay = I_delay (sim_grtime (), ea, op); /* next instruction */ + break; + +case OP_I: /* input */ + if (Q_LGP21) { /* LGP-21 */ + ch = 0; /* initial shift */ + sh4 = ir & SIGN; /* 4b/6b select */ + dev = I_GETTK (ir); } /* device select */ + else { /* LGP-30 */ + ch = I_GETTK (ir); /* initial shift */ + sh4 = Q_IN4B; /* 4b/6b select */ + dev = Q_INPT? DEV_PT: DEV_TT; } /* device select */ + if (dev == DEV_SHIFT) /* shift? */ + A = shift_in (A, 0, sh4); /* shift 4/6b */ + else reason = op_i (dev & DEV_MASK, ch, sh4); /* input */ + delay = I_delay (sim_grtime (), ea, op); /* next instruction */ + break; + +case OP_Z: + if (Q_LGP21) { /* LGP-21 */ + if (ea & 0xF80) { /* no stop? */ + if (((ea & 0x800) && !bp32) || /* skip if any */ + ((ea & 0x400) && !bp16) || /* selected switch */ + ((ea & 0x200) && !bp8) || /* is off */ + ((ea & 0x100) && !bp4) || /* or if */ + ((ir & SIGN) && !OVF)) /* ovf sel and off */ + PC = (PC + 1) & AMASK; + if (ir & SIGN) OVF = 0; } /* -Z? clr overflow */ + else { /* stop */ + lgp21_sov = (ir & SIGN)? 1: 0; /* pending sense? */ + reason = STOP_STOP; } } /* stop */ + else { /* LGP-30 */ + if (out_done) out_done = 0; /* P complete? */ + else if (((ea & 0x800) && bp32) || /* bpt switch set? */ + ((ea & 0x400) && bp16) || + ((ea & 0x200) && bp8) || + ((ea & 0x100) && bp4)) ; /* don't stop or stall */ + else if (out_strt) reason = STOP_STALL; /* P pending? stall */ + else reason = STOP_STOP; } /* no, stop */ + delay = I_delay (sim_grtime (), ea, op); /* next instruction */ + break; } /* end switch */ + +if (ovf_this_cycle) { + if (Q_LGP21) OVF = 1; /* LGP-21? set OVF */ + else reason = STOP_OVF; } /* LGP-30? stop */ +return reason; +} + +/* Support routines */ + +uint32 Read (uint32 ea) +{ +return M[ea] & MMASK; +} + +void Write (uint32 ea, uint32 dat) +{ +M[ea] = dat & MMASK; +return; +} + +/* Input shift */ + +uint32 shift_in (uint32 a, uint32 dat, uint32 sh4) +{ +if (sh4) return (((a << 4) | (dat >> 2)) & DMASK); +return (((a << 6) | dat) & DMASK); +} + +/* 32b * 32b multiply, signed */ + +uint32 Mul64 (uint32 a, uint32 b, uint32 *low) +{ +uint32 sgn = a ^ b; +uint32 ah, bh, al, bl, rhi, rlo, rmid1, rmid2; + +if ((a == 0) || (b == 0)) { /* zero argument? */ + if (low) *low = 0; + return 0; } +a = ABS (a); +b = ABS (b); +ah = (a >> 16) & M16; /* split operands */ +bh = (b >> 16) & M16; /* into 16b chunks */ +al = a & M16; +bl = b & M16; +rhi = ah * bh; /* high result */ +rmid1 = ah * bl; +rmid2 = al * bh; +rlo = al * bl; +rhi = rhi + ((rmid1 >> 16) & M16) + ((rmid2 >> 16) & M16); +rmid1 = (rlo + (rmid1 << 16)) & M32; /* add mid1 to lo */ +if (rmid1 < rlo) rhi = rhi + 1; /* carry? incr hi */ +rmid2 = (rmid1 + (rmid2 << 16)) & M32; /* add mid2 to to */ +if (rmid2 < rmid1) rhi = rhi + 1; /* carry? incr hi */ +if (sgn & SIGN) { /* result negative? */ + rmid2 = NEG (rmid2); /* negate */ + rhi = (~rhi + (rmid2 == 0)) & M32; } +if (low) *low = rmid2; /* low result */ +return rhi & M32; +} + +/* 32b/32b divide (done as 32b'0/32b) */ + +t_bool Div32 (uint32 dvd, uint32 dvr, uint32 *q) +{ +uint32 sgn = dvd ^ dvr; +uint32 i, quo; + +dvd = ABS (dvd); +dvr = ABS (dvr); +if (dvd >= dvr) return TRUE; +for (i = quo = 0; i < 31; i++) { /* 31 iterations */ + quo = quo << 1; /* shift quotient */ + dvd = dvd << 1; /* shift dividend */ + if (dvd >= dvr) { /* step work? */ + dvd = (dvd - dvr) & M32; /* subtract dvr */ + quo = quo + 1; } } +quo = (quo + 1) & MMASK; /* round low bit */ +if (sgn & SIGN) quo = NEG (quo); /* result -? */ +if (q) *q = quo; /* return quo */ +return FALSE; /* no overflow */ +} + +/* Rotational delay */ + +uint32 I_delay (uint32 opc, uint32 ea, uint32 op) +{ +uint32 tmin = Q_LGP21? min_21[op]: min_30[op]; +uint32 tmax = Q_LGP21? max_21[op]: max_30[op]; +uint32 nsc, curp, newp, oprp, pcdelta, opdelta; + +if (Q_LGP21) { /* LGP21 */ + nsc = NSC_21; /* full rotation delay */ + curp = log_to_phys_21[opc & SCMASK_21]; /* current phys pos */ + newp = log_to_phys_21[PC & SCMASK_21]; /* new PC phys pos */ + oprp = log_to_phys_21[ea & SCMASK_21]; /* ea phys pos */ + pcdelta = (newp - curp + NSC_21) & SCMASK_21; + opdelta = (oprp - curp + NSC_21) & SCMASK_21; } +else { nsc = NSC_30; + curp = log_to_phys_30[opc & SCMASK_30]; + newp = log_to_phys_30[PC & SCMASK_30]; + oprp = log_to_phys_30[ea & SCMASK_30]; + pcdelta = (newp - curp + NSC_30) & SCMASK_30; + opdelta = (oprp - curp + NSC_30) & SCMASK_30; } +if (tmax == 0) { /* skip ea calc? */ + if (pcdelta >= tmin) return pcdelta - 1; /* new PC >= min? */ + return pcdelta + nsc - 1; } +if ((opdelta >= tmin) && (opdelta <= tmax)) return pcdelta - 1; +return pcdelta + nsc - 1; +} + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +OVF = 0; +inp_strt = 0; +inp_done = 0; +out_strt = 0; +out_done = 0; +lgp21_sov = 0; +delay = 0; +pcq_r = find_reg ("CQ", NULL, dptr); +if (pcq_r) pcq_r->qptr = 0; +else return SCPE_IERR; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; +} + +/* Validate option, must be LGP30 */ + +t_stat cpu_set_30opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (Q_LGP21) return SCPE_ARG; +return SCPE_OK; +} + +/* Validate input option, must be LGP30 */ + +t_stat cpu_set_30opt_i (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (Q_LGP21 || (cptr == NULL)) return SCPE_ARG; +if (strcmp (cptr, "TTI") == 0) uptr->flags = uptr->flags & ~UNIT_INPT; +else if (strcmp (cptr, "PTR") == 0) uptr->flags = uptr->flags | UNIT_INPT; +else return SCPE_ARG; +return SCPE_OK; +} + +/* Validate output option, must be LGP30 */ + +t_stat cpu_set_30opt_o (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (Q_LGP21 || (cptr == NULL)) return SCPE_ARG; +if (strcmp (cptr, "TTO") == 0) uptr->flags = uptr->flags & ~UNIT_OUTPT; +else if (strcmp (cptr, "PTP") == 0) uptr->flags = uptr->flags | UNIT_OUTPT; +else return SCPE_ARG; +return SCPE_OK; +} + +/* Set CPU to LGP21 or LPG30 */ + +t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val) uptr->flags = uptr->flags & ~(UNIT_IN4B|UNIT_INPT|UNIT_OUTPT); +return reset_all (0); +} + +/* Show CPU type and all options */ + +t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fputs (Q_LGP21? "LGP-21": "LGP-30", st); +if (uptr->flags & UNIT_TTSS_D) fputs (", track/sector", st); +if (uptr->flags & UNIT_LGPH_D) fputs (", LGP hex", st); +fputs (Q_MANI? ", manual": ", tape", st); +if (!Q_LGP21) { + fputs (Q_IN4B? ", 4b": ", 6b", st); + fputs (Q_INPT? ", in=PTR": ", in=TTI", st); + fputs (Q_OUTPT? ", out=PTP": ", out=TTO", st); } +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 = Read (addr); +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; +Write (addr, val); +return SCPE_OK; +} + +/* Execute */ + +t_stat cpu_set_exec (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 inst; +t_stat r; + +if (cptr) { + inst = get_uint (cptr, 16, DMASK, &r); + if (r != SCPE_OK) r; } +else inst = IR; +while ((r = cpu_one_inst (PC, inst)) == STOP_STALL) { + sim_interval = 0; + if (r = sim_process_event ()) return r; } +return r; +} + +/* Fill */ + +t_stat cpu_set_fill (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 inst; +t_stat r; + +if (cptr) { + inst = get_uint (cptr, 16, DMASK, &r); + if (r != SCPE_OK) r; + IR = inst; } +else IR = A; +return SCPE_OK; +} diff --git a/LGP/lgp_defs.h b/LGP/lgp_defs.h new file mode 100644 index 00000000..c40c3f78 --- /dev/null +++ b/LGP/lgp_defs.h @@ -0,0 +1,134 @@ +/* lgp_defs.h: LGP simulator definitions + + Copyright (c) 2004, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 _LGP_DEFS_H_ +#define _LGP_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ + +/* Simulator stop codes */ + +#define STOP_STOP 1 /* STOP */ +#define STOP_IBKPT 2 /* breakpoint */ +#define STOP_OVF 3 /* overflow */ +#define STOP_NXDEV 4 /* non-existent device */ +#define STOP_STALL 5 /* IO stall */ + +/* Memory */ + +#define MEMSIZE 4096 /* memory size */ +#define AMASK 0xFFF /* addr mask */ +#define NTK_30 64 +#define NSC_30 64 +#define SCMASK_30 0x03F /* sector mask */ +#define NTK_21 32 +#define NSC_21 128 +#define SCMASK_21 0x07F +#define RPM 4000 /* rev/minutes */ +#define WPS ((NSC_30 * RPM) / 60) /* words/second */ + +/* Architectural constants */ + +#define SIGN 0x80000000 /* sign */ +#define DMASK 0xFFFFFFFF /* data mask */ +#define MMASK 0xFFFFFFFE /* memory mask */ + +/* Instruction format */ + +#define I_M_OP 0xF /* opcode */ +#define I_V_OP 16 +#define I_OP (I_M_OP << I_V_OP) +#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP) +#define I_M_EA AMASK /* address */ +#define I_V_EA 2 +#define I_EA (I_M_EA << I_V_EA) +#define I_GETEA(x) (((x) >> I_V_EA) & I_M_EA) +#define I_M_TK 0x3F /* LGP-30 char */ +#define I_V_TK 8 /* LGP-21 device */ +#define I_GETTK(x) (((x) >> I_V_TK) & I_M_TK) + +/* Unit flags */ + +#define UNIT_V_LGP21 (UNIT_V_UF + 0) +#define UNIT_V_MANI (UNIT_V_UF + 1) +#define UNIT_V_INPT (UNIT_V_UF + 2) +#define UNIT_V_OUTPT (UNIT_V_UF + 3) +#define UNIT_V_IN4B (UNIT_V_UF + 4) +#define UNIT_V_TTSS_D (UNIT_V_UF + 5) +#define UNIT_V_LGPH_D (UNIT_V_UF + 6) +#define UNIT_V_FLEX_D (UNIT_V_UF + 7) /* Flex default */ +#define UNIT_V_FLEX (UNIT_V_UF + 8) /* Flex format */ +#define UNIT_V_NOCS (UNIT_V_UF + 9) /* ignore cond stop */ +#define UNIT_LGP21 (1u << UNIT_V_LGP21) +#define UNIT_MANI (1u << UNIT_V_MANI) +#define UNIT_INPT (1u << UNIT_V_INPT) +#define UNIT_OUTPT (1u << UNIT_V_OUTPT) +#define UNIT_IN4B (1u << UNIT_V_IN4B) +#define UNIT_TTSS_D (1u << UNIT_V_TTSS_D) +#define UNIT_LGPH_D (1u << UNIT_V_LGPH_D) +#define UNIT_FLEX_D (1u << UNIT_V_FLEX_D) +#define UNIT_FLEX (1u << UNIT_V_FLEX) +#define UNIT_NOCS (1u << UNIT_V_NOCS) +#define Q_LGP21 (cpu_unit.flags & UNIT_LGP21) +#define Q_MANI (cpu_unit.flags & UNIT_MANI) +#define Q_INPT (cpu_unit.flags & UNIT_INPT) +#define Q_OUTPT (cpu_unit.flags & UNIT_OUTPT) +#define Q_IN4B (cpu_unit.flags & UNIT_IN4B) + +/* IO return */ + +#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ + +/* Significant characters */ + +#define FLEX_LC 0x04 +#define FLEX_UC 0x08 +#define FLEX_CR 0x10 +#define FLEX_BS 0x14 +#define FLEX_CSTOP 0x20 +#define FLEX_DEL 0x3F + +/* LGP-21 device assignments */ + +#define DEV_PT 0 +#define DEV_TT 2 +#define DEV_MASK 0x1F +#define DEV_SHIFT 62 + +/* Instructions */ + +enum opcodes { + OP_Z, OP_B, OP_Y, OP_R, + OP_I, OP_D, OP_N, OP_M, + OP_P, OP_E, OP_U, OP_T, + OP_H, OP_C, OP_A, OP_S }; + +/* Prototypes */ + +uint32 Read (uint32 ea); +void Write (uint32 ea, uint32 dat); + +#endif diff --git a/LGP/lgp_doc.txt b/LGP/lgp_doc.txt new file mode 100644 index 00000000..253ada4b --- /dev/null +++ b/LGP/lgp_doc.txt @@ -0,0 +1,465 @@ +To: Users +From: Bob Supnik +Subj: LGP Simulator Usage +Date: 15-Feb-2004 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + +This memorandum documents the GRI-909 simulator. + + +1. Simulator Files + +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h + sim_rev.h + sim_sock.h + sim_timer.h + sim_tmxr.h + scp.c + sim_console.c + sim_fio.c + sim_sock.c + sim_timer.c + sim_tmxr.c + +sim/gri/ lgp_defs.h + lgp_cpu.c + lgp_stddev.c + lgp_sys.c + +2. LGP Features + +The LGP is configured as follows: + +device simulates +name(s) + +CPU LGP-30 or LGP-21 CPU with 4096 words of memory +TTI Typewriter input (keyboard and reader) +TTO Typewriter output (printer and punch) +PTR high-speed paper tape reader +PTP high-speed paper tape punch + +The LGP simulator implements the following unique stop conditions: + + - LGP-30 only: arithmetic overflow + - LGP-21 only: reference to undefined I/O device. + +The LOAD and DUMP commands are not implemented. + +2.1 CPU + +The CPU implements either the LGP-30 or the LGP-21: + + SET CPU LGP30 set LGP-30 + SET CPU LGP21 set LGP-21 + +The default is the LGP-30. Memory size is fixed at 4096 words. + +The following commands implement various front panel functions: + + D A value equivalent to the MANUAL INPUT button + SET CPU FILL{=value} equivalent to the FILL INSTRUCTION button; + if no value is given, fills IR from A; + otherwise, fills IR from the specified value + SET CPU EXEC{=value} equivalent to the EXECUTE button; + if no value is given, executes the instruction + in IR; otherwise, executes the instruction + specified by the value + SET CPU MANUAL equivalent to setting the MANUAL INPUT switch + on the Typewriter; Typewriter input is taken + from the keyboard + SET CPU TAPE equivalent to clearing the MANUAL INPUT switch + on the Typewriter; TYpewriter input is taken + from the Typewriter paper tape reader + +The following commands control the display of information: + + SET CPU LGPHEX numeric displays use LGP hexadecimal encoding + SET CPU STANDARD numeric displays use standard hexadecimal + SET CPU TRACK symbolic addresses are ttss, where tt = track + (0-63) and ss = sector (0-63) + SET CPU NORMAL symbolic addresses are normal linear addresses, + from 0 to 4095. + +The defaults are STANDARD hex and TRACK addresses. + +The LGP-30 implements the following additional commands: + + SET CPU 4B sets the CPU to 4-bit input mode + SET CPU 6B sets the CPU to 6-bit input mode + SET CPU INPUT=TTI sets the CPU to read from the Typewriter + SET CPU INPUT=PTR sets the CPU to read from the high-speed reader + SET CPU OUTPUT=TTO sets the CPU to output to the Typewriter + SET CPU OUTPUT=PTP sets the CPU to output to the high-speed punch + +The defaults are TAPE input, 4B input mode, input and output assigned to the +Typewriter. + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + PC 12 counter + A 32 accumulator + IR 32 instruction register + OVF 1 overflow flag (LGP-21 only) + TSW 1 transfer switch + BP32 1 breakpoint 32 switch + BP16 1 breakpoint 16 switch + BP8 1 breakpoint 8 switch + BP4 1 breakpoint 4 switch + INPST 1 input pending flag + INPDN 1 input done flag + OUTST 1 output pending flag + OUTDN 1 output done flag + WRU 8 interrupt character + +2.2 Typewriter Input (TTI) + +The Typewriter input consists of two units: the keyboard (unit 0) and +the paper-tape reader (unit 1). The keyboard is permanently associated +with the console window. The paper-tape reader can be attached to a +disk file. The RPOS register specifies the number of the next data item +to be read. Thus, by changing RPOS, the user can backspace or advance +the reader. + +The Typewriter input has the following options: + + SET TTI1 ASCII default tape file format is ASCII-encoded + Flex + SET TTI1 FLEX default tape file format is transposed Flex + SET TTI1 CSTOP reader recognizes conditional stop + SET TTI1 NOCSTOP reader ignores conditional stop + SET TTI RSTART start the reader; equivalent to the + START READER lever + SET TTI RSTOP stop the reader; equivalent to the + STOP READER lever + SET TTI START send START signal to the CPU; equivalent + to the START COMPUTE lever + +Transposed Flex has the tape channels in this order: 6-1-2-3-4-5. + +The ATTACH command recognizes two switches: + + ATT -A TTI1 file file format is ASCII-encoded Flex + ATT -F TTI1 file file format is transposed Flex + +The Typewriter input implements these registers: + + name size comments + + BUF 6 data buffer + RDY 1 data ready flag + KPOS 32 count of keyboard characters + RPOS 32 position in the reader input file + TIME 24 time between keyboard polls/reader characters + STOP_IOE 1 stop on I/O error + +Error handling for the Typewriter paper-tape reader is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.3 Typewriter Output (TTO) + +The Typewriter output consists of two units: the printer (unit 0) and +the paper-tape punch (unit 1). The printer is permanently associated +with the console window. The paper-tape punch can be attached to a +disk file. The PPOS register specifies the number of the next data item +to be written. Thus, by changing PPOS, the user can backspace or advance +the reader. + +The Typewriter output has the following options: + + SET TTO1 ASCII default tape file format is ASCII-encoded + Flex + SET TTO1 FLEX default tape file format is transposed Flex + SET TTO1 FEED=n punch 'n' feed (0) characters + + +Transposed Flex has the tape channels in this order: 6-1-2-3-4-5. The +default is ASCII-encoded Flex. + +The ATTACH command recognizes two switches: + + ATT -A TTO1 file file format is ASCII-encoded Flex + ATT -F TTO1 file file format is transposed Flex + +The Typewriter output implements these registers: + + name size comments + + BUF 6 data buffer + UC 1 upper case flag + TPOS 32 count of output characters + PPOS 32 position in the punch output file + TIME 24 time from I/O initiation to completion + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + + +2.4 High Speed Paper-Tape Reader (PTR) + +The paper tape reader (PTR) reads data from or a disk file. The POS +register specifies the number of the next data item to be read. +Thus, by changing POS, the user can backspace or advance the reader. + +The paper-tape reader has the following options: + + SET PTR ASCII default tape file format is ASCII-encoded + Flex + SET PTR FLEX default tape file format is transposed Flex + +Transposed Flex has the tape channels in this order: 6-1-2-3-4-5. The +default is ASCII-encoded Flex. + +The ATTACH command recognizes two switches: + + ATT -A PTR file file format is ASCII-encoded Flex + ATT -F PTR file file format is transposed Flex + +The paper tape reader implements these registers: + + name size comments + + BUF t last data item processed + RDY 1 data ready flag + POS 32 position in the input file + TIME 24 time from I/O initiation to completion + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.5 High Speed Paper-Tape Punch (PTP) + +The paper tape punch (PTP) writes data to a disk file. The POS +register specifies the number of the next data item to be written. +Thus, by changing POS, the user can backspace or advance the punch. + +The paper tape punch has the following options: + + SET PTP ASCII default tape file format is ASCII-encoded + Flex + SET PTP FLEX default tape file format is transposed Flex + SET PTP FEED=n punch 'n' feed (0) characters + +Transposed Flex has the tape channels in this order: 6-1-2-3-4-5. The +default is ASCII-encoded Flex. + +The ATTACH command recognizes two switches: + + ATT -A PTP file file format is ASCII-encoded Flex + ATT -F PTP file file format is transposed Flex + +The paper tape punch implements these registers: + + name size comments + + BUF 6 last data item processed + POS 32 position in the output file + TIME 24 time from I/O initiation to completion + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.6 Symbolic Display and Input + +The LGP simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as character (tape files only) + -h display as standard hexadecimal + -l display as LGP hexadecimal + -m display instruction mnemonics + -n display addresses in normal format + (overrides SET CPU TRACK) + -t display addresses as track/sector + (overrides SET CPU NORMAL) + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a Flex character + - or opcode instruction mnemonic + numeric hexadecimal number + +LGP hexadecimal differs from standard hexadecimal in the characters used +for digits 10-15 + + digit standard hex LPG hex + + 10 A F + 11 B G + 12 C J + 13 D K + 14 E Q + 15 F W + +There is only instruction format: + + {-}op address + +'op' is always a single letter. A track/sector address (specified by +SET CPU TRACK or switch -t) is two decimal numbers between 0 and 63, +representing the track and sector. A linear address (specified by +SET CPU NORMAL or switch -n) is one decimal number between 0 and 4095. +For example: + + sim> d -n 64 10640 + sim> ex -mn 64 + 64: B 400 + sim> ex -mt 100 + 0100: B 0616 + +2.7 Character Set + +The LGP Typewriter was a Friden Flexowriter. Input was always upper case; +output could be either upper case or lower case. The following table provides +equivalences between LPG Typewriter coding and ASCII. + +Typewriter Input LC output UC output +code (hex) + +00 illegal illegal illegal +01 z or Z z Z +02 0 or ) 0 ) +03 space space space +04 illegal lower case lower case +05 b or B b B +06 1 or L 1 L +07 - or _ 0 _ +10 illegal upper case upper case +11 y or Y y Y +12 2 or * 2 * +13 + or = + = +14 illegal color shift color shift +15 r or R r R +16 3 or " 3 " +17 ; or : ; : +20 newline newline newline +21 i or I i I +22 4 or ^ 4 ^ +23 / or ? / ? +24 illegal backspace backspace +25 d or D d D +26 5 or % 5 % +27 . or ] . ] +30 tab tab tab +31 n or N n N +32 6 or $ 6 $ +33 , or [ , [ +34 illegal illegal illegal +35 m or M m M +36 7 or ~ 7 ~ +37 v or V v V +40 ' (cond stop) ' ' +41 p or P p P +42 8 or # 8 # +43 o or O o O +44 illegal illegal illegal +45 e or E e E +46 9 or ( 9 ( +47 x or X x X +50 illegal illegal illegal +51 u or U u U +52 f or F f F +53 illegal illegal illegal +54 illegal illegal illegal +55 t or T t T +56 g or G g G +57 illegal illegal illegal +60 illegal illegal illegal +61 h or H h H +62 j or J j J +63 illegal illegal illegal +64 illegal illegal illegal +65 c or C c C +66 k or K k K +67 illegal illegal illegal +70 illegal illegal illegal +71 a or A a A +72 q or Q q Q +73 illegal illegal illegal +74 illegal illegal illegal +75 s or S s S +76 w or W w W +77 illegal illegal illegal + +Certain characters on the Flexowriter keyboard don't exist in ASCII. +The following table provides ASCII substitution characters for the unique +Flexowriter characters (this is compatible with the coding in the LGP30 +paper tape archive): + +Typewriter Flex ASCII +code + +UC 12 delta ^ +UC 1E pi ~ +UC 22 sigma # + +Certain Flexowriter codes have no character equivalent of any kind. +For paper-tape reader and punch files, these are encoded as #dd, where +dd is a decimal number between 0 and 63. diff --git a/LGP/lgp_stddev.c b/LGP/lgp_stddev.c new file mode 100644 index 00000000..d6619ccc --- /dev/null +++ b/LGP/lgp_stddev.c @@ -0,0 +1,597 @@ +/* lgp_stddev.c: LGP-30 standard devices + + Copyright (c) 2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 typewriter input (keyboard and reader) + tto typewriter output (printer and punch) + ptr high speed reader + ptpp high speed punch +*/ + +#include "lgp_defs.h" +#include + +uint32 tt_wait = WPS / 10; +uint32 tti_buf = 0; +uint32 tti_rdy = 0; +uint32 tto_uc = 0; +uint32 tto_buf = 0; +uint32 ttr_stopioe = 1; +uint32 ptr_rdy = 0; +uint32 ptr_stopioe = 1; +uint32 ptp_stopioe = 1; + +extern uint32 A; +extern uint32 inp_strt, inp_done; +extern uint32 out_strt, out_done; +extern UNIT cpu_unit; +extern int32 sim_switches; + +t_stat tti_svc (UNIT *uptr); +t_stat ttr_svc (UNIT *uptr); +t_stat tto_svc (UNIT *uptr); +t_stat tti_reset (DEVICE *uptr); +t_stat tto_reset (DEVICE *uptr); +t_stat ptr_svc (UNIT *uptr); +t_stat ptp_svc (UNIT *uptr); +t_stat ptr_reset (DEVICE *uptr); +t_stat ptp_reset (DEVICE *uptr); +t_stat tap_attach (UNIT *uptr, char *cptr); +t_stat tap_attable (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat read_reader (UNIT *uptr, int32 stop, int32 *c); +t_stat write_tto (int32 flex); +t_stat write_punch (UNIT *uptr, int32 flex); +t_stat tti_rdrss (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat punch_feed (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat send_start (UNIT *uptr, int32 val, char *cptr, void *desc); + +extern uint32 shift_in (uint32 a, uint32 dat, uint32 sh4); + +/* Conversion tables */ + +const int32 flex_to_ascii[128] = { + -1 , 'z', '0', ' ', '>', 'b', '1', '-', + '<' , 'y', '2', '+', '|', 'r', '3', ';', + '\r', 'i', '4', '/','\\', 'd', '5', '.', + '\t', 'n', '6', ',', -1 , 'm', '7', 'v', + '\'', 'p', '8', 'o', -1 , 'e', '9', 'x', + -1 , 'u', 'f', -1 , -1 , 't', 'g', -1 , + -1 , 'h', 'j', -1 , -1 , 'c', 'k', -1 , + -1 , 'a', 'q', -1 , -1 , 's', 'w', 0 , + + -1 , 'Z', ')', ' ', -1 , 'B', 'L', '_', + -1 , 'Y', '*', '=', '|', 'R', '"', ':', + '\r', 'I', '^', '?','\\', 'D', '%', ']', + '\t', 'N', '$', '[', -1 , 'M', '~', 'V', + '\'', 'P', '#', 'O', -1 , 'E', '(', 'X', + -1 , 'U', 'F', -1 , -1 , 'T', 'G', -1 , + -1 , 'H', 'J', -1 , -1 , 'C', 'K', -1 , + -1 , 'A', 'Q', -1 , -1 , 'S', 'W', 0 }; + +const int32 ascii_to_flex[128] = { + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , + 024, 030, -1 , -1 , -1 , 020, -1 , -1 , + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , + 003, -1 , 016, 042, 032, 026, -1 , 040, + 046, 001, 012, 013, 033, 007, 027, 023, + 002, 006, 012, 016, 022, 026, 032, 036, + 042, 046, 017, 017, 004, 013, 010, 023, + -1 , 071, 005, 065, 025, 045, 052, 056, + 061, 021, 062, 066, 006, 035, 031, 043, + 041, 072, 015, 075, 055, 051, 037, 076, + 047, 011, 001, 033, -1 , 027, 022, 007, + - 1, 071, 005, 065, 025, 045, 052, 056, + 061, 021, 062, 066, 006, 035, 031, 043, + 041, 072, 015, 075, 055, 051, 037, 076, + 047, 011, 001, -1 , 014, -1 , 036, 077 }; + +static const uint8 flex_inp_valid[64] = { + 1, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1 }; + +/* TTI data structures + + tti_dev TTI device descriptor + tti_unit TTI unit descriptor + tti_mod TTI modifier list + tti_reg TTI register list +*/ + +UNIT tti_unit[] = { + { UDATA (&tti_svc, 0, 0) }, + { UDATA (&ttr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) } }; + +REG tti_reg[] = { + { HRDATA (BUF, tti_buf, 6) }, + { FLDATA (RDY, tti_rdy, 0) }, + { DRDATA (KPOS, tti_unit[0].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (RPOS, tti_unit[1].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, tt_wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (STOP_IOE, ttr_stopioe, 0) }, + { NULL } }; + +MTAB tti_mod[] = { + { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable }, + { UNIT_FLEX_D, 0, NULL, "ASCII", &tap_attable }, + { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX, + "file is Flex", NULL }, + { UNIT_ATT+UNIT_FLEX, UNIT_ATT, + "file is ASCII", NULL }, + { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX, + "default is Flex", NULL }, + { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE, + "default is ASCII", NULL }, + { UNIT_ATTABLE+UNIT_NOCS, UNIT_ATTABLE+UNIT_NOCS, + "ignore conditional stop", "NOCSTOP", &tap_attable }, + { UNIT_ATTABLE+UNIT_NOCS, UNIT_ATTABLE , + NULL, "CSTOP", &tap_attable }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "START", &send_start }, + { MTAB_XTD|MTAB_VDV, 1, NULL, "RSTART", &tti_rdrss }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "RSTOP", &tti_rdrss }, + { 0, 0 } }; + +DEVICE tti_dev = { + "TTI", tti_unit, tti_reg, tti_mod, + 2, 10, 31, 1, 16, 7, + NULL, NULL, &tti_reset, + NULL, &tap_attach, NULL }; + +/* TTO data structures + + tto_dev TTO device descriptor + tto_unit TTO unit descriptor + tto_mod TTO modifier list + tto_reg TTO register list +*/ + +UNIT tto_unit[] = { + { UDATA (&tto_svc, 0, 0) }, + { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } }; + +REG tto_reg[] = { + { HRDATA (BUF, tto_buf, 6) }, + { FLDATA (UC, tto_uc, 0) }, + { DRDATA (TPOS, tto_unit[0].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (PPOS, tto_unit[1].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, tt_wait, 24), PV_LEFT }, + { NULL } }; + +MTAB tto_mod[] = { + { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable }, + { UNIT_FLEX_D, 0, NULL, "ASCII", &tap_attable }, + { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX, + "file is Flex", NULL }, + { UNIT_ATT+UNIT_FLEX, UNIT_ATT, + "file is ASCII", NULL }, + { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX, + "default is Flex", NULL }, + { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE, + "default is ASCII", NULL }, + { MTAB_XTD|MTAB_VUN, 0, NULL, "FEED", &punch_feed }, + { 0, 0 } }; + +DEVICE tto_dev = { + "TTO", tto_unit, tto_reg, tto_mod, + 2, 10, 31, 1, 16, 7, + NULL, NULL, &tto_reset, + NULL, &tap_attach, NULL }; + +/* PTR data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_mod PTR modifier list + ptr_reg PTR register list +*/ + +UNIT ptr_unit = { + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), WPS / 200 }; + +REG ptr_reg[] = { + { HRDATA (BUF, ptr_unit.buf, 6) }, + { FLDATA (RDY, ptr_rdy, 0) }, + { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, ptr_unit.wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (STOP_IOE, ptr_stopioe, 0) }, + { NULL } }; + +MTAB ptr_mod[] = { + { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable }, + { UNIT_FLEX_D, 0, NULL, "ASCII", &tap_attable }, + { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX, + "file is Flex", NULL }, + { UNIT_ATT+UNIT_FLEX, UNIT_ATT, + "file is ASCII", NULL }, + { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX, + "default is Flex", NULL }, + { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE, + "default is ASCII", NULL }, + { 0, 0 } }; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, ptr_reg, ptr_mod, + 1, 10, 31, 1, 16, 7, + NULL, NULL, &ptr_reset, + NULL, &tap_attach, NULL }; + +/* PTP data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_mod PTP modifier list + ptp_reg PTP register list +*/ + +UNIT ptp_unit = { + UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), WPS / 20 }; + +REG ptp_reg[] = { + { ORDATA (BUF, ptp_unit.buf, 8) }, + { 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[] = { + { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable }, + { UNIT_FLEX_D, 0, NULL, "ASCII", &tap_attable }, + { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX, + "file is Flex", NULL }, + { UNIT_ATT+UNIT_FLEX, UNIT_ATT, + "file is ASCII", NULL }, + { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX, + "default is Flex", NULL }, + { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE, + "default is ASCII", NULL }, + { 0, 0 } }; + +DEVICE ptp_dev = { + "PTP", &ptp_unit, ptp_reg, ptp_mod, + 1, 10, 31, 1, 16, 7, + NULL, NULL, &ptp_reset, + NULL, &tap_attach, NULL }; + +/* Input instruction */ + +void op_i_strt (uint32 dev) +{ +switch (dev) { /* case on device */ +case DEV_PT: /* ptr */ + sim_activate (&ptr_unit, ptr_unit.wait); /* activate */ + break; +case DEV_TT: /* tti/ttr */ + if (Q_MANI) sim_putchar ('`'); /* manual input? */ + else sim_activate (&tti_unit[1], tt_wait); /* no, must be ttr */ + break; } +return; +} + +t_stat op_i (uint32 dev, uint32 ch, uint32 sh4) +{ +if (Q_LGP21 && out_strt) return STOP_STALL; /* LGP-21? must be idle */ +if (!inp_strt) { /* input started? */ + inp_strt = 1; /* no, set start */ + inp_done = 0; /* clear done */ + A = shift_in (A, ch, sh4); + tti_rdy = ptr_rdy = 0; /* no input */ + if (Q_LGP21 || Q_INPT) op_i_strt (dev); } /* LGP-21 or PTR? start */ + +switch (dev) { /* case on device */ +case DEV_PT: /* ptr */ + if (ptr_rdy) { /* char ready? */ + ptr_rdy = 0; /* reset ready */ + if ((ptr_unit.buf != FLEX_DEL) && /* ignore delete and */ + (!Q_LGP21 || ((ptr_unit.buf & 3) == 2))) /* LGP-21 4b? zone != 2 */ + A = shift_in (A, ptr_unit.buf, sh4); } /* shift data in */ + break; +case DEV_TT: /* tti/ttr */ + if (tti_rdy) { /* char ready? */ + tti_rdy = 0; /* reset ready */ + if ((tti_buf != FLEX_DEL) && /* ignore delete and */ + (!Q_LGP21 || ((tti_buf & 3) != 0))) /* LGP-21 4b? zone == 0 */ + A = shift_in (A, tti_buf, sh4); } /* shift data in */ + break; +default: /* nx device */ + return STOP_NXDEV; } /* return error */ + +if (inp_done) { /* done? */ + inp_strt = inp_done = 0; /* clear start, done */ + return SCPE_OK; } /* no stall */ +return STOP_STALL; /* stall */ +} + +t_stat tti_svc (UNIT *uptr) +{ +int32 c, flex; + +sim_activate (uptr, tt_wait); /* continue poll */ +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ +flex = ascii_to_flex[c & 0x1FF]; /* cvt to flex */ +if (flex > 0) { /* it's a typewriter... */ + write_tto (flex); /* always echos */ + if (tto_unit[1].flags & UNIT_ATT) /* ttp attached? */ + write_punch (&tto_unit[1], tto_buf); } /* punch to ttp */ +else write_tto ('\a'); /* don't echo bad */ +if (Q_MANI && (flex > 0) && flex_inp_valid[flex]) { /* wanted, valid? */ + if (flex == FLEX_CSTOP) inp_done = 1; /* conditional stop? */ + else tti_rdy = 1; /* no, set ready */ + tti_buf = flex; /* save char */ + uptr->pos = uptr->pos + 1; } +return SCPE_OK; +} + +t_stat ttr_svc (UNIT *uptr) +{ +t_stat r; + +if (r = read_reader (uptr, ttr_stopioe, (int32 *) &tti_buf)) return r; +if (!(uptr->flags & UNIT_NOCS) && /* cstop enable? */ + (tti_buf == FLEX_CSTOP)) inp_done = 1; /* cond stop? */ +else { tti_rdy = 1; /* no, set ready */ + sim_activate (uptr, tt_wait); } /* cont reading */ +write_tto (tti_buf); /* echo to tto */ +if (tto_unit[1].flags & UNIT_ATT) /* ttp attached? */ + return write_punch (&tto_unit[1], tti_buf); /* punch to ttp */ +return SCPE_OK; +} + +t_stat ptr_svc (UNIT *uptr) +{ +t_stat r; + +if (r = read_reader (uptr, ptr_stopioe, &uptr->buf)) return r; +if (uptr->buf == FLEX_CSTOP) inp_done = 1; /* cond stop? */ +else { ptr_rdy = 1; /* no, set ready */ + sim_activate (uptr, uptr->wait); } /* cont reading */ +return SCPE_OK; +} + +/* Output instruction */ + +t_stat op_p (uint32 dev, uint32 ch) +{ +switch (dev) { /* case on device */ +case DEV_PT: /* paper tape punch */ + if (sim_is_active (&ptp_unit)) /* busy? */ + return (Q_LGP21? STOP_STALL: SCPE_OK); /* LGP-21: stall */ + ptp_unit.buf = ch; /* save char */ + sim_activate (&ptp_unit, ptp_unit.wait); /* activate ptp */ + break; +case DEV_TT: /* typewriter */ + if (ch == 0) { /* start input? */ + if (!Q_LGP21 && !Q_INPT) /* ignore if LGP-21, ptr */ + op_i_strt (DEV_TT); /* start tti */ + return SCPE_OK; } /* no stall */ + if (sim_is_active (&tto_unit[0])) /* busy? */ + return (Q_LGP21? STOP_STALL: SCPE_OK); /* LGP-21: stall */ + tto_buf = ch; /* save char */ + sim_activate (&tto_unit[0], tt_wait); /* activate tto */ + break; +default: /* unknown */ + return STOP_NXDEV; } /* return error */ + +if (out_strt == 0) { /* output started? */ + out_strt = 1; /* flag start */ + out_done = 0; } /* clear done */ +return SCPE_OK; /* no stall */ +} + +/* TTO unit service */ + +t_stat tto_svc (UNIT *uptr) +{ +t_stat r; + +if ((r = write_tto (tto_buf)) != SCPE_OK) { /* output; error? */ + sim_activate (uptr, tt_wait); /* try again */ + return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */ +out_strt = 0; +out_done = 1; +if (tto_unit[1].flags & UNIT_ATT) /* ttp attached? */ + return write_punch (&tto_unit[1], tto_buf); /* punch to ttp */ +return SCPE_OK; +} + +/* PTP unit service */ + +t_stat ptp_svc (UNIT *uptr) +{ +out_strt = 0; +out_done = 1; +if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return IORETURN (ptp_stopioe, SCPE_UNATT); /* error */ +return write_punch (uptr, uptr->buf); /* write to ptp */ +} + +/* Utility routines */ + +t_stat read_reader (UNIT *uptr, int32 stop, int32 *fl) +{ +int32 ch, flex; + +if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ + return IORETURN (stop, SCPE_UNATT); +do { if ((ch = getc (uptr->fileref)) == EOF) { /* read char */ + if (feof (uptr->fileref)) { /* err or eof? */ + if (stop) printf ("Reader end of file\n"); + else return SCPE_OK; } + else perror ("Reader I/O error"); + clearerr (uptr->fileref); + return SCPE_IOERR; } + if (uptr->flags & UNIT_FLEX) /* transposed flex? */ + flex = ((ch << 1) | (ch >> 5)) & 0x3F; /* undo 612345 */ + else if (ch == '#') { /* encoded? */ + int32 d1 = getc (uptr->fileref); /* get 2 digits */ + int32 d2 = getc (uptr->fileref); + if ((d1 == EOF) || (d2 == EOF)) { /* error? */ + if (feof (uptr->fileref)) { /* eof? */ + if (stop) printf ("Reader end of file\n"); + else return SCPE_OK; } + else perror ("Reader I/O error"); + clearerr (uptr->fileref); + return SCPE_IOERR; } + flex = (((d1 - '0') * 10) + (d2 - '0')) & 0x3F; + uptr->pos = uptr->pos + 2; } + else flex = ascii_to_flex[ch & 0x7F]; /* convert */ + uptr->pos = uptr->pos + 1; } +while (flex < 0); /* until valid */ +*fl = flex; /* return char */ +return SCPE_OK; +} + +t_stat write_tto (int32 flex) +{ +int32 ch; +t_stat r; + +if (flex == FLEX_UC) tto_uc = 1; /* UC? set state */ +else if (flex == FLEX_LC) tto_uc = 0; /* LC? set state */ +else { if (flex == FLEX_BS) ch = '\b'; /* backspace? */ + else ch = flex_to_ascii[flex | (tto_uc << 6)]; /* cvt flex to ascii */ + if (ch > 0) { /* legit? */ + if (r = sim_putchar_s (ch)) return r; /* write char */ + tto_unit[0].pos = tto_unit[0].pos + 1; + if (flex == FLEX_CR) { /* cr? */ + sim_putchar ('\n'); /* add lf */ + tto_unit[0].pos = tto_unit[0].pos + 1; } } } +return SCPE_OK; +} + +t_stat write_punch (UNIT *uptr, int32 flex) +{ +int32 c, sta; + +if (uptr->flags & UNIT_FLEX) /* transposed flex? */ + c = ((flex >> 1) | (flex << 5)) & 0x3F; /* reorder to 612345 */ +else c = flex_to_ascii[flex]; /* convert to ASCII */ +if (c >= 0) sta = fputc (c, uptr->fileref); /* valid? */ +else sta = fprintf (uptr->fileref, "#%02d", flex); /* no, encode */ +if (sta == EOF) { /* error? */ + perror ("Punch I/O error"); /* error? */ + clearerr (uptr->fileref); + return SCPE_IOERR; } +uptr->pos = uptr->pos + ((c >= 0)? 1: 3); /* incr position */ +return SCPE_OK; +} + +/* Reset routines */ + +t_stat tti_reset (DEVICE *dptr) +{ +sim_activate (&tti_unit[0], tt_wait); +sim_cancel (&tti_unit[1]); +tti_buf = 0; +tti_rdy = 0; +return SCPE_OK; +} + +t_stat tto_reset (DEVICE *dptr) +{ +sim_cancel (&tto_unit[0]); +tto_buf = 0; +tto_uc = 0; +return SCPE_OK; +} + +t_stat ptr_reset (DEVICE *dptr) +{ +sim_cancel (&ptr_unit); +ptr_unit.buf = 0; +ptr_rdy = 0; +return SCPE_OK; +} + +t_stat ptp_reset (DEVICE *dptr) +{ +sim_cancel (&ptp_unit); +ptp_unit.buf = 0; +return SCPE_OK; +} + +/* Attach paper tape unit */ + +t_stat tap_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +if ((r = attach_unit (uptr,cptr)) != SCPE_OK) return r; +if ((sim_switches & SWMASK ('F')) || + ((uptr->flags & UNIT_FLEX_D) && !(sim_switches & SWMASK ('A')))) + uptr->flags = uptr->flags | UNIT_FLEX; +else uptr->flags = uptr->flags & ~UNIT_FLEX; +return SCPE_OK; +} + +/* Validate unit is attachable */ + +t_stat tap_attable (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATTABLE) return SCPE_OK; +return SCPE_NOFNC; +} + +/* Typewriter reader start/stop */ + +t_stat tti_rdrss (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val) { + if ((tti_unit[1].flags & UNIT_ATT) == 0) return SCPE_UNATT; + sim_activate (&tti_unit[1], tt_wait); } +else sim_cancel (&tti_unit[1]); +return SCPE_OK; +} + +/* Punch feed routine */ + +t_stat punch_feed (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 cnt; +t_stat r; + +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; +if (cptr) { + cnt = (int32) get_uint (cptr, 10, 512, &r); + if ((r != SCPE_OK) || (cnt == 0)) return SCPE_ARG; } +else cnt = 10; +while (cnt-- > 0) { + r = write_punch (uptr, 0); + if (r != SCPE_OK) return r; } +return SCPE_OK; +} + +/* Send start signal */ + +t_stat send_start (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (inp_strt) inp_done = 1; +else if (out_strt) out_done = 1; +return SCPE_OK; +} diff --git a/LGP/lgp_sys.c b/LGP/lgp_sys.c new file mode 100644 index 00000000..f5a955aa --- /dev/null +++ b/LGP/lgp_sys.c @@ -0,0 +1,345 @@ +/* lgp_sys.c: LGP-30 simulator interface + + Copyright (c) 2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "lgp_defs.h" +#include + +t_stat parse_sym_m (char *cptr, t_value *val, int32 sw); +void lgp_init (void); + +extern DEVICE cpu_dev; +extern UNIT cpu_unit; +extern DEVICE tti_dev, tto_dev; +extern DEVICE ptr_dev, ptp_dev; +extern REG cpu_reg[]; +extern uint32 M[]; +extern uint32 PC; +extern uint32 ts_flag; +extern int32 sim_switches; +extern int32 flex_to_ascii[128], ascii_to_flex[128]; + +void (*sim_vm_init) (void) = &lgp_init; +extern void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr); +extern t_addr (*sim_vm_parse_addr) (DEVICE *dptr, char *cptr, char **tptr); + +/* 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_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "LGP30"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 1; + +DEVICE *sim_devices[] = { + &cpu_dev, + &tti_dev, + &tto_dev, + &ptr_dev, + &ptp_dev, + NULL }; + +const char *sim_stop_messages[] = { + "Unknown error", + "STOP", + "Breakpoint", + "Arithmetic overflow" }; + +/* Binary loader - implements a restricted form of subroutine 10.4 + + Switches: + -t, input file is transposed Flex + -n, no checksums on v commands (10.0 compatible) + default is ASCII encoded Flex + Commands (in bits 0-3): + (blank) instruction + + command (not supported) + ; start fill + / set modifier + . stop and transfer + , hex words + v hex fill (checksummed unless -n) + 8 negative instruction +*/ + +/* Utility routine - read characters until ' (conditional stop) */ + +t_stat load_getw (FILE *fi, uint32 *wd) +{ +int32 flex, c; + +*wd = 0; +while ((c = fgetc (fi)) != EOF) { + if (sim_switches & SWMASK ('T')) + flex = ((c << 1) | (c >> 5)) & 0x3F; + else flex = ascii_to_flex[c & 0x7F]; + if ((flex == FLEX_CR) || (flex == FLEX_DEL) || + (flex == FLEX_UC) || (flex == FLEX_LC) || + (flex == FLEX_BS) || (flex < 0)) continue; + if (flex == FLEX_CSTOP) return SCPE_OK; + *wd = (*wd << 4) | ((flex >> 2) & 0xF); } +return SCPE_FMT; +} + +/* Utility routine - convert ttss decimal address to binary */ + +t_stat load_geta (uint32 wd, uint32 *ad) +{ +uint32 n1, n2, n3, n4, tr, sc; + +n1 = (wd >> 12) & 0xF; +n2 = (wd >> 8) & 0xF; +n3 = (wd >> 4) & 0xF; +n4 = wd & 0xF; +if ((n2 > 9) || (n4 > 9)) return SCPE_ARG; +tr = (n1 * 10) + n2; +sc = (n3 * 10) + n4; +if ((tr >= NTK_30) || (sc >= NSC_30)) return SCPE_ARG; +*ad = (tr * NSC_30) + sc; +return SCPE_OK; +} + +/* Loader proper */ + +t_stat sim_load (FILE *fi, char *cptr, char *fnam, int flag) +{ +uint32 wd, origin, amod, csum, cnt, tr, sc, ad, cmd; + +origin = amod = 0; +for (;;) { /* until stopped */ + if (load_getw (fi, &wd)) break; /* get ctrl word */ + cmd = (wd >> 28) & 0xF; /* get <0:3> */ + switch (cmd) { /* decode <0:3> */ + case 0x2: /* + command */ + return SCPE_FMT; + case 0x3: /* ; start fill */ + if (load_geta (wd, &origin)) return SCPE_FMT; /* origin = addr */ + break; + case 0x4: /* / set modifier */ + if (load_geta (wd, &amod)) return SCPE_FMT; /* modifier = addr */ + break; + case 0x5: /* . transfer */ + if (load_geta (wd, &PC)) return SCPE_FMT; /* PC = addr */ + return SCPE_OK; /* done! */ + case 0x6: /* hex words */ + if (load_geta (wd, &cnt)) return SCPE_FMT; /* count = addr */ + if ((cnt == 0) || (cnt > 63)) return SCPE_FMT; + while (cnt--) { /* fill hex words */ + if (load_getw (fi, &wd)) return SCPE_FMT; + Write (origin, wd); + origin = (origin + 1) & AMASK; } + break; + case 0x7: /* hex fill */ + cnt = (wd >> 16) & 0xFFF; /* hex count */ + tr = (wd >> 8) & 0xFF; /* hex track */ + sc = wd & 0xFF; /* hex sector */ + if ((cnt == 0) || (cnt > 0x7FF) || /* validate */ + (tr >= NTK_30) || (sc >= NSC_30)) return SCPE_ARG; + ad = (tr * NSC_30) + sc; /* decimal addr */ + for (csum = 0; cnt; cnt--) { /* fill words */ + if (load_getw (fi, &wd)) return SCPE_FMT; + Write (ad, wd); + csum = (csum + wd) & MMASK; + ad = (ad + 1) & AMASK; } + if (!(sim_switches & SWMASK ('N'))) { /* unless -n, csum */ + if (load_getw (fi, &wd)) return SCPE_FMT; +/* if ((csum ^wd) & MMASK) return SCPE_CSUM; */ } + break; + case 0x0: case 0x8: /* instructions */ + if (load_geta (wd, &ad)) return SCPE_FMT; /* get address */ + if ((wd & 0x00F00000) != 0x00900000) /* if not x, */ + ad = (ad + amod) & AMASK; /* modify */ + wd = (wd & (SIGN|I_OP)) + (ad << I_V_EA); /* instruction */ + default: /* data word */ + Write (origin, wd); + origin = (origin + 1) & AMASK; + break; + } /* end case */ + } /* end for */ +return SCPE_OK; +} + +/* Symbol tables */ + +static const char opcode[] = "ZBYRIDNMPEUTHCAS"; + +static const char hex_decode[] = "0123456789FGJKQW"; + +void lgp_fprint_addr (FILE *st, DEVICE *dptr, t_addr addr) +{ +if ((dptr == sim_devices[0]) && + ((sim_switches & SWMASK ('T')) || + ((cpu_unit.flags & UNIT_TTSS_D) && !(sim_switches & SWMASK ('N'))))) + fprintf (st, "%02d%02d", addr >> 6, addr & SCMASK_30); +else fprint_val (st, addr, dptr->aradix, dptr->awidth, PV_LEFT); +return; +} + +t_addr lgp_parse_addr (DEVICE *dptr, char *cptr, char **tptr) +{ +t_addr ad, ea; + +if ((dptr == sim_devices[0]) && + ((sim_switches & SWMASK ('T')) || + ((cpu_unit.flags & UNIT_TTSS_D) && !(sim_switches & SWMASK ('N'))))) { + ad = (t_addr) strtotv (cptr, tptr, 10); + if (((ad / 100) >= NTK_30) || ((ad % 100) >= NSC_30)) { + *tptr = cptr; + return 0; } + ea = ((ad / 100) * NSC_30) | (ad % 100); } +else ea = (t_addr) strtotv (cptr, tptr, dptr->aradix); +return ea; +} + +void lgp_init (void) +{ +sim_vm_fprint_addr = &lgp_fprint_addr; +sim_vm_parse_addr = &lgp_parse_addr; +return; +} + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current PC + *val = pointer to data + *uptr = pointer to unit + sw = switches + Outputs: + return = status code +*/ + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ +int32 i, c; +uint32 inst, op, ea; + +inst = val[0]; +if (sw & SWMASK ('A')) { /* alphabetic? */ + if ((uptr == NULL) || !(uptr->flags & UNIT_ATT)) return SCPE_ARG; + if (uptr->flags & UNIT_FLEX) { /* Flex file? */ + c = flex_to_ascii[inst]; /* get ASCII equiv */ + if (c <= 0) return SCPE_ARG; } + else c = inst & 0x7F; /* ASCII file */ + fputc (c, of); + return SCPE_OK; } + +if (uptr && (uptr != &cpu_unit)) return SCPE_ARG; /* must be CPU */ +if ((sw & SWMASK ('M')) && /* symbolic decode? */ + ((inst & ~(SIGN|I_OP|I_EA)) == 0)) { + op = I_GETOP (inst); + ea = I_GETEA (inst); + if (inst & SIGN) fputc ('-', of); + fprintf (of, "%c ", opcode[op]); + lgp_fprint_addr (of, sim_devices[0], ea); + return SCPE_OK; } + +if ((sw & SWMASK ('L')) || /* LGP hex? */ + ((cpu_unit.flags & UNIT_LGPH_D) && !(sw & SWMASK ('H')))) { + for (i = 0; i < 8; i++) { + c = (inst >> (4 * (7 - i))) & 0xF; + fputc (hex_decode[c], of); } + return SCPE_OK; } +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 i, c; +char *tptr; + +while (isspace (*cptr)) cptr++; /* absorb spaces */ +if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { + if ((uptr == NULL) || !(uptr->flags & UNIT_ATT)) return SCPE_ARG; + if (uptr->flags & UNIT_FLEX) { /* Flex file? */ + c = ascii_to_flex[*cptr & 0x7F]; /* get Flex equiv */ + if (c < 0) return SCPE_ARG; + val[0] = ((c >> 1) | (c << 5)) & 0x3F; } /* transpose */ + else val[0] = *cptr & 0x7F; /* ASCII file */ + return SCPE_OK; } + +if (uptr && (uptr != &cpu_unit)) return SCPE_ARG; /* must be CPU */ +if (!parse_sym_m (cptr, val, sw)) return SCPE_OK; /* symbolic parse? */ +if ((sw & SWMASK ('L')) || /* LGP hex? */ + ((cpu_unit.flags & UNIT_LGPH_D) && !(sw & SWMASK ('H')))) { + val[0] = 0; + while (isspace (*cptr)) cptr++; /* absorb spaces */ + for (i = 0; i < 8; i++) { + c = *cptr++; /* get char */ + if (c == 0) return SCPE_OK; + if (islower (c)) c = toupper (c); + if (tptr = strchr (hex_decode, c)) + val[0] = (val[0] << 4) | (tptr - hex_decode); + else return SCPE_ARG; } + if (*cptr == 0) return SCPE_OK; } +return SCPE_ARG; +} + +/* Instruction parse */ + +t_stat parse_sym_m (char *cptr, t_value *val, int32 sw) +{ +uint32 ea, sgn; +char *tptr, gbuf[CBUFSIZE]; + +if (*cptr == '-') { + cptr++; + sgn = SIGN; } +else sgn = 0; +cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ +if (gbuf[1] != 0) return SCPE_ARG; +if (tptr = strchr (opcode, gbuf[0])) + val[0] = ((tptr - opcode) << I_V_OP) | sgn; /* merge opcode */ +else return SCPE_ARG; +cptr = get_glyph (cptr, gbuf, 0); /* get address */ +ea = lgp_parse_addr (sim_devices[0], gbuf, &tptr); +if ((tptr == gbuf) || (*tptr != 0) || (ea > AMASK)) + return SCPE_ARG; +val[0] = val[0] | (ea << I_V_EA); /* merge address */ +if (*cptr != 0) return SCPE_2MARG; +return SCPE_OK; +} diff --git a/NOVA/eclipse_cpu.c b/NOVA/eclipse_cpu.c index 58a4b1b2..c0690b62 100644 --- a/NOVA/eclipse_cpu.c +++ b/NOVA/eclipse_cpu.c @@ -3915,7 +3915,7 @@ if ((IR & 0100017) == 0100010) { /* This pattern for all */ j = (IR >> 11) & 3; i = (AC[0] >> 8) & 0x007F; FPAC[j] &= 0x80FFFFFFFFFFFFFF; /* clear exponent */ - FPAC[j] |= (t_int64)(i << 56); + FPAC[j] |= ((t_int64) i << 56); if ((FPAC[j] & 0x00ffffffffffffff) == 0) FPAC[j] = 0; if (FPAC[j] == 0) @@ -5996,7 +5996,8 @@ for (i = 0; i < 64; i++) { /* clr dev_table */ dev_table[i].pi = 0; dev_table[i].routine = NULL; } for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - if (dibp = (DIB *) dptr->ctxt) { /* get DIB */ + if (!(dptr->flags & DEV_DIS) && /* enabled and */ + (dibp = (DIB *) dptr->ctxt)) { /* defined DIB? */ dn = dibp->dnum; /* get dev num */ dev_table[dn].mask = dibp->mask; /* copy entries */ dev_table[dn].pi = dibp->pi; diff --git a/NOVA/nova_clk.c b/NOVA/nova_clk.c index 315e4050..2691a4b6 100644 --- a/NOVA/nova_clk.c +++ b/NOVA/nova_clk.c @@ -1,6 +1,6 @@ /* nova_clk.c: NOVA real-time clock simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/NOVA/nova_cpu.c b/NOVA/nova_cpu.c index 864786d7..417866f2 100644 --- a/NOVA/nova_cpu.c +++ b/NOVA/nova_cpu.c @@ -1,6 +1,6 @@ /* nova_cpu.c: NOVA CPU simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu Nova central processor + 14-Jan-04 RMS Fixed device enable/disable support (found by Bruce Ray) 19-Jan-03 RMS Changed CMASK to CDMASK for Apple Dev Kit conflict 03-Oct-02 RMS Added DIB infrastructure 30-Dec-01 RMS Added old PC queue @@ -831,7 +832,8 @@ for (i = 0; i < 64; i++) { /* clr dev_table */ dev_table[i].pi = 0; dev_table[i].routine = NULL; } for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - if (dibp = (DIB *) dptr->ctxt) { /* get DIB */ + if (!(dptr->flags & DEV_DIS) && /* enabled and */ + (dibp = (DIB *) dptr->ctxt)) { /* defined DIB? */ dn = dibp->dnum; /* get dev num */ dev_table[dn].mask = dibp->mask; /* copy entries */ dev_table[dn].pi = dibp->pi; diff --git a/NOVA/nova_defs.h b/NOVA/nova_defs.h index fec481ae..9d0aa4d6 100644 --- a/NOVA/nova_defs.h +++ b/NOVA/nova_defs.h @@ -1,6 +1,6 @@ /* nova_defs.h: NOVA/Eclipse simulator definitions - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 14-Jan-04 BKR Added support for QTY and ALM 22-Nov-03 CEO Added support for PIT device 19-Jan-03 RMS Changed CMASK to CDMASK for Apple Dev kit conflict 03-Oct-02 RMS Added device information structure @@ -173,8 +174,10 @@ #define DEV_MTA 022 /* magtape */ #define DEV_DCM 024 /* data comm mux */ #define DEV_ADCV 030 /* A/D converter */ +#define DEV_QTY 030 /* 4060 multiplexor */ #define DEV_DKP 033 /* disk pack */ #define DEV_CAS 034 /* cassette */ +#define DEV_ALM 034 /* ALM/ULM multiplexor */ #define DEV_PIT 043 /* programmable interval timer */ #define DEV_TTI1 050 /* second console input */ #define DEV_TTO1 051 /* second console output */ @@ -226,9 +229,11 @@ typedef struct nova_dib DIB; #define INT_V_TTO 12 /* terminal */ #define INT_V_TTI1 13 /* second keyboard */ #define INT_V_TTO1 14 /* second terminal */ -#define INT_V_STK 15 /* stack overflow */ -#define INT_V_NO_ION_PENDING 16 /* ion delay */ -#define INT_V_ION 17 /* interrupts on */ +#define INT_V_QTY 15 /* QTY multiplexor */ +#define INT_V_ALM 16 /* ALM multiplexor */ +#define INT_V_STK 17 /* stack overflow */ +#define INT_V_NO_ION_PENDING 18 /* ion delay */ +#define INT_V_ION 19 /* interrupts on */ #define INT_PIT (1 << INT_V_PIT) #define INT_DKP (1 << INT_V_DKP) @@ -243,6 +248,8 @@ typedef struct nova_dib DIB; #define INT_TTO (1 << INT_V_TTO) #define INT_TTI1 (1 << INT_V_TTI1) #define INT_TTO1 (1 << INT_V_TTO1) +#define INT_QTY (1 << INT_V_QTY) +#define INT_ALM (1 << INT_V_ALM) #define INT_STK (1 << INT_V_STK) #define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING) #define INT_ION (1 << INT_V_ION) @@ -260,6 +267,8 @@ typedef struct nova_dib DIB; #define PI_PTR 0000020 #define PI_PTP 0000004 #define PI_PLT 0000010 +#define PI_QTY 0000002 +#define PI_ALM 0000002 #define PI_TTI 0000002 #define PI_TTO 0000001 #define PI_TTI1 PI_TTI diff --git a/NOVA/nova_dkp.c b/NOVA/nova_dkp.c index 20e139ff..ea70e6a7 100644 --- a/NOVA/nova_dkp.c +++ b/NOVA/nova_dkp.c @@ -1,6 +1,6 @@ /* nova_dkp.c: NOVA moving head disk simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ dkp moving head disk + 04-Jan-04 RMS Changed attach routine to use sim_fsize 28-Nov-03 CEO Boot from DP now puts device address in SR 24-Nov-03 CEO Added support for disk sizing on 6099/6103 19-Nov-03 CEO Corrected major DMA Mapping bug @@ -688,13 +689,12 @@ t_stat dkp_attach (UNIT *uptr, char *cptr) int32 i, p; t_stat r; -uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; -r = attach_unit (uptr, cptr); -if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0)) return r; -if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; -if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK; +uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; /* restore capac */ +r = attach_unit (uptr, cptr); /* attach */ +if ((r != SCPE_OK) || !(uptr->flags & UNIT_AUTO)) return r; +if ((p = sim_fsize (uptr->fileref)) == 0) return SCPE_OK; /* get file size */ for (i = 0; drv_tab[i].sect != 0; i++) { - if (p <= (drv_tab[i].size * (int) sizeof (short))) { + if (p <= (drv_tab[i].size * (int32) sizeof (uint16))) { uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); uptr->capac = drv_tab[i].size; return SCPE_OK; } } diff --git a/NOVA/nova_doc.txt b/NOVA/nova_doc.txt index ad0a3872..aaa8f45c 100644 --- a/NOVA/nova_doc.txt +++ b/NOVA/nova_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: Nova Simulator Usage -Date: 15-Mar-2003 +Date: 15-Mar-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,15 +36,21 @@ This memorandum documents the Nova simulator. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/nova/ nova_defs.h @@ -55,6 +61,7 @@ sim/nova/ nova_defs.h nova_lp.c nova_mta.c nova_plt.c + nova_qty.c nova_sys.c nova_tt.c nova_tt1.c @@ -66,7 +73,7 @@ The Nova simulator is configured as follows: device simulates name(s) -CPU Nova CPU with 32KW of memory +CPU Nova, Nova 3, or Nova 4 CPU with 32KW of memory - hardware multiply/divide PTR,PTP paper tape reader/punch TTI,TTO console terminal @@ -77,6 +84,8 @@ CLK real-time clock DK head-per-track disk controller DP moving head disk controller with four drives MT magnetic tape controller with eight drives +QTY 4060 multiplexor with up to 64 lines +ALM 4255 multiplexor with up to 64 lines The Nova simulator implements these unique stop conditions: @@ -86,6 +95,11 @@ The Nova simulator implements these unique stop conditions: - more than INDMAX indirect addresses are detected during memory reference address decoding +Note that indirect address loop detection does not exist on unmapped +Novas. Some DG diagnostics test thousands of levels of indirect +addressing. INDMAX may have to be set to 32,000 to get diagnostics +to run properly. + The Nova loader supports standard binary format tapes. The DUMP command is not implemented. @@ -122,6 +136,11 @@ If memory size is being reduced, and the memory being truncated contains non-zero data, the simulator asks for confirmation. Data in the truncated portion of memory is lost. Initial memory size is 32K. +The CPU supports the boot command. BOOT CPU simulates the Nova hardware +APL (automatic program load) feature. The switch register (SR) bits 12:17 +must contain the device code of the device to be booted. If the device is +a "high-speed" (channel) device, SR bit 0 should also be set. + CPU registers include the visible state of the processor as well as the control registers for the interrupt system. @@ -363,6 +382,12 @@ setting limited Dasher-compatibility mode or ANSI mode: Setting either TTI1 or TTO1 changes both devices. In Dasher mode, carriage return is changed to newline on input, and ^X is changed to backspace. +TTO1 supports output logging. The SET TTO1 LOG command enables logging: + + SET TTO1 LOG=filename log output to filename + +The SET TTO1 NOLOG command disables logging and closes the open log +file, if any. The SHOW TTI1 CONNECTIONS command displays the current connection to TTI1. The SHOW TTI1 STATISTICS command displays statistics for the current connection. @@ -390,6 +415,67 @@ The second terminal output implements these registers: INT 1 interrupt pending flag TIME 24 time from I/O initiation to interrupt +2.2.8 Asynchronous Multiplexors (QTY, ALM) + +The QTY and ALM are terminal multiplexors with up to 64 lines. Either +the QTY or ALM can be enabled, but not both; the ALM is enabled by +default. The number of lines can be changed with the command + + SET {QTY|ALM} LINES=n set line count to n + +The line count maximum is 64. + +The QTY and ALM support 8-bit input and output of characters. 8-bit I/O +may be incompatible with certain operating systems; 7-bit is the default. +The command + + SET {QTY|ALM} 8B + +enables 8-bit input and output. + +The terminal lines perform input and output through Telnet sessions +connected to a user-specified port. The ATTACH command specifies +the port to be used: + + ATTACH {-am} {QTY|ALM} set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. For the ALM multiplexor, the optional switch +-m turns on the multiplexor modem controls; the optional switch -a turns on +active disconnects (disconnect session if computer clears Data Terminal Ready). +The QTY multiplexor does not support modem control. Without modem control, +the multiplexor behaves as though terminals were directly connected; +disconnecting the Telnet session does not cause any operating system- +visible change in line status. + +Once the multiplexor is attached and the simulator is running, it will listen +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connection remains open until +disconnected by the simulated program, the Telnet client, a SET {QTY|ALM} +DISCONNECT command, or a DETACH {QTY|ALM} command. + +The SHOW {QTY|ALM} CONNECTIONS command displays the current connections to +the multiplexor. The SHOW {QTY|ALM} STATISTICS command displays statistics +for active connections. The SET {QTY|ALM| DISCONNECT=linenumber disconnects +the specified line. + +The QTY/ALM implement these registers: + + name size comments + + BUF 8 character buffer + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 device disable flag + INT 1 interrupt pending flag + MDMCTL 1 modem control flag + AUTODS 1 autodisconnect flag + POLLS 32 number of service polls + STOP_IOE 1 stop on I/O error + +The multiplexors do not support save and restore. All open connections are +lost when the simulator shuts down or the multiplexor is detached. + 2.3 Fixed Head Disk (DK) Fixed head disk options include the ability to set the number of platters diff --git a/NOVA/nova_dsk.c b/NOVA/nova_dsk.c index 45e1e873..e75ec25d 100644 --- a/NOVA/nova_dsk.c +++ b/NOVA/nova_dsk.c @@ -1,6 +1,6 @@ /* nova_dsk.c: 4019 fixed head disk simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ dsk fixed head disk + 04-Jan-04 RMS Changed sim_fsize calling sequence 26-Jul-03 RMS Fixed bug in set size routine 14-Mar-03 RMS Fixed variable capacity interaction with save/restore 03-Mar-03 RMS Fixed variable capacity and autosizing @@ -276,14 +277,17 @@ t_stat dsk_attach (UNIT *uptr, char *cptr) { uint32 sz, p; uint32 ds_bytes = DSK_DKSIZE * sizeof (int16); +t_stat r; -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) { +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) { p = (sz + ds_bytes - 1) / ds_bytes; if (p >= DSK_NUMDK) p = DSK_NUMDK - 1; uptr->flags = (uptr->flags & ~UNIT_PLAT) | (p << UNIT_V_PLAT); } uptr->capac = UNIT_GETP (uptr->flags) * DSK_DKSIZE; /* set capacity */ -return attach_unit (uptr, cptr); +return SCPE_OK; } /* Change disk size */ diff --git a/NOVA/nova_lp.c b/NOVA/nova_lp.c index 36817c27..93f2d737 100644 --- a/NOVA/nova_lp.c +++ b/NOVA/nova_lp.c @@ -1,6 +1,6 @@ /* nova_lp.c: NOVA line printer simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/NOVA/nova_mta.c b/NOVA/nova_mta.c index f1b9b659..7fb44064 100644 --- a/NOVA/nova_mta.c +++ b/NOVA/nova_mta.c @@ -1,6 +1,6 @@ /* nova_mta.c: NOVA magnetic tape simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/NOVA/nova_plt.c b/NOVA/nova_plt.c index f954733e..c0efb0df 100644 --- a/NOVA/nova_plt.c +++ b/NOVA/nova_plt.c @@ -1,6 +1,6 @@ /* nova_plt.c: NOVA plotter simulator - Copyright (c) 2000-2003, Robert M. Supnik + Copyright (c) 2000-2004, Robert M. Supnik Written by Bruce Ray and used with his gracious permission. Permission is hereby granted, free of charge, to any person obtaining a diff --git a/NOVA/nova_pt.c b/NOVA/nova_pt.c index 33333d91..38bc441e 100644 --- a/NOVA/nova_pt.c +++ b/NOVA/nova_pt.c @@ -1,6 +1,6 @@ /* nova_pt.c: NOVA paper tape read/punch simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/NOVA/nova_qty.c b/NOVA/nova_qty.c new file mode 100644 index 00000000..e92b2997 --- /dev/null +++ b/NOVA/nova_qty.c @@ -0,0 +1,1130 @@ +/* nova_qty.c: NOVA multiplexor (QTY/ALM) simulator + + Copyright (c) 2000-2003, Robert M. Supnik + Written by Bruce Ray and used with his gracious permission. + + Permission is hereby granted, free of charge, to any person obtaining a + 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. + + qty multiplexor: QTY = 4060, ALM = 42xx + + 25-Mar-04 RMS Updated for V3.2 + 12-Jan-04 BKR Initial release + includes both original DG "quad" multiplexor (QTY) + and later Asynchronous Line Multiplexor (ALM) support. +*/ + + +/*----------------------------------------------------------------------*/ +/* QTY [4060-compatible] multiplexor */ +/*----------------------------------------------------------------------*/ + +/* + * Emulate the DG 4060 "quad" (QTY) serial port multiplexor. DG modem + * control is not supported in this revision due to its obtuse nature + * of using a separate [semi-secret] device MDM which is actually part + * of the DG 4026/4027 multiplexor hardware(!). + * (Full modem support is provided in the ALM driver.) + * + * + * 4060 Hardware + * + * device code: 030 [primary], + * 070 [secondary] + * interrupt mask: B14 [000002] + * ASM mnemonic: QTY + * + * + * 4060 Input/Output Word Format: + * + * _________________________________________________________________ + * | RI| TI| channel | character | + * ----+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * + * + * RI - receiver interrupt + * TI - transmitter interrupt + * channel - channel number, 0 - 63. + * character- character (valid if receiver interrupt, undefined if transmitter) + * + * Notes: + * + * Maximum 64 lines supported. + * DONE set whenever any received character fully assembled and ready, + * or when any output character transmitted and line is ready + * to accept next output character. + * BUSY set whenever output character is being sent on any line. + * Note that early 4060s did NOT have a busy flag! + * IORST clears device Done, no other user instruction does. + * IORST clears each line's individual R.I. and T.I. + * + * + * Instructions: + * + * DIA get multiplexor status word [format defined above] + * DOA send character to QTY line [format defined above, RI & SI ] + * DIB [returns backplane bus noise] + * DOB clear QTY line + * DIC [returns backplace bus noise] + * DOC + * 'C' clears global done, then checks for RI and TI; + * 'P' + * 'S' + */ + + +#include "nova_defs.h" + +#include "sim_sock.h" +#include "sim_tmxr.h" + + +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ +#define UNIT_8B (1 << UNIT_V_8B) + + + +extern int32 int_req, dev_busy, dev_done, dev_disable ; +extern int32 sim_switches ; +extern FILE * sim_log ; +extern int32 tmxr_poll ; /* calibrated delay */ + +t_stat qty_summary ( FILE * st, UNIT * uptr, int32 val, void * desc ) ; +t_stat qty_show ( FILE * st, UNIT * uptr, int32 val, void * desc ) ; +t_stat qty_setnl ( UNIT * uptr, int32 val, char * cptr, void * desc ) ; + +t_stat qty_attach ( UNIT * uptr, char * cptr ) ; +t_stat qty_detach ( UNIT * uptr ) ; +t_stat qty_reset ( DEVICE * dptr ) ; +t_stat qty_svc ( UNIT * uptr ) ; +int32 qty ( int32 pulse, int32 code, int32 AC ) ; + +t_stat alm_reset ( DEVICE * dptr ) ; +t_stat alm_svc ( UNIT * uptr ) ; +int32 alm ( int32 pulse, int32 code, int32 AC ) ; + +DEVICE alm_dev ; + + +#define QTY_MAX 64 /* max number of QTY lines - hardware */ + + +int32 qty_brkio = SCPE_OK ; /* default I/O status code */ +int32 qty_max = QTY_MAX ; /* max # QTY lines - user */ + /* controllable */ +int32 qty_mdm = 0 ; /* QTY modem control active? */ +int32 qty_auto = 0 ; /* QTY auto disconnect active? */ +int32 qty_polls = 0 ; /* total 'qty_svc' polls */ + + +TMLN qty_ldsc[ QTY_MAX ] = { 0 } ; /* QTY line descriptors */ +TMXR qty_desc = { QTY_MAX, 0, 0, qty_ldsc } ; /* mux descriptor */ +int32 qty_status[ QTY_MAX ] = { 0 } ; /* QTY line status */ + /* (must be at least 32 bits) */ +int32 qty_tx_chr[ QTY_MAX ] = { 0 } ; /* QTY line output character */ + + +/* QTY data structures + + qty_dev QTY device descriptor + qty_unit QTY unit descriptor + qty_reg QTY register list +*/ + +DIB qty_dib = { DEV_QTY, INT_QTY, PI_QTY, &qty } ; + +UNIT qty_unit = + { + UDATA (&qty_svc, (UNIT_ATTABLE), 0) + } ; + +REG qty_nlreg = { DRDATA (NLINES, qty_desc.lines, 7), PV_LEFT }; + +REG qty_reg[] = /* ('alm_reg' should be similar to this except for device code related items) */ + { + { ORDATA (BUF, qty_unit.buf, 8) }, + { FLDATA (BUSY, dev_busy, INT_V_QTY) }, + { FLDATA (DONE, dev_done, INT_V_QTY) }, + { FLDATA (DISABLE, dev_disable, INT_V_QTY) }, + { FLDATA (INT, int_req, INT_V_QTY) }, + + { FLDATA (MDMCTL, qty_mdm, 0) }, + { FLDATA (AUTODS, qty_auto, 0) }, + { DRDATA (POLLS, qty_polls, 32) }, + { NULL } + } ; + +MTAB qty_mod[] = + { + { UNIT_8B, 0, "7b", "7B", NULL }, + { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &qty_desc }, + { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &qty_summary }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &qty_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &qty_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES", + &qty_setnl, NULL, &qty_nlreg }, + { 0 } + } ; + +DEVICE qty_dev = + { + "QTY", &qty_unit, qty_reg, qty_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &qty_reset, + NULL, &qty_attach, &qty_detach, + &qty_dib, (DEV_DISABLE | DEV_DIS | DEV_NET) + }; + + + /* */ + /* (need to mask off non-interrupt bit devices) */ + +#define DEV_SET_BUSY( dibp ) dev_busy = dev_busy | ( (dibp)->mask ) ; +#define DEV_CLEAR_BUSY( dibp ) dev_busy = dev_busy & ~( (dibp)->mask ) ; +#define DEV_SET_DONE( dibp ) dev_done = dev_done | ( (dibp)->mask ) ; int_req = int_req & ~( (dibp)->mask ) ; +#define DEV_CLEAR_DONE( dibp ) dev_done = dev_done & ~( (dibp)->mask ) ; int_req = int_req & ~( (dibp)->mask ) ; +#define DEV_UPDATE_INTR int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable) ; + +#define DG_RETURN( status, data ) (int32)(((status) << IOT_V_REASON) | ((data) & 0x0FFFF) ) + +/* + * QTY_S_xxx QTY device status reference + * QTY_L_xxx QTY line status word reference (qty_status[]) + */ + + /*----------------------------------------------*/ + /* QTY device status */ + /*----------------------------------------------*/ + +#define QTY_S_RI 0x8000 /* Receiver Interrupt */ +#define QTY_S_TI 0x4000 /* Transmitter interrupt */ +#define QTY_S_LMASK 0x3F00 /* line mask */ +#define QTY_S_DMASK 0x00FF /* data mask (received char) */ + + + +#define QTY_MASTER_ACTIVE( desc ) ( (desc)->master ) + +#define QTY_LINE_EXTRACT( x ) (((x) & QTY_S_LMASK) >> 8) + +#define QTY_LINE_TX_CHAR( line ) qty_tx_chr[ ((line) % QTY_MAX) ] +#define QTY_LINE_RX_CHAR( line ) (qty_status[ (line) ] & QTY_S_DMASK) +#define QTY_UNIT_ACTIVE( unitp ) ( (unitp)->conn ) + +#define QTY_LINE_BITS( line, bits ) qty_status[ (line) ] & bits + +#define QTY_LINE_SET_BIT( line, bit ) qty_status[ (line) ] |= (bit) ; +#define QTY_LINE_CLEAR_BIT( line, bit ) qty_status[ (line) ] &= ~(bit) ; +#define QTY_LINE_BIT_SET( line, bit ) (qty_status[ (line) ] & (bit)) + + + + /*----------------------------------------------*/ + /* QTY line status */ + /*----------------------------------------------*/ + +#define QTY_L_RXE 0x800000 /* receiver enabled? */ +#define QTY_L_RXBZ 0x400000 /* receiver busy? */ +#define QTY_L_RXDN 0x200000 /* receiver done? */ +#define QTY_L_TXE 0x080000 /* transmitter enabled? */ +#define QTY_L_TXBZ 0x040000 /* transmitter busy? */ +#define QTY_L_TXDN 0x020000 /* transmitter done? */ + +#define QTY_L_BREAK 0x008000 /* BREAK character received */ +#define QTY_L_RING 0x004000 /* Ring interrupt */ +#define QTY_L_CD 0x002000 /* Carrier Detect */ +#define QTY_L_DTR 0x001000 /* Data Terminal Ready */ + /* <0x00FF = character> */ + +#define QTY_L_LOOPBK 0x00010000 /* loopback mode */ +#define QTY_L_OVRERR 0x00020000 /* overrun error */ +#define QTY_L_FRMERR 0x00040000 /* framing error */ +#define QTY_L_PARERR 0x00080000 /* parity error */ + + +/* CD, CTS, DSR, RI */ + /* */ + +#define QTY_L_MODEM 0x0080 /* */ +#define QTY_L_TELNET 0x0040 /* */ +#define QTY_L_AUTODIS 0x0020 /* */ +#define QTY_L_PARITY +#define QTY_L_7BIT +#define QTY_L_BAUD /* <4 bits> */ + + +#define QTY_L_DMASK 0x000FF /* data mask (always 8 bits) */ + +/* Note: use at least an 'int32' for this guy */ + + + /*------------------------------*/ + /* qty_tmxr_putc */ + /*------------------------------*/ + + int qty_tmxr_putc( int line, TMLN * lp, int kar ) + { + int a ; + + /*----------------------------------------------*/ + /* Send character to given QTY/telnet line. */ + /* */ + /* enter: line QTY line # */ + /* lp Telnet unit def ptr */ + /* kar character to send */ + /* */ + /* return: SCPE_OK */ + /* SCPE_STALL */ + /* SCPE_LOST */ + /*----------------------------------------------*/ + + a = tmxr_putc_ln( lp, kar ) ; + if ( a == SCPE_OK) + { + QTY_LINE_SET_BIT( line, QTY_L_TXDN ) + QTY_LINE_CLEAR_BIT( line, QTY_L_TXBZ ) + } + else if ( a == SCPE_STALL ) + { + /* + (should we try to output the buffer + and then regroup...?) + */ + QTY_LINE_SET_BIT( line, QTY_L_TXBZ ) + QTY_LINE_CLEAR_BIT( line, QTY_L_TXDN ) + QTY_LINE_TX_CHAR( line ) = kar ; + } + else if ( a == SCPE_LOST ) + { + /* no connection - hangup? */ + QTY_LINE_SET_BIT( line, QTY_L_TXBZ ) + QTY_LINE_CLEAR_BIT( line, QTY_L_TXDN ) + QTY_LINE_TX_CHAR( line ) = kar ; + } + return ( a ) ; + } /* end of 'qty_tmxr_putc' */ + + + /*----------------------------------------------*/ + /* qty_update_rcvi */ + /*----------------------------------------------*/ + + int qty_update_rcvi( TMXR * mp ) + { + int line ; + TMLN * lp ; + int32 datum ; + int changes ; + + /*------------------------------------------------------*/ + /* Search through connected telnet lines for any input */ + /* activity. */ + /* */ + /* enter: mp master telnet qty desc ptr */ + /* */ + /* return: int change count (0 = none seen) */ + /*------------------------------------------------------*/ + + for ( changes = line = 0; line < mp->lines; ++line ) + if ( (lp=mp->ldsc+line)->conn && lp->rcve ) + if ( (datum=tmxr_getc_ln(lp)) ) + { + if ( datum & SCPE_BREAK ) + { + /* what should we do here - set QTY_L_BREAK? */ + datum = datum & 0x00FF ; + } + else + { + datum = datum & 0x00FF ; + } + /* */ + + QTY_LINE_CLEAR_BIT( line, (QTY_L_RXBZ | QTY_L_DMASK) ) ; + QTY_LINE_SET_BIT( line, (QTY_L_RXDN | datum) ) ; + ++changes ; + } + return ( changes ) ; + } /* end of 'qty_update_rcvi' */ + + + /*----------------------------------------------*/ + /* qty_update_xmti */ + /*----------------------------------------------*/ + + int qty_update_xmti( TMXR * mp ) + { + int line ; + TMLN * lp ; + int changes ; + + /*------------------------------------------------------*/ + /* Search through connected telnet lines for any de- */ + /* ferred output activity. */ + /* */ + /* enter: mp master telnet qty desc ptr */ + /* */ + /* return: int change count (0 = none seen) */ + /*------------------------------------------------------*/ + + /* any TX DONE flags set + * any TX BUSY flags set + */ + + for ( changes = line = 0; line < mp->lines; ++line ) + if ( QTY_LINE_BIT_SET(line,QTY_L_TXBZ) ) + if ( (lp=mp->ldsc+line)->conn && lp->xmte ) + { + /* why are we busy? buffer was full? */ + /* now some space available - try + * to stuff pending character in + * buffer and free up the world + */ + qty_tmxr_putc( line, lp, QTY_LINE_TX_CHAR(line) ) ; + ++changes ; + } + return ( changes ) ; + } /* end of 'qty_update_xmti' */ + + + /*----------------------------------------------*/ + /* qty_update_status */ + /*----------------------------------------------*/ + + int qty_update_status( DIB * dibp, TMXR * tmxr_desc ) + { + int line ; + int status ; + int txbusy ; + + /*----------------------------------------------*/ + /* return global device status for current qty */ + /* state. */ + /* */ + /* Receiver interrupts have higher priority */ + /* than transmitter interrupts according to DG */ + /* but this routine could be modified to use */ + /* different priority criteria. */ + /* */ + /* Round-robin polling could also be used in */ + /* some future release rather than starting */ + /* with line 0 each time. */ + /* */ + /* Return of */ + /* first waiting character, else return */ + /* of first finished line */ + /* output, else return 0. */ + /* */ + /* This routine does -not- clear input line */ + /* BZ/DN flags; caller should do this. */ + /* */ + /* Global device done and busy flags are */ + /* updated. */ + /*----------------------------------------------*/ + + for ( txbusy = status = line = 0 ; line < qty_max ; ++line ) + { + txbusy |= (QTY_LINE_BIT_SET(line,QTY_L_TXBZ)) ; + if ( QTY_LINE_BIT_SET(line,QTY_L_RXDN) ) + { + if ( ! status ) + { + status = QTY_LINE_BITS( line, QTY_S_DMASK ) | QTY_S_RI ; + status = status | (line << 8) ; + } + break ; + } + else if ( QTY_LINE_BIT_SET(line,QTY_L_TXDN) ) + { + if ( ! (status & QTY_S_RI) ) + if ( ! (status & QTY_S_RI) ) + { + status = QTY_S_TI ; + status = status | (line << 8) ; + } + } + } + /* */ + DEV_CLEAR_BUSY( dibp ) + DEV_CLEAR_DONE( dibp ) + if ( txbusy ) + { + DEV_SET_BUSY( dibp ) ; + } + if ( status & (QTY_S_RI | QTY_S_TI) ) + { + DEV_SET_DONE( dibp ) + } + DEV_UPDATE_INTR /* update final intr status */ + return ( status ) ; + } /* end of 'qty_update_status' */ + + + /*--------------------------------------------------------------*/ + /* qty_attach */ + /*--------------------------------------------------------------*/ + +t_stat qty_attach( UNIT * unitp, char * cptr ) + { + t_stat r ; + int a ; + + /* switches: A auto-disconnect + * M modem control + */ + + qty_mdm = qty_auto = 0; /* modem ctl off */ + r = tmxr_attach( &qty_desc, unitp, cptr ) ; /* attach QTY */ + if ( r != SCPE_OK ) + { + return ( r ) ; /* error! */ + } + if ( sim_switches & SWMASK('M') ) /* modem control? */ + { + qty_mdm = 1; + printf( "Modem control activated\n" ) ; + if ( sim_log ) fprintf( sim_log, "Modem control activated\n" ) ; + if ( sim_switches & SWMASK ('A') ) /* autodisconnect? */ + { + qty_auto = 1 ; + printf( "Auto disconnect activated\n" ) ; + if ( sim_log ) fprintf( sim_log, "Auto disconnect activated\n" ) ; + } + } + qty_polls = 0 ; + for ( a = 0 ; a < QTY_MAX ; ++a ) + { + /* QTY lines are always enabled - force RX and TX to 'enabled' */ + qty_status[ a ] = (QTY_L_RXE | QTY_L_TXE) ; + } + sim_activate( unitp, tmxr_poll ) ; + return ( SCPE_OK ) ; + } /* end of 'qty_attach' */ + + + /*--------------------------------------------------------------*/ + /* qty_detach */ + /*--------------------------------------------------------------*/ + +t_stat qty_detach( UNIT * unitp ) + { + sim_cancel( unitp ) ; + return ( tmxr_detach(&qty_desc,unitp) ) ; + } /* end of 'qty_detach' */ + + + /*--------------------------------------------------------------*/ + /* qty_clear */ + /*--------------------------------------------------------------*/ + +t_stat qty_clear( t_bool flag ) + { + int line ; + + for ( line = 0 ; line < qty_max ; ++line ) + { + qty_ldsc[line].xmte = 0 ; + qty_ldsc[line].rcve = 0 ; + if ( ! qty_ldsc[line].conn ) + { + qty_ldsc[line].xmte = 1 ; /* set xmt enb */ + qty_ldsc[line].rcve = 1 ; /* clr rcv enb */ + } + } + return ( SCPE_OK ) ; + } /* end of 'qty_clear' */ + + + /*----------------------------------------------*/ + /* qty_common_reset */ + /*----------------------------------------------*/ + + t_stat qty_common_reset( DIB * dibp, UNIT * unitp, DEVICE * dptr ) + { + if ((dptr->flags & DEV_DIS) == 0) + { + if (dptr == &qty_dev) alm_dev.flags |= DEV_DIS; + else qty_dev.flags |= DEV_DIS; + } + qty_clear( TRUE ) ; + DEV_CLEAR_BUSY( dibp ) /* clear busy */ + DEV_CLEAR_DONE( dibp ) /* clear done, int */ + DEV_UPDATE_INTR + if ( QTY_MASTER_ACTIVE(&qty_desc) ) + { + sim_activate( unitp, tmxr_poll ) ; + } + else + { + sim_cancel( unitp ) ; + } + return ( SCPE_OK ) ; + } /* end of 'qty_common_reset' */ + + + /*--------------------------------------------------------------*/ + /* qty_reset */ + /*--------------------------------------------------------------*/ + +t_stat qty_reset( DEVICE * dptr ) + { + return ( qty_common_reset(&qty_dib,&qty_unit,dptr) ) ; + } /* end of 'qty_reset' */ + + +/* Unit service routine + + The QTY/ALM polls to see if asynchronous activity has occurred and now + needs to be processed. The polling interval is controlled by the clock + simulator, so for most environments, it is calibrated to real time. + + The simulator assumes that software enables all of the multiplexors, + or none of them. +*/ + + /*----------------------------------------------*/ + /* qty_common_svc */ + /*----------------------------------------------*/ + + t_stat qty_common_svc( DIB * dibp, UNIT * unitp ) + { + int line ; + int newln ; + TMLN * tmlnp ; + + ++qty_polls ; /* another time 'round the track */ + newln = tmxr_poll_conn( &qty_desc ) ; /* anybody knocking at the door? */ + if ( (newln >= 0) && qty_mdm ) + if ( newln >= qty_max ) + { + return SCPE_IERR; /* WTF - sanity check failed, over? */ + } + else + { + line = newln ; /* handle modem control */ + tmlnp =&qty_ldsc[ line ] ; + tmlnp->rcve = tmlnp->xmte = 1 ; + /* do QTY_LINE_ bit fiddling and state machine + * manipulation with modem control signals + */ + } + + tmxr_poll_rx( &qty_desc ) ; /* poll input */ + qty_update_rcvi( &qty_desc ) ; /* update receiver interrupt status */ + + tmxr_poll_tx( &qty_desc ) ; /* poll output */ + qty_update_xmti( &qty_desc ) ; /* update transmitter interrupt status */ + + qty_update_status( dibp, &qty_desc ) ;/* update device status */ + + sim_activate( unitp, tmxr_poll ) ; /* restart the bubble machine */ + return ( SCPE_OK ) ; + } /* end of 'qty_common_svc' */ + + + /*--------------------------------------------------------------*/ + /* qty_svc */ + /*--------------------------------------------------------------*/ + +t_stat qty_svc( UNIT * uptr ) + { + return ( qty_common_svc(&qty_dib,uptr) ) ; + } /* end of 'qty_svc' */ + + + /*--------------------------------------------------------------*/ + /* qty */ + /*--------------------------------------------------------------*/ + +int32 qty( int32 pulse, int32 code, int32 AC ) + { + int32 iodata ; + int32 ioresult ; + int line ; + TMLN * tmlnp ; + int a ; + int kar ; + + /*--------------------------------------------------------------*/ + /* DG 4060[-compatible] "quad" multiplexor instruction handler */ + /*--------------------------------------------------------------*/ + + ioresult= qty_brkio ; /* (assume returning I/O break value */ + iodata = 0 ; /* (assume 16-bit Nova/Eclipse bus) */ + switch ( code ) + { + case ioNIO : /* */ + break ; + + case ioDIA : /* get current QTY status */ + iodata = qty_update_status( &qty_dib, &qty_desc ) ; + if ( iodata & QTY_S_RI ) + { /* clear line's input buffer */ + QTY_LINE_CLEAR_BIT( (QTY_LINE_EXTRACT(iodata)), (QTY_L_RXBZ | QTY_L_RXDN) ) + /* + character masking ; + parity checking ; + parity generating ; + */ + } + qty_update_status( &qty_dib, &qty_desc ) ; + break ; + + case ioDOA : /* send character to QTY */ + line = QTY_LINE_EXTRACT( iodata ) ; + if ( line < qty_max ) + if ( QTY_LINE_BIT_SET(line,QTY_L_TXE) ) + { + /* + perform any character translation: + 7 bit/ 8 bit + parity generation + */ + kar = AC & ((qty_unit.flags & UNIT_8B)? 0377: 0177) ; + /* do any parity calculations also */ + + tmlnp = &qty_ldsc[ line ] ; + a = qty_tmxr_putc( line, tmlnp, kar ) ; + if ( a != SCPE_OK) + { + /* do anything at this point? */ + } + qty_update_status( &qty_dib, &qty_desc ) ; + } + break ; + + case ioDIB : /* no QTY function - return bus noise in AC */ + break ; + + case ioDOB : /* clear QTY output channel busy and done flag */ + QTY_LINE_CLEAR_BIT( (QTY_LINE_EXTRACT(AC)), (QTY_L_TXBZ | QTY_L_TXDN) ) + qty_update_status( &qty_dib, &qty_desc ) ; + break ; + + case ioDIC : /* no QTY function - return bus noise in AC */ + break ; + + case ioDOC : /* no QTY function - ignore */ + break ; + + case ioSKP : /* I/O skip test - should never come here */ + break ; + + default : + /* */ + break ; + } + + switch ( pulse ) + { + case iopN : /* */ + break ; + + case iopS : /* */ + break ; + + case iopP : /* */ + break ; + + case iopC : + qty_update_status( &qty_dib, &qty_desc ) ; + break ; + + default : + /* */ + break ; + } + + return ( DG_RETURN( ioresult, iodata ) ) ; + } /* end of 'qty' */ + + /*--------------------------------------------------------------*/ + /* qty_summary */ + /*--------------------------------------------------------------*/ + +t_stat qty_summary( FILE * st, UNIT * uptr, int32 val, void * desc ) + { + int32 i, t ; + + for (i = t = 0 ; i < qty_desc.lines ; ++i ) + if ( qty_ldsc[i].conn ) + { + ++t ; + } + fprintf( st, "%d connection%s", t, ((t)? "s" : "") ) ; + return ( SCPE_OK ) ; + } /* end of 'qty_summ' */ + + + /*--------------------------------------------------------------*/ + /* qty_show */ + /*--------------------------------------------------------------*/ + +t_stat qty_show( FILE * st, UNIT * uptr, int32 val, void * desc ) + { + int32 i, t ; + + for (i = t = 0 ; i < qty_desc.lines ; ++i ) + if ( qty_ldsc[i].conn ) + { + t = 1; + if ( val ) + { + tmxr_fconns( st, &qty_ldsc[i], i ) ; + } + else + { + tmxr_fstats( st, &qty_ldsc[i], i ) ; + } + } + if ( t == 0 ) fprintf( st, "none connected\n" ) ; + return ( SCPE_OK ) ; + } /* end of 'qty_show' */ + + + /*--------------------------------------------------------------*/ + /* qty_setnl */ + /*--------------------------------------------------------------*/ + +t_stat qty_setnl( UNIT * uptr, int32 val, char * cptr, void * desc ) + { + int32 newln, i, t ; + + t_stat r ; + if ( cptr == NULL ) + { + return ( SCPE_ARG ) ; + } + newln = (int32) get_uint( cptr, 10, QTY_MAX, &r ) ; + if ( (r != SCPE_OK) || (newln == qty_desc.lines) ) + { + return ( r ) ; + } + if ( (newln == 0) || (newln > QTY_MAX) ) + { + return ( SCPE_ARG ) ; + } + if ( newln < qty_desc.lines ) + { + for ( i = newln, t = 0 ; i < qty_desc.lines ; ++i ) + { + t = t | qty_ldsc[i].conn ; + } + if ( t && ! get_yn("This will disconnect users; proceed [N]?", FALSE) ) + { + return ( SCPE_OK ) ; + } + for ( i = newln ; i < qty_desc.lines ; ++i ) + { + if ( qty_ldsc[i].conn ) + { /* reset line */ + tmxr_msg( qty_ldsc[i].conn, "\r\nOperator disconnected line\r\n" ) ; + tmxr_reset_ln( &qty_ldsc[i] ) ; + } + qty_clear( TRUE ) ; /* reset mux */ + } + } + qty_max = qty_desc.lines = newln ; + /* Huh, I don't understand this yet... + qty_max = ((qty_dev.flags & DEV_DIS)? 0 : (qty_desc.lines / QTY_MAX)) ; + */ + return ( SCPE_OK ) ; + } /* end of 'qty_setnl' */ + + +/*----------------------------------------------------------------------*/ +/* ALM [425x-compatible] multiplexor */ +/*----------------------------------------------------------------------*/ + +/* + * device code: 034 [primary], + * 074 [secondary] + * interrupt mask: B14 [000002] + * ASM mnemonic: ALM + * + * ALM [4255-4258] I/O instructions + * + * DIA read line and section requesting service + * DOA select line and section (lines 0-255, 8-bits) + rcvr/xmit + * DIB receive data + * DOB 00 transmit data + * 01 transmit BREAK + * 10 set modem control status + * 11 + * DIC read receiver or modem status + * DOC 00 control line section and diag mode + * 01 + * 10 specify line characteristics + * 11 + * + * undocumented DG "features": + * + * NIOS sets board offline + * NIOC sets board online + * Modem control signal state change can signal interrupt + * explicit line select with DOA + * implicit line select with DIA + * + * We support 64 lines maximum in this release although some ALM's could + * theoretically support up to 256. + */ + + +DIB alm_dib = { DEV_ALM, INT_ALM, PI_ALM, &alm } ; +UNIT alm_unit = + { + UDATA (&alm_svc, (UNIT_ATTABLE), 0) + } ; + +REG alm_reg[] = /* ('qty_reg' should be similar to this except for device code related items) */ + { + { ORDATA (BUF, alm_unit.buf, 8) }, + { FLDATA (BUSY, dev_busy, INT_V_ALM) }, + { FLDATA (DONE, dev_done, INT_V_ALM) }, + { FLDATA (DISABLE, dev_disable, INT_V_ALM) }, + { FLDATA (INT, int_req, INT_V_ALM) }, + + { FLDATA (MDMCTL, qty_mdm, 0) }, + { FLDATA (AUTODS, qty_auto, 0) }, + { DRDATA (POLLS, qty_polls, 32) }, + { NULL } + } ; + +DEVICE alm_dev = + { + "ALM", &alm_unit, alm_reg, qty_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &alm_reset, + NULL, &qty_attach, &qty_detach, + &alm_dib, (DEV_DISABLE | DEV_NET) + } ; + +int alm_section = -1 ; /* current line "section" (0 = RCV, 1 = XMT) */ +int alm_line = -1 ; /* current line [0-63] */ +int alm_diag_mode = 0 ; /* */ +int alm_line_mask = 0x003F ; /* maximum of 64 lines in this rev */ + + +#define ALM_LINE_EXTRACT( x ) (((x) >> 1) & alm_line_mask) +#define ALM_SECT_EXTRACT( x ) ((x) & 0x0001) + + + /*--------------------------------------------------------------*/ + /* alm_reset */ + /*--------------------------------------------------------------*/ + +t_stat alm_reset( DEVICE * dptr ) + { + return ( qty_common_reset(&alm_dib,&alm_unit,dptr) ) ; + } /* end of 'alm_reset' */ + + + /*--------------------------------------------------------------*/ + /* alm_svc */ + /*--------------------------------------------------------------*/ + +t_stat alm_svc( UNIT * uptr ) + { + return ( qty_common_svc(&alm_dib,uptr) ) ; + } /* end of 'alm_svc' */ + + + /*--------------------------------------------------------------*/ + /* alm */ + /*--------------------------------------------------------------*/ + +int32 alm( int32 pulse, int32 code, int32 AC ) + { + int32 iodata ; + int32 ioresult ; + TMLN * tmlnp ; + int a ; + int kar ; + + /*--------------------------------------------------------------*/ + /* DG 425x[-compatible] "ALM" multiplexor instruction handler */ + /*--------------------------------------------------------------*/ + + ioresult= qty_brkio ; /* (assume returning I/O break value */ + iodata = 0 ; /* (assume 16-bit Nova/Eclipse bus) */ + switch ( code ) + { + case ioNIO : /* */ + break ; + + case ioDIA : /* read line and section requesting service */ + iodata = qty_update_status( &alm_dib, &qty_desc ) ; + alm_line = (QTY_LINE_EXTRACT(iodata) & alm_line_mask) ; + /* (mask with 'alm_line_mask' in case ALM mask is different than QTY */ + alm_section = 0 ; + if ( ! ( iodata & QTY_S_RI) ) + if ( iodata & QTY_S_TI ) + { + alm_section = 1 ; /* receiver quiet - transmitter done */ + } + iodata = (alm_line << 1) | alm_section ; + break ; + + case ioDOA : /* set line and section */ + alm_section = ALM_SECT_EXTRACT( AC ) ; + alm_line = ALM_LINE_EXTRACT( AC ) ; + break ; + + case ioDIB : /* no ALM function - return bus noise in AC */ + if ( alm_line < qty_max ) + { + iodata = QTY_LINE_RX_CHAR( alm_line ) ; + } + break ; + + case ioDOB : /* output and modem control functions */ + switch ( (AC >> 14) & 03 ) + { + case 00 : /* transmit data */ + if ( alm_line < qty_max ) + if ( QTY_LINE_BIT_SET(alm_line,QTY_L_TXE) ) + { + /* + perform any character translation: + 7 bit/ 8 bit + parity generation + */ + kar = AC & ((alm_unit.flags & UNIT_8B)? 0377: 0177) ; + /* do any parity calculations also */ + + tmlnp = &qty_ldsc[ alm_line ] ; + a = qty_tmxr_putc( alm_line, tmlnp, kar ) ; + if ( a != SCPE_OK) + { + /* do anything at this point? */ + } + qty_update_status( &alm_dib, &qty_desc ) ; + } + break ; + + case 01 : /* transmit break */ + if ( alm_line < qty_max ) + if ( QTY_LINE_BIT_SET(alm_line,QTY_L_TXE) ) + { + tmlnp = &qty_ldsc[ alm_line ] ; + /* + a = qty_tmxr_putc( alm_line, tmlnp, kar ) ; + if ( a != SCPE_OK) + { + } + */ + qty_update_status( &alm_dib, &qty_desc ) ; + } + break ; + + case 02 : /* set modem control status */ + break ; + + case 03 : /* unused */ + break ; + } + break ; + + case ioDIC : /* get modem or receiver status */ + if ( alm_line < qty_max ) + if ( alm_section ) + { + /* get modem section status */ + if ( qty_ldsc[ alm_line ].xmte ) + { + iodata = 0035 ; /* set CD, CTS, DSR, MDM flags */ + } + } + else + { + /* get receiver section status */ + iodata = 0 ; /* receiver error status - no errors by default */ + } + break ; + + case ioDOC : /* set line attributes */ + switch ( (AC >> 14) & 03 ) + { + case 00 : /* control line section */ + break ; + + case 01 : /* unused */ + break ; + + case 02 : /* set line characteristics */ + break ; + + case 03 : /* unused */ + break ; + } + break ; + + case ioSKP : /* I/O skip test - should never come here */ + break ; + + default : + /* */ + break ; + } + + switch ( pulse ) + { + case iopN : /* */ + break ; + + case iopS : /* set device busy + * set all lines on board offline + * clear each line's done + * clear internal system + * clear device busy + */ + for ( a = 0 ; a < qty_max ; ++a ) + if ( 1 ) + { + QTY_LINE_CLEAR_BIT( a, (QTY_L_RXBZ | QTY_L_RXDN | QTY_L_TXBZ | QTY_L_TXDN) ) ; + } + qty_update_status( &alm_dib, &qty_desc ) ; + break ; + + case iopP : /* stop clock for all boards in off-line mode */ + break ; + + case iopC : + for ( a = 0 ; a < qty_max ; ++a ) + if ( 1 ) + { + QTY_LINE_CLEAR_BIT( a, (QTY_L_RXBZ | QTY_L_RXDN | QTY_L_TXBZ | QTY_L_TXDN) ) ; + } + qty_update_status( &alm_dib, &qty_desc ) ; + break ; + + default : + /* */ + break ; + } + + return ( DG_RETURN( ioresult, iodata ) ) ; + } /* end of 'alm' */ diff --git a/NOVA/nova_sys.c b/NOVA/nova_sys.c index 3e302a41..9adc3cfe 100644 --- a/NOVA/nova_sys.c +++ b/NOVA/nova_sys.c @@ -1,6 +1,6 @@ /* nova_sys.c: NOVA simulator interface - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 26-Mar-04 RMS Fixed warning with -std=c99 + 14-Jan-04 BKR Added support for QTY and ALM + 04-Jan-04 RMS Fixed 64b issues found by VMS 8.1 24-Nov-03 CEO Added symbolic support for LEF instruction 17-Sep-01 RMS Removed multiconsole support 31-May-01 RMS Added multiconsole support @@ -61,6 +64,8 @@ extern DEVICE lpt_dev; extern DEVICE dkp_dev; extern DEVICE dsk_dev; extern DEVICE mta_dev; +extern DEVICE qty_dev; +extern DEVICE alm_dev; extern REG cpu_reg[]; extern uint16 M[]; extern int32 saved_PC; @@ -104,6 +109,8 @@ DEVICE *sim_devices[] = { &dsk_dev, &dkp_dev, &mta_dev, + &qty_dev, + &alm_dev, NULL }; const char *sim_stop_messages[] = { @@ -387,7 +394,7 @@ static const char *opcode[] = { #endif NULL }; -static const opc_val[] = { +static const int32 opc_val[] = { 0000000+I_M, 0004000+I_M, 0010000+I_M, 0014000+I_M, 0020000+I_RM, 0040000+I_RM, #if defined (ECLIPSE) @@ -596,7 +603,7 @@ return SCPE_OK; t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { -int32 cflag, i, j, c1, c2, inst, dv, src, dst, skp; +int32 cflag, i, j, c1, c2, inst, inst1, dv, src, dst, skp; int32 ind, mode, disp, dev; int32 byac, extind, extdisp, xop; @@ -615,6 +622,7 @@ if (!(sw & SWMASK ('M'))) return SCPE_ARG; /* mnemonic? */ /* Instruction decode */ inst = (int32) val[0]; +inst1 = (int32) val[1]; for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ if ((opc_val[i] & 0177777) == (inst & masks[j])) { /* match? */ @@ -627,8 +635,8 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ dev = I_GETDEV (inst); /* IOT fields */ byac = I_GETPULSE (inst); /* byte fields */ xop = I_GETXOP (inst); /* XOP fields */ - extind = (int32) val[1] & A_IND; /* extended fields */ - extdisp = (int32) val[1] & AMASK; + extind = inst1 & A_IND; /* extended fields */ + extdisp = inst1 & AMASK; for (dv = 0; (dev_val[dv] >= 0) && (dev_val[dv] != dev); dv++) ; switch (j) { /* switch on class */ @@ -677,10 +685,10 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ fprintf (of, "%s %-o,%-o", opcode[i], src + 1, dst); break; case I_V_LI: /* long imm */ - fprintf (of, "%s %-o", opcode[i], val[1]); + fprintf (of, "%s %-o", opcode[i], inst1); return -1; case I_V_RLI: /* reg, long imm */ - fprintf (of, "%s %-o,%-o", opcode[i], val[1], dst); + fprintf (of, "%s %-o,%-o", opcode[i], inst1, dst); return -1; case I_V_LM: /* long addr */ fprintf (of, "%s ", opcode[i]); diff --git a/NOVA/nova_tt1.c b/NOVA/nova_tt1.c index ea3f1bd3..5b31f137 100644 --- a/NOVA/nova_tt1.c +++ b/NOVA/nova_tt1.c @@ -1,6 +1,6 @@ /* nova_tt1.c: NOVA second terminal simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Written by Bruce Ray and used with his gracious permission. Permission is hereby granted, free of charge, to any person obtaining a diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index afe90b39..bb617526 100644 --- a/PDP1/pdp1_cpu.c +++ b/PDP1/pdp1_cpu.c @@ -1,6 +1,6 @@ /* pdp1_cpu.c: PDP-1 CPU simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -331,6 +331,7 @@ REG cpu_reg[] = { { FLDATA (SBIP, sbs, SB_V_IP) }, { FLDATA (IOH, ioh, 0) }, { FLDATA (IOS, ios, 0) }, + { ORDATA (CPLS, cpls, 6) }, { BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { FLDATA (STOP_INST, stop_inst, 0) }, diff --git a/PDP1/pdp1_defs.h b/PDP1/pdp1_defs.h index 5f2280ec..309f93de 100644 --- a/PDP1/pdp1_defs.h +++ b/PDP1/pdp1_defs.h @@ -1,6 +1,6 @@ /* pdp1_defs.h: 18b PDP simulator definitions - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -19,10 +19,11 @@ 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 + 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. + 08-Feb-04 PLB Added support for display 08-Dec-03 RMS Added support for parallel drum 18-Oct-03 RMS Added DECtape off reel message 22-Jul-03 RMS Updated for "hardware" RIM loader @@ -40,6 +41,7 @@ Memory extension control Type 15 Parallel drum Type 23 Serial drum Type 24 + Graphic display Type 30 Line printer control Type 62 Microtape (DECtape) control Type 550 */ @@ -115,10 +117,12 @@ #define CPLS_V_PTP 4 #define CPLS_V_TTO 3 #define CPLS_V_LPT 2 +#define CPLS_V_DPY 1 #define CPLS_PTR (1 << CPLS_V_PTR) #define CPLS_PTP (1 << CPLS_V_PTP) #define CPLS_TTO (1 << CPLS_V_TTO) #define CPLS_LPT (1 << CPLS_V_LPT) +#define CPLS_DPY (1 << CPLS_V_TTY) /* Sequence break flags */ diff --git a/PDP1/pdp1_doc.txt b/PDP1/pdp1_doc.txt index c20fc2c2..cd8b04ba 100644 --- a/PDP1/pdp1_doc.txt +++ b/PDP1/pdp1_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: PDP-1 Simulator Usage -Date: 15-Dec-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,13 +36,19 @@ This memorandum documents the PDP-1 simulator. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c + sim_timer.c sim_tmxr.c sim/pdp1/ pdp1_defs.h @@ -308,6 +314,7 @@ The DECtape controller implements these registers: SUBSTATE 2 read/write command substate POS[0:7] 32 position, in lines, units 0-7 STATT[0:7] 18 unit state, units 0-7 + STOP_OFFR 1 stop on off-reel error It is critically important to maintain certain timing relationships among the DECtape parameters, or the DECtape simulator will fail to diff --git a/PDP1/pdp1_drm.c b/PDP1/pdp1_drm.c index a7c840be..de47fe50 100644 --- a/PDP1/pdp1_drm.c +++ b/PDP1/pdp1_drm.c @@ -1,6 +1,6 @@ /* pdp1_drm.c: PDP-1 drum simulator - Copyright (c) 1993-2002, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP1/pdp1_dt.c b/PDP1/pdp1_dt.c index 7b9f379a..add68055 100644 --- a/PDP1/pdp1_dt.c +++ b/PDP1/pdp1_dt.c @@ -1,6 +1,6 @@ /* pdp1_dt.c: 18b DECtape simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ dt Type 550/555 DECtape + 25-Jan-04 RMS Revised for device debug support + 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR 26-Oct-03 RMS Cleaned up buffer copy code 18-Oct-03 RMS Added DECtape off reel message, simplified timing 25-Apr-03 RMS Revised for extended file support @@ -239,9 +241,8 @@ /* Logging */ #define LOG_MS 001 /* move, search */ -#define LOG_RW 002 /* read, write */ -#define LOG_RA 004 /* read all */ -#define LOG_BL 010 /* block # lblk */ +#define LOG_RW 002 /* read write */ +#define LOG_BL 004 /* block # lblk */ #define ABS(x) (((x) < 0)? (-(x)): (x)) @@ -251,6 +252,7 @@ extern int32 stop_inst; extern UNIT cpu_unit; extern int32 sim_switches; extern int32 sim_is_running; +extern FILE *sim_deb; int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ @@ -258,8 +260,8 @@ int32 dtdb = 0; /* data buffer */ int32 dt_ltime = 12; /* interline time */ int32 dt_dctime = 40000; /* decel time */ int32 dt_substate = 0; -int32 dt_log = 0; int32 dt_logblk = 0; +int32 dt_stopoffr = 0; static const int32 map_unit[16] = { /* Type 550 unit map */ -1, 1, 2, 3, 4, 5, 6, 7, 0, -1, -1, -1, -1, -1, -1, -1 }; @@ -314,7 +316,6 @@ REG dt_reg[] = { { DRDATA (LTIME, dt_ltime, 31), REG_NZ }, { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, { ORDATA (SUBSTATE, dt_substate, 2) }, - { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, { URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 0, DT_NUMDR, PV_LEFT | REG_RO) }, @@ -322,6 +323,7 @@ REG dt_reg[] = { DT_NUMDR, REG_RO) }, { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0, DT_NUMDR, REG_HRO) }, + { FLDATA (STOP_OFFR, dt_stopoffr, 0) }, { NULL } }; MTAB dt_mod[] = { @@ -332,12 +334,19 @@ MTAB dt_mod[] = { { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, 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, 18, NULL, NULL, &dt_reset, NULL, &dt_attach, &dt_detach, - NULL, DEV_DISABLE }; + NULL, DEV_DISABLE | DEV_DEBUG, 0, + dt_deb, NULL, NULL }; int32 dt (int32 IR, int32 dev, int32 dat) { @@ -524,7 +533,7 @@ case DTS_OFR: /* off reel */ break; case FNC_MOVE: /* move */ dt_schedez (uptr, dir); /* sched end zone */ - if (dt_log & LOG_MS) printf ("[DT%d: moving %s]\n", unum, (dir? + 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 */ @@ -532,7 +541,7 @@ case FNC_SRCH: /* search */ 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 (dt_log & LOG_MS) printf ("[DT%d: searching %s]\n", unum, + if (DEBUG_PRI (dt_dev, LOG_MS)) fprintf (sim_deb, ">>DT%d: searching %s\n", unum, (dir? "backward": "forward")); break; case FNC_WRIT: /* write */ @@ -545,10 +554,11 @@ case FNC_WALL: /* write all */ else { newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE; if (!dir) newpos = newpos + (DT_WSIZE - 1); } - if ((dt_log & LOG_RA) || ((dt_log & LOG_BL) && (blk == dt_logblk))) - printf ("[DT%d: read all block %d %s%s\n", + if (DEBUG_PRI (dt_dev, LOG_RW) || + (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) + fprintf (sim_deb, ">>DT%d: read all block %d %s%s\n", unum, blk, (dir? "backward": "forward"), - ((dtsa & DTA_MODE)? " continuous]": "]")); + ((dtsa & DTA_MODE)? " continuous": " ")); break; default: dt_seterr (uptr, DTB_SEL); /* bad state */ @@ -642,7 +652,8 @@ uint32 ba; switch (mot) { case DTS_DECF: case DTS_DECR: /* decelerating */ - if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */ + 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)); /* reversing */ @@ -663,7 +674,8 @@ default: /* other */ Off reel - detach unit (it must be deselected) */ -if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */ +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; } @@ -888,7 +900,7 @@ if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ else if (sim_switches & SWMASK ('S')) /* att 16b? */ uptr->flags = uptr->flags | UNIT_11FMT; else if (!(sim_switches & SWMASK ('T')) && /* autosize? */ - (sz = sim_fsize (cptr))) { + (sz = sim_fsize (uptr->fileref))) { if (sz == D8_FILSIZ) uptr->flags = uptr->flags | UNIT_8FMT; else if (sz == D11_FILSIZ) diff --git a/PDP1/pdp1_lp.c b/PDP1/pdp1_lp.c index b57e4728..c41451bd 100644 --- a/PDP1/pdp1_lp.c +++ b/PDP1/pdp1_lp.c @@ -1,6 +1,6 @@ /* pdp1_lp.c: PDP-1 line printer simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP1/pdp1_stddev.c b/PDP1/pdp1_stddev.c index ed211419..4e84bbac 100644 --- a/PDP1/pdp1_stddev.c +++ b/PDP1/pdp1_stddev.c @@ -1,6 +1,6 @@ /* pdp1_stddev.c: PDP-1 standard devices - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP1/pdp1_sys.c b/PDP1/pdp1_sys.c index 87946792..04418a96 100644 --- a/PDP1/pdp1_sys.c +++ b/PDP1/pdp1_sys.c @@ -1,6 +1,6 @@ /* pdp1_sys.c: PDP-1 simulator interface - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -19,10 +19,12 @@ 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 + 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. + 06-Apr-04 RMS Fixed bug in binary loader (found by Mark Crispin) + 08-Feb-04 PLB Merged display support 08-Dec-03 RMS Added parallel drum support, drum mnemonics 18-Oct-03 RMS Added DECtape off reel message 01-Sep-03 RMS Added support for loading in multiple fields @@ -51,6 +53,7 @@ extern DEVICE lpt_dev; extern DEVICE dt_dev; extern DEVICE drm_dev; extern DEVICE drp_dev; +extern DEVICE dpy_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern int32 M[]; @@ -84,6 +87,7 @@ DEVICE *sim_devices[] = { &dt_dev, &drm_dev, &drp_dev, +// &dpy_dev, NULL }; const char *sim_stop_messages[] = { @@ -167,7 +171,7 @@ t_stat sta; int32 fld; if (flag != 0) return SCPE_ARG; -if (cptr) { +if (cptr && (*cptr != 0)) { fld = get_uint (cptr, 8, AMASK, &sta); if (sta != SCPE_OK) return sta; fld = fld & EPCMASK; } @@ -215,6 +219,7 @@ static const char *opcode[] = { "IOH", "RPA", "RPB", "RRB", /* I/O instructions */ "PPA", "PPB", "TYO", "TYI", + "DPY", "LSM", "ESM", "CBS", "LEM", "EEM", "CKS", "MSE", "MLC", "MRD", "MWR", "MRS", @@ -270,6 +275,7 @@ static const int32 opc_val[] = { 0730000+I_NPN, 0720001+I_IOT, 0720002+I_IOT, 0720030+I_IOT, 0720005+I_IOT, 0720006+I_IOT, 0720003+I_IOT, 0720004+I_IOT, + 0720007+I_IOT, 0720054+I_NPN, 0720055+I_NPN, 0720056+I_NPN, 0720074+I_NPN, 0724074+I_NPN, 0720033+I_NPN, 0720301+I_NPN, 0720401+I_NPN, 0720501+I_NPN, 0720601+I_NPN, 0720701+I_NPN, diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index 7ee895d8..a05a53a1 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -1,6 +1,6 @@ /* pdp10_cpu.c: PDP-10 CPU simulator - Copyright (c) 1993-2003, Robert M. Supnik + Copyright (c) 1993-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index c4d42286..f51546b9 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -744,6 +744,7 @@ int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf, t_bool ub); int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf, t_bool ub); int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf, t_bool ub); t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); diff --git a/PDP10/pdp10_doc.txt b/PDP10/pdp10_doc.txt index fb31fe4e..1f776c88 100644 --- a/PDP10/pdp10_doc.txt +++ b/PDP10/pdp10_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: PDP-10 Simulator Usage -Date: 15-May-2003 +Date: 04-Apr-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -39,17 +39,23 @@ This memorandum documents the PDP-10 simulator. To compile the PDP-10, you must define VM_PDP10 and USE_INT64 as part of the compilation command line. -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h sim_ether.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c sim_ether.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/pdp10/ pdp10_defs.h @@ -329,6 +335,22 @@ output is incompatible with TOPS-20 and is off by default. The command allows output characters to be 8 bits. +The DZ11 supports logging on a per-line basis. The command + + SET DZ LOG=line=filename + +enables logging for the specified line to the indicated file. The +command + + SET DZ NOLOG=line + +disables logging for the specified line and closes any open log file. +Finally, the command + + SHOW DZ LOG + +displays logging information for all DZ lines. + The terminal lines perform input and output through Telnet sessions connected to a user-specified port. The ATTACH command specifies the port to be used: diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c index ec54d729..5f9a8673 100644 --- a/PDP10/pdp10_ksio.c +++ b/PDP10/pdp10_ksio.c @@ -1,6 +1,6 @@ /* pdp10_ksio.c: PDP-10 KS10 I/O subsystem simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ uba Unibus adapters + 25-Jan-04 RMS Added stub floating address routine 12-Mar-03 RMS Added logical name support 10-Oct-02 RMS Revised for dynamic table generation Added SHOW IOSPACE routine @@ -663,7 +664,7 @@ if (dptr == NULL) return SCPE_IERR; dibp = (DIB *) dptr->ctxt; if (dibp == NULL) return SCPE_IERR; newvec = (uint32) get_uint (cptr, 8, VEC_Q + 01000, &r); -if ((r != SCPE_OK) || (newvec <= VEC_Q) || +if ((r != SCPE_OK) || (newvec == VEC_Q) || ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) || (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG; dibp->vec = newvec; @@ -795,3 +796,10 @@ t_stat auto_config (uint32 rank, uint32 num) { return SCPE_OK; } + +/* Stub floating address */ + +t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +return SCPE_OK; +} diff --git a/PDP10/pdp10_mdfp.c b/PDP10/pdp10_mdfp.c index 5c3e1ad9..0b753705 100644 --- a/PDP10/pdp10_mdfp.c +++ b/PDP10/pdp10_mdfp.c @@ -1,6 +1,6 @@ /* pdp10_mdfp.c: PDP-10 multiply/divide and floating point simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 2-Apr-04 RMS Fixed bug in floating point unpack + Fixed bug in FIXR (found by Phil Stone, fixed by + Chris Smith) + Instructions handled in this module: imul integer multiply idiv integer divide @@ -346,7 +350,7 @@ AC(ADDAC(ac, 3)) = dvd[1]; return; } -/* Single precision floating add - checked against KS10 ucode +/* Single precision floating add/subtract - checked against KS10 ucode The KS10 shifts the smaller operand regardless of the exponent diff. This code will not shift more than 63 places; shifts beyond that cannot change the value of the smaller operand. @@ -486,7 +490,7 @@ UFP a; funpack (mb, 0, &a, AFRC); /* unpack operand */ if (a.exp > (FP_BIAS + FP_N_FHI + FP_N_EXP)) SETF (F_AOV | F_T1); -else if (a.exp < (FP_BIAS - 1)) AC(ac) = 0; +else if (a.exp < FP_BIAS) AC(ac) = 0; /* < 1/2? */ else { sc = FP_V_UNORM - (a.exp - FP_BIAS) + 1; AC(ac) = a.fhi >> sc; if (rnd) { @@ -629,9 +633,13 @@ fplo = GET_FPLO (l); r->fhi = (fphi << FP_V_UFHI) | (fplo << FP_V_UFLO); r->flo = 0; if (r->sign) { - r->exp = r->exp ^ FP_M_EXP; - if (sgn) r->fhi = r->fhi | FP_UCRY; /* ext sign */ - else { + r->exp = r->exp ^ FP_M_EXP; /* 1s comp exp */ + if (sgn) { /* signed frac? */ + if (r->fhi) r->fhi = r->fhi | FP_UCRY; /* extend sign */ + else { + r->exp = r->exp + 1; + r->fhi = FP_UCRY | FP_UNORM; } } + else { /* abs frac */ if (r->fhi) r->fhi = UNEG (r->fhi) & FP_UFRAC; else { r->exp = r->exp + 1; @@ -648,7 +656,13 @@ static t_uint64 normmask[6] = { 0x6000000000000000, 0x7800000000000000, 0x7F80000000000000, 0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF }; static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 }; +extern a10 pager_PC; +if (a->fhi & FP_UCRY) { /* carry set? */ + printf ("%%PDP-10 FP: carry bit set at normalization, PC = %o\n", pager_PC); + a->flo = (a->flo >> 1) | ((a->fhi & 1) << 63); /* try to recover */ + a->fhi = a->fhi >> 1; /* but root cause */ + a->exp = a->exp + 1; } /* should be fixed! */ if ((a->fhi | a->flo) == 0) { /* if fraction = 0 */ a->sign = a->exp = 0; /* result is 0 */ return; } diff --git a/PDP10/pdp10_pag.c b/PDP10/pdp10_pag.c index bcb6d9c8..52367833 100644 --- a/PDP10/pdp10_pag.c +++ b/PDP10/pdp10_pag.c @@ -1,6 +1,6 @@ /* pdp10_pag.c: PDP-10 paging subsystem simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index 712a6bbc..28ece327 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -1,6 +1,6 @@ /* pdp10_rp.c - RH11/RP04/05/06/07 RM02/03/05/80 "Massbus" disk controller - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rp RH/RP/RM moving head disks + 04-Jan-04 RMS Changed sim_fsize calling sequence 23-Jul-03 RMS Fixed bug in read header stub 25-Apr-03 RMS Revised for extended file support 21-Nov-02 RMS Fixed bug in bootstrap (reported by Michael Thompson) @@ -989,8 +990,7 @@ rper1[drv] = 0; update_rpcs (CS1_SC, drv); if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */ -if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; -if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK; +if ((p = sim_fsize (uptr->fileref)) == 0) return SCPE_OK; for (i = 0; drv_tab[i].sect != 0; i++) { if (p <= (drv_tab[i].size * (int) sizeof (d10))) { uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 477b5c47..3dd677fd 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -1,6 +1,6 @@ /* pdp10_sys.c: PDP-10 simulator interface - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP10/pdp10_tim.c b/PDP10/pdp10_tim.c index e2a0036b..8d7d1c52 100644 --- a/PDP10/pdp10_tim.c +++ b/PDP10/pdp10_tim.c @@ -1,6 +1,6 @@ /* pdp10_tim.c: PDP-10 tim subsystem simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ tim timer subsystem + 02-Feb-04 RMS Exported variables needed by Ethernet simulator 29-Jan-02 RMS New data structures 06-Jan-02 RMS Added enable/disable support 02-Dec-01 RMS Fixed bug in ITS PC sampling (found by Dave Conroy) @@ -56,6 +57,11 @@ d10 quant = 0; /* ITS quantum */ int32 diagflg = 0; /* diagnostics? */ int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */ +/* Exported variables */ + +int32 clk_tps = TIM_TPS; /* clock ticks/sec */ +int32 tmr_poll = TIM_DELAY; /* clock poll */ + DEVICE tim_dev; t_stat tcu_rd (int32 *data, int32 PA, int32 access); extern t_stat wr_nop (int32 data, int32 PA, int32 access); @@ -144,6 +150,7 @@ int32 t; t = diagflg? tim_unit.wait: sim_rtc_calb (TIM_TPS); /* calibrate clock */ sim_activate (&tim_unit, t); /* reactivate unit */ +tmr_poll = t; /* set timer poll */ tmxr_poll = t * DZ_MULT; /* set mux poll */ timebase = (timebase + 1) & TB_MASK; /* increment timebase */ ttg = ttg - TIM_HWRE; /* decrement timer */ @@ -161,10 +168,14 @@ return SCPE_OK; t_stat tim_reset (DEVICE *dptr) { +int32 t; + period = ttg = 0; /* clear timer */ apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */ -sim_activate (&tim_unit, tim_unit.wait); /* activate unit */ -tmxr_poll = tim_unit.wait * DZ_MULT; /* set mux poll */ +t = sim_rtc_init (tim_unit.wait); /* init timer */ +sim_activate (&tim_unit, t); /* activate unit */ +tmr_poll = t; /* set timer poll */ +tmxr_poll = t * DZ_MULT; /* set mux poll */ return SCPE_OK; } diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index f457131a..aa30a584 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -1,6 +1,6 @@ /* pdp10_tu.c - PDP-10 RH11/TM03/TU45 magnetic tape simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP10/pdp10_xtnd.c b/PDP10/pdp10_xtnd.c index 3c17e676..e22546ae 100644 --- a/PDP10/pdp10_xtnd.c +++ b/PDP10/pdp10_xtnd.c @@ -1,6 +1,6 @@ /* pdp10_xtnd.c: PDP-10 extended instruction simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c index 4190b7be..0b5d80f9 100644 --- a/PDP11/pdp11_cis.c +++ b/PDP11/pdp11_cis.c @@ -1,6 +1,6 @@ /* pdp11_cis.c: PDP-11 CIS optional instruction set simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index e025dbef..f61ded05 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -25,6 +25,7 @@ cpu PDP-11 CPU (J-11 microprocessor) + 25-Jan-04 RMS Removed local debug logging support 29-Dec-03 RMS Formalized 18b Qbus support 21-Dec-03 RMS Added autoconfiguration controls 05-Jun-03 RMS Fixed bugs in memory size table @@ -277,7 +278,6 @@ int32 stop_trap = 1; /* stop on trap */ int32 stop_vecabort = 1; /* stop on vec abort */ int32 stop_spabort = 1; /* stop on SP abort */ int32 wait_enable = 0; /* wait state enable */ -int32 cpu_log = 0; /* logging */ int32 autcon_enb = 1; /* autoconfig enable */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ @@ -420,7 +420,6 @@ REG cpu_reg[] = { { ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) }, { FLDATA (STOP_VECA, stop_vecabort, 0) }, { FLDATA (STOP_SPA, stop_spabort, 0) }, - { HRDATA (DBGLOG, cpu_log, 16), REG_HIDDEN }, { ORDATA (FAC0H, FR[0].h, 32) }, { ORDATA (FAC0L, FR[0].l, 32) }, { ORDATA (FAC1H, FR[1].h, 32) }, @@ -583,7 +582,8 @@ DEVICE cpu_dev = { 1, 8, 22, 2, 8, 16, &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL, - NULL, DEV_DYNM, &cpu_set_size }; + NULL, DEV_DYNM | DEV_DEBUG, 0, + NULL, &cpu_set_size, NULL }; t_stat sim_instr (void) { diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 00323c38..28e21a2c 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -1,6 +1,6 @@ /* pdp11_defs.h: PDP-11 simulator definitions - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 25-Jan-04 RMS Removed local debug logging support 22-Dec-03 RMS Added second DEUNA/DELUA support 18-Oct-03 RMS Added DECtape off reel message 19-May-03 RMS Revised for new conditional compilation @@ -564,25 +565,6 @@ typedef struct pdp_dib DIB; #define SP R[6] #define PC R[7] -/* Logging */ - -#define LOG_CPU_I 0x0001 -#define LOG_TM 0x0008 -#define LOG_RP 0x0010 -#define LOG_TS 0x0020 -#define LOG_RQ 0x0040 -#define LOG_TQ 0x0080 -#define LOG_XQ0 0x0100 -#define LOG_XQ1 0x0200 -#define LOG_XQ2 0x0400 -#define LOG_XQ3 0x0800 -#define LOG_TC_MS 0x1000 -#define LOG_TC_RW 0x2000 -#define LOG_TC_BL 0x4000 -#define LOG_HK 0x8000 - -#define DBG_LOG(x) (sim_log && (cpu_log & (x))) - /* Function prototypes */ t_bool Map_Addr (uint32 qa, uint32 *ma); diff --git a/PDP11/pdp11_doc.txt b/PDP11/pdp11_doc.txt index e7b4541d..22864ee1 100644 --- a/PDP11/pdp11_doc.txt +++ b/PDP11/pdp11_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: PDP-11 Simulator Usage -Date: 15-Dec-2003 +Date: 04-Apr-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -40,17 +40,23 @@ To compile the PDP-11, you must define VM_PDP11 as part of the compilation command line. If you want expanded file support, you must also define USE_INT64 and USE_ADDR64 as part of the compilation command line. -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h sim_ether.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c sim_ether.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/pdp11/ pdp11_defs.h @@ -509,6 +515,22 @@ may be incompatible with certain operating systems. The command forces output characters (only) to be masked to 7 bits. +The DZ11 supports logging on a per-line basis. The command + + SET DZ LOG=line=filename + +enables logging for the specified line to the indicated file. The +command + + SET DZ NOLOG=line + +disables logging for the specified line and closes any open log file. +Finally, the command + + SHOW DZ LOG + +displays logging information for all DZ lines. + The terminal lines perform input and output through Telnet sessions connected to a user-specified port. The ATTACH command specifies the port to be used: @@ -1001,6 +1023,7 @@ The TC controller implements these registers: SUBSTATE 2 read/write command substate POS[0:7] 32 position, in lines, units 0-7 STATT[0-7] 31 unit state, units 0-7 + STOP_OFFR 1 stop on off-reel error It is critically important to maintain certain timing relationships among the DECtape parameters, or the DECtape simulator will fail to @@ -1230,6 +1253,19 @@ state of this switch. Note that only the DEQNA (or the DELQA in DEQNA- LOCK mode (=DEQNA)) supports the sanity timer - it is ignored by a DELQA in Normal mode, which uses switch S4 for a different purpose. + SET XQ POLL={DEFAULT|4..2500} + SHOW XQ POLL + +These commands change or display the service polling timer. The polling +timer is calibrated to run the service thread 200 times per second. This +value can be changed to accomodate particular system requirements for +more (or less) frequent polling. + + SHOW XQ STATS + +This command will display the accumulated statistics for the simulated +Ethernet controller. + To access the network, the simulated Ethernet controller must be attached to a real Ethernet interface: @@ -1244,7 +1280,7 @@ The device list can be quite cryptic, depending on the host system, but is probably better than guessing. If you do not attach the device, the controller will behave as though the ethernet cable were unplugged. -XQ has the following registers: +XQ and XQB have the following registers: name size comments @@ -1254,10 +1290,11 @@ XQ has the following registers: SA3 16 station address word 3 SA4 16 station address word 4 SA5 16 station address word 5 + RBDL 32 receive buffer descriptor list + XBDL 32 trans(X)mit buffer descriptor list CSR 16 control status register VAR 16 vector address register - RBDL 32 receive buffer descriptor list - XBDL 32 trans(X)mit buffer descriptorlList + INT 1 interrupt request flag One final note: because of it's asynchronous nature, the XQ controller is not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers, diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index 6b6c33bb..eb9c8e83 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -1,6 +1,6 @@ /* pdp11_dz.c: DZ11 terminal multiplexor simulator - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ dz DZ11 terminal multiplexor + 4-Apr-04 RMS Added per-line logging + 05-Jan-04 RMS Revised for tmxr library changes 19-May-03 RMS Revised for new conditional compilation scheme 09-May-03 RMS Added network device flag 22-Dec-02 RMS Added break (framing error) support @@ -155,7 +157,7 @@ uint32 dz_txi = 0; /* xmt interrupts */ int32 dz_mctl = 0; /* modem ctrl enabled */ int32 dz_auto = 0; /* autodiscon enabled */ TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { 0 }; /* line descriptors */ -TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, NULL }; /* mux descriptor */ +TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, dz_ldsc }; /* mux descriptor */ DEVICE dz_dev; t_stat dz_rd (int32 *data, int32 PA, int32 access); @@ -178,6 +180,9 @@ t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc); /* DZ data structures @@ -229,6 +234,12 @@ MTAB dz_mod[] = { #endif { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES", &dz_setnl, NULL, &dz_nlreg }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "LOG", + &dz_set_log, NULL, &dz_desc }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "NOLOG", + &dz_set_nolog, NULL, &dz_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LOG", NULL, + NULL, &dz_show_log, &dz_desc }, { 0 } }; DEVICE dz_dev = { @@ -317,7 +328,7 @@ case 02: /* TCR */ line = (dz * DZ_LINES) + i; /* get line num */ lp = &dz_ldsc[line]; /* get line desc */ if (lp->conn && (drop & (1 << i))) { - tmxr_msg (lp->conn, "\r\nLine hangup\r\n"); + tmxr_linemsg (lp, "\r\nLine hangup\r\n"); tmxr_reset_ln (lp); /* reset line, cdet */ dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); } /* end if drop */ @@ -528,8 +539,6 @@ t_stat dz_reset (DEVICE *dptr) { int32 i, ndev; -for (i = 0; i < (DZ_MUXES * DZ_LINES); i++) /* init mux desc */ - dz_desc.ldsc[i] = &dz_ldsc[i]; for (i = 0; i < DZ_MUXES; i++) dz_clear (i, TRUE); /* init muxes */ dz_rxi = dz_txi = 0; /* clr master int */ CLR_INT (DZRX); @@ -614,7 +623,7 @@ if (newln < dz_desc.lines) { return SCPE_OK; for (i = newln; i < dz_desc.lines; i++) { if (dz_ldsc[i].conn) { - tmxr_msg (dz_ldsc[i].conn, "\r\nOperator disconnected line\r\n"); + tmxr_linemsg (&dz_ldsc[i], "\r\nOperator disconnected line\r\n"); tmxr_reset_ln (&dz_ldsc[i]); } /* reset line */ if ((i % DZ_LINES) == (DZ_LINES - 1)) dz_clear (i / DZ_LINES, TRUE); } /* reset mux */ @@ -631,3 +640,50 @@ t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc) { return show_vec (st, uptr, ((dz_desc.lines * 2) / DZ_LINES), desc); } + +/* SET LOG processor */ + +t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +char *tptr; +t_stat r; +int32 ln; + +if (cptr == NULL) return SCPE_ARG; +tptr = strchr (cptr, '='); +if ((tptr == NULL) || (*tptr == 0)) return SCPE_ARG; +*tptr++ = 0; +ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r); +if ((r != SCPE_OK) || (ln >= dz_desc.lines)) return SCPE_ARG; +return tmxr_set_log (NULL, ln, tptr, desc); +} + +/* SET NOLOG processor */ + +t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +t_stat r; +int32 ln; + +if (cptr == NULL) return SCPE_ARG; +ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r); +if ((r != SCPE_OK) || (ln >= dz_desc.lines)) return SCPE_ARG; +return tmxr_set_nolog (NULL, ln, NULL, desc); +} + +/* SHOW LOG processor */ + +t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i; + +for (i = 0; i < dz_desc.lines; i++) { + fprintf (st, "line %d: ", i); + tmxr_show_log (st, NULL, i, desc); + fprintf (st, "\n"); + } +return SCPE_OK; +} + + + diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 50185330..6e729a8c 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -1,6 +1,6 @@ /* pdp11_fp.c: PDP-11 floating point simulator (32b version) - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -712,7 +712,7 @@ if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */ F_GET_FRAC_P (facp, facfrac); /* get fractions */ F_GET_FRAC_P (fsrcp, fsrcfrac); facexp = facexp + fsrcexp - FP_BIAS; /* calculate exp */ -facp->h = facp->h ^ fsrcp->h; /* calculate sign */ +facp->h = facp->h ^ fsrcp->h; /* calculate sign */ frac_mulfp11 (&facfrac, &fsrcfrac); /* multiply fracs */ /* Multiplying two numbers in the range [.5,1) produces a result in the diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index b7dc2e3e..730530ba 100644 --- a/PDP11/pdp11_hk.c +++ b/PDP11/pdp11_hk.c @@ -1,6 +1,6 @@ /* pdp11_hk.c - RK611/RK06/RK07 disk controller - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ hk RK611/RK06/RK07 disk + 26-Mar-04 RMS Fixed warnings with -std=c99 + 25-Jan-04 RMS Revised for device debug support + 04-Jan-04 RMS Changed sim_fsize calling sequence 29-Dec-03 RMS Added 18b Qbus support 25-Apr-03 RMS Revised for extended file support @@ -301,8 +304,7 @@ extern uint16 *M; extern int32 int_req[IPL_HLVL]; extern int32 int_vec[IPL_HLVL][32]; -extern int32 cpu_log; -extern FILE *sim_log; +extern FILE *sim_deb; uint16 *hkxb = NULL; /* xfer buffer */ int32 hkcs1 = 0; /* control/status 1 */ @@ -439,7 +441,7 @@ DEVICE hk_dev = { HK_NUMDR, HK_RDX, 24, 1, HK_RDX, HK_WID, NULL, NULL, &hk_reset, &hk_boot, &hk_attach, &hk_detach, - &hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 }; + &hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG }; /* I/O dispatch routines, I/O addresses 17777440 - 17777476 */ @@ -591,9 +593,9 @@ return SCPE_OK; void hk_go (int32 drv) { - int32 fnc, t; UNIT *uptr; + static int32 fnc_nxf[16] = { 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0 }; static int32 fnc_att[16] = { @@ -604,7 +606,7 @@ static int32 fnc_cyl[16] = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; fnc = GET_FNC (hkcs1); -if (DBG_LOG (LOG_HK)) fprintf (sim_log, +if (DEBUG_PRS (hk_dev)) fprintf (sim_deb, ">>HK%d: fnc=%o, ds=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", drv, fnc, hkds[drv], hkdc, hkda, hkba, hkwc); uptr = hk_dev.units + drv; /* get unit */ @@ -875,7 +877,7 @@ return; /* Drive status update */ -void update_hkds (drv) +void update_hkds (int32 drv) { if (hk_unit[drv].flags & UNIT_DIS) { /* disabled? */ hkds[drv] = hker[drv] = 0; /* all clear */ @@ -1035,8 +1037,7 @@ hk_dif[drv] = 0; uptr->CYL = 0; update_hkcs (CS1_DI, drv); /* upd ctlr status */ -if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; /* seek to end */ -if ((p = ftell (uptr->fileref)) == 0) { /* new disk image? */ +if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ if (uptr->flags & UNIT_RO) return SCPE_OK; return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD); } if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */ diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index 3d6e7f89..e9f5ca3d 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -1,6 +1,6 @@ /* pdp11_io.c: PDP-11 I/O simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 25-Jan-04 RMS Removed local debug logging support 21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls 21-Nov-03 RMS Added check for interrupt slot conflict (found by Dave Hittner) 12-Mar-03 RMS Added logical name support @@ -139,8 +140,6 @@ for (i = IPL_HLVL - 1; i > nipl; i--) { /* loop thru lvls */ int_req[i] = int_req[i] & ~(1u << j); /* clr irq */ if (int_ack[i][j]) vec = int_ack[i][j](); else vec = int_vec[i][j]; - if (DBG_LOG (LOG_CPU_I)) fprintf (sim_log, - ">>INT: lvl=%d, flag=%d, vec=%o\n", i, j, vec); return vec; /* return vector */ } /* end if t */ } /* end for j */ @@ -392,7 +391,7 @@ if (dptr == NULL) return SCPE_IERR; dibp = (DIB *) dptr->ctxt; if (dibp == NULL) return SCPE_IERR; newvec = get_uint (cptr, 8, VEC_Q + 01000, &r); -if ((r != SCPE_OK) || (newvec <= VEC_Q) || +if ((r != SCPE_OK) || (newvec == VEC_Q) || ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) || (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG; dibp->vec = newvec; diff --git a/PDP11/pdp11_lp.c b/PDP11/pdp11_lp.c index 022497a9..dccc65b6 100644 --- a/PDP11/pdp11_lp.c +++ b/PDP11/pdp11_lp.c @@ -1,6 +1,6 @@ /* pdp11_lp.c: PDP-11 line printer simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_mscp.h b/PDP11/pdp11_mscp.h index cc1fb214..8af9dfdb 100644 --- a/PDP11/pdp11_mscp.h +++ b/PDP11/pdp11_mscp.h @@ -1,6 +1,6 @@ /* pdp11_mscp.h: DEC MSCP and TMSCP definitionsn - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Derived from work by Stephen F. Shirron Permission is hereby granted, free of charge, to any person obtaining a diff --git a/PDP11/pdp11_pclk.c b/PDP11/pdp11_pclk.c index af088679..512c2552 100644 --- a/PDP11/pdp11_pclk.c +++ b/PDP11/pdp11_pclk.c @@ -1,6 +1,6 @@ /* pdp11_pclk.c: KW11P programmable clock simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Written by John Dundas, used with his gracious permission Permission is hereby granted, free of charge, to any person obtaining a diff --git a/PDP11/pdp11_pt.c b/PDP11/pdp11_pt.c index 169c4d4c..34dc1352 100644 --- a/PDP11/pdp11_pt.c +++ b/PDP11/pdp11_pt.c @@ -1,6 +1,6 @@ /* pdp11_pt.c: PC11 paper tape reader/punch simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index 5fbc17d7..f0d37dcc 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -25,6 +25,7 @@ rk RK11/RKV11/RK05 cartridge disk + 24-Jan-04 RMS Added increment inhibit, overrun detection, formatting 29-Dec-03 RMS Added RKV11 support 29-Sep-02 RMS Added variable address support to bootstrap Added vector change/display support @@ -384,7 +385,8 @@ if (uptr->flags & UNIT_DIS) { /* not present? */ if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { rk_set_done (RKER_DRE); /* not att or busy */ return; } -if (rkcs & (RKCS_INH + RKCS_FMT)) { /* format? */ +if ((rkcs & RKCS_FMT) && /* format and */ + (func != RKCS_READ) && (func != RKCS_WRITE)) { /* not read or write? */ rk_set_done (RKER_PGE); return; } if ((func == RKCS_WRITE) && (uptr->flags & UNIT_WPRT)) { @@ -427,8 +429,8 @@ return; t_stat rk_svc (UNIT *uptr) { -int32 i, drv, err, awc, wc, t; -int32 da, track, sect; +int32 i, drv, err, awc, wc, cma, cda, t; +int32 da, cyl, track, sect; uint32 ma; uint16 comp; @@ -446,51 +448,103 @@ if (uptr->FUNC == RKCS_SEEK) { /* seek */ if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ rk_set_done (RKER_DRE); return IORETURN (rk_stopioe, SCPE_UNATT); } +sect = GET_SECT (rkda); /* get sector, cyl */ +cyl = GET_CYL (rkda); +if (sect >= RK_NUMSC) { /* bad sector? */ + rk_set_done (RKER_NXS); + return SCPE_OK; } +if (cyl >= RK_NUMCY) { /* bad cyl? */ + rk_set_done (RKER_NXC); + return SCPE_OK; } ma = ((rkcs & RKCS_MEX) << (16 - RKCS_V_MEX)) | rkba; /* get mem addr */ da = GET_DA (rkda) * RK_NUMWD; /* get disk addr */ wc = 0200000 - rkwc; /* get wd cnt */ +if ((da + wc) > (int32) uptr->capac) { /* overrun? */ + wc = uptr->capac - da; /* trim transfer */ + rker = rker | RKER_OVR; } /* set overrun err */ err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); +if (wc && (err == 0)) { /* seek ok? */ + switch (uptr->FUNC) { /* case on function */ -if ((uptr->FUNC == RKCS_READ) && (err == 0)) { /* read? */ - i = fxread (rkxb, sizeof (int16), wc, uptr->fileref); - err = ferror (uptr->fileref); - for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */ - if (t = Map_WriteW (ma, wc << 1, rkxb, MAP)) { /* store buf */ - rker = rker | RKER_NXM; /* NXM? set flg */ - wc = wc - t; } /* adj wd cnt */ - } /* end read */ + case RKCS_READ: /* read */ + if (rkcs & RKCS_FMT) { /* format? */ + for (i = 0, cda = da; i < wc; i++) { /* fill buffer with cyl #s */ + if (cda >= (int32) uptr->capac) { /* overrun? */ + rker = rker | RKER_OVR; /* set overrun err */ + wc = i; /* trim transfer */ + break; } + rkxb[i] = (cda / RK_NUMWD) / (RK_NUMSF * RK_NUMSC); + cda = cda + RK_NUMWD; /* next sector */ + } /* end for wc */ + } /* end if format */ + else { /* normal read */ + i = fxread (rkxb, sizeof (int16), wc, uptr->fileref); + err = ferror (uptr->fileref); /* read file */ + for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */ + } + if (rkcs & RKCS_INH) { /* incr inhibit? */ + if (t = Map_WriteW (ma, 2, &rkxb[wc - 1], MAP)) { /* store last */ + rker = rker | RKER_NXM; /* NXM? set flag */ + wc = 0; } /* no transfer */ + } + else { /* normal store */ + if (t = Map_WriteW (ma, wc << 1, rkxb, MAP)) { /* store buf */ + rker = rker | RKER_NXM; /* NXM? set flag */ + wc = wc - t; } /* adj wd cnt */ + } + break; /* end read */ -if ((uptr->FUNC == RKCS_WRITE) && (err == 0)) { /* write? */ - if (t = Map_ReadW (ma, wc << 1, rkxb, MAP)) { /* get buf */ - rker = rker | RKER_NXM; /* NXM? set flg */ - wc = wc - t; } /* adj wd cnt */ + case RKCS_WRITE: /* write */ + if (rkcs & RKCS_INH) { /* incr inhibit? */ + if (t = Map_ReadW (ma, 2, &comp, MAP)) { /* get 1st word */ + rker = rker | RKER_NXM; /* NXM? set flag */ + wc = 0; } /* no transfer */ + for (i = 0; i < wc; i++) rkxb[i] = comp; /* all words same */ + } + else { /* normal fetch */ + if (t = Map_ReadW (ma, wc << 1, rkxb, MAP)) { /* get buf */ + rker = rker | RKER_NXM; /* NXM? set flg */ + wc = wc - t; } /* adj wd cnt */ + } if (wc) { /* any xfer? */ awc = (wc + (RK_NUMWD - 1)) & ~(RK_NUMWD - 1); /* clr to */ for (i = wc; i < awc; i++) rkxb[i] = 0; /* end of blk */ fxwrite (rkxb, sizeof (int16), awc, uptr->fileref); - err = ferror (uptr->fileref); } - } /* end write */ + err = ferror (uptr->fileref); + } + break; /* end write */ -if ((uptr->FUNC == RKCS_WCHK) && (err == 0)) { /* write check? */ + case RKCS_WCHK: /* write check */ i = fxread (rkxb, sizeof (int16), wc, uptr->fileref); - err = ferror (uptr->fileref); + if (err = ferror (uptr->fileref)) { /* read error? */ + wc = 0; /* no transfer */ + break; } for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */ awc = wc; /* save wc */ - for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */ - if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */ + for (wc = 0, cma = ma; wc < awc; wc++) { /* loop thru buf */ + if (Map_ReadW (cma, 2, &comp, MAP)) { /* mem wd */ rker = rker | RKER_NXM; /* NXM? set flg */ break; } if (comp != rkxb[wc]) { /* match to disk? */ rker = rker | RKER_WCE; /* no, err */ - if (rkcs & RKCS_SSE) break; } } - } /* end wcheck */ + if (rkcs & RKCS_SSE) break; } + if (!(rkcs & RKCS_INH)) cma = cma + 2; /* next mem addr */ + } /* end for */ + break; /* end wcheck */ + + default: /* read check */ + break; + } /* end switch */ + } /* end else */ rkwc = (rkwc + wc) & 0177777; /* final word count */ -ma = ma + (wc << 1); /* final byte addr */ +if (!(rkcs & RKCS_INH)) ma = ma + (wc << 1); /* final byte addr */ rkba = ma & RKBA_IMP; /* lower 16b */ rkcs = (rkcs & ~RKCS_MEX) | ((ma >> (16 - RKCS_V_MEX)) & RKCS_MEX); -da = da + wc + (RK_NUMWD - 1); +if ((uptr->FUNC == RKCS_READ) && (rkcs & RKCS_FMT)) /* read format? */ + da = da + (wc * RK_NUMWD); /* count by sectors */ +else da = da + wc + (RK_NUMWD - 1); /* count by words */ track = (da / RK_NUMWD) / RK_NUMSC; sect = (da / RK_NUMWD) % RK_NUMSC; rkda = (rkda & RKDA_DRIVE) | (track << RKDA_V_TRACK) | (sect << RKDA_V_SECT); diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 67932ae4..0e27c1a5 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -1,6 +1,6 @@ /* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk + 04-Jan-04 RMS Changed sim_fsize calling sequence 19-May-03 RMS Revised for new conditional compilation scheme 25-Apr-03 RMS Revised for extended file support 29-Sep-02 RMS Added variable address support to bootstrap @@ -551,8 +552,7 @@ r = attach_unit (uptr, cptr); /* attach unit */ if (r != SCPE_OK) return r; /* error? */ uptr->TRK = 0; /* cylinder 0 */ uptr->STAT = RLDS_VCK; /* new volume */ -if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; /* seek to end */ -if ((p = ftell (uptr->fileref)) == 0) { /* new disk image? */ +if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ if (uptr->flags & UNIT_RO) return SCPE_OK; /* if ro, done */ return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); } if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */ diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index d8246211..347987da 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -1,6 +1,6 @@ /* pdp11_rp.c - RP04/05/06/07 RM02/03/05/80 "Massbus style" disk controller - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ rp RH/RP/RM moving head disks + 25-Jan-04 RMS Revised for device debug support + 04-Jan-04 RMS Changed sim_fsize calling sequence 19-May-03 RMS Revised for new conditional compilation scheme 25-Apr-03 RMS Revised for extended file support 29-Sep-02 RMS Added variable address support to bootstrap @@ -374,8 +376,7 @@ static struct drvtyp drv_tab[] = { extern int32 int_req[IPL_HLVL]; extern int32 int_vec[IPL_HLVL][32]; -extern int32 cpu_log; -extern FILE *sim_log; +extern FILE *sim_deb; uint16 *rpxb = NULL; /* xfer buffer */ int32 rpcs1 = 0; /* control/status 1 */ @@ -534,7 +535,7 @@ DEVICE rp_dev = { RP_NUMDR, DEV_RDX, 30, 1, DEV_RDX, RP_WID, NULL, NULL, &rp_reset, &rp_boot, &rp_attach, &rp_detach, - &rp_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS }; + &rp_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; /* I/O dispatch routines, I/O addresses 17776700 - 17776776 */ @@ -767,7 +768,7 @@ void rp_go (int32 drv, int32 fnc) int32 dc, dtype, t; UNIT *uptr; -if (DBG_LOG (LOG_RP)) fprintf (sim_log, +if (DEBUG_PRS (rp_dev)) fprintf (sim_deb, ">>RP%d: fnc=%o, ds=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", drv, fnc, rpds[drv], rpdc, rpda, (rpbae << 16) | rpba, rpwc); uptr = rp_dev.units + drv; /* get unit */ @@ -1078,8 +1079,7 @@ rpds[drv] = DS_ATA | DS_MOL | DS_RDY | DS_DPR | /* upd drv status */ rper1[drv] = 0; update_rpcs (CS1_SC, drv); /* upd ctlr status */ -if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; /* seek to end */ -if ((p = ftell (uptr->fileref)) == 0) { /* new disk image? */ +if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ if (uptr->flags & UNIT_RO) return SCPE_OK; return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD); } diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index 3bc002cb..8e24fe80 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -1,6 +1,6 @@ /* pdp11_rq.c: MSCP disk controller simulator - Copyright (c) 2002-2003, Robert M Supnik + Copyright (c) 2002-2004, Robert M Supnik Derived from work by Stephen F. Shirron Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,9 @@ rq RQDX3 disk controller + 05-Feb-04 RMS Revised for file I/O library + 25-Jan-04 RMS Revised for device debug support + 12-Jan-04 RMS Fixed bug in interrupt control (found by Tom Evans) 07-Oct-03 RMS Fixed problem with multiple RAUSER drives 17-Sep-03 RMS Fixed MB to LBN conversion to be more accurate 11-Jul-03 RMS Fixed bug in user disk size (found by Chaskiel M Grundman) @@ -467,9 +470,8 @@ static struct drvtyp drv_tab[] = { extern int32 int_req[IPL_HLVL]; extern int32 tmr_poll, clk_tps; -extern int32 cpu_log; extern UNIT cpu_unit; -extern FILE *sim_log; +extern FILE *sim_deb; extern uint32 sim_taddr_64; uint16 *rqxb = NULL; /* xfer buffer */ @@ -687,7 +689,7 @@ DEVICE rq_dev = { RQ_NUMDR + 2, DEV_RDX, 31, RQ_AINC, DEV_RDX, RQ_WID, NULL, NULL, &rq_reset, &rq_boot, &rq_attach, &rq_detach, - &rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS }; + &rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; /* RQB data structures @@ -751,7 +753,7 @@ DEVICE rqb_dev = { RQ_NUMDR + 2, DEV_RDX, 31, RQ_AINC, DEV_RDX, RQ_WID, NULL, NULL, &rq_reset, &rq_boot, &rq_attach, &rq_detach, - &rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS }; + &rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; /* RQC data structures @@ -815,7 +817,7 @@ DEVICE rqc_dev = { RQ_NUMDR + 2, DEV_RDX, 31, RQ_AINC, DEV_RDX, RQ_WID, NULL, NULL, &rq_reset, &rq_boot, &rq_attach, &rq_detach, - &rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS }; + &rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; /* RQD data structures @@ -879,7 +881,7 @@ DEVICE rqd_dev = { RQ_NUMDR + 2, DEV_RDX, 31, RQ_AINC, DEV_RDX, RQ_WID, NULL, NULL, &rq_reset, &rq_boot, &rq_attach, &rq_detach, - &rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS }; + &rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; static DEVICE *rq_devmap[RQ_NUMCT] = { &rq_dev, &rqb_dev, &rqc_dev, &rqd_dev }; @@ -924,7 +926,7 @@ if (cidx < 0) return SCPE_IERR; switch ((PA >> 1) & 01) { /* decode PA<1> */ case 0: /* IP */ rq_reset (rq_devmap[cidx]); /* init device */ - if (DBG_LOG (LOG_RQ)) fprintf (sim_log, + if (DEBUG_PRD (dptr)) fprintf (sim_deb, ">>RQ%c: initialization started\n", 'A' + cp->cnum); break; case 1: /* SA */ @@ -1042,7 +1044,7 @@ if (cp->csta < CST_UP) { /* still init? */ break; case CST_S4: /* need S4 reply */ if (cp->saw & SA_S4H_GO) { /* go set? */ - if (DBG_LOG (LOG_RQ)) fprintf (sim_log, + if (DEBUG_PRD (dptr)) fprintf (sim_deb, ">>RQ%c: initialization complete\n", 'A' + cp->cnum); cp->csta = CST_UP; /* we're up */ cp->sa = 0; /* clear SA */ @@ -1060,11 +1062,11 @@ for (i = 0; i < RQ_NUMDR; i++) { /* chk unit q's */ if ((pkt == 0) && cp->pip) { /* polling? */ if (!rq_getpkt (cp, &pkt)) return SCPE_OK; /* get host pkt */ if (pkt) { /* got one? */ - if (DBG_LOG (LOG_RQ)) { - fprintf (sim_log, ">>RQ%c: cmd=%04X, mod=%04X, unit=%d, ", + if (DEBUG_PRD (dptr)) { + fprintf (sim_deb, ">>RQ%c: cmd=%04X, mod=%04X, unit=%d, ", 'A' + cp->cnum, cp->pak[pkt].d[CMD_OPC], cp->pak[pkt].d[CMD_MOD], cp->pak[pkt].d[CMD_UN]); - fprintf (sim_log, "bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n", + fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n", cp->pak[pkt].d[RW_BCH], cp->pak[pkt].d[RW_BCL], cp->pak[pkt].d[RW_BAH], cp->pak[pkt].d[RW_BAL], cp->pak[pkt].d[RW_LBNH], cp->pak[pkt].d[RW_LBNL]); } @@ -1459,7 +1461,8 @@ t_stat rq_svc (UNIT *uptr) { MSC *cp = rq_ctxmap[uptr->cnum]; -uint32 i, t, err, tbc, abc, wwc; +uint32 i, t, tbc, abc, wwc; +uint32 err = 0; int32 pkt = uptr->cpkt; /* get packet */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ uint32 ba = GETP32 (pkt, RW_WBAL); /* buf addr */ @@ -1488,8 +1491,8 @@ if ((cmd == OP_ERS) || (cmd == OP_WR)) { /* write op? */ if (cmd == OP_ERS) { /* erase? */ wwc = ((tbc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; for (i = 0; i < wwc; i++) rqxb[i] = 0; /* clr buf */ - err = fseek_ext (uptr->fileref, da, SEEK_SET); /* set pos */ - if (!err) fxwrite (rqxb, sizeof (int16), wwc, uptr->fileref); + err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ + if (!err) sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref); err = ferror (uptr->fileref); } /* end if erase */ else if (cmd == OP_WR) { /* write? */ @@ -1497,8 +1500,8 @@ else if (cmd == OP_WR) { /* write? */ if (abc = tbc - t) { /* any xfer? */ wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; for (i = (abc >> 1); i < wwc; i++) rqxb[i] = 0; - err = fseek_ext (uptr->fileref, da, SEEK_SET); - if (!err) fxwrite (rqxb, sizeof (int16), wwc, uptr->fileref); + err = sim_fseek (uptr->fileref, da, SEEK_SET); + if (!err) sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref); err = ferror (uptr->fileref); } if (t) { /* nxm? */ PUTP32 (pkt, RW_WBCL, bc - abc); /* adj bc */ @@ -1507,9 +1510,9 @@ else if (cmd == OP_WR) { /* write? */ rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); return SCPE_OK; } } /* end else wr */ -else { err = fseek_ext (uptr->fileref, da, SEEK_SET); /* set pos */ +else { err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ if (!err) { - i = fxread (rqxb, sizeof (int16), tbc >> 1, uptr->fileref); + i = sim_fread (rqxb, sizeof (int16), tbc >> 1, uptr->fileref); for ( ; i < (tbc >> 1); i++) rqxb[i] = 0; /* fill */ err = ferror (uptr->fileref); } if ((cmd == OP_RD) && !err) { /* read? */ @@ -1774,7 +1777,7 @@ uint32 addr, desc, lnt, cr; DEVICE *dptr = rq_devmap[cp->cnum]; if (pkt == 0) return OK; /* any packet? */ -if (DBG_LOG (LOG_RQ)) fprintf (sim_log, +if (DEBUG_PRD (dptr)) fprintf (sim_deb, ">>RQ%c: rsp=%04X, sts=%04X\n", 'A' + cp->cnum, cp->pak[pkt].d[RSP_OPF], cp->pak[pkt].d[RSP_STS]); if (!rq_getdesc (cp, &cp->rq, &desc)) return ERR; /* get rsp desc */ @@ -1906,7 +1909,8 @@ return; void rq_init_int (MSC *cp) { -if (cp->s1dat & (SA_S1H_IE | SA_S1H_VEC)) rq_setint (cp); +if ((cp->s1dat & SA_S1H_IE) && /* int enab & */ + (cp->s1dat & SA_S1H_VEC)) rq_setint (cp); /* ved set? int */ return; } @@ -1971,8 +1975,10 @@ return 0; /* no intr req */ t_bool rq_fatal (MSC *cp, uint32 err) { -if (DBG_LOG (LOG_RQ)) - fprintf (sim_log, ">>RQ%c: fatal err=%X\n", 'A' + cp->cnum, err); +DEVICE *dptr = rq_devmap[cp->cnum]; + +if (DEBUG_PRD (dptr)) + fprintf (sim_deb, ">>RQ%c: fatal err=%X\n", 'A' + cp->cnum, err); rq_reset (rq_devmap[cp->cnum]); /* reset device */ cp->sa = SA_ER | err; /* SA = dead code */ cp->csta = CST_DEAD; /* state = dead */ diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index a8b8ca09..5cf836ab 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -1,6 +1,6 @@ /* pdp11_rx.c: RX11/RX01 floppy disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index a383fa02..893b255f 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -25,6 +25,7 @@ ry RX211/RXV21/RX02 floppy disk + 21-Mar-04 RMS Added VAX support 29-Dec-03 RMS Added RXV21 support 19-May-03 RMS Revised for new conditional compilation scheme 25-Apr-03 RMS Revised for extended file support @@ -40,14 +41,19 @@ #include "pdp10_defs.h" extern int32 int_req; extern int32 int_vec[32]; +#define DEV_DISI DEV_DIS #elif defined (VM_VAX) /* VAX version */ -#error "RX211 not supported on VAX!" +#include "vax_defs.h" +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; +#define DEV_DISI 0 #else /* PDP-11 version */ #include "pdp11_defs.h" extern int32 int_req[IPL_HLVL]; extern int32 int_vec[IPL_HLVL][32]; +#define DEV_DISI DEV_DIS #endif #define RX_NUMTR 77 /* tracks/disk */ @@ -176,14 +182,14 @@ UNIT ry_unit[] = { UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RY_SIZE) } }; REG ry_reg[] = { - { ORDATA (RYCS, ry_csr, 16) }, - { ORDATA (RYBA, ry_ba, 16) }, - { ORDATA (RYWC, ry_wc, 8) }, - { ORDATA (RYDB, ry_dbr, 16) }, - { ORDATA (RYES, ry_esr, 12) }, - { ORDATA (RYERR, ry_ecode, 8) }, - { ORDATA (RYTA, ry_track, 8) }, - { ORDATA (RYSA, ry_sector, 8) }, + { GRDATA (RYCS, ry_csr, DEV_RDX, 16, 0) }, + { GRDATA (RYBA, ry_ba, DEV_RDX, 16, 0) }, + { GRDATA (RYWC, ry_wc, DEV_RDX, 8, 0) }, + { GRDATA (RYDB, ry_dbr, DEV_RDX, 16, 0) }, + { GRDATA (RYES, ry_esr, DEV_RDX, 12, 0) }, + { GRDATA (RYERR, ry_ecode, DEV_RDX, 8, 0) }, + { GRDATA (RYTA, ry_track, DEV_RDX, 8, 0) }, + { GRDATA (RYSA, ry_sector, DEV_RDX, 8, 0) }, { DRDATA (STAPTR, ry_state, 4), REG_RO }, { FLDATA (INT, IREQ (RY), INT_V_RY) }, { FLDATA (ERR, ry_csr, RYCS_V_ERR) }, @@ -197,8 +203,8 @@ REG ry_reg[] = { { FLDATA (STOP_IOE, ry_stopioe, 0) }, { URDATA (CAPAC, ry_unit[0].capac, 10, T_ADDR_W, 0, RX_NUMDR, REG_HRO | PV_LEFT) }, - { ORDATA (DEVADDR, ry_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, ry_dib.vec, 16), REG_HRO }, + { GRDATA (DEVADDR, ry_dib.ba, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, ry_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } }; MTAB ry_mod[] = { @@ -224,10 +230,10 @@ MTAB ry_mod[] = { DEVICE ry_dev = { "RY", ry_unit, ry_reg, ry_mod, - RX_NUMDR, 8, 20, 1, 8, 8, + RX_NUMDR, DEV_RDX, 20, 1, DEV_RDX, 8, NULL, NULL, &ry_reset, &ry_boot, &ry_attach, NULL, - &ry_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_Q18 }; + &ry_dib, DEV_FLTA | DEV_DISABLE | DEV_DISI | DEV_UBUS | DEV_Q18 }; /* I/O dispatch routine, I/O addresses 17777170 - 17777172 @@ -520,12 +526,15 @@ return auto_config (0, 0); /* run autoconfig */ t_stat ry_attach (UNIT *uptr, char *cptr) { uint32 sz; +t_stat r; -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) { +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) { if (sz > RX_SIZE) uptr->flags = uptr->flags | UNIT_DEN; else uptr->flags = uptr->flags & ~UNIT_DEN; } uptr->capac = (uptr->flags & UNIT_DEN)? RY_SIZE: RX_SIZE; -return attach_unit (uptr, cptr); +return SCPE_OK; } /* Set size routine */ diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index b6f230f2..55b4d416 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -1,6 +1,6 @@ /* pdp11_sys.c: PDP-11 simulator interface - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index 943f7fca..8a59b6c4 100644 --- a/PDP11/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -25,6 +25,8 @@ tc TC11/TU56 DECtape + 25-Jan-04 RMS Revised for device debug support + 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR 29-Dec-03 RMS Changed initial status to disabled (in Qbus system) 18-Oct-03 RMS Fixed reverse checksum in read all Added DECtape off reel message @@ -253,10 +255,9 @@ /* Logging */ -#define LOG_MS 001 /* move, search */ -#define LOG_RW 002 /* read, write */ -#define LOG_RA 004 /* read all */ -#define LOG_BL 010 /* block # lblk */ +#define LOG_MS 0x1 +#define LOG_RW 0x2 +#define LOG_BL 0x4 #define DT_SETDONE tccm = tccm | CSR_DONE; \ if (tccm & CSR_IE) SET_INT (DTA) @@ -269,8 +270,7 @@ extern int32 int_req[IPL_HLVL]; extern int32 int_vec[IPL_HLVL][32]; extern UNIT cpu_unit; extern int32 sim_switches; -extern int32 cpu_log; -extern FILE *sim_log; +extern FILE *sim_deb; int32 tcst = 0; /* status */ int32 tccm = 0; /* command */ @@ -282,6 +282,7 @@ 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; t_stat dt_rd (int32 *data, int32 PA, int32 access); @@ -357,6 +358,7 @@ REG dt_reg[] = { DT_NUMDR, REG_RO) }, { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0, DT_NUMDR, REG_HRO) }, + { FLDATA (STOP_OFFR, dt_stopoffr, 0) }, { ORDATA (DEVADDR, dt_dib.ba, 32), REG_HRO }, { ORDATA (DEVVEC, dt_dib.vec, 16), REG_HRO }, { NULL } }; @@ -373,12 +375,19 @@ MTAB dt_mod[] = { &set_vec, &show_vec, NULL }, { 0 } }; +DEBTAB dt_deb[] = { + { "MOTION", LOG_MS }, + { "DATA", LOG_RW }, + { "BLOCK", LOG_BL }, + { NULL, 0 } }; + DEVICE dt_dev = { "TC", dt_unit, dt_reg, dt_mod, DT_NUMDR + 1, 8, 24, 1, 8, 18, NULL, NULL, &dt_reset, &dt_boot, &dt_attach, &dt_detach, - &dt_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS }; + &dt_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, 0, + dt_deb, NULL, NULL }; /* IO dispatch routines, I/O addresses 17777340 - 17777350 */ @@ -599,7 +608,7 @@ case FNC_SRCH: /* search */ 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 (DBG_LOG (LOG_TC_MS)) fprintf (sim_log, ">>DT%d: searching %s\n", + if (DEBUG_PRI (dt_dev, LOG_MS)) fprintf (sim_deb, ">>DT%d: searching %s\n", unum, (dir? "backward": "forward")); break; case FNC_WRIT: /* write */ @@ -617,8 +626,9 @@ case FNC_READ: /* read */ blk + 1: blk), uptr) - DT_HTLIN - DT_WSIZE; else newpos = DT_BLK2LN (((relpos < DT_HTLIN)? blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1); - if (DBG_LOG (LOG_TC_RW) || (DBG_LOG (LOG_TC_BL) && (blk == dt_logblk))) - fprintf (sim_log, ">>DT%d: %s block %d %s\n", + if (DEBUG_PRI (dt_dev, LOG_RW) || + (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) + fprintf (sim_deb, ">>DT%d: %s block %d %s\n", unum, ((fnc == FNC_READ)? "read": "write"), blk, (dir? "backward": "forward")); break; @@ -637,8 +647,9 @@ case FNC_WALL: /* write all */ else newpos = DT_BLK2LN (blk, uptr) + DT_CSMLN + (DT_WSIZE - 1); } if (fnc == FNC_WALL) sim_activate /* write all? */ (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */ - if (DBG_LOG (LOG_TC_RW) || (DBG_LOG (LOG_TC_BL) && (blk == dt_logblk))) - fprintf (sim_log, ">>DT%d: read all block %d %s\n", + if (DEBUG_PRI (dt_dev, LOG_RW) || + (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) + fprintf (sim_deb, ">>DT%d: read all block %d %s\n", unum, blk, (dir? "backward": "forward")); break; default: @@ -737,7 +748,8 @@ uint32 ba, ma, mma; switch (mot) { case DTS_DECF: case DTS_DECR: /* decelerating */ - if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */ + 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)); /* reversing */ @@ -757,7 +769,8 @@ default: /* other */ Off reel - detach unit (it must be deselected) */ -if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */ +if (dt_setpos (uptr)) /* upd pos; off reel? */ + return IORETURN (dt_stopoffr, STOP_DTOFF); if (DT_QEZ (uptr)) { /* in end zone? */ dt_seterr (uptr, STA_END); /* end zone error */ return SCPE_OK; } @@ -1090,7 +1103,7 @@ if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ else if (sim_switches & SWMASK ('T')) /* att 18b? */ uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); else if (!(sim_switches & SWMASK ('S')) && /* autosize? */ - ((sz = sim_fsize (cptr)) > D16_FILSIZ)) { + ((sz = sim_fsize (uptr->fileref)) > D16_FILSIZ)) { if (sz <= D8_FILSIZ) uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; else uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); } } diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index 8d7be404..8edc7620 100644 --- a/PDP11/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -25,6 +25,7 @@ tm TM11/TU10 magtape + 25-Jan-04 RMS Revised for device debug support 29-Dec-03 RMS Added 18b Qbus support 25-Apr-03 RMS Revised for extended file support 28-Mar-03 RMS Added multiformat support @@ -148,8 +149,7 @@ extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; extern int32 int_vec[IPL_HLVL][32]; -extern int32 cpu_log; -extern FILE *sim_log; +extern FILE *sim_deb; uint8 *tmxb = NULL; /* xfer buffer */ int32 tm_sta = 0; /* status register */ @@ -232,7 +232,7 @@ DEVICE tm_dev = { TM_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &tm_reset, &tm_boot, &tm_attach, &tm_detach, - &tm_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 }; + &tm_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG }; /* I/O dispatch routine, I/O addresses 17772520 - 17772532 @@ -384,7 +384,7 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */ tm_updcsta (uptr); /* update status */ return IORETURN (tm_stopioe, SCPE_UNATT); } -if (DBG_LOG (LOG_TM)) fprintf (sim_log, +if (DEBUG_PRS (tm_dev)) fprintf (sim_deb, ">>TM: op=%o, ma=%o, bc=%o, pos=%d\n", f, xma, cbc, uptr->pos); switch (f) { /* case on function */ @@ -449,7 +449,7 @@ tm_cmd = (tm_cmd & ~MTC_EMA) | ((xma >> (16 - MTC_V_EMA)) & MTC_EMA); tm_ca = xma & 0177777; /* update mem addr */ tm_set_done (); /* set done */ tm_updcsta (uptr); /* update status */ -if (DBG_LOG (LOG_TM)) fprintf (sim_log, +if (DEBUG_PRS (tm_dev)) fprintf (sim_deb, ">>TM: sta=%o, ma=%o, wc=%o, pos=%d\n", tm_sta, tm_ca, tm_bc, uptr->pos); return r; diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index d310372b..2dd4256b 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -1,6 +1,6 @@ /* pdp11_tq.c: TMSCP tape controller simulator - Copyright (c) 2002-2003, Robert M Supnik + Copyright (c) 2002-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ tq TQK50 tape controller + 26-Mar-04 RMS Fixed warnings with -std=c99 + 25-Jan-04 RMS Revised for device debug support 19-May-03 RMS Revised for new conditional compilation scheme 25-Apr-03 RMS Revised for extended file support 28-Mar-03 RMS Added multiformat support @@ -206,9 +208,8 @@ static struct drvtyp drv_tab[] = { extern int32 int_req[IPL_HLVL]; extern int32 tmr_poll, clk_tps; -extern int32 cpu_log; extern UNIT cpu_unit; -extern FILE *sim_log; +extern FILE *sim_deb; extern uint32 sim_taddr_64; uint8 *tqxb = NULL; /* xfer buffer */ @@ -441,7 +442,7 @@ DEVICE tq_dev = { TQ_NUMDR + 2, 10, 31, 1, DEV_RDX, 8, NULL, NULL, &tq_reset, &tq_boot, &tq_attach, &tq_detach, - &tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS }; + &tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; /* I/O dispatch routine, I/O addresses 17772150 - 17772152 @@ -470,7 +471,7 @@ t_stat tq_wr (int32 data, int32 PA, int32 access) switch ((PA >> 1) & 01) { /* decode PA<1> */ case 0: /* IP */ tq_reset (&tq_dev); /* init device */ - if (DBG_LOG (LOG_TQ)) fprintf (sim_log, + if (DEBUG_PRS (tq_dev)) fprintf (sim_deb, ">>TQ: initialization started, time=%.0f\n", sim_gtime ()); break; case 1: /* SA */ @@ -568,7 +569,7 @@ if (tq_csta < CST_UP) { /* still init? */ break; case CST_S4: /* need S4 reply */ if (tq_saw & SA_S4H_GO) { /* go set? */ - if (DBG_LOG (LOG_TQ)) fprintf (sim_log, + if (DEBUG_PRS (tq_dev)) fprintf (sim_deb, ">>TQ: initialization complete\n"); tq_csta = CST_UP; /* we're up */ tq_sa = 0; /* clear SA */ @@ -586,16 +587,16 @@ for (i = 0; i < TQ_NUMDR; i++) { /* chk unit q's */ if ((pkt == 0) && tq_pip) { /* polling? */ if (!tq_getpkt (&pkt)) return SCPE_OK; /* get host pkt */ if (pkt) { /* got one? */ - if (DBG_LOG (LOG_TQ)) { + if (DEBUG_PRS (tq_dev)) { UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); - fprintf (sim_log, ">>TQ: cmd=%04X, mod=%04X, unit=%d, ", + fprintf (sim_deb, ">>TQ: cmd=%04X, mod=%04X, unit=%d, ", tq_pkt[pkt].d[CMD_OPC], tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN]); - fprintf (sim_log, "bc=%04X%04X, ma=%04X%04X", + fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X", tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL], tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]); - if (up) fprintf (sim_log, ", pos=%d, obj=%d\n", up->pos, up->objp); - else fprintf (sim_log, "\n"); - fflush (sim_log); } + if (up) fprintf (sim_deb, ", pos=%d, obj=%d\n", up->pos, up->objp); + else fprintf (sim_deb, "\n"); + fflush (sim_deb); } if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ return tq_fatal (PE_PIE); /* no, term thread */ cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ @@ -1493,13 +1494,13 @@ t_bool tq_putpkt (int32 pkt, t_bool qt) uint32 addr, desc, lnt, cr; if (pkt == 0) return OK; /* any packet? */ -if (DBG_LOG (LOG_TQ)) { +if (DEBUG_PRS (tq_dev)) { UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); - fprintf (sim_log, ">>TQ: rsp=%04X, sts=%04X", + fprintf (sim_deb, ">>TQ: rsp=%04X, sts=%04X", tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]); - if (up) fprintf (sim_log, ", pos=%d, obj=%d\n", up->pos, up->objp); - else fprintf (sim_log, "\n"); - fflush (sim_log); } + if (up) fprintf (sim_deb, ", pos=%d, obj=%d\n", up->pos, up->objp); + else fprintf (sim_deb, "\n"); + fflush (sim_deb); } if (!tq_getdesc (&tq_rq, &desc)) return ERR; /* get rsp desc */ if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ if (qt) tq_enqt (&tq_rspq, pkt); /* normal? q tail */ @@ -1665,7 +1666,7 @@ return tq_dib.vec; /* prog vector */ t_bool tq_fatal (uint32 err) { -if (DBG_LOG (LOG_TQ)) fprintf (sim_log, ">>TQ: fatal err=%X\n", err); +if (DEBUG_PRS (tq_dev)) fprintf (sim_deb, ">>TQ: fatal err=%X\n", err); tq_reset (&tq_dev); /* reset device */ tq_sa = SA_ER | err; /* SA = dead code */ tq_csta = CST_DEAD; /* state = dead */ @@ -1982,7 +1983,7 @@ return SCPE_OK; /* Set controller type (and capacity for user-defined type) */ -tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc) { uint32 i, cap; uint32 max = sim_taddr_64? TQU_EMAXC: TQU_MAXC; @@ -2002,7 +2003,7 @@ return SCPE_OK; /* Show controller type (and capacity for user-defined type) */ -tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc) { fprintf (st, "%s", drv_tab[tq_typ].name); if (tq_typ == TQU_TYPE) fprintf (st, " (%dMB)", drv_tab[tq_typ].cap >> 20); diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index caa95439..8e42473b 100644 --- a/PDP11/pdp11_ts.c +++ b/PDP11/pdp11_ts.c @@ -1,6 +1,6 @@ /* pdp11_ts.c: TS11/TSV05 magnetic tape simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ ts TS11/TSV05 magtape + 25-Jan-04 RMS Revised for device debug support 19-May-03 RMS Revised for new conditional compilation scheme 25-Apr-03 RMS Revised for extended file support 28-Mar-03 RMS Added multiformat support @@ -270,10 +271,9 @@ extern int32 cpu_18b, cpu_ubm; extern int32 int_req[IPL_HLVL]; extern int32 int_vec[IPL_HLVL][32]; - extern UNIT cpu_unit; -extern int32 cpu_log; -extern FILE *sim_log; +extern FILE *sim_deb; + uint8 *tsxb = NULL; /* xfer buffer */ int32 tssr = 0; /* status register */ int32 tsba = 0; /* mem addr */ @@ -361,7 +361,7 @@ DEVICE ts_dev = { 1, 10, 31, 1, DEV_RDX, 8, NULL, NULL, &ts_reset, &ts_boot, &ts_attach, &ts_detach, - &ts_dib, DEV_DISABLE | TS_DIS | DEV_UBUS | DEV_QBUS }; + &ts_dib, DEV_DISABLE | TS_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; /* I/O dispatch routine, I/O addresses 17772520 - 17772522 @@ -658,8 +658,8 @@ if (!(cmdhdr & CMD_ACK)) { /* no acknowledge? */ return SCPE_OK; } fnc = GET_FNC (cmdhdr); /* get fnc+mode */ mod = GET_MOD (cmdhdr); -if (DBG_LOG (LOG_TS)) - fprintf (sim_log, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%d, pos=%d\n", +if (DEBUG_PRS (ts_dev)) + fprintf (sim_deb, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%d, pos=%d\n", fnc, mod, cmdadl, cmdlnt, ts_unit.pos); if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */ ts_endcmd (TC3, 0, 0); /* error */ @@ -879,8 +879,8 @@ if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */ tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0)); if (cmdhdr & CMD_IE) SET_INT (TS); ts_ownm = 0; ts_ownc = 0; -if (DBG_LOG (LOG_TS)) - fprintf (sim_log, ">>TS: sta=%o, tc=%o, rfc=%d, pos=%d\n", +if (DEBUG_PRS (ts_dev)) + fprintf (sim_deb, ">>TS: sta=%o, tc=%o, rfc=%d, pos=%d\n", msgxs0, GET_TC (tssr), msgrfc, ts_unit.pos); return; } diff --git a/PDP11/pdp11_uqssp.h b/PDP11/pdp11_uqssp.h index 257d41bc..77703740 100644 --- a/PDP11/pdp11_uqssp.h +++ b/PDP11/pdp11_uqssp.h @@ -1,6 +1,6 @@ /* pdp11_uqssp.h: Unibus/Qbus storage systems port definitions file - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Derived from work by Stephen F. Shirron Permission is hereby granted, free of charge, to any person obtaining a diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index 9d832d80..d60e0bdb 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -1,7 +1,7 @@ /* pdp11_xq.c: DEQNA/DELQA ethernet controller simulator ------------------------------------------------------------------------------ - Copyright (c) 2002-2003, David T. Hittner + Copyright (c) 2002-2004, 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"), @@ -46,29 +46,34 @@ seen by the simulated cpu since there are no minimum response times. Known Bugs or Unsupported features, in priority order: - 1) PDP11 (modified) bootrom loader [done! 10-Apr-03] - 2) Second controller [done! 05-May-03] - 3) Cannot split inbound packet into multiple buffers [done! 05-Jun-03] - 4) PDP11 bootstrap - 5) MOP functionality not implemented - 6) Local packet processing not implemented + 1) PDP11 bootstrap + 2) MOP functionality not implemented + 3) Local packet processing not implemented - Regression Tests used by the Author: - VAX: - 1. Console SHOW DEVICE - 2. VMS v7.2 boots/initializes/shows device - 3. VMS DECNET - SET HOST and COPY tests - 4. VMS MultiNet - SET HOST/TELNET and FTP tests - 5. VMS LAT - SET HOST/LAT tests - 6. VMS Cluster - SHOW CLUSTER, SHOW DEVICE, and cluster disk COPY tests - 7. Console boot into VMSCluster (>>>B XQAO) - PDP11: - 1. RT-11 v5.3 - FTPSB copy test + Regression Tests: + VAX: 1. Console SHOW DEVICE + 2. VMS v7.2 boots/initializes/shows device + 3. VMS DECNET - SET HOST and COPY tests + 4. VMS MultiNet - SET HOST/TELNET and FTP tests + 5. VMS LAT - SET HOST/LAT tests + 6. VMS Cluster - SHOW CLUSTER, SHOW DEVICE, and cluster COPY tests + 7. Console boot into VMSCluster (>>>B XQAO) + + PDP11: 1. RT-11 v5.3 - FTPSB copy test + 2. RSTS/E v10.1 - detects/enables device ------------------------------------------------------------------------------ Modification history: + 27-Feb-04 DTH Removed struct timeb deuggers + 31-Jan-04 DTH Replaced #ifdef debuggers with inline debugging + 19-Jan-04 DTH Combined service timers into one for efficiency + 16-Jan-04 DTH Added more info to SHOW MOD commands, added SET/SHOW XQ DEBUG + 13-Jan-04 DTH Corrected interrupt code with help from Tom Evans + 06-Jan-04 DTH Added protection against changing mac and type if attached + 05-Jan-04 DTH Moved most of xq_setmac to sim_ether + 26-Dec-03 DTH Moved ethernet show and queue functions to sim_ether 03-Dec-03 DTH Added minimum name length to show xq eth 25-Nov-03 DTH Reworked interrupts to fix broken XQB implementation 19-Nov-03 MP Rearranged timer reset sequencing to allow for a device to be @@ -195,31 +200,17 @@ ------------------------------------------------------------------------------ */ -/* compiler directives to help the Author keep the code clean :-) */ -#if defined (__BORLANDC__) -#pragma warn +8070 /* function should return value */ -/* #pragma warn +8071 *//* conversion may lose significant digits */ -#pragma warn +8075 /* suspicious pointer conversion */ -#pragma warn +8079 /* mixing different char pointers */ -#pragma warn +8080 /* variable declared but not used */ -#endif /* __BORLANDC__ */ - #include #include "pdp11_xq.h" #include "pdp11_xq_bootrom.h" -#define XQ_MAX_CONTROLLERS 2 /* maximum controllers allowed */ - -extern int32 int_req[IPL_HLVL]; extern int32 tmr_poll, clk_tps; -extern FILE *sim_log; +extern FILE* sim_deb; /* forward declarations */ t_stat xq_rd(int32* data, int32 PA, int32 access); t_stat xq_wr(int32 data, int32 PA, int32 access); t_stat xq_svc(UNIT * uptr); -t_stat xq_sansvc(UNIT * uptr); -t_stat xq_idsvc(UNIT * uptr); t_stat xq_reset (DEVICE * dptr); t_stat xq_attach (UNIT * uptr, char * cptr); t_stat xq_detach (UNIT * uptr); @@ -232,18 +223,16 @@ t_stat xq_show_type (FILE* st, UNIT* uptr, int32 val, void* desc); t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc); t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc); t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat xq_showeth (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xq_show_poll (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xq_set_poll (UNIT* uptr, int32 val, char* cptr, void* desc); t_stat xq_process_xbdl(CTLR* xq); t_stat xq_dispatch_xbdl(CTLR* xq); void xq_start_receiver(void); void xq_sw_reset(CTLR* xq); t_stat xq_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat xq_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -void xq_start_santmr(CTLR* xq); -void xq_cancel_santmr(CTLR* xq); void xq_reset_santmr(CTLR* xq); -t_stat xq_boot_host(void); -void xq_start_idtmr(CTLR* xq); +t_stat xq_boot_host(CTLR* xq); t_stat xq_system_id(CTLR* xq, const ETH_MAC dst, uint16 receipt_id); void xqa_read_callback(int status); void xqb_read_callback(int status); @@ -252,12 +241,14 @@ void xqb_write_callback(int status); void xq_setint (CTLR* xq); void xq_clrint (CTLR* xq); int32 xq_int (void); +void xq_csr_set_clr(CTLR* xq, uint16 set_bits, uint16 clear_bits); struct xq_device xqa = { xqa_read_callback, /* read callback routine */ xqa_write_callback, /* write callback routine */ {0x08, 0x00, 0x2B, 0xAA, 0xBB, 0xCC}, /* mac */ XQ_T_DELQA, /* type */ + XQ_SERVICE_INTERVAL, /* poll */ {0} /* sanity */ }; @@ -266,6 +257,7 @@ struct xq_device xqb = { xqb_write_callback, /* write callback routine */ {0x08, 0x00, 0x2B, 0xBB, 0xCC, 0xDD}, /* mac */ XQ_T_DELQA, /* type */ + XQ_SERVICE_INTERVAL, /* poll */ {0} /* sanity */ }; @@ -275,8 +267,6 @@ DIB xqa_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr, UNIT xqa_unit[] = { { UDATA (&xq_svc, UNIT_ATTABLE + UNIT_DISABLE, 2047) }, /* receive timer */ - { UDATA (&xq_sansvc, UNIT_DIS, 0) }, /* sanity timer */ - { UDATA (&xq_idsvc, UNIT_DIS, 0) } /* system id timer */ }; REG xqa_reg[] = { @@ -306,8 +296,6 @@ DIB xqb_dib = { IOBA_XQB, IOLN_XQB, &xq_rd, &xq_wr, UNIT xqb_unit[] = { { UDATA (&xq_svc, UNIT_ATTABLE + UNIT_DISABLE, 2047) }, /* receive timer */ - { UDATA (&xq_sansvc, UNIT_DIS, 0) }, /* sanity timer */ - { UDATA (&xq_idsvc, UNIT_DIS, 0) } /* system id timer */ }; REG xqb_reg[] = { @@ -337,35 +325,52 @@ MTAB xq_mod[] = { NULL, &show_addr, NULL }, { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC", + { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", &xq_setmac, &xq_showmac, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", NULL, - NULL, &xq_showeth, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "FILTERS", NULL, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH", + NULL, ð_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "FILTERS", "FILTERS", NULL, &xq_show_filters, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATS", "STATS", &xq_set_stats, &xq_show_stats, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE", + { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE={DEQNA|DELQA}", &xq_set_type, &xq_show_type, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "SANITY", "SANITY", + { MTAB_XTD | MTAB_VDV, 0, "POLL", "POLL={DEFAULT|4..2500]", + &xq_set_poll, &xq_show_poll, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "SANITY", "SANITY={ON|OFF}", &xq_set_sanity, &xq_show_sanity, NULL }, { 0 }, }; +DEBTAB xq_debug[] = { + {"TRACE", DBG_TRC}, + {"CSR", DBG_CSR}, + {"VAR", DBG_VAR}, + {"WARN", DBG_WRN}, + {"SETUP", DBG_SET}, + {"SANITY", DBG_SAN}, + {"REG", DBG_REG}, + {"PACKET", DBG_PCK}, + {"ETH", DBG_ETH}, + {0} +}; + DEVICE xq_dev = { "XQ", xqa_unit, xqa_reg, xq_mod, - 3, XQ_RDX, 11, 1, XQ_RDX, 16, + 1, XQ_RDX, 11, 1, XQ_RDX, 16, &xq_ex, &xq_dep, &xq_reset, NULL, &xq_attach, &xq_detach, - &xqa_dib, DEV_DISABLE | DEV_QBUS + &xqa_dib, DEV_DISABLE | DEV_QBUS | DEV_DEBUG, + 0, xq_debug }; DEVICE xqb_dev = { "XQB", xqb_unit, xqb_reg, xq_mod, - 3, XQ_RDX, 11, 1, XQ_RDX, 16, + 1, XQ_RDX, 11, 1, XQ_RDX, 16, &xq_ex, &xq_dep, &xq_reset, NULL, &xq_attach, &xq_detach, - &xqb_dib, DEV_DISABLE | DEV_DIS | DEV_QBUS + &xqb_dib, DEV_DISABLE | DEV_DIS | DEV_QBUS | DEV_DEBUG, + 0, xq_debug }; CTLR xq_ctrl[] = { @@ -373,8 +378,6 @@ CTLR xq_ctrl[] = { {&xqb_dev, xqb_unit, &xqb_dib, &xqb} /* XQB controller */ }; -#ifdef XQ_DEBUG - const char* const xq_recv_regnames[] = { "MAC0", "MAC1", "MAC2", "MAC3", "MAC4", "MAC5", "VAR", "CSR" }; @@ -384,116 +387,17 @@ const char* const xq_xmit_regnames[] = { }; const char* const xq_csr_bits[] = { - "RE ", "SR ", "NI ", "BD ", "XL ", "RL ", "IE ", "XI ", - "IL ", "EL ", "SE ", "RR ", "OK ", "CA ", "PE ", "RI" + "RE", "SR", "NI", "BD", "XL", "RL", "IE", "XI", + "IL", "EL", "SE", "RR", "OK", "CA", "PE", "RI" +}; + +const char* const xq_var_bits[] = { + "ID", "RR", "V0", "V1", "V2", "V3", "V4", "V5", + "V6", "V7", "S1", "S2", "S3", "RS", "OS", "MS" }; /* internal debugging routines */ void xq_debug_setup(CTLR* xq); -void xq_dump_csr(CTLR* xq); -void xq_dump_var(CTLR* xq); -void xq_csr_changes(CTLR* xq, uint16 data); -void xq_var_changes(CTLR* xq, uint16 data); - -/* sanity timer debugging */ -#include -struct timeb start, finish; - -#endif /* XQ_DEBUG */ - -/* -================================================================================ - Queue Management -================================================================================ -*/ - -t_stat xq_init_queue(CTLR* xq, struct xq_msg_que* que) -{ - /* create dynamic queue if it does not exist */ - if (!que->item) { - size_t size = sizeof(struct xq_msg_itm) * XQ_QUE_MAX; - que->item = malloc(size); - if (que->item) { - /* init dynamic memory */ - memset(que->item, 0, size); - } else { - /* failed to allocate memory */ - printf("%s: failed to allocate dynamic queue\n", xq->dev->name); - if (sim_log) fprintf(sim_log, "%s: failed to allocate dynamic queue\n", xq->dev->name); - return SCPE_MEM; - }; - }; - return SCPE_OK; -} - -void xq_clear_queue(struct xq_msg_que* que) -{ - int i; - struct xq_msg_itm* item; - - for (i = 0; i < XQ_QUE_MAX; i++) { - item = &que->item[i]; - item->type = 0; - item->packet.len = 0; - item->packet.used = 0; - item->status = 0; - }; - que->count = que->head = que->tail = que->loss = 0; -} - -void xq_remove_queue(struct xq_msg_que* que) -{ - struct xq_msg_itm* item = &que->item[que->head]; - - if (que->count) { - item->type = 0; - item->packet.len = 0; - item->packet.used = 0; - item->status = 0; - if (++que->head == XQ_QUE_MAX) - que->head = 0; - que->count--; - } -} - -void xq_insert_queue(struct xq_msg_que* que, int32 type, ETH_PACK* packet, int32 status) -{ - struct xq_msg_itm* 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 == XQ_QUE_MAX) - que->tail = 0; - if (++que->count > XQ_QUE_MAX) { - que->count = XQ_QUE_MAX; - /* lose oldest packet */ - if (++que->head == XQ_QUE_MAX) - que->head = 0; - que->loss++; -#ifdef XQ_DEBUG - fprintf(stderr, "Packet Lost\n"); -#endif - } - 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 = packet->len; - item->packet.used = 0; - memcpy(item->packet.msg, packet->msg, packet->len); - item->status = status; -} - -/* -================================================================================ -*/ /*============================================================================*/ @@ -504,7 +408,8 @@ CTLR* xq_unit2ctlr(UNIT* uptr) unsigned int i,j; for (i=0; inumunits; j++) - if (&xq_ctrl[i].unit[j] == uptr) return &xq_ctrl[i]; + if (&xq_ctrl[i].unit[j] == uptr) + return &xq_ctrl[i]; /* not found */ return 0; } @@ -513,7 +418,8 @@ CTLR* xq_dev2ctlr(DEVICE* dptr) { int i; for (i=0; ivar->mac, newmac, sizeof(ETH_MAC)); - /* calculate MAC checksum */ + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + status = eth_mac_scan(&xq->var->mac, cptr); + if (status != SCPE_OK) + return status; + + /* calculate mac checksum */ xq_make_checksum(xq); return SCPE_OK; } -t_stat xq_showeth (FILE* st, UNIT* uptr, int32 val, void* desc) -{ -#define XQ_MAX_LIST 10 - ETH_LIST list[XQ_MAX_LIST]; - int number = eth_devices(XQ_MAX_LIST, list); - - fprintf(st, "ETH devices:\n"); - if (number) { - int i, min, len; - for (i=0, min=0; i min) min = len; - for (i=0; ivar->stats; - int elements = sizeof(struct xq_stats)/sizeof(int); - int i; - for (i=0; ivar->stats, 0, sizeof(struct xq_stats)); -#endif + + if (cptr) { + /* set individual stats to passed parameter value */ + int init = atoi(cptr); + int* stat_array = (int*) &xq->var->stats; + int elements = sizeof(struct xq_stats)/sizeof(int); + int i; + for (i=0; ivar->stats, 0, sizeof(struct xq_stats)); + } return SCPE_OK; } @@ -712,6 +577,7 @@ t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc) { CTLR* xq = xq_unit2ctlr(uptr); if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; /* this assumes that the parameter has already been upcased */ if (!strcmp(cptr, "DEQNA")) xq->var->type = XQ_T_DEQNA; @@ -721,14 +587,42 @@ t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc) return SCPE_OK; } +t_stat xq_show_poll (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR* xq = xq_unit2ctlr(uptr); + fprintf(st, "poll=%d", xq->var->poll); + return SCPE_OK; +} + +t_stat xq_set_poll (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + CTLR* xq = xq_unit2ctlr(uptr); + if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + + /* this assumes that the parameter has already been upcased */ + if (!strcmp(cptr, "DEFAULT")) + xq->var->poll = XQ_SERVICE_INTERVAL; + else { + int newpoll = 0; + sscanf(cptr, "%d", &newpoll); + if ((newpoll >= 4) && (newpoll <= 2500)) + xq->var->poll = newpoll; + else + return SCPE_ARG; + } + + return SCPE_OK; +} + t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc) { CTLR* xq = xq_unit2ctlr(uptr); fprintf(st, "sanity="); switch (xq->var->sanity.enabled) { - case 0: fprintf(st, "OFF\n"); break; - case 1: fprintf(st, "ON\n"); break; + case 2: fprintf(st, "ON\n"); break; + default: fprintf(st, "OFF\n"); break; } return SCPE_OK; } @@ -737,27 +631,25 @@ t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc) { CTLR* xq = xq_unit2ctlr(uptr); if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; /* this assumes that the parameter has already been upcased */ - if (!strcmp(cptr, "ON")) xq->var->sanity.enabled = 1; + if (!strcmp(cptr, "ON")) xq->var->sanity.enabled = 2; else if (!strcmp(cptr, "OFF")) xq->var->sanity.enabled = 0; else return SCPE_ARG; return SCPE_OK; } +/*============================================================================*/ + t_stat xq_nxm_error(CTLR* xq) { -#ifdef XQ_DEBUG - fprintf(stderr,"%s: Non Existent Memory Error\n", xq->dev->name); -#endif + const uint16 set_bits = XQ_CSR_NI | XQ_CSR_XI | XQ_CSR_XL | XQ_CSR_RL; + sim_debug(DBG_WRN, xq->dev, "Non Existent Memory Error!\n"); + /* set NXM and associated bits in CSR */ - xq->var->csr |= (XQ_CSR_NI | XQ_CSR_XI | XQ_CSR_XL | XQ_CSR_RL); - - /* interrupt if required */ - if (xq->var->csr & XQ_CSR_IE) - xq_setint(xq); - + xq_csr_set_clr(xq, set_bits , 0); return SCPE_OK; } @@ -773,15 +665,13 @@ void xq_write_callback (CTLR* xq, int status) uint16 write_failure[2] = {XQ_DSC_C}; write_success[1] = TDR & 0x03FF; /* Does TDR get set on successful packets ?? */ write_failure[1] = TDR & 0x03FF; /* TSW2<09:00> */ - + xq->var->stats.xmit += 1; /* update write status words */ if (status == 0) { /* success */ wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_success, NOMAP); } else { /* failure */ -#ifdef XQ_DEBUG - fprintf(stderr, "%s: Packet Write Error\n", xq->dev->name); -#endif + sim_debug(DBG_WRN, xq->dev, "Packet Write Error!\n"); xq->var->stats.fail += 1; wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_failure, NOMAP); } @@ -791,9 +681,7 @@ void xq_write_callback (CTLR* xq, int status) } /* update csr */ - xq->var->csr |= XQ_CSR_XI; - if (xq->var->csr & XQ_CSR_IE) - xq_setint(xq); + xq_csr_set_clr(xq, XQ_CSR_XI, 0); /* reset sanity timer */ xq_reset_santmr(xq); @@ -824,17 +712,7 @@ t_stat xq_rd(int32* data, int32 PA, int32 access) CTLR* xq = xq_pa2ctlr(PA); int index = (PA >> 1) & 07; /* word index */ -#ifdef XQ_DEBUG - if (index != 7) -#if defined(VM_VAX) - fprintf (stderr,"%s: %s %08X %08X read: %X\n", - xq->dev->name, xq_recv_regnames[index], fault_PC, PSL, *data); -#else - fprintf (stderr,"%s: %s read: %X\n", - xq->dev->name, xq_recv_regnames[index], *data); -#endif /* VM_VAX */ -#endif - + sim_debug(DBG_REG, xq->dev, "xq_rd(PA=0x%08X [%s], access=%d)\n", PA, xq_recv_regnames[index], access); switch (index) { case 0: case 1: @@ -851,17 +729,12 @@ t_stat xq_rd(int32* data, int32 PA, int32 access) *data = 0xFF00 | xq->var->mac[index]; break; case 6: -#if 0 -#ifdef XQ_DEBUG - xq_dump_var(xq); -#endif -#endif + sim_debug_u16(DBG_VAR, xq->dev, xq_var_bits, xq->var->var, xq->var->var, 0); + sim_debug (DBG_VAR, xq->dev, ", vec = 0%o\n", (xq->var->var & XQ_VEC_IV)); *data = xq->var->var; break; case 7: -#ifdef XQ_DEBUG - xq_dump_csr(xq); -#endif + sim_debug_u16(DBG_CSR, xq->dev, xq_csr_bits, xq->var->csr, xq->var->csr, 1); *data = xq->var->csr; break; } @@ -877,12 +750,11 @@ t_stat xq_process_rbdl(CTLR* xq) int32 rstatus, wstatus; uint16 b_length, w_length, rbl; uint32 address; - struct xq_msg_itm* item; + ETH_ITEM* item; uint8* rbuf; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: CSR - Processing read\n", xq->dev->name); -#endif + sim_debug(DBG_TRC, xq->dev, "xq_process_rdbl\n"); + /* process buffer descriptors */ while(1) { @@ -894,7 +766,7 @@ t_stat xq_process_rbdl(CTLR* xq) /* invalid buffer? */ if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq->var->csr |= XQ_CSR_RL; + xq_csr_set_clr(xq, XQ_CSR_RL, 0); return SCPE_OK; } @@ -933,9 +805,7 @@ t_stat xq_process_rbdl(CTLR* xq) /* adjust runt packets */ if (rbl < ETH_MIN_PACKET) { xq->var->stats.runt += 1; -#ifdef XQ_DEBUG - printf("%s: Runt detected, size = %d\n", xq->dev->name, rbl); -#endif + sim_debug(DBG_WRN, xq->dev, "Runt detected, size = %d\n", rbl); /* pad runts with zeros up to minimum size - this allows "legal" (size - 60) processing of those weird short ARP packets that seem to occur occasionally */ memset(&item->packet.msg[rbl], 0, ETH_MIN_PACKET-rbl); @@ -945,9 +815,7 @@ t_stat xq_process_rbdl(CTLR* xq) /* adjust oversized packets */ if (rbl > ETH_MAX_PACKET) { xq->var->stats.giant += 1; -#ifdef XQ_DEBUG - printf("%s: Giant detected, size = %d\n", xq->dev->name, rbl); -#endif + sim_debug(DBG_WRN, xq->dev, "Giant detected, size=%d\n", rbl); /* trim giants down to maximum size - no documentation on how to handle the data loss */ item->packet.len = ETH_MAX_PACKET; rbl = ETH_MAX_PACKET; @@ -955,7 +823,6 @@ t_stat xq_process_rbdl(CTLR* xq) }; /* make sure entire packet fits in buffer - if not, will need to split into multiple buffers */ - /* assert(rbl <= b_length); */ /* abort if packet won't fit into single buffer */ if (rbl > b_length) rbl = b_length; item->packet.used += rbl; @@ -987,9 +854,7 @@ t_stat xq_process_rbdl(CTLR* xq) xq->var->rbdl_buf[4] |= 0xC000; /* not last segment */ xq->var->rbdl_buf[5] = ((rbl & 0x00FF) << 8) | (rbl & 0x00FF); if (xq->var->ReadQ.loss) { -#ifdef XQ_DEBUG - fprintf(stderr, "%s: ReadQ overflow\n", xq->dev->name); -#endif + sim_debug(DBG_WRN, xq->dev, "ReadQ overflow!\n"); xq->var->rbdl_buf[4] |= 0x0001; /* set overflow bit */ xq->var->ReadQ.loss = 0; /* reset loss counter */ } @@ -1000,15 +865,10 @@ t_stat xq_process_rbdl(CTLR* xq) /* remove packet from queue */ if (item->packet.used >= item->packet.len) - xq_remove_queue(&xq->var->ReadQ); - - /* reset sanity timer */ - xq_reset_santmr(xq); + ethq_remove(&xq->var->ReadQ); /* mark transmission complete */ - xq->var->csr |= XQ_CSR_RI; - if (xq->var->csr & XQ_CSR_IE) - xq_setint(xq); + xq_csr_set_clr(xq, XQ_CSR_RI, 0); /* set to next bdl (implicit chain) */ xq->var->rbdl_ba += 12; @@ -1026,9 +886,8 @@ t_stat xq_process_mop(CTLR* xq) struct xq_meb* meb = (struct xq_meb*) &xq->var->write_buffer.msg[0200]; const struct xq_meb* limit = (struct xq_meb*) &xq->var->write_buffer.msg[0400]; -#ifdef XQ_DEBUG - fprintf(stderr, "%s: Processing MOP data\n", xq->dev->name); -#endif + sim_debug(DBG_TRC, xq->dev, "xq_process_mop()\n"); + if (xq->var->type == XQ_T_DEQNA) /* DEQNA's don't MOP */ return SCPE_NOFNC; @@ -1037,10 +896,7 @@ t_stat xq_process_mop(CTLR* xq) size = (meb->siz_hi << 8) || meb->siz_lo; /* MOP stuff here - NOT YET FULLY IMPLEMENTED */ - -#ifdef XQ_DEBUG - printf("%s: Processing MEB type: %d\n", xq->dev->name, meb->type); -#endif + sim_debug (DBG_WRN, xq->dev, "Processing MEB type: %d\n", meb->type); switch (meb->type) { case 0: /* MOP Termination */ break; @@ -1082,6 +938,8 @@ t_stat xq_process_setup(CTLR* xq) ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; ETH_MAC filters[XQ_FILTER_MAX + 1]; + sim_debug(DBG_TRC, xq->dev, "xq_process_setup()\n"); + /* extract filter addresses from setup packet */ memset(xq->var->setup.macs, '\0', sizeof(xq->var->setup.macs)); for (i = 0; i < 7; i++) @@ -1134,6 +992,7 @@ t_stat xq_process_setup(CTLR* xq) case 3: xq->var->setup.l3 = 0; break; } /* switch */ } /* if led */ + /* set sanity timer timeout */ san = (len & XQ_SETUP_ST) >> 4; switch(san) { @@ -1147,12 +1006,16 @@ t_stat xq_process_setup(CTLR* xq) case 7: secs = 64 * 60; break; /* 64 minutes */ } xq->var->sanity.quarter_secs = (int) (secs * 4); + xq->var->sanity.max = (int) (secs * xq->var->poll); + } - /* if sanity timer enabled, start sanity timer */ - if (xq->var->csr & XQ_CSR_SE || xq->var->sanity.enabled) - xq_start_santmr(xq); + /* finalize sanity timer state */ + xq->var->sanity.timer = xq->var->sanity.max; + if (xq->var->sanity.enabled != 2) { + if (xq->var->csr & XQ_CSR_SE) + xq->var->sanity.enabled = 1; else - xq_cancel_santmr(xq); + xq->var->sanity.enabled = 0; } /* set ethernet filter */ @@ -1169,9 +1032,8 @@ t_stat xq_process_setup(CTLR* xq) /* mark setup block valid */ xq->var->setup.valid = 1; -#ifdef XQ_DEBUG - xq_debug_setup(xq); -#endif + if (sim_deb && (xq->dev->dctrl & DBG_SET)) + xq_debug_setup(xq); return SCPE_OK; } @@ -1186,15 +1048,13 @@ t_stat xq_process_xbdl(CTLR* xq) { const uint16 implicit_chain_status[2] = {XQ_DSC_V | XQ_DSC_C, 1}; const uint16 write_success[2] = {0, 1 /*Non-Zero TDR*/}; - uint16 b_length, w_length; int32 rstatus, wstatus; uint32 address; t_stat status; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: xq_process_xbdl - Processing write\n", xq->dev->name); -#endif + sim_debug(DBG_TRC, xq->dev, "xq_process_xbdl()\n"); + /* clear write buffer */ xq->var->write_buffer.len = 0; @@ -1209,18 +1069,11 @@ t_stat xq_process_xbdl(CTLR* xq) /* invalid buffer? */ if (~xq->var->xbdl_buf[1] & XQ_DSC_V) { - xq->var->csr |= XQ_CSR_XL; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: xq_process_xbdl - List Empty - Done Processing write\n", xq->dev->name); -#endif + xq_csr_set_clr(xq, XQ_CSR_XL, 0); + sim_debug(DBG_WRN, xq->dev, "XBDL List empty\n"); return SCPE_OK; } -#ifdef XQ_DEBUG - fprintf(stderr,"%s: xq_process_xbdl: Buffer Descriptor Information: %04X %04X %04X %04X %04X \n", - xq->dev->name, xq->var->xbdl_buf[1], xq->var->xbdl_buf[2], - xq->var->xbdl_buf[3], xq->var->xbdl_buf[4], xq->var->xbdl_buf[5]); -#endif /* compute host memory address */ address = ((xq->var->xbdl_buf[1] & 0x3F) << 16) | xq->var->xbdl_buf[2]; @@ -1233,9 +1086,7 @@ t_stat xq_process_xbdl(CTLR* xq) /* explicit chain buffer? */ if (xq->var->xbdl_buf[1] & XQ_DSC_C) { xq->var->xbdl_ba = address; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: xq_process_xbdl: Chained Buffer Encountered: %d\n", xq->dev->name, b_length); -#endif + sim_debug(DBG_WRN, xq->dev, "XBDL chained buffer encountered: %d\n", b_length); continue; } @@ -1254,10 +1105,10 @@ t_stat xq_process_xbdl(CTLR* xq) status = xq_process_setup(xq); /* put packet in read buffer */ - xq_insert_queue (&xq->var->ReadQ, 0, &xq->var->write_buffer, status); + ethq_insert (&xq->var->ReadQ, 0, &xq->var->write_buffer, status); } else { /* loopback */ /* put packet in read buffer */ - xq_insert_queue (&xq->var->ReadQ, 1, &xq->var->write_buffer, 0); + ethq_insert (&xq->var->ReadQ, 1, &xq->var->write_buffer, 0); } /* update write status */ @@ -1271,9 +1122,7 @@ t_stat xq_process_xbdl(CTLR* xq) xq_reset_santmr(xq); /* mark transmission complete */ - xq->var->csr |= XQ_CSR_XI; - if (xq->var->csr & XQ_CSR_IE) - xq_setint(xq); + xq_csr_set_clr(xq, XQ_CSR_XI, 0); /* now trigger "read" of setup or loopback packet */ if (~xq->var->csr & XQ_CSR_RL) @@ -1284,19 +1133,17 @@ t_stat xq_process_xbdl(CTLR* xq) status = eth_write(xq->var->etherface, &xq->var->write_buffer, xq->var->wcallback); if (status != SCPE_OK) /* not implemented or unattached */ xq_write_callback(xq, 1); /* fake failure */ +#if 0 else xq_svc(&xq->unit[0]); /* service any received data */ -#ifdef XQ_DEBUG - fprintf(stderr,"%s: xq_process_xbdl: Completed Processing write\n", xq->dev->name); #endif + sim_debug(DBG_WRN, xq->dev, "XBDL completed processing write\n"); return SCPE_OK; } /* loopback/non-loopback */ } else { /* not at end-of-message */ -#ifdef XQ_DEBUG - fprintf(stderr,"%s: xq_process_xbdl: Processing Implicit Chained Buffer Segment\n", xq->dev->name); -#endif + sim_debug(DBG_WRN, xq->dev, "XBDL processing implicit chain buffer segment\n"); /* update bdl status words */ wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) implicit_chain_status, NOMAP); if(wstatus) return xq_nxm_error(xq); @@ -1314,12 +1161,10 @@ t_stat xq_dispatch_rbdl(CTLR* xq) int32 rstatus, wstatus; t_stat status; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: CSR - Dispatching read\n", xq->dev->name); -#endif + sim_debug(DBG_TRC, xq->dev, "xq_dispatch_rbdl()\n"); /* mark receive bdl valid */ - xq->var->csr &= ~XQ_CSR_RL; + xq_csr_set_clr(xq, 0, XQ_CSR_RL); /* init receive bdl buffer */ for (i=0; i<6; i++) @@ -1336,7 +1181,7 @@ t_stat xq_dispatch_rbdl(CTLR* xq) /* is buffer valid? */ if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq->var->csr |= XQ_CSR_RL; + xq_csr_set_clr(xq, XQ_CSR_RL, 0); return SCPE_OK; } @@ -1351,11 +1196,11 @@ t_stat xq_dispatch_xbdl(CTLR* xq) { int i; t_stat status; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: CSR - Dispatching write\n", xq->dev->name); -#endif + + sim_debug(DBG_TRC, xq->dev, "xq_dispatch_xbdl()\n"); + /* mark transmit bdl valid */ - xq->var->csr &= ~XQ_CSR_XL; + xq_csr_set_clr(xq, 0, XQ_CSR_XL); /* initialize transmit bdl buffers */ for (i=0; i<6; i++) @@ -1381,6 +1226,8 @@ t_stat xq_process_loopback(CTLR* xq, ETH_PACK* pack) int offset = pack->msg[14] | (pack->msg[15] << 8); int function = pack->msg[offset] | (pack->msg[offset+1] << 8); + sim_debug(DBG_TRC, xq->dev, "xq_process_loopback()\n"); + if (function != 2 /*forward*/) return SCPE_NOFNC; @@ -1408,6 +1255,8 @@ t_stat xq_process_remote_console (CTLR* xq, ETH_PACK* pack) uint16 receipt; int code = pack->msg[16]; + sim_debug(DBG_TRC, xq->dev, "xq_process_remote_console()\n"); + switch (code) { case 0x05: /* request id */ receipt = pack->msg[18] | (pack->msg[19] << 8); @@ -1432,7 +1281,7 @@ t_stat xq_process_remote_console (CTLR* xq, ETH_PACK* pack) have a mechanism to pass these to the host, so just reboot. */ - status = xq_boot_host(); + status = xq_boot_host(xq); return status; break; } /* switch */ @@ -1446,6 +1295,7 @@ t_stat xq_process_local (CTLR* xq, ETH_PACK* pack) otherwise returns SCPE_NOFNC or some other code */ int protocol; + sim_debug(DBG_TRC, xq->dev, "xq_process_local()\n"); /* DEQNA's have no local processing capability */ if (xq->var->type == XQ_T_DEQNA) return SCPE_NOFNC; @@ -1472,12 +1322,10 @@ void xq_read_callback(CTLR* xq, int status) /* add packet to read queue */ if (status != SCPE_OK) - xq_insert_queue(&xq->var->ReadQ, 2, &xq->var->read_buffer, status); + ethq_insert(&xq->var->ReadQ, 2, &xq->var->read_buffer, status); + } else { + sim_debug(DBG_WRN, xq->dev, "packet received with receiver disabled\n"); } -#ifdef XQ_DEBUG - else - fprintf(stderr, "%s: packet received with receiver disabled\n", xq->dev->name); -#endif } void xqa_read_callback(int status) @@ -1492,23 +1340,22 @@ void xqb_read_callback(int status) void xq_sw_reset(CTLR* xq) { + const uint16 set_bits = XQ_CSR_XL | XQ_CSR_RL; int i; - /* cancel all timers (ethernet, sanity, system_id) */ - for (i=0; i<3; i++) - sim_cancel(&xq->unit[i]); + sim_debug(DBG_TRC, xq->dev, "xq_sw_reset()\n"); /* reset csr bits */ - xq->var->csr = XQ_CSR_XL | XQ_CSR_RL; + xq_csr_set_clr(xq, set_bits, (uint16) ~set_bits); if (xq->var->etherface) - xq->var->csr |= XQ_CSR_OK; + xq_csr_set_clr(xq, XQ_CSR_OK, 0); - /* clear CPU interrupts */ + /* clear interrupt unconditionally */ xq_clrint(xq); /* flush read queue */ - xq_clear_queue(&xq->var->ReadQ); + ethq_clear(&xq->var->ReadQ); /* clear setup info */ xq->var->setup.multicast = 0; @@ -1531,11 +1378,9 @@ void xq_sw_reset(CTLR* xq) t_stat xq_wr_var(CTLR* xq, int32 data) { - -#ifdef XQ_DEBUG - xq_var_changes(xq, data); -#endif - + uint16 save_var = xq->var->var; + sim_debug(DBG_REG, xq->dev, "xq_wr_var(data= 0x%08X\n", data); + switch (xq->var->type) { case XQ_T_DEQNA: xq->var->var = (data & XQ_VEC_IV); @@ -1555,6 +1400,8 @@ t_stat xq_wr_var(CTLR* xq, int32 data) else xq->dib->vec = 0; + sim_debug_u16(DBG_VAR, xq->dev, xq_var_bits, save_var, xq->var->var, 1); + return SCPE_OK; } @@ -1580,9 +1427,7 @@ t_stat xq_process_bootrom (CTLR* xq) uint8* bootrom = (uint8*) xq_bootrom; int i, checksum; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: CSR - Processing boot rom load\n", xq->dev->name); -#endif + sim_debug(DBG_TRC, xq->dev, "xq_process_bootrom()\n"); /* RSTS/E v10.1 invokes the Citizenship tests in the Bootrom. For some @@ -1621,7 +1466,7 @@ t_stat xq_process_bootrom (CTLR* xq) /* invalid buffer? */ if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq->var->csr |= XQ_CSR_RL; + xq_csr_set_clr(xq, XQ_CSR_RL, 0); return SCPE_OK; } @@ -1632,10 +1477,6 @@ t_stat xq_process_bootrom (CTLR* xq) /* get host memory address */ address = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2]; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: BootRom1 load address: 0%o\n", xq->dev->name, address); -#endif - /* decode buffer length - two's complement (in words) */ w_length = ~xq->var->rbdl_buf[3] + 1; b_length = w_length * 2; @@ -1670,7 +1511,7 @@ t_stat xq_process_bootrom (CTLR* xq) /* invalid buffer? */ if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq->var->csr |= XQ_CSR_RL; + xq_csr_set_clr(xq, XQ_CSR_RL, 0); return SCPE_OK; } @@ -1681,10 +1522,6 @@ t_stat xq_process_bootrom (CTLR* xq) /* get host memory address */ address = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2]; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: BootRom2 load address: 0%o\n", xq->dev->name, address); -#endif - /* decode buffer length - two's complement (in words) */ w_length = ~xq->var->rbdl_buf[3] + 1; b_length = w_length * 2; @@ -1722,7 +1559,7 @@ t_stat xq_process_bootrom (CTLR* xq) /* invalid buffer? */ if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq->var->csr |= XQ_CSR_RL; + xq_csr_set_clr(xq, XQ_CSR_RL, 0); return SCPE_OK; } @@ -1746,9 +1583,7 @@ t_stat xq_process_bootrom (CTLR* xq) /* --------------------------- Done, finish up -----------------------------*/ /* mark transmission complete */ - xq->var->csr |= XQ_CSR_RI; - if (xq->var->csr & XQ_CSR_IE) - xq_setint(xq); + xq_csr_set_clr(xq, XQ_CSR_RI, 0); /* reset sanity timer */ xq_reset_santmr(xq); @@ -1759,15 +1594,12 @@ t_stat xq_process_bootrom (CTLR* xq) t_stat xq_wr_csr(CTLR* xq, int32 data) { -#ifdef VM_PDP11 - static const uint16 bd_bits_on = XQ_CSR_BD | XQ_CSR_EL; -#endif - int old_int_state, new_int_state; - const uint16 saved_csr = xq->var->csr; + uint16 set_bits = data & XQ_CSR_RW; /* set RW set bits */ + uint16 clr_bits = ((data ^ XQ_CSR_RW) & XQ_CSR_RW) /* clear RW cleared bits */ + | (data & XQ_CSR_W1) /* write 1 to clear bits */ + | ((data & XQ_CSR_XI) ? XQ_CSR_NI : 0); /* clearing XI clears NI */ -#ifdef XQ_DEBUG - xq_csr_changes(xq, data); -#endif + sim_debug(DBG_REG, xq->dev, "xq_wr_csr(data=0x%08X)\n", data); /* reset controller when SR transitions to cleared */ if (xq->var->csr & XQ_CSR_SR & ~data) { @@ -1775,33 +1607,22 @@ t_stat xq_wr_csr(CTLR* xq, int32 data) return SCPE_OK; } - /* write the writeable bits */ - xq->var->csr = (xq->var->csr & XQ_CSR_RO) | (data & XQ_CSR_RW); - - /* clear write-one-to-clear bits */ - xq->var->csr &= ~(data & XQ_CSR_W1); - if (data & XQ_CSR_XI) /* clearing XI clears NI too */ - xq->var->csr &= ~XQ_CSR_NI; - - /* start receiver timer when RE transitions to set */ - if (~saved_csr & XQ_CSR_RE & data) { - sim_activate(&xq->unit[0], (clk_tps * tmr_poll)/100); +#if 0 /* controller should ALWAYS have an active timer if enabled (for HW sanity) */ + /* start/stop receive timer when RE transitions */ + if ((xq->var->csr ^ data) & XQ_CSR_RE) { + if (data & XQ_CSR_RE) + sim_activate(&xq->unit[0], (clk_tps * tmr_poll)/xq->var->poll); + else + sim_cancel(&xq->unit[0]); } +#endif - /* stop receiver timer when RE transitions to clear */ - if (saved_csr & XQ_CSR_RE & ~data) { - sim_cancel(&xq->unit[0]); - } - - /* check and correct CPU interrupt state */ - old_int_state = (saved_csr & XQ_CSR_IE) && (saved_csr & (XQ_CSR_XI | XQ_CSR_RI)); - new_int_state = (xq->var->csr & XQ_CSR_IE) && (xq->var->csr & (XQ_CSR_XI | XQ_CSR_RI)); - if ( old_int_state && !new_int_state) xq_clrint(xq); - if (!old_int_state && new_int_state) xq_setint(xq); + /* update CSR bits */ + xq_csr_set_clr (xq, set_bits, clr_bits); #ifdef VM_PDP11 /* request boot/diagnostic rom? [PDP-11 only] */ - if ((bd_bits_on & data) == bd_bits_on) /* all bits must be on */ + if ((xq->var->csr & XQ_CSR_BP) == XQ_CSR_BP) /* all bits must be on */ xq_process_bootrom(xq); #endif @@ -1814,14 +1635,7 @@ t_stat xq_wr(int32 data, int32 PA, int32 access) CTLR* xq = xq_pa2ctlr(PA); int index = (PA >> 1) & 07; /* word index */ -#ifdef XQ_DEBUG - if (index != 7) - fprintf (stderr,"%s: %s", xq->dev->name, xq_xmit_regnames[index]); -#if defined(VM_VAX) - fprintf (stderr," %08X %08X", fault_PC, PSL); -#endif /* VM_VAX */ - fprintf (stderr," write: %X\n", data); -#endif + sim_debug(DBG_REG, xq->dev, "xq_wr(data=0x%08X, PA=0x%08X[%s], access=%d)\n", data, PA, xq_xmit_regnames[index], access); switch (index) { case 0: /* these should not be written */ @@ -1857,6 +1671,11 @@ t_stat xq_reset(DEVICE* dptr) { t_stat status; CTLR* xq = xq_dev2ctlr(dptr); + const uint16 set_bits = XQ_CSR_RL | XQ_CSR_XL; + /* must be recalculated each time since tmr_poll is a dynamic number */ + const int32 one_second = clk_tps * tmr_poll; + + sim_debug(DBG_TRC, xq->dev, "xq_reset()\n"); /* calculate MAC checksum */ xq_make_checksum(xq); @@ -1873,113 +1692,50 @@ t_stat xq_reset(DEVICE* dptr) xq->dib->vec = 0; /* init control status register */ - xq->var->csr = XQ_CSR_RL | XQ_CSR_XL; + xq_csr_set_clr(xq, set_bits, (uint16) ~set_bits); + + /* clear interrupts unconditionally */ + xq_clrint(xq); /* init read queue (first time only) */ - status = xq_init_queue (xq, &xq->var->ReadQ); + status = ethq_init(&xq->var->ReadQ, XQ_QUE_MAX); if (status != SCPE_OK) return status; /* clear read queue */ - xq_clear_queue(&xq->var->ReadQ); + ethq_clear(&xq->var->ReadQ); /* reset ethernet interface */ if (xq->var->etherface) { status = eth_filter (xq->var->etherface, 1, &xq->var->mac, 0, 0); - xq->var->csr |= XQ_CSR_OK; + xq_csr_set_clr(xq, XQ_CSR_OK, 0); - /* start sanity timer if power-on SANITY is set */ - switch (xq->var->type) { - case XQ_T_DEQNA: - if (xq->var->sanity.enabled) { - xq->var->sanity.quarter_secs = 4 * (4 * 60); /* default is 4 minutes */; - xq_start_santmr(xq); - } - break; - case XQ_T_DELQA: - /* note that the DELQA in NORMAL mode has no power-on SANITY state! */ - xq_start_idtmr(xq); - break; - }; + /* start service timer */ + sim_activate(&xq->unit[0], one_second/xq->var->poll); } - + /* set hardware sanity controls */ + if (xq->var->sanity.enabled) { + xq->var->sanity.quarter_secs = XQ_HW_SANITY_SECS * 4/*qsec*/; + xq->var->sanity.max = XQ_HW_SANITY_SECS * xq->var->poll; + } return SCPE_OK; } -void xq_start_santmr(CTLR* xq) -{ - UNIT* xq_santmr = &xq->unit[1]; /* sanity timer uses unit 1 */ - - /* must be recalculated each time since tmr_poll is a dynamic number */ - const int32 quarter_sec = (clk_tps * tmr_poll) / 4; - -#ifdef XQ_DEBUG - fprintf(stderr,"%s: SANITY TIMER ENABLED, qsecs: %d, poll:%d\n", - xq->dev->name, xq->var->sanity.quarter_secs, tmr_poll); -#endif - if (sim_is_active(xq_santmr)) /* cancel timer, just in case */ - sim_cancel(xq_santmr); - xq_reset_santmr(xq); - sim_activate(xq_santmr, quarter_sec); -} - -void xq_cancel_santmr(CTLR* xq) -{ - UNIT* xq_santmr = &xq->unit[1]; /* sanity timer uses unit 1 */ - - /* can't cancel hardware switch sanity timer */ - if (sim_is_active(xq_santmr) && !xq->var->sanity.enabled) { -#if 0 -#ifdef XQ_DEBUG - fprintf(stderr,"%s: SANITY TIMER CANCELLED, qsecs: %d\n", - xq->dev->name, xq->var->sanity.quarter_secs); -#endif -#endif - sim_cancel(xq_santmr); - } -} - void xq_reset_santmr(CTLR* xq) { -#if 0 -#ifdef XQ_DEBUG - ftime(&start); - fprintf(stderr,"%s: SANITY TIMER RESETTING, qsecs: %d\n", - xq->dev->name, xq->var->sanity.quarter_secs); -#endif -#endif - xq->var->sanity.countdown = xq->var->sanity.quarter_secs; -} + sim_debug(DBG_TRC, xq->dev, "xq_reset_santmr()\n"); + if (xq->var->sanity.enabled) { + sim_debug(DBG_SAN, xq->dev, "SANITY TIMER RESETTING, qsecs: %d\n", xq->var->sanity.quarter_secs); -t_stat xq_sansvc(UNIT* uptr) -{ - CTLR* xq = xq_unit2ctlr(uptr); - UNIT* xq_santmr = &xq->unit[1]; /* sanity timer uses unit 1 */ - - if (--xq->var->sanity.countdown) { - /* must be recalculated each time since tmr_poll is a dynamic number */ - const int32 quarter_sec = (clk_tps * tmr_poll) / 4; - - /* haven't hit the end of the countdown timer yet, resubmit */ - sim_activate(xq_santmr, quarter_sec); - } else { - /* - If this section is entered, it means that the sanity timer has expired - without being reset, and the controller must reboot the processor. - */ -#ifdef XQ_DEBUG - ftime(&finish); - fprintf(stderr,"%s: SANITY TIMER EXPIRED, qsecs: %d, poll: %d, elapsed: %d\n", - xq->dev->name, xq->var->sanity.quarter_secs, tmr_poll, finish.time - start.time); -#endif - xq_boot_host(); + /* reset sanity countdown timer to max count */ + xq->var->sanity.timer = xq->var->sanity.max; } - return SCPE_OK; } -t_stat xq_boot_host(void) +t_stat xq_boot_host(CTLR* xq) { + sim_debug(DBG_TRC, xq->dev, "xq_boot_host()\n"); /* The manual says the hardware should force the Qbus BDCOK low for 3.6 microseconds, which will cause the host to reboot. @@ -1991,21 +1747,6 @@ t_stat xq_boot_host(void) return STOP_SANITY; } -void xq_start_idtmr(CTLR* xq) -{ - UNIT* xq_idtmr = &xq->unit[2]; /* system id timer uses unit 2 */ - - /* must be recalculated each time since tmr_poll is a dynamic number */ - const int32 one_sec = clk_tps * tmr_poll; - - if (sim_is_active(xq_idtmr)) /* cancel timer, just in case */ - sim_cancel(xq_idtmr); - xq->var->id.enabled = 1; - /* every 8-10 minutes (9 in this case) the DELQA broadcasts a system id message */ - xq->var->id.countdown = 9 * 60; - sim_activate(xq_idtmr, one_sec); -} - t_stat xq_system_id (CTLR* xq, const ETH_MAC dest, uint16 receipt_id) { static uint16 receipt = 0; @@ -2013,9 +1754,10 @@ t_stat xq_system_id (CTLR* xq, const ETH_MAC dest, uint16 receipt_id) uint8* const msg = &system_id.msg[0]; t_stat status; -#ifdef XQ_DEBUG - fprintf(stderr,"%s: SYSTEM ID BROADCAST\n", xq->dev->name); -#endif + sim_debug(DBG_TRC, xq->dev, "xq_system_id()\n"); + if (xq->var->type != XQ_T_DELQA) /* DELQA-only function */ + return SCPE_NOFNC; + memset (&system_id, 0, sizeof(system_id)); memcpy (&msg[0], dest, sizeof(ETH_MAC)); memcpy (&msg[6], xq->var->setup.valid ? xq->var->setup.macs[0] : xq->var->mac, sizeof(ETH_MAC)); @@ -2067,73 +1809,60 @@ t_stat xq_system_id (CTLR* xq, const ETH_MAC dest, uint16 receipt_id) return status; } -t_stat xq_idsvc(UNIT* uptr) -{ - CTLR* xq = xq_unit2ctlr(uptr); - UNIT* xq_idtmr = &xq->unit[2]; /* system id timer uses unit 2 */ - - /* must be recalculated each time since tmr_poll is a dynamic number */ - const int32 one_sec = clk_tps * tmr_poll; - const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00}; - - /* DEQNAs don't issue system id messages */ - if (xq->var->type == XQ_T_DEQNA) - return SCPE_NOFNC; - - if (--xq->var->id.countdown <= 0) { - /* - If this section is entered, it means that the 9 minute interval has elapsed - so broadcast system id to MOP multicast address - */ - xq_system_id(xq, mop_multicast, 0); - /* every 8-10 minutes (9 in this case) the DELQA broadcasts a system id message */ - xq->var->id.countdown = 9 * 60; - } - - /* resubmit - for one second to get a well calibrated value of tmr_poll */ - sim_activate(xq_idtmr, one_sec); - return SCPE_OK; -} - /* ** service routine - used for ethernet reading loop */ t_stat xq_svc(UNIT* uptr) { - t_stat status; - int queue_size; CTLR* xq = xq_unit2ctlr(uptr); - UNIT* xq_svctmr = &xq->unit[0]; - /* Don't try a read if the receiver is disabled */ - if (!(xq->var->csr & XQ_CSR_RE)) return SCPE_OK; + /* must be recalculated each time since tmr_poll is a dynamic number */ + const int32 one_second = clk_tps * tmr_poll; - /* First pump any queued packets into the system */ - if ((xq->var->ReadQ.count > 0) && (~xq->var->csr & XQ_CSR_RL)) - status = xq_process_rbdl(xq); + /* if the receiver is enabled */ + if (xq->var->csr & XQ_CSR_RE) { + t_stat status; + int queue_size; - /* Now read and queue packets that have arrived */ - /* This is repeated as long as they are available and we have room */ - do - { - queue_size = xq->var->ReadQ.count; - /* read a packet from the ethernet - processing is via the callback */ - status = eth_read (xq->var->etherface, &xq->var->read_buffer, xq->var->rcallback); - } while (queue_size != xq->var->ReadQ.count); + /* First pump any queued packets into the system */ + if ((xq->var->ReadQ.count > 0) && (~xq->var->csr & XQ_CSR_RL)) + status = xq_process_rbdl(xq); - /* Now pump any still queued packets into the system */ - if ((xq->var->ReadQ.count > 0) && (~xq->var->csr & XQ_CSR_RL)) - status = xq_process_rbdl(xq); + /* Now read and queue packets that have arrived */ + /* This is repeated as long as they are available and we have room */ + do + { + queue_size = xq->var->ReadQ.count; + /* read a packet from the ethernet - processing is via the callback */ + status = eth_read (xq->var->etherface, &xq->var->read_buffer, xq->var->rcallback); + } while (queue_size != xq->var->ReadQ.count); - /* resubmit if still receive enabled */ - if (xq->var->csr & XQ_CSR_RE) - sim_activate(xq_svctmr, (clk_tps * tmr_poll)/100); + /* Now pump any still queued packets into the system */ + if ((xq->var->ReadQ.count > 0) && (~xq->var->csr & XQ_CSR_RL)) + status = xq_process_rbdl(xq); + } + + /* has sanity timer expired? if so, reboot */ + if (xq->var->sanity.enabled) + if (--xq->var->sanity.timer <= 0) + xq_boot_host(xq); + + /* has system id timer expired? if so, do system id */ + if (--xq->var->idtmr <= 0) { + const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00}; + xq_system_id(xq, mop_multicast, 0); + + /* reset system ID counter for next event */ + xq->var->idtmr = XQ_SYSTEM_ID_SECS * xq->var->poll; + } + + /* resubmit service timer */ + sim_activate(&xq->unit[0], one_second/xq->var->poll); return SCPE_OK; } - /* attach device: */ t_stat xq_attach(UNIT* uptr, char* cptr) { @@ -2141,6 +1870,8 @@ t_stat xq_attach(UNIT* uptr, char* cptr) char* tptr; CTLR* xq = xq_unit2ctlr(uptr); + sim_debug(DBG_TRC, xq->dev, "xq_attach(cptr=%s)\n", cptr); + tptr = malloc(strlen(cptr) + 1); if (tptr == NULL) return SCPE_MEM; strcpy(tptr, cptr); @@ -2148,7 +1879,7 @@ t_stat xq_attach(UNIT* uptr, char* cptr) xq->var->etherface = malloc(sizeof(ETH_DEV)); if (!xq->var->etherface) return SCPE_MEM; - status = eth_open(xq->var->etherface, cptr); + status = eth_open(xq->var->etherface, cptr, xq->dev, DBG_ETH); if (status != SCPE_OK) { free(tptr); free(xq->var->etherface); @@ -2159,7 +1890,7 @@ t_stat xq_attach(UNIT* uptr, char* cptr) uptr->flags |= UNIT_ATT; /* turn on transceiver power indicator */ - xq->var->csr |= XQ_CSR_OK; + xq_csr_set_clr(xq, XQ_CSR_OK, 0); /* reset the device with the new attach info */ xq_reset(xq->dev); @@ -2171,24 +1902,22 @@ t_stat xq_attach(UNIT* uptr, char* cptr) t_stat xq_detach(UNIT* uptr) { - t_stat status; CTLR* xq = xq_unit2ctlr(uptr); - int i; + sim_debug(DBG_TRC, xq->dev, "xq_detach()\n"); if (uptr->flags & UNIT_ATT) { - status = eth_close (xq->var->etherface); + t_stat status = eth_close (xq->var->etherface); free(xq->var->etherface); xq->var->etherface = 0; free(uptr->filename); uptr->filename = NULL; uptr->flags &= ~UNIT_ATT; - /* cancel all timers (ethernet, sanity, system_id) */ - for (i=0; i<3; i++) - sim_cancel(&xq->unit[i]); + /* cancel service timer */ + sim_cancel(&xq->unit[0]); } /* turn off transceiver power indicator */ - xq->var->csr &= ~XQ_CSR_OK; + xq_csr_set_clr(xq, 0, XQ_CSR_OK); return SCPE_OK; } @@ -2227,106 +1956,68 @@ int32 xq_int (void) return 0; /* no interrupt request active */ } +void xq_csr_set_clr (CTLR* xq, uint16 set_bits, uint16 clear_bits) +{ + uint16 saved_csr = xq->var->csr; + + /* set the bits in the csr */ + xq->var->csr = (xq->var->csr | set_bits) & ~clear_bits; + + sim_debug_u16(DBG_CSR, xq->dev, xq_csr_bits, saved_csr, xq->var->csr, 1); + + /* check and correct the state of controller interrupt */ + + /* if IE is transitioning, process it */ + if ((saved_csr ^ xq->var->csr) & XQ_CSR_IE) { + + /* if IE transitioning low and interrupt set, clear interrupt */ + if ((clear_bits & XQ_CSR_IE) && xq->var->irq) + xq_clrint(xq); + + /* if IE transitioning high, and XI or RI is high, + set interrupt if interrupt is off */ + if ((set_bits & XQ_CSR_IE) && (xq->var->csr & XQ_CSR_XIRI) && !xq->var->irq) + xq_setint(xq); + + } else { /* IE is not transitioning */ + + /* if interrupts are enabled */ + if (xq->var->csr & XQ_CSR_IE) { + + /* if XI or RI transitioning high and interrupt off, set interrupt */ + if (((saved_csr ^ xq->var->csr) & (set_bits & XQ_CSR_XIRI)) && !xq->var->irq) { + xq_setint(xq); + + } else { + + /* if XI or RI transitioning low, and both XI and RI are now low, + clear interrupt if interrupt is on */ + if (((saved_csr ^ xq->var->csr) & (clear_bits & XQ_CSR_XIRI)) + && !(xq->var->csr & XQ_CSR_XIRI) + && xq->var->irq) + xq_clrint(xq); + } + + } /* IE enabled */ + + } /* IE transitioning */ +} + /*============================================================================== / debugging routines /=============================================================================*/ -#ifdef XQ_DEBUG - -void xq_dump_csr (CTLR* xq) -{ - static int cnt = 0; - /* tell user what is changing in register */ - int i; - int mask = 1; - uint16 csr = xq->var->csr; - char hi[256] = "Set: "; - char lo[256] = "Reset: "; - for (i=0; i<16; i++, mask <<= 1) { - if ((csr & mask)) strcat (hi, xq_csr_bits[i]); - if ((~csr & mask)) strcat (lo, xq_csr_bits[i]); - } -#if defined (VM_VAX) - printf ("%s: CSR %08X %08X read: %s %s\n", xq->dev->name, fault_PC, PSL, hi, lo); -#else -if (cnt < 20) - printf ("%s: CSR read[%d]: %s %s\n", xq->dev->name, cnt++, hi, lo); -#endif /* VM_VAX */ -} - -void xq_dump_var (CTLR* xq) -{ - /* tell user what is changing in register */ - uint16 var = xq->var->var; - char hi[256] = "Set: "; - char lo[256] = "Reset: "; - int vec = (var & XQ_VEC_IV) >> 2; - strcat((var & XQ_VEC_MS) ? hi : lo, "MS "); - strcat((var & XQ_VEC_OS) ? hi : lo, "OS "); - strcat((var & XQ_VEC_RS) ? hi : lo, "RS "); - strcat((var & XQ_VEC_S3) ? hi : lo, "S3 "); - strcat((var & XQ_VEC_S2) ? hi : lo, "S2 "); - strcat((var & XQ_VEC_S1) ? hi : lo, "S1 "); - strcat((var & XQ_VEC_RR) ? hi : lo, "RR "); - strcat((var & XQ_VEC_ID) ? hi : lo, "ID "); - printf ("%s: VAR read: %s %s - Vec: %d \n", xq->dev->name, hi, lo, vec); -} - -void xq_csr_changes (CTLR* xq, uint16 data) -{ - /* tell user what is changing in register */ - int i; - int mask = 1; - uint16 csr = xq->var->csr; - char hi[256] = "Setting: "; - char lo[256] = "Resetting: "; - for (i=0; i<16; i++, mask <<= 1) { - if ((csr & mask) && (~data & mask)) strcat (lo, xq_csr_bits[i]); - if ((~csr & mask) && (data & mask)) strcat (hi, xq_csr_bits[i]); - } - /* write-one-to-clear bits*/ - if (data & XQ_CSR_RI) strcat(lo, "RI "); - if (data & XQ_CSR_XI) strcat(lo, "XI "); -#if defined(VM_VAX) - printf ("%s: CSR %08X %08X write: %s %s\n", xq->dev->name, fault_PC, PSL, hi, lo); -#else - printf ("%s: CSR write: %s %s\n", xq->dev->name, hi, lo); -#endif /* VM_VAX */ -} - -void xq_var_changes (CTLR* xq, uint16 data) -{ - /* tell user what is changing in register */ - uint16 vec; - uint16 var = xq->var->var; - char hi[256] = "Setting: "; - char lo[256] = "Resetting: "; - if (~var & XQ_VEC_MS & data) strcat (hi, "MS "); - if (var & XQ_VEC_MS & ~data) strcat (lo, "MS "); - if (~var & XQ_VEC_OS & data) strcat (hi, "OS "); - if (var & XQ_VEC_OS & ~data) strcat (lo, "OS "); - if (~var & XQ_VEC_RS & data) strcat (hi, "RS "); - if (var & XQ_VEC_RS & ~data) strcat (lo, "RS "); - if (~var & XQ_VEC_ID & data) strcat (hi, "ID "); - if (var & XQ_VEC_ID & ~data) strcat (lo, "ID "); - - if ((var & XQ_VEC_IV) != (data & XQ_VEC_IV)) { - vec = (data & XQ_VEC_IV) >> 2; - printf ("%s: VAR write: %s %s - Vec: %d\n", xq->dev->name, hi, lo, vec); - } else - printf ("%s: VAR write: %s %s\n", xq->dev->name, hi, lo); -} void xq_debug_setup(CTLR* xq) { int i; char buffer[20]; if (xq->var->write_buffer.msg[0]) - printf ("%s: Setup: MOP info present!\n", xq->dev->name); + printf ("%s: setup> MOP info present!\n", xq->dev->name); for (i = 0; i < XQ_FILTER_MAX; i++) { eth_mac_fmt(&xq->var->setup.macs[i], buffer); - printf ("%s: Setup: set addr[%d]: %s\n", xq->dev->name, i, buffer); + printf ("%s: setup> set addr[%d]: %s\n", xq->dev->name, i, buffer); } if (xq->var->write_buffer.len > 128) { @@ -2336,8 +2027,7 @@ void xq_debug_setup(CTLR* xq) if (len & XQ_SETUP_PM) strcat(buffer, "PM "); if (len & XQ_SETUP_LD) strcat(buffer, "LD "); if (len & XQ_SETUP_ST) strcat(buffer, "ST "); - printf ("%s: Setup: Length [%d =0x%X, LD:%d, ST:%d] info: %s\n", + printf ("%s: setup> Length [%d =0x%X, LD:%d, ST:%d] info: %s\n", xq->dev->name, len, len, (len & XQ_SETUP_LD) >> 2, (len & XQ_SETUP_ST) >> 4, buffer); } } -#endif diff --git a/PDP11/pdp11_xq.h b/PDP11/pdp11_xq.h index 939ebde8..b54339c6 100644 --- a/PDP11/pdp11_xq.h +++ b/PDP11/pdp11_xq.h @@ -1,7 +1,7 @@ /* pdp11_xq.h: DEQNA/DELQA ethernet controller information ------------------------------------------------------------------------------ - Copyright (c) 2002-2003, David T. Hittner + Copyright (c) 2002-2004, 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"), @@ -28,6 +28,10 @@ Modification history: + 20-Jan-04 DTH Added new sanity timer and system id timer + 19-Jan-04 DTH Added XQ_SERVICE_INTERVAL, poll + 09-Jan-04 DTH Added Boot PDP diagnostic definition, XI/RI combination + 26-Dec-03 DTH Moved ethernet queue definitions to sim_ether 25-Nov-03 DTH Added interrupt request flag 02-Jun-03 DTH Added struct xq_stats 28-May-03 DTH Made xq_msg_que.item dynamic @@ -74,36 +78,20 @@ extern int32 int_vec[IPL_HLVL][32]; #include "sim_ether.h" -/* message queue arrays */ -#define XQ_QUE_MAX 500 -#define XQ_FILTER_MAX 14 +#define XQ_QUE_MAX 500 /* read queue size in packets */ +#define XQ_FILTER_MAX 14 /* number of filters allowed */ +#define XQ_SERVICE_INTERVAL 100 /* polling interval - X per second */ +#define XQ_SYSTEM_ID_SECS 540 /* seconds before system ID timer expires */ +#define XQ_HW_SANITY_SECS 240 /* seconds before HW sanity timer expires */ +#define XQ_MAX_CONTROLLERS 2 /* maximum controllers allowed */ enum xq_type {XQ_T_DEQNA, XQ_T_DELQA}; struct xq_sanity { - int enabled; /* sanity timer enabled ? */ - int quarter_secs; /* sanity timer value in 1/4 seconds */ - int countdown; /* sanity timer countdown in 1/4 seconds */ -}; - -struct xq_id { - int enabled; /* System ID timer enabled ? */ - int countdown; /* System ID timer countdown in seconds */ -}; - -struct xq_msg_itm { - int type; /* receive (0=setup, 1=loopback, 2=normal) */ - int32 status; /* message size */ - ETH_PACK packet; /* packet */ -}; - -struct xq_msg_que { - int count; - int head; - int tail; - int loss; - int high; - struct xq_msg_itm* item; + int enabled; /* sanity timer enabled? 2=HW, 1=SW, 0=off */ + int quarter_secs; /* sanity timer value in 1/4 seconds */ + int max; /* maximum timeout (based on poll) */ + int timer; /* countdown timer */ }; struct xq_setup { @@ -139,12 +127,12 @@ struct xq_meb { /* MEB block */ struct xq_device { /*+ initialized values - DO NOT MOVE */ - ETH_PCALLBACK rcallback; /* read callback routine */ + ETH_PCALLBACK rcallback; /* read callback routine */ ETH_PCALLBACK wcallback; /* write callback routine */ ETH_MAC mac; /* MAC address */ enum xq_type type; /* controller type */ + int poll; /* poll ethernet times/sec */ struct xq_sanity sanity; /* sanity timer information */ - struct xq_id id; /* System ID timer information */ /*- initialized values - DO NOT MOVE */ /* I/O register storage */ @@ -167,7 +155,8 @@ struct xq_device { int receiving; ETH_PACK read_buffer; ETH_PACK write_buffer; - struct xq_msg_que ReadQ; + ETH_QUE ReadQ; + int idtmr; /* countdown for ID Timer */ }; struct xq_controller { @@ -198,9 +187,11 @@ typedef struct xq_controller CTLR; #define XQ_CSR_RE 0x0001 /* Receiver Enable (RE) [RW] */ /* special access bitmaps */ -#define XQ_CSR_RO 0xF8B4 /* Read-Only bits */ -#define XQ_CSR_RW 0x074B /* Read/Write bits */ -#define XQ_CSR_W1 0x8080 /* Write-one-to-clear bits */ +#define XQ_CSR_RO 0xF8B4 /* Read-Only bits */ +#define XQ_CSR_RW 0x074B /* Read/Write bits */ +#define XQ_CSR_W1 0x8080 /* Write-one-to-clear bits */ +#define XQ_CSR_BP 0x0208 /* Boot PDP diagnostic ROM */ +#define XQ_CSR_XIRI 0X8080 /* Transmit & Receive Interrupts */ #define XQ_VEC_MS 0x8000 /* Mode Select (MO) [RW] */ #define XQ_VEC_OS 0x4000 /* Option Switch Setting (OS) [RO] */ @@ -229,4 +220,15 @@ typedef struct xq_controller CTLR; #define XQ_SETUP_LD 0x000C /* led bits */ #define XQ_SETUP_ST 0x0070 /* sanity timer bits */ +/* debugging bitmaps */ +#define DBG_TRC 0x0001 /* trace routine calls */ +#define DBG_REG 0x0002 /* trace read/write registers */ +#define DBG_CSR 0x0004 /* watch CSR */ +#define DBG_VAR 0x0008 /* watch VAR */ +#define DBG_WRN 0x0010 /* display warnings */ +#define DBG_SAN 0x0020 /* display sanity timer info */ +#define DBG_SET 0x0040 /* display setup info */ +#define DBG_PCK 0x0080 /* display packets */ +#define DBG_ETH 0x8000 /* debug ethernet device */ + #endif /* _PDP11_XQ_H */ diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index 359c9528..284c2df2 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -1,6 +1,7 @@ -/* pdp11_xu.c: DEUNA/DELUA Unibus Ethernet interface (stub) +/* pdp11_xu.c: DEUNA/DELUA ethernet controller simulator + ------------------------------------------------------------------------------ - Copyright (c) 2003, Robert M Supnik + Copyright (c) 2003-2004, 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"), @@ -15,77 +16,1360 @@ 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 + 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 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. + 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. - xu DEUNA/DELUNA Ethernet interface (stub) + ------------------------------------------------------------------------------ - 22-Dec-03 RMS Added second (stub) device + This DEUNA/DELUA simulation is based on: + Digital DELUA Users Guide, Part# EK-DELUA-UG-002 + Digital DEUNA Users Guide, Part# EK-DEUNA-UG-001 + These manuals can be found online at: + http://www.spies.com/~aek/pdf/dec/unibus + + + What this BETA version contains: + 1) Basic Transmit/Receive packet functionality. + 2) Promiscuous/All_Multicast/Multicast/MAC support + + Testing performed: + 1) Receives/Transmits single packet under custom RSX driver + 2) Passes RSTS 10.1 controller diagnostics during boot + + Known issues: + 1) Transmit/Receive rings have not been thoroughly tested, + particularly when and where the ring pointers get reset. + 2) Most auxiliary commands are not implemented yet. + 3) System_ID broadcast is not implemented + 4) Error/Interrupt signalling is still iffy from merge of FvK and sim_ether + + ------------------------------------------------------------------------------ + + Modification history: + + 16-Jan-04 DTH Added more info to SHOW MOD commands + 09-Jan-04 DTH Made XU floating address so that XUB will float correctly + 08-Jan-04 DTH Added system_id message + 06-Jan-04 DTH Added protection against changing mac and type if attached + 05-Jan-04 DTH Moved most of xu_setmac to sim_ether + Implemented auxiliary function 12/13 + Added SET/SHOW XU STATS + 31-Dec-03 DTH RSTS 10.1 accepts controller during boot tests + Implemented chained buffers in transmit/receive processing + 29-Dec-03 DTH Primitive RSX packet sending succeeds + 23-Dec-03 DTH Implemented write function + 17-Dec-03 DTH Implemented read function + 05-May-03 DTH Started XU simulation - + core logic pirated from unreleased FvK PDP10 variant + + ------------------------------------------------------------------------------ */ -#if defined (VM_PDP10) /* PDP10 version */ -#include "pdp10_defs.h" -extern int32 int_req; -extern int32 int_vec[32]; +#include "pdp11_xu.h" -#elif defined (VM_VAX) /* VAX version */ -#error "DEUNA/DELUA not supported on VAX!" +extern int32 tmr_poll, clk_tps; +extern FILE *sim_log; -#else /* PDP-11 version */ -#include "pdp11_defs.h" -extern int32 int_req[IPL_HLVL]; -extern int32 int_vec[IPL_HLVL][32]; +t_stat xu_rd(int32* data, int32 PA, int32 access); +t_stat xu_wr(int32 data, int32 PA, int32 access); +t_stat xu_svc(UNIT * uptr); +t_stat xu_reset (DEVICE * dptr); +t_stat xu_attach (UNIT * uptr, char * cptr); +t_stat xu_detach (UNIT * uptr); +t_stat xu_showmac (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xu_setmac (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat xu_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xu_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat xu_show_type (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xu_set_type (UNIT* uptr, int32 val, char* cptr, void* desc); +int32 xu_int (void); +t_stat xu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat xu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +void xua_read_callback(int status); +void xub_read_callback(int status); +void xua_write_callback(int status); +void xub_write_callback(int status); +void xu_setint (CTLR* xu); +void xu_clrint (CTLR* xu); +void xu_process_receive(CTLR* xu); + +DIB xua_dib = { IOBA_XU, IOLN_XU, &xu_rd, &xu_wr, +1, IVCL (XU), VEC_XU, {&xu_int} }; + +UNIT xua_unit[] = { + { UDATA (&xu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } /* receive timer */ +}; + +struct xu_device xua = { + xua_read_callback, /* read callback routine */ + xua_write_callback, /* write callback routine */ + {0x08, 0x00, 0x2B, 0xCC, 0xDD, 0xEE}, /* mac */ + XU_T_DELUA /* type */ + }; + +MTAB xu_mod[] = { +#if defined (VM_PDP11) + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, +#else + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, + NULL, &show_addr, NULL }, #endif + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", + &xu_setmac, &xu_showmac, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH", + NULL, ð_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATS", "STATS", + &xu_set_stats, &xu_show_stats, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE={DEUNA|DELUA}", + &xu_set_type, &xu_show_type, NULL }, + { 0 }, +}; -/* XU data structures - - xu_dev XU device descriptor - xu_unit XU unit list - xu_reg XU register list -*/ - -DIB xu_dib = { IOBA_XU, IOLN_XU, NULL, NULL, - 1, IVCL (XU), VEC_XU, { NULL } }; - -UNIT xu_unit = { UDATA (NULL, 0, 0) }; - -REG xu_reg[] = { +REG xua_reg[] = { { NULL } }; +DEBTAB xu_debug[] = { + {"TRACE", DBG_TRC}, + {"WARN", DBG_WRN}, + {"REG", DBG_REG}, + {"ETH", DBG_ETH}, + {0} +}; + + DEVICE xu_dev = { - "XU", &xu_unit, xu_reg, NULL, - 1, 8, 8, 1, 8, 8, - NULL, NULL, NULL, - NULL, NULL, NULL, - &xu_dib, DEV_DIS | DEV_UBUS }; + "XU", xua_unit, xua_reg, xu_mod, + 1, XU_RDX, 8, 1, XU_RDX, 8, + &xu_ex, &xu_dep, &xu_reset, + NULL, &xu_attach, &xu_detach, + &xua_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, + 0, xu_debug + }; -#if defined (VM_PDP11) -/* XUB data structures +/* XUB does not exist in the PDP10 simulation */ +#if defined(IOBA_XUB) - xub_dev XUB device descriptor - xub_unit XUB unit list - xub_reg XUB register list -*/ +DIB xub_dib = { IOBA_XUB, IOLN_XUB, &xu_rd, &xu_wr, + 1, IVCL (XU), 0, { &xu_int } }; -DIB xub_dib = { IOBA_XUB, IOLN_XUB, NULL, NULL, - 1, IVCL (XU), VEC_XU, { NULL } }; +UNIT xub_unit[] = { + { UDATA (&xu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } /* receive timer */ +}; -UNIT xub_unit = { UDATA (NULL, 0, 0) }; +struct xu_device xub = { + xub_read_callback, /* read callback routine */ + xub_write_callback, /* write callback routine */ + {0x08, 0x00, 0x2B, 0xDD, 0xEE, 0xFF}, /* mac */ + XU_T_DELUA /* type */ + }; REG xub_reg[] = { { NULL } }; DEVICE xub_dev = { - "XUB", &xub_unit, xub_reg, NULL, - 1, 8, 8, 1, 8, 8, - NULL, NULL, NULL, - NULL, NULL, NULL, - &xub_dib, DEV_DIS | DEV_UBUS }; + "XUB", xub_unit, xub_reg, xu_mod, + 1, XU_RDX, 8, 1, XU_RDX, 8, + &xu_ex, &xu_dep, &xu_reset, + NULL, &xu_attach, &xu_detach, + &xub_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, + 0, xu_debug +}; -#endif +#define XU_MAX_CONTROLLERS 2 +CTLR xu_ctrl[] = { + {&xu_dev, xua_unit, &xua_dib, &xua} /* XUA controller */ + ,{&xub_dev, xub_unit, &xub_dib, &xub} /* XUB controller */ +}; +#else /* IOBA_XUB */ +#define XU_MAX_CONTROLLERS 1 +CTLR xu_ctrl[] = { + {&xu_dev, xua_unit, &xua_dib, &xua} /* XUA controller */ +}; +#endif /* IOBA_XUB */ + +/*============================================================================*/ + +/* Multicontroller support */ + +CTLR* xu_unit2ctlr(UNIT* uptr) +{ + int i; + unsigned int j; + for (i=0; inumunits; j++) + if (&xu_ctrl[i].unit[j] == uptr) + return &xu_ctrl[i]; + /* not found */ + return 0; +} + +CTLR* xu_dev2ctlr(DEVICE* dptr) +{ + int i; + for (i=0; i= xu_ctrl[i].dib->ba) && (PA < (xu_ctrl[i].dib->ba + xu_ctrl[i].dib->lnt))) + return &xu_ctrl[i]; + /* not found */ + return 0; +} + +/*============================================================================*/ + +/* stop simh from reading non-existant unit data stream */ +t_stat xu_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw) +{ + return SCPE_NOFNC; +} + +/* stop simh from writing non-existant unit data stream */ +t_stat xu_dep (t_value val, t_addr addr, UNIT* uptr, int32 sw) +{ + return SCPE_NOFNC; +} + +t_stat xu_showmac (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR* xu = xu_unit2ctlr(uptr); + char buffer[20]; + + eth_mac_fmt((ETH_MAC*)xu->var->mac, buffer); + fprintf(st, "MAC=%s", buffer); + return SCPE_OK; +} + +t_stat xu_setmac (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + t_stat status; + CTLR* xu = xu_unit2ctlr(uptr); + + if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + status = eth_mac_scan(&xu->var->mac, cptr); + return status; +} + +t_stat xu_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + CTLR* xu = xu_unit2ctlr(uptr); + + /* set stats to zero, regardless of passed parameter */ + memset(&xu->var->stats, 0, sizeof(struct xu_stats)); + return SCPE_OK; +} + +t_stat xu_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + char* fmt = " %-24s%d\n"; + CTLR* xu = xu_unit2ctlr(uptr); + struct xu_stats* stats = &xu->var->stats; + + fprintf(st, "Ethernet statistics:\n"); + fprintf(st, fmt, "Seconds since cleared:", stats->secs); + fprintf(st, fmt, "Recv frames:", stats->frecv); + fprintf(st, fmt, "Recv dbytes:", stats->rbytes); + fprintf(st, fmt, "Xmit frames:", stats->ftrans); + fprintf(st, fmt, "Xmit dbytes:", stats->tbytes); + fprintf(st, fmt, "Recv frames(multicast):", stats->mfrecv); + fprintf(st, fmt, "Recv dbytes(multicast):", stats->mrbytes); + fprintf(st, fmt, "Xmit frames(multicast):", stats->mftrans); + fprintf(st, fmt, "Xmit dbytes(multicast):", stats->mtbytes); + return SCPE_OK; +} + +t_stat xu_show_type (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR* xu = xu_unit2ctlr(uptr); + fprintf(st, "type="); + switch (xu->var->type) { + case XU_T_DEUNA: fprintf(st, "DEUNA"); break; + case XU_T_DELUA: fprintf(st, "DELUA"); break; + } + return SCPE_OK; +} + +t_stat xu_set_type (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + CTLR* xu = xu_unit2ctlr(uptr); + if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + + /* this assumes that the parameter has already been upcased */ + if (!strcmp(cptr, "DEUNA")) xu->var->type = XU_T_DEUNA; + else if (!strcmp(cptr, "DELUA")) xu->var->type = XU_T_DELUA; + else return SCPE_ARG; + + return SCPE_OK; +} + +/*============================================================================*/ + +void upd_stat16(uint16* stat, uint16 add) +{ + *stat += add; + /* did stat roll over? latches at maximum */ + if (*stat < add) + *stat = 0xFFFF; +} + +void upd_stat32(uint32* stat, uint32 add) +{ + *stat += add; + /* did stat roll over? latches at maximum */ + if (*stat < add) + *stat = 0xFFFFFFFF; +} + +void bit_stat16(uint16* stat, uint16 bits) +{ + *stat |= bits; +} + +t_stat xu_process_local (CTLR* xu, ETH_PACK* pack) +{ + return SCPE_NOFNC; /* not implemented yet */ +} + +void xu_read_callback(CTLR* xu, int status) +{ + /* process any packets locally that can be */ + status = xu_process_local (xu, &xu->var->read_buffer); + + /* add packet to read queue */ + if (status != SCPE_OK) + ethq_insert(&xu->var->ReadQ, 2, &xu->var->read_buffer, 0); +} + +void xua_read_callback(int status) +{ + xu_read_callback(&xu_ctrl[0], status); +} + +void xub_read_callback(int status) +{ + xu_read_callback(&xu_ctrl[1], status); +} + +t_stat xu_system_id (CTLR* xu, const ETH_MAC dest, uint16 receipt_id) +{ + static uint16 receipt = 0; + ETH_PACK system_id; + uint8* const msg = &system_id.msg[0]; + t_stat status; + + sim_debug(DBG_TRC, xu->dev, "xu_system_id()\n"); + memset (&system_id, 0, sizeof(system_id)); + memcpy (&msg[0], dest, sizeof(ETH_MAC)); + memcpy (&msg[6], xu->var->setup.macs[0], sizeof(ETH_MAC)); + msg[12] = 0x60; /* type */ + msg[13] = 0x02; /* type */ + msg[14] = 0x1C; /* character count */ + msg[15] = 0x00; /* character count */ + msg[16] = 0x07; /* code */ + msg[17] = 0x00; /* zero pad */ + if (receipt_id) { + msg[18] = receipt_id & 0xFF; /* receipt number */ + msg[19] = (receipt_id >> 8) & 0xFF; /* receipt number */ + } else { + msg[18] = receipt & 0xFF; /* receipt number */ + msg[19] = (receipt++ >> 8) & 0xFF; /* receipt number */ + } + + /* MOP VERSION */ + msg[20] = 0x01; /* type */ + msg[21] = 0x00; /* type */ + msg[22] = 0x03; /* length */ + msg[23] = 0x03; /* version */ + msg[24] = 0x00; /* eco */ + msg[25] = 0x00; /* user eco */ + + /* FUNCTION */ + msg[26] = 0x02; /* type */ + msg[27] = 0x00; /* type */ + msg[28] = 0x02; /* length */ + msg[29] = 0x05; /* value 1 */ + msg[30] = 0x00; /* value 2 */ + + /* HARDWARE ADDRESS */ + msg[31] = 0x07; /* type */ + msg[32] = 0x00; /* type */ + msg[33] = 0x06; /* length */ + memcpy (&msg[34], xu->var->mac, sizeof(ETH_MAC)); /* ROM address */ + + /* DEVICE TYPE */ + msg[40] = 0x64; /* type */ + msg[41] = 0x00; /* type */ + msg[42] = 0x01; /* length */ + if (xu->var->type == XU_T_DEUNA) + msg[43] = 1; /* value (1=DEUNA) */ + else + msg[43] = 11; /* value (11=DELUA) */ + + /* write system id */ + system_id.len = 60; + status = eth_write(xu->var->etherface, &system_id, NULL); + + return status; +} + +t_stat xu_svc(UNIT* uptr) +{ + int queue_size; + t_stat status; + CTLR* xu = xu_unit2ctlr(uptr); + const int one_second = clk_tps * tmr_poll; /* recalibrate timer */ + const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00}; + + /* First pump any queued packets into the system */ + if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING)) + xu_process_receive(xu); + + /* Now read and queue packets that have arrived */ + /* This is repeated as long as they are available and we have room */ + do + { + queue_size = xu->var->ReadQ.count; + /* read a packet from the ethernet - processing is via the callback */ + status = eth_read (xu->var->etherface, &xu->var->read_buffer, xu->var->rcallback); + } while (queue_size != xu->var->ReadQ.count); + + /* Now pump any still queued packets into the system */ + if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING)) + xu_process_receive(xu); + + /* send identity packet when timer expires */ + if (--xu->var->idtmr <= 0) { + if ((xu->var->mode & MODE_DMNT) == 0) /* if maint msg is not disabled */ + status = xu_system_id(xu, mop_multicast, 0); /* then send ID packet */ + xu->var->idtmr = XU_ID_TIMER_VAL; /* reset timer */ + } + + /* has one second timer expired? if so, update stats and reset timer */ + if (++xu->var->sectmr >= XU_SERVICE_INTERVAL) { + upd_stat16 (&xu->var->stats.secs, 1); + xu->var->sectmr = 0; + } + + /* resubmit service timer if controller not halted */ + switch (xu->var->pcsr1 & PCSR1_STATE) { + case STATE_READY: + case STATE_RUNNING: + sim_activate(&xu->unit[0], one_second/XU_SERVICE_INTERVAL); + break; + }; + + return SCPE_OK; +} + +void xu_write_callback (CTLR* xu, int status) +{ + xu->var->write_buffer.status = status; +} + +void xua_write_callback (int status) +{ + xu_write_callback(&xu_ctrl[0], status); +} + +void xub_write_callback (int status) +{ + xu_write_callback(&xu_ctrl[1], status); +} + +void xu_setclrint(CTLR* xu, int32 bits) +{ + if (xu->var->pcsr0 & 0xFF00) { /* if any interrupt bits on, */ + xu->var->pcsr0 |= PCSR0_INTR; /* turn master bit on */ + xu_setint(xu); /* and trigger interrupt */ + } else { + xu->var->pcsr0 &= ~PCSR0_INTR; /* ... or off */ + xu_clrint(xu); /* and clear interrupt if needed*/ + } +} + +t_stat xu_sw_reset (CTLR* xu) +{ + t_stat status; + const int one_second = clk_tps * tmr_poll; /* recalibrate timer */ + + sim_debug(DBG_TRC, xu->dev, "xu_sw_reset()\n"); + + /* Clear the registers. */ + xu->var->pcsr0 = 0; + xu->var->pcsr1 = STATE_READY; + switch (xu->var->type) { + case XU_T_DELUA: xu->var->pcsr1 |= TYPE_DELUA; break; + case XU_T_DEUNA: xu->var->pcsr1 |= TYPE_DEUNA; break; + } + xu->var->pcsr2 = 0; + xu->var->pcsr3 = 0; + + /* Clear the parameters. */ + xu->var->mode = 0; + xu->var->pcbb = 0; + xu->var->stat = 0; + + /* clear read queue */ + ethq_clear(&xu->var->ReadQ); + + /* clear setup info */ + memset(&xu->var->setup, 0, sizeof(struct xu_setup)); + + /* clear network statistics */ + memset(&xu->var->stats, 0, sizeof(struct xu_stats)); + + /* reset ethernet interface */ + memcpy (xu->var->setup.macs[0], xu->var->mac, sizeof(ETH_MAC)); + xu->var->setup.mac_count = 1; + if (xu->var->etherface) + status = eth_filter (xu->var->etherface, xu->var->setup.mac_count, + &xu->var->mac, xu->var->setup.multicast, + xu->var->setup.promiscuous); + + /* activate device if not disabled - cancel first, just in case */ + if ((xu->dev->flags & DEV_DIS) == 0) { + sim_cancel(&xu->unit[0]); + sim_activate(&xu->unit[0], one_second/XU_SERVICE_INTERVAL); + } + + return SCPE_OK; +} + +/* Reset device. */ +t_stat xu_reset(DEVICE* dptr) +{ + t_stat status; + CTLR* xu = xu_dev2ctlr(dptr); + + /* init read queue (first time only) */ + status = ethq_init (&xu->var->ReadQ, XU_QUE_MAX); + if (status != SCPE_OK) + return status; + + /* software reset controller */ + xu_sw_reset(xu); + + return SCPE_OK; +} + +/* Perform one of the defined ancillary functions. */ +int32 xu_command(CTLR* xu) +{ + uint32 udbb; + int fnc, mtlen; + uint16 value; + t_stat status, rstatus, wstatus, wstatus2, wstatus3; + struct xu_stats* stats = &xu->var->stats; + uint16* udb = xu->var->udb; + static char* command[] = { + "NO-OP", + "Start Microaddress", + "Read Default Physical Address", + "NO-OP", + "Read Physical Address", + "Write Physical Address", + "Read Multicast Address List", + "Write Multicast Address List", + "Read Descriptor Ring Format", + "Write Descriptor Ring Format", + "Read Counters", + "Read/Clear Counters", + "Read Mode Register", + "Write Mode Register", + "Read Status", + "Read/Clear Status", + "Dump Internal Memory", + "Load Internal Memory", + "Read System ID", + "Write System ID", + "Read Load Server Address", + "Write Load Server Address" + }; + + /* Grab the PCB from the host. */ + rstatus = Map_ReadW(xu->var->pcbb, 8, xu->var->pcb, MAP); + if (rstatus != SCPE_OK) + return PCSR0_PCEI + 1; + + /* High 8 bits are defined as MBZ. */ + if (xu->var->pcb[0] & 0177400) return PCSR0_PCEI; + + /* Decode the function to be performed. */ + fnc = xu->var->pcb[0] & 0377; + sim_debug(DBG_TRC, xu->dev, "xu_command(), Command: %s [0%o]\n", command[fnc], fnc); + + switch (fnc) { + case FC_NOOP: + break; + + case FC_RDPA: /* read default physical address */ + wstatus = Map_WriteW(xu->var->pcbb + 2, 6, (uint16*)xu->var->mac, MAP); + if (wstatus != SCPE_OK) + return PCSR0_PCEI + 1; + break; + + case FC_RPA: /* read current physical address */ + wstatus = Map_WriteW(xu->var->pcbb + 2, 6, (uint16*)&xu->var->setup.macs[0], MAP); + if (wstatus != SCPE_OK) + return PCSR0_PCEI + 1; + break; + + case FC_WPA: /* write current physical address */ + rstatus = Map_ReadW(xu->var->pcbb + 2, 6, (uint16*)&xu->var->setup.macs[0], MAP); + if (xu->var->pcb[1] & 1) return PCSR0_PCEI; + break; + + case FC_WMAL: /* write multicast address list */ + mtlen = (xu->var->pcb[2] & 0xFF00) >> 8; + if (mtlen > 10) return PCSR0_PCEI; + udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16); + rstatus = Map_ReadW(udbb, mtlen * 6, (uint16*) &xu->var->setup.macs[1], MAP); + if (rstatus == SCPE_OK) { + xu->var->setup.mac_count = mtlen + 1; + status = eth_filter (xu->var->etherface, xu->var->setup.mac_count, + xu->var->setup.macs, xu->var->setup.multicast, + xu->var->setup.promiscuous); + } else { + xu->var->pcsr0 |= PCSR0_PCEI; + } + break; + + case FC_RRF: /* read ring format */ + if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374)) + return PCSR0_PCEI; + xu->var->udb[0] = xu->var->tdrb & 0177776; + xu->var->udb[1] = (xu->var->telen << 8) + ((xu->var->tdrb >> 16) & 3); + xu->var->udb[2] = xu->var->trlen; + xu->var->udb[3] = xu->var->rdrb & 0177776; + xu->var->udb[4] = (xu->var->relen << 8) + ((xu->var->rdrb >> 16) & 3); + xu->var->udb[5] = xu->var->rrlen; + + /* Write UDB to host memory. */ + udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); + wstatus = Map_WriteW(udbb, 12, xu->var->pcb, MAP); + if (wstatus != SCPE_OK) + return PCSR0_PCEI+1; + break; + + case FC_WRF: /* write ring format */ + if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374)) + return PCSR0_PCEI; + if ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING) + return PCSR0_PCEI; + + /* Read UDB into local memory. */ + udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); + rstatus = Map_ReadW(udbb, 12, xu->var->udb, MAP); + if (rstatus != SCPE_OK) + return PCSR0_PCEI+1; + + if ((xu->var->udb[0] & 1) || (xu->var->udb[1] & 0374) || + (xu->var->udb[3] & 1) || (xu->var->udb[4] & 0374) || + (xu->var->udb[5] < 2)) { + return PCSR0_PCEI; + } + + xu->var->tdrb = ((xu->var->udb[1] & 3) << 16) + (xu->var->udb[0] & 0177776); + xu->var->telen = (xu->var->udb[1] >> 8) & 0377; + xu->var->trlen = xu->var->udb[2]; + xu->var->rdrb = ((xu->var->udb[4] & 3) << 16) + (xu->var->udb[3] & 0177776); + xu->var->relen = (xu->var->udb[4] >> 8) & 0377; + xu->var->rrlen = xu->var->udb[5]; + xu->var->rxnext = 0; + xu->var->txnext = 0; + break; + + case FC_RDCTR: /* read counters */ + case FC_RDCLCTR: /* read and clear counters */ + /* prepare udb for stats transfer */ + memset(xu->var->udb, 0, sizeof(xu->var->udb)); + + /* place stats in udb */ + udb[0] = 68; /* udb length */ + udb[1] = stats->secs; /* seconds since zeroed */ + udb[2] = stats->frecv & 0xFFFF; /* frames received <15:00> */ + udb[3] = stats->frecv >> 16; /* frames received <31:16> */ + udb[4] = stats->mfrecv & 0xFFFF; /* multicast frames received <15:00> */ + udb[5] = stats->mfrecv >> 16; /* multicast frames received <31:16> */ + udb[6] = stats->rxerf; /* receive error status bits */ + udb[7] = stats->frecve; /* frames received with error */ + udb[8] = stats->rbytes & 0xFFFF; /* data bytes received <15:00> */ + udb[9] = stats->rbytes >> 16; /* data bytes received <31:16> */ + udb[10] = stats->mrbytes & 0xFFFF; /* multicast data bytes received <15:00> */ + udb[11] = stats->mrbytes >> 16; /* multicast data bytes received <31:16> */ + udb[12] = stats->rlossi; /* received frames lost - internal buffer */ + udb[13] = stats->rlossl; /* received frames lost - local buffer */ + udb[14] = stats->ftrans & 0xFFFF; /* frames transmitted <15:00> */ + udb[15] = stats->ftrans >> 16; /* frames transmitted <31:16> */ + udb[16] = stats->mftrans & 0xFFFF; /* multicast frames transmitted <15:00> */ + udb[17] = stats->mftrans >> 16; /* multicast frames transmitted <31:16> */ + udb[18] = stats->ftrans3 & 0xFFFF; /* frames transmitted 3+ tries <15:00> */ + udb[19] = stats->ftrans3 >> 16; /* frames transmitted 3+ tries <31:16> */ + udb[20] = stats->ftrans2 & 0xFFFF; /* frames transmitted 2 tries <15:00> */ + udb[21] = stats->ftrans2 >> 16; /* frames transmitted 2 tries <31:16> */ + udb[22] = stats->ftransd & 0xFFFF; /* frames transmitted deferred <15:00> */ + udb[23] = stats->ftransd >> 16; /* frames transmitted deferred <31:16> */ + udb[24] = stats->tbytes & 0xFFFF; /* data bytes transmitted <15:00> */ + udb[25] = stats->tbytes >> 16; /* data bytes transmitted <31:16> */ + udb[26] = stats->mtbytes & 0xFFFF; /* multicast data bytes transmitted <15:00> */ + udb[27] = stats->mtbytes >> 16; /* multicast data bytes transmitted <31:16> */ + udb[28] = stats->txerf; /* transmit frame error status bits */ + udb[29] = stats->ftransa; /* transmit frames aborted */ + udb[30] = stats->txccf; /* transmit collision check failure */ + udb[31] = 0; /* MBZ */ + udb[32] = stats->porterr; /* port driver error */ + udb[33] = stats->bablcnt; /* babble counter */ + + /* transfer udb to host */ + udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); + wstatus = Map_WriteW(udbb, 68, xu->var->udb, MAP); + if (wstatus != SCPE_OK) { + xu->var->pcsr0 |= PCSR0_PCEI; + } + + /* if clear function, clear network stats */ + if (fnc == FC_RDCLCTR) + memset(stats, 0, sizeof(struct xu_stats)); + break; + + case FC_RMODE: /* read mode register */ + value = xu->var->mode; + wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value, MAP); + if (wstatus != SCPE_OK) + return PCSR0_PCEI + 1; + break; + + case FC_WMODE: /* write mode register */ + value = xu->var->mode; + xu->var->mode = xu->var->pcb[1]; + + /* set promiscuous and multicast flags */ + xu->var->setup.promiscuous = (xu->var->mode & MODE_PROM) ? 1 : 0; + xu->var->setup.multicast = (xu->var->mode & MODE_ENAL) ? 1 : 0; + + /* if promiscuous or multicast flags changed, change filter */ + if ((value ^ xu->var->mode) & (MODE_PROM | MODE_ENAL)) + status = eth_filter (xu->var->etherface, xu->var->setup.mac_count, + &xu->var->mac, xu->var->setup.multicast, + xu->var->setup.promiscuous); + break; + + case FC_RSTAT: /* read extended status */ + case FC_RCSTAT: /* read and clear extended status */ + value = xu->var->stat; + wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value, MAP); + value = 10; + wstatus2 = Map_WriteW(xu->var->pcbb+4, 2, &value, MAP); + value = 32; + wstatus3 = Map_WriteW(xu->var->pcbb+6, 2, &value, MAP); + if ((wstatus != SCPE_OK) || (wstatus2 != SCPE_OK) || (wstatus3 != SCPE_OK)) + return PCSR0_PCEI + 1; + + if (fnc = FC_RCSTAT) + xu->var->stat &= 0377; /* clear high byte */ + break; + + default: /* Unknown (unimplemented) command. */ + printf("%s: unknown ancilliary command 0%o requested !\n", xu->dev->name, fnc); + return PCSR0_PCEI; + break; + + } /* switch */ + + return PCSR0_DNI; +} + +/* Transfer received packets into receive ring. */ +void xu_process_receive(CTLR* xu) +{ + uint32 segb, ba; + int slen, wlen, off; + t_stat rstatus, wstatus; + ETH_ITEM* item = 0; + int state = xu->var->pcsr1 & PCSR1_STATE; + int no_buffers = xu->var->pcsr0 & PCSR0_RCBI; + + sim_debug(DBG_TRC, xu->dev, "xu_process_receive(), buffers: %d\n", xu->var->rrlen); + + /* process only when in the running state, and host buffers are available */ + if ((state != STATE_RUNNING) || no_buffers) + return; + + /* check read queue for buffer loss */ + if (xu->var->ReadQ.loss) { + upd_stat16(&xu->var->stats.rlossl, (uint16) xu->var->ReadQ.loss); + xu->var->ReadQ.loss = 0; + } + + /* while there are still packets left to process in the queue */ + while (xu->var->ReadQ.count > 0) { + + /* get next receive buffer */ + ba = xu->var->rdrb + (xu->var->relen * 2) * xu->var->rxnext; + rstatus = Map_ReadW (ba, 8, xu->var->rxhdr, MAP); + if (rstatus) { + /* tell host bus read failed */ + xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; + xu->var->pcsr0 |= PCSR0_SERI; + break; + } + + /* if buffer not owned by controller, exit [at end of ring] */ + if (!(xu->var->rxhdr[2] & RXR_OWN)) { + /* tell the host there are no more buffers */ + xu->var->pcsr0 |= PCSR0_RCBI; + break; + } + + /* set buffer length and address */ + slen = xu->var->rxhdr[0]; + segb = xu->var->rxhdr[1] + ((xu->var->rxhdr[2] & 3) << 16); + + /* get first packet from receive queue */ + if (!item) { + item = &xu->var->ReadQ.item[xu->var->ReadQ.head]; + /* + * 2.11BSD does not seem to like small packets. + * For example.. an incoming ARP packet is: + * ETH dstaddr [6] + * ETH srcaddr [6] + * ETH type [2] + * ARP arphdr [8] + * ARP dstha [6] + * ARP dstpa [4] + * ARP srcha [6] + * ARP srcpa [4] + * + * for a total of 42 bytes. According to the 2.11BSD + * driver for DEUNA (if_de.c), this is not a legal size, + * and the packet is dropped. Therefore, we pad the + * thing to minimum size here. Stupid runts... + */ + if (item->packet.len < ETH_MIN_PACKET) { + int len = item->packet.len; + memset (&item->packet.msg[len], 0, ETH_MIN_PACKET - len); + item->packet.len = ETH_MIN_PACKET; + } + } + + /* is this the start of frame? */ + if (item->packet.used == 0) { + xu->var->rxhdr[2] |= RXR_STF; + off = 0; + } + + /* figure out chained packet size */ + wlen = item->packet.len - item->packet.used; + if (wlen > slen) + wlen = slen; + + /* transfer chained packet to host buffer */ + wstatus = Map_WriteB (segb, wlen, &item->packet.msg[off], MAP); + if (wstatus) { + /* error during write */ + xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; + xu->var->pcsr0 |= PCSR0_SERI; + break; + } + + /* update chained counts */ + item->packet.used += wlen; + off += wlen; + + /* Is this the end-of-frame? */ + if (item->packet.used == item->packet.len) { + /* mark end-of-frame */ + xu->var->rxhdr[2] |= RXR_ENF; + + /* + * Fill in the Received Message Length field. + * The documenation notes that the DEUNA actually performs + * a full CRC check on the data buffer, and adds this CRC + * value to the data, in the last 4 bytes. The question + * is: does MLEN include these 4 bytes, or not??? --FvK + * + * A quick look at the RSX Process Software driver shows + * that the CRC byte count(4) is added to MLEN, but does + * not show if the DEUNA/DELUA actually transfers the + * CRC bytes to the host buffers, since the driver never + * tries to use them. However, since the host max buffer + * size is only 1514, not 1518, I doubt the CRC is actually + * transferred in normal mode. Maybe CRC is transferred + * and used in Loopback mode.. -- DTH + */ + xu->var->rxhdr[3] &= ~RXR_MLEN; + xu->var->rxhdr[3] |= (item->packet.len + 4/*CRC*/); + + /* update stats */ + upd_stat32(&xu->var->stats.frecv, 1); + upd_stat32(&xu->var->stats.rbytes, item->packet.len - 14); + if (item->packet.msg[0] & 1) { /* multicast? */ + upd_stat32(&xu->var->stats.mfrecv, 1); + upd_stat32(&xu->var->stats.mrbytes, item->packet.len - 14); + } + + /* remove processed packet from the receive queue */ + ethq_remove (&xu->var->ReadQ); + item = 0; + + /* tell host we received a packet */ + xu->var->pcsr0 |= PCSR0_RXI; + } /* if end-of-frame */ + + /* give buffer back to host */ + xu->var->rxhdr[2] &= ~RXR_OWN; /* clear ownership flag */ + + /* update the ring entry in host memory. */ + wstatus = Map_WriteW (ba, 8, xu->var->rxhdr, MAP); + if (wstatus) { + /* tell host bus write failed */ + xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; + xu->var->pcsr0 |= PCSR0_SERI; + /* if this was end-of-frame, log frame loss */ + if (xu->var->rxhdr[2] & RXR_ENF) + upd_stat16(&xu->var->stats.rlossi, 1); + } + + /* set to next receive ring buffer */ + xu->var->rxnext += 1; + if (xu->var->rxnext == xu->var->rrlen) + xu->var->rxnext = 0; + + } /* while */ + + /* if we failed to finish receiving the frame, flush the packet */ + if (item) { + ethq_remove(&xu->var->ReadQ); + upd_stat16(&xu->var->stats.rlossl, 1); + } + + /* set or clear interrupt, depending on what happened */ + xu_setclrint(xu, 0); +} + +void xu_process_transmit(CTLR* xu) +{ + uint32 segb, ba; + int slen, wlen, i, off, giant, runt; + t_stat rstatus, wstatus; + const ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; + + sim_debug(DBG_TRC, xu->dev, "xu_process_transmit()\n"); + + for (;;) { + + /* get next transmit buffer */ + ba = xu->var->tdrb + (xu->var->telen * 2) * xu->var->txnext; + rstatus = Map_ReadW (ba, 8, xu->var->txhdr, MAP); + if (rstatus) { + /* tell host bus read failed */ + xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG; + xu->var->pcsr0 |= PCSR0_SERI; + break; + } + + /* if buffer not owned by controller, exit [at end of ring] */ + if (!(xu->var->txhdr[2] & TXR_OWN)) + break; + + /* set buffer length and address */ + slen = xu->var->txhdr[0]; + segb = xu->var->txhdr[1] + ((xu->var->txhdr[2] & 3) << 16); + wlen = slen; + + /* prepare to accumulate transmit information if start of frame */ + if (xu->var->txhdr[2] & TXR_STF) { + memset(&xu->var->write_buffer, 0, sizeof(ETH_PACK)); + off = giant = runt = 0; + } + + /* get packet data from host */ + if (xu->var->write_buffer.len + slen > ETH_MAX_PACKET) { + wlen = ETH_MAX_PACKET - xu->var->write_buffer.len; + giant = 1; + } + if (wlen > 0) { + rstatus = Map_ReadB(segb, wlen, &xu->var->write_buffer.msg[off], MAP); + if (rstatus) { + /* tell host bus read failed */ + xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG; + xu->var->pcsr0 |= PCSR0_SERI; + break; + } + } + off += wlen; + xu->var->write_buffer.len += wlen; + + /* transmit packet when end-of-frame is reached */ + if (xu->var->txhdr[2] & TXR_ENF) { + + /* make sure packet is minimum length */ + if ((xu->var->write_buffer.len < ETH_MIN_PACKET) && (xu->var->mode & MODE_TPAD)) { + xu->var->write_buffer.len = ETH_MIN_PACKET; + runt = 1; + } + + /* are we in internal loopback mode ? */ + if ((xu->var->mode & MODE_LOOP) && (xu->var->mode & MODE_INTL)) { + /* just put packet in receive buffer */ + ethq_insert (&xu->var->ReadQ, 1, &xu->var->write_buffer, 0); + } else { + /* transmit packet synchronously - write callback sets status */ + wstatus = eth_write(xu->var->etherface, &xu->var->write_buffer, xu->var->wcallback); + if (wstatus) + xu->var->pcsr0 |= PCSR0_PCEI; + } + + /* update transmit status in transmit buffer */ + if (xu->var->write_buffer.status != 0) { + /* failure */ + const uint16 tdr = 100 + wlen * 8; /* arbitrary value */ + xu->var->txhdr[3] |= TXR_RTRY; + xu->var->txhdr[3] |= tdr & TXR_TDR; + xu->var->txhdr[2] |= TXR_ERRS; + } + + /* was packet too big or too small? */ + if (giant || runt) { + xu->var->txhdr[3] |= TXR_BUFL; + xu->var->txhdr[2] |= TXR_ERRS; + } + + /* was packet self-addressed? */ + for (i=0; ivar->write_buffer.msg, xu->var->setup.macs[i], sizeof(ETH_MAC)) == 0) + xu->var->txhdr[2] |= TXR_MTCH; + + /* tell host we transmitted a packet */ + xu->var->pcsr0 |= PCSR0_TXI; + + /* update stats */ + upd_stat32(&xu->var->stats.ftrans, 1); + upd_stat32(&xu->var->stats.tbytes, xu->var->write_buffer.len - 14); + if (xu->var->write_buffer.msg[0] & 1) { /* multicast? */ + upd_stat32(&xu->var->stats.mftrans, 1); + upd_stat32(&xu->var->stats.mtbytes, xu->var->write_buffer.len - 14); + } + if (giant) + bit_stat16(&xu->var->stats.txerf, 0x10); + + } /* if end-of-frame */ + + + /* give buffer ownership back to host */ + xu->var->txhdr[2] &= ~TXR_OWN; + + /* update transmit buffer */ + wstatus = Map_WriteW (ba, 8, xu->var->txhdr, MAP); + if (wstatus) { + /* tell host bus write failed */ + xu->var->pcsr0 |= PCSR0_PCEI; + /* update stats */ + upd_stat16(&xu->var->stats.ftransa, 1); + break; + } + + /* set to next transmit ring buffer */ + xu->var->txnext += 1; + if (xu->var->txnext == xu->var->trlen) + xu->var->txnext = 0; + + } /* while */ +} + +void xu_port_command (CTLR* xu) +{ + char* msg; + int command = xu->var->pcsr0 & PCSR0_PCMD; + int state = xu->var->pcsr1 & PCSR1_STATE; + int bits; + static char* commands[] = { + "NO-OP", + "GET PCBB", + "GET CMD", + "SELFTEST", + "START", + "BOOT", + "Reserved NO-OP", + "Reserved NO-OP", + "PDMD", + "Reserved NO-OP", + "Reserved NO-OP", + "Reserved NO-OP", + "Reserved NO-OP", + "Reserved NO-OP", + "HALT", + "STOP" + }; + + sim_debug(DBG_TRC, xu->dev, "xu_port_command(), Command = %s [0%o]\n", commands[command], command); + switch (command) { + case CMD_NOOP: /* NO-OP */ + /* NOOP does NOT set DNI */ + break; + + case CMD_GETPCBB: /* GET PCB-BASE */ + xu->var->pcbb = (xu->var->pcsr3 << 16) | xu->var->pcsr2; + xu->var->pcsr0 |= PCSR0_DNI; + break; + + case CMD_GETCMD: /* GET COMMAND */ + bits = xu_command(xu); + xu->var->pcsr0 |= PCSR0_DNI; + break; + + case CMD_SELFTEST: /* SELFTEST */ + xu_sw_reset(xu); + xu->var->pcsr0 |= PCSR0_DNI; + break; + + case CMD_START: /* START */ + if (state == STATE_READY) { + xu->var->pcsr1 &= ~PCSR1_STATE; + xu->var->pcsr1 |= STATE_RUNNING; + xu->var->pcsr0 |= PCSR0_DNI; + + /* reset ring pointers */ + xu->var->rxnext = 0; + xu->var->txnext = 0; + + } else + xu->var->pcsr0 |= PCSR0_PCEI; + break; + + case CMD_BOOT: /* BOOT */ + /* not implemented */ + msg = "%s: BOOT command not implemented!\n"; + printf (msg, xu->dev->name); + if (sim_log) fprintf(sim_log, msg, xu->dev->name); + + xu->var->pcsr0 |= PCSR0_PCEI; + break; + + case CMD_PDMD: /* POLLING DEMAND */ + /* process transmit buffers, receive buffers are done in the service timer */ + xu_process_transmit(xu); + xu->var->pcsr0 |= PCSR0_DNI; + break; + + case CMD_HALT: /* HALT */ + if ((state == STATE_READY) || (state == STATE_RUNNING)) { + sim_cancel (&xu->unit[0]); /* cancel service timer */ + xu->var->pcsr1 &= ~PCSR1_STATE; + xu->var->pcsr1 |= STATE_HALT; + xu->var->pcsr0 |= PCSR0_DNI; + } else + xu->var->pcsr0 |= PCSR0_PCEI; + break; + + case CMD_STOP: /* STOP */ + if (state == STATE_RUNNING) { + xu->var->pcsr1 &= ~PCSR1_STATE; + xu->var->pcsr1 |= STATE_READY; + xu->var->pcsr0 |= PCSR0_DNI; + } else + xu->var->pcsr0 |= PCSR0_PCEI; + break; + + case CMD_RSV06: /* RESERVED */ + case CMD_RSV07: /* RESERVED */ + case CMD_RSV11: /* RESERVED */ + case CMD_RSV12: /* RESERVED */ + case CMD_RSV13: /* RESERVED */ + case CMD_RSV14: /* RESERVED */ + case CMD_RSV15: /* RESERVED */ + xu->var->pcsr0 |= PCSR0_DNI; + break; /* all reserved commands act as a no-op but set DNI */ + } /* switch */ + + /* set interrupt if needed */ + xu_setclrint(xu, 0); +} + +t_stat xu_rd(int32 *data, int32 PA, int32 access) +{ + CTLR* xu = xu_pa2ctlr(PA); + int reg = (PA >> 1) & 03; + + sim_debug(DBG_TRC, xu->dev, "xu_rd(), PCSR%d\n", reg); + if (PA & 1) + sim_debug(DBG_WRN, xu->dev, "xu_rd(), Unexpected Odd address access of PCSR%d\n", reg); + + switch (reg) { + case 00: + *data = xu->var->pcsr0; + break; + case 01: + *data = xu->var->pcsr1; + break; + case 02: + *data = xu->var->pcsr2; + break; + case 03: + *data = xu->var->pcsr3; + break; + } + return SCPE_OK; +} + +t_stat xu_wr(int32 data, int32 PA, int32 access) +{ + CTLR* xu = xu_pa2ctlr(PA); + int reg = (PA >> 1) & 03; + + sim_debug(DBG_TRC, xu->dev, "xu_wr(), PCSR%d\n", reg); + switch (reg) { + case 00: + if (access == WRITEB) { + data &= 0377; + if (PA & 1) { + /* Handle WriteOneToClear trick. */ + xu->var->pcsr0 &= ~((data << 8) & 0177400); + + /* set/reset interrupt */ + xu_setclrint(xu, 0); + + /* Bail out early to avoid PCMD crap. */ + break; + } + } + /* RESET function requested? */ + if (data & PCSR0_RSET) { + xu_sw_reset(xu); + xu->var->pcsr0 |= PCSR0_DNI; + xu_setclrint(xu, 0); + return SCPE_OK; + } + /* Nope. Handle the INTE interlock thingie. */ + if ((xu->var->pcsr0 ^ data) & PCSR0_INTE) { + xu->var->pcsr0 ^= PCSR0_INTE; + xu->var->pcsr0 |= PCSR0_DNI; + } else { + /* Normal write, no interlock. */ + xu->var->pcsr0 &= ~PCSR0_PCMD; + xu->var->pcsr0 |= (data & PCSR0_PCMD); + xu_port_command(xu); + } + /* We might have changed the interrupt sys. */ + xu_setclrint(xu, 0); + break; + + case 01: + sim_debug(DBG_WRN, xu->dev, "xu_wr(), invalid write access on PCSR1!\n"); + break; + + case 02: + xu->var->pcsr2 = data & 0177776; /* store word, but not MBZ LSB */ + break; + + case 03: + xu->var->pcsr3 = data & 0000003; /* store significant bits */ + break; + } + return SCPE_OK; +} + + +/* attach device: */ +t_stat xu_attach(UNIT* uptr, char* cptr) +{ + t_stat status; + char* tptr; + CTLR* xu = xu_unit2ctlr(uptr); + + sim_debug(DBG_TRC, xu->dev, "xu_attach(cptr=%s)\n", cptr); + tptr = malloc(strlen(cptr) + 1); + if (tptr == NULL) return SCPE_MEM; + strcpy(tptr, cptr); + + xu->var->etherface = malloc(sizeof(ETH_DEV)); + if (!xu->var->etherface) return SCPE_MEM; + + status = eth_open(xu->var->etherface, cptr, xu->dev, DBG_ETH); + if (status != SCPE_OK) { + free(tptr); + free(xu->var->etherface); + xu->var->etherface = 0; + return status; + } + uptr->filename = tptr; + uptr->flags |= UNIT_ATT; + + /* reset the device with the new attach info */ + xu_reset(xu->dev); + + return SCPE_OK; +} + +/* detach device: */ + +t_stat xu_detach(UNIT* uptr) +{ + t_stat status; + CTLR* xu = xu_unit2ctlr(uptr); + sim_debug(DBG_TRC, xu->dev, "xu_detach()\n"); + + if (uptr->flags & UNIT_ATT) { + status = eth_close (xu->var->etherface); + free(xu->var->etherface); + xu->var->etherface = 0; + free(uptr->filename); + uptr->filename = NULL; + uptr->flags &= ~UNIT_ATT; + } + return SCPE_OK; +} + +void xu_setint(CTLR* xu) +{ + if (xu->var->pcsr0 & PCSR0_INTE) { + xu->var->irq = 1; + SET_INT(XU); + } + return; +} + +void xu_clrint(CTLR* xu) +{ + int i; + xu->var->irq = 0; /* set controller irq off */ + /* clear master interrupt? */ + for (i=0; iirq) { /* if any irqs enabled */ + SET_INT(XU); /* set master interrupt on */ + return; + } + CLR_INT(XU); /* clear master interrupt */ + return; +} + +int32 xu_int (void) +{ + int i; + for (i=0; ivar->irq) { /* if interrupt pending */ + xu_clrint(xu); /* clear interrupt */ + return xu->dib->vec; /* return vector */ + } + } + return 0; /* no interrupt request active */ +} diff --git a/PDP11/pdp11_xu.h b/PDP11/pdp11_xu.h new file mode 100644 index 00000000..8bceaf8c --- /dev/null +++ b/PDP11/pdp11_xu.h @@ -0,0 +1,301 @@ +/* pdp11_xu.h: DEUNA/DELUA ethernet controller information + ------------------------------------------------------------------------------ + + Copyright (c) 2003-2004, 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: + + 05-Jan-04 DTH Added network statistics + 31-Dec-03 DTH Added reserved states + 28-Dec-03 DTH Corrected MODE bitmasks + 23-Dec-03 DTH Corrected TXR and RXR bitmasks + 03-Dec-03 DTH Refitted to SIMH v3.0 platform + 05-May-03 DTH Started XU simulation + + ------------------------------------------------------------------------------ +*/ + +#ifndef _PDP11_XU_H +#define _PDP11_XU_H + + +#if defined (VM_PDP10) /* PDP10 version */ +#include "pdp10_defs.h" +#define XU_RDX 8 +#define XU_WID 16 +extern int32 int_req; +extern int32 int_vec[32]; + +#elif defined (VM_VAX) /* VAX version */ +#error "DEUNA/DELUA not supported on VAX!" + +#else /* PDP-11 version */ +#include "pdp11_defs.h" +#define XU_RDX 8 +#define XU_WID 16 +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; +#endif /* VM_PDP10 */ + +#include "sim_ether.h" + +#define XU_QUE_MAX 500 /* message queue array */ +#define XU_FILTER_MAX 11 /* mac + 10 multicast addrs */ +#define XU_SERVICE_INTERVAL 100 /* times per second */ +#define XU_ID_TIMER_VAL 540 /* 9 min * 60 sec */ +#define UDBSIZE 100 /* max size of UDB (in words) */ + +enum xu_type {XU_T_DEUNA, XU_T_DELUA}; + +struct xu_setup { + int promiscuous; /* promiscuous mode enabled */ + int multicast; /* enable all multicast addresses */ + int mac_count; /* number of multicast mac addresses */ + ETH_MAC macs[XU_FILTER_MAX]; /* MAC addresses to respond to */ +}; + +/* Network Statistics - + some of these will always be zero in the simulated environment, + since there is no ability for the sim_ether network driver to see + things like incoming runts, collision tests, babbling, etc. + */ +struct xu_stats { + uint16 secs; /* seconds since last clear */ + uint32 frecv; /* frames received */ + uint32 mfrecv; /* multicast frames received */ + uint16 rxerf; /* receive error flags */ + uint32 frecve; /* frames received with errors */ + uint32 rbytes; /* data bytes received */ + uint32 mrbytes; /* multicast data bytes received */ + uint16 rlossi; /* received frames lost - internal err */ + uint16 rlossl; /* received frames lost - local buffers */ + uint32 ftrans; /* frames transmitted */ + uint32 mftrans; /* multicast frames transmitted */ + uint32 ftrans3; /* frames transmitted with 3+ tries */ + uint32 ftrans2; /* frames transmitted - two tries */ + uint32 ftransd; /* frames transmitted - deferred */ + uint32 tbytes; /* data bytes transmitted */ + uint32 mtbytes; /* multicast data bytes transmitted */ + uint16 txerf; /* transmit error flags summary */ + uint16 ftransa; /* transmit frames aborted */ + uint16 txccf; /* transmit collision test failure */ + uint16 porterr; /* port driver errors */ + uint16 bablcnt; /* babble counter */ +}; + +struct xu_device { + /*+ initialized values - DO NOT MOVE */ + ETH_PCALLBACK rcallback; /* read callback routine */ + ETH_PCALLBACK wcallback; /* write callback routine */ + ETH_MAC mac; /* MAC address */ + enum xu_type type; /* controller type */ + /*- initialized values - DO NOT MOVE */ + + /* I/O register storage */ + uint32 irq; /* interrupt request flag */ + + /* buffers, etc. */ + ETH_DEV* etherface; + ETH_PACK read_buffer; + ETH_PACK write_buffer; + ETH_QUE ReadQ; + int idtmr; /* countdown for ID Timer */ + int sectmr; /* countup for one second timer */ + struct xu_setup setup; + struct xu_stats stats; /* reportable network statistics */ + + /* copied from dec_deuna.h */ + uint16 pcsr0; /* primary DEUNA registers */ + uint16 pcsr1; + uint16 pcsr2; + uint16 pcsr3; + uint32 mode; /* mode register */ + uint32 pcbb; /* port command block base */ + uint32 stat; /* extended port status */ + + uint32 tdrb; /* transmit desc ring base */ + uint32 telen; /* transmit desc ring entry len */ + uint32 trlen; /* transmit desc ring length */ + uint32 txnext; /* transmit buffer pointer */ + uint32 rdrb; /* receive desc ring base */ + uint32 relen; /* receive desc ring entry len */ + uint32 rrlen; /* receive desc ring length */ + uint32 rxnext; /* receive buffer pointer */ + + uint16 pcb[4]; /* copy of Port Command Block */ + uint16 udb[UDBSIZE]; /* copy of Unibus Data Block */ + uint16 rxhdr[4]; /* content of RX ring entry, during wait */ + uint16 txhdr[4]; /* content of TX ring entry, during xmit */ +}; + +struct xu_controller { + DEVICE* dev; /* device block */ + UNIT* unit; /* unit block */ + DIB* dib; /* device interface block */ + struct xu_device* var; /* controller-specific variables */ +}; + +typedef struct xu_controller CTLR; + +/* PCSR0 register definitions */ +#define PCSR0_SERI 0100000 /* <15> Status Error Intr */ +#define PCSR0_PCEI 0040000 /* <14> Port Command Error Intr */ +#define PCSR0_RXI 0020000 /* <13> Receive Interrupt */ +#define PCSR0_TXI 0010000 /* <12> Transmit Interrupt */ +#define PCSR0_DNI 0004000 /* <11> Done Interrupt */ +#define PCSR0_RCBI 0002000 /* <10> Recv Buffer Unavail Intr */ +#define PCSR0_USCI 0000400 /* <08> Unsolicited State Chg Inter */ +#define PCSR0_INTR 0000200 /* <07> Interrupt Summary */ +#define PCSR0_INTE 0000100 /* <06> Interrupt Enable */ +#define PCSR0_RSET 0000040 /* <05> Reset */ +#define PCSR0_PCMD 0000017 /* <03:00> Port Command field */ + +/* PCSR0 Port Commands */ +#define CMD_NOOP 000 /* No-op */ +#define CMD_GETPCBB 001 /* Get PCB base */ +#define CMD_GETCMD 002 /* Get Command */ +#define CMD_SELFTEST 003 /* Self-test init */ +#define CMD_START 004 /* Start xmit/recv */ +#define CMD_BOOT 005 /* Boot */ +#define CMD_RSV06 006 /* Reserved */ +#define CMD_RSV07 007 /* Reserved */ +#define CMD_PDMD 010 /* Polling Demand */ +#define CMD_RSV11 011 /* Reserved */ +#define CMD_RSV12 012 /* Reserved */ +#define CMD_RSV13 013 /* Reserved */ +#define CMD_RSV14 014 /* Reserved */ +#define CMD_RSV15 015 /* Reserved */ +#define CMD_HALT 016 /* Halt */ +#define CMD_STOP 017 /* Stop */ + +/* PCSR1 register definitions */ +#define PCSR1_XPWR 0100000 /* <15> Tranceiver power failure */ +#define PCSR1_ICAB 0040000 /* <14> Port/Link cable failure */ +#define PCSR1_ECOD 0037400 /* <13:08> Self-test error code */ +#define PCSR1_PCTO 0000200 /* <07> Port Command Timeout */ +#define PCSR1_TYPE 0000160 /* <06:04> Interface type */ +#define PCSR1_STATE 0000017 /* <03:00> State: */ + +/* PCSR1 Types */ +#define TYPE_DEUNA (0 << 4) /* Controller is a DEUNA */ +#define TYPE_DELUA (1 << 4) /* Controller is a DELUA */ + +/* PCSR1 States */ +#define STATE_RESET 000 /* Reset */ +#define STATE_PLOAD 001 /* Primary Load */ +#define STATE_READY 002 /* Ready */ +#define STATE_RUNNING 003 /* Running */ +#define STATE_UHALT 005 /* UNIBUS Halted */ +#define STATE_NHALT 006 /* NI Halted */ +#define STATE_NUHALT 007 /* NI and UNIBUS Halted */ +#define STATE_HALT 010 /* Halted */ +#define STATE_SLOAD 017 /* Secondary Load */ + +/* Status register definitions */ +#define STAT_ERRS 0100000 /* <15> error summary */ +#define STAT_MERR 0040000 /* <14> multiple errors */ +#define STAT_BABL 0020000 /* <13> Transmitter on too long [DELUA only] */ +#define STAT_CERR 0010000 /* <12> collision test error */ +#define STAT_TMOT 0004000 /* <11> UNIBUS timeout */ +#define STAT_RRNG 0001000 /* <09> receive ring error */ +#define STAT_TRNG 0000400 /* <08> transmit ring error */ +#define STAT_PTCH 0000200 /* <07> ROM patch */ +#define STAT_RRAM 0000100 /* <06> running from RAM */ +#define STAT_RREV 0000077 /* <05:00> ROM version */ + +/* Mode definitions */ +#define MODE_PROM 0100000 /* <15> Promiscuous Mode */ +#define MODE_ENAL 0040000 /* <14> Enable All Multicasts */ +#define MODE_DRDC 0020000 /* <13> Disable Data Chaining */ +#define MODE_TPAD 0010000 /* <12> Transmit Msg Pad Enable */ +#define MODE_ECT 0004000 /* <11> Enable Collision Test */ +#define MODE_DMNT 0001000 /* <09> Disable Maint Message */ +#define MODE_INTL 0000200 /* <07> Internal Loopback [DELUA only] */ +#define MODE_DTCR 0000010 /* <03> Disable Transmit CRC */ +#define MODE_LOOP 0000004 /* <02> Internal Loopback Mode */ +#define MODE_HDPX 0000001 /* <00> Half-Duplex Mode */ + +/* Function Code definitions */ +#define FC_NOOP 0000000 /* no-op */ +#define FC_LSM 0000001 /* Load and Start Microaddress */ +#define FC_RDPA 0000002 /* Read Default Physical Address */ +#define FC_RPA 0000004 /* Read Physical Address */ +#define FC_WPA 0000005 /* Write Physical Address */ +#define FC_RMAL 0000006 /* Read Multicast Address List */ +#define FC_WMAL 0000007 /* Write Multicast Address List */ +#define FC_RRF 0000010 /* Read Ring Format */ +#define FC_WRF 0000011 /* Write Ring Format */ +#define FC_RDCTR 0000012 /* Read Counters */ +#define FC_RDCLCTR 0000013 /* Read and Clear Counters */ +#define FC_RMODE 0000014 /* Read Mode */ +#define FC_WMODE 0000015 /* Write Mode */ +#define FC_RSTAT 0000016 /* Read Status */ +#define FC_RCSTAT 0000017 /* Read and Clear Status */ +#define FC_DIM 0000020 /* Dump Internal Memory */ +#define FC_LIM 0000021 /* Load Internal Memory */ +#define FC_RSID 0000022 /* Read System ID parameters */ +#define FC_WSID 0000023 /* Write System ID parameters */ +#define FC_RLSA 0000024 /* Read Load Server Address */ +#define FC_WLSA 0000025 /* Write Load Server Address */ + +/* Transmitter Ring definitions */ +#define TXR_OWN 0100000 /* <15> we own it (1) */ +#define TXR_ERRS 0040000 /* <14> error summary */ +#define TXR_MTCH 0020000 /* <13> Station Match */ +#define TXR_MORE 0010000 /* <12> Mult Retries Needed */ +#define TXR_ONE 0004000 /* <11> One Collision */ +#define TXR_DEF 0002000 /* <10> Deferred */ +#define TXR_STF 0001000 /* <09> Start Of Frame */ +#define TXR_ENF 0000400 /* <08> End Of Frame */ +#define TXR_BUFL 0100000 /* <15> Buffer Length Error */ +#define TXR_UBTO 0040000 /* <14> UNIBUS TimeOut */ +#define TXR_UFLO 0020000 /* <13> Underflow Error */ +#define TXR_LCOL 0010000 /* <12> Late Collision */ +#define TXR_LCAR 0004000 /* <11> Lost Carrier */ +#define TXR_RTRY 0002000 /* <10> Retry Failure (16x) */ +#define TXR_TDR 0001777 /* <9:0> TDR value if RTRY=1 */ + +/* Receiver Ring definitions */ +#define RXR_OWN 0100000 /* <15> we own it (1) */ +#define RXR_ERRS 0040000 /* <14> Error Summary */ +#define RXR_FRAM 0020000 /* <13> Frame Error */ +#define RXR_OFLO 0010000 /* <12> Message Overflow */ +#define RXR_CRC 0004000 /* <11> CRC Check Error */ +#define RXR_STF 0001000 /* <09> Start Of Frame */ +#define RXR_ENF 0000400 /* <08> End Of Frame */ +#define RXR_BUFL 0100000 /* <15> Buffer Length error */ +#define RXR_UBTO 0040000 /* <14> UNIBUS TimeOut */ +#define RXR_NCHN 0020000 /* <13> No Data Chaining */ +#define RXR_OVRN 0010000 /* <12> Overrun Error [DELUA only] */ +#define RXR_MLEN 0007777 /* <11:0> Message Length */ + +/* debugging bitmaps */ +#define DBG_TRC 0x0001 /* trace routine calls */ +#define DBG_REG 0x0002 /* trace read/write registers */ +#define DBG_WRN 0x0004 /* display warnings */ +#define DBG_ETH 0x8000 /* debug ethernet device */ + +#endif /* _PDP11_XU_H */ diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index 1f46dc56..681847fd 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -25,6 +25,10 @@ cpu PDP-4/7/9/15 central processor + 26-Mar-04 RMS Fixed warning from -std=c99 + 14-Jan-04 RMS Fixed g_mode in XVM implementation + PDP-15 index, autoincrement generate 18b addresses + Revised IO device call interface 31-Dec-03 RMS Fixed bug in cpu_set_hist 02-Nov-03 RMS Changed PDP-9,-15 default to API 26-Oct-03 RMS Fixed bug in PDP-4,-7,-9 autoincrement addressing @@ -386,7 +390,7 @@ t_stat Ia (int32 ma, int32 *ea, t_bool jmp); int32 Incr_addr (int32 addr); int32 Jms_word (int32 t); #if defined (PDP15) -#define INDEX(i,x) if (!memm && ((i) & I_IDX)) x = ((x) + XR) & AMASK +#define INDEX(i,x) if (!memm && ((i) & I_IDX)) x = ((x) + XR) & DMASK int32 Prot15 (int32 ma, t_bool bndchk); int32 Reloc15 (int32 ma, int32 acc); int32 RelocXVM (int32 ma, int32 acc); @@ -395,9 +399,9 @@ extern t_stat fp15 (int32 ir); #define INDEX(i,x) #endif -extern clk (int32 pulse, int32 AC); +extern int32 clk (int32 dev, int32 pulse, int32 AC); -int32 (*dev_tab[DEV_MAX])(int32 pulse, int32 AC); /* device dispatch */ +int32 (*dev_tab[DEV_MAX])(int32 dev, int32 pulse, int32 AC); /* device dispatch */ int32 (*dev_iors[DEV_MAX])(void); /* IORS dispatch */ @@ -851,7 +855,7 @@ case 004: /* JMS, dir */ #endif MB = Jms_word (api_usmd | usmd); /* save state */ if (Write (MA, MB, WR)) break; - PC = Incr_addr (MA); + PC = Incr_addr (MA) & AMASK; break; /* JMP: opcode 60 */ @@ -861,7 +865,7 @@ case 031: /* JMP, indir */ case 030: /* JMP, dir */ INDEX (IR, MA); PCQ_ENTRY; /* save old PC */ - PC = MA; + PC = MA & AMASK; break; /* OPR: opcode 74 */ @@ -1276,7 +1280,7 @@ case 034: /* IOT */ case 0: /* CPU and clock */ if (pulse == 002) ion = 0; /* IOF */ else if (pulse == 042) ion = ion_defer = 1; /* ION */ - else iot_data = clk (pulse, iot_data); + else iot_data = clk (device, pulse, iot_data); break; #endif @@ -1289,7 +1293,7 @@ case 034: /* IOT */ else if (pulse == 042) ion = ion_defer = 1; /* ION */ else if (pulse == 062) /* ITON */ usmd = usmd_buf = ion = ion_defer = 1; - else iot_data = clk (pulse, iot_data); + else iot_data = clk (device, pulse, iot_data); break; case 033: /* CPU control */ if ((pulse == 001) || (pulse == 041)) PC = Incr_addr (PC); @@ -1313,7 +1317,7 @@ case 034: /* IOT */ case 000: /* CPU and clock */ if (pulse == 002) ion = 0; /* IOF */ else if (pulse == 042) ion = 1; /* ION */ - else iot_data = clk (pulse, iot_data); + else iot_data = clk (device, pulse, iot_data); break; case 017: /* mem protection */ if (PROT) { /* enabled? */ @@ -1375,7 +1379,7 @@ case 034: /* IOT */ iot_data = MMR; else if (XVM && (pulse == 024)) /* LDMM */ MMR = iot_data; - else iot_data = clk (pulse, iot_data); + else iot_data = clk (device, pulse, iot_data); break; case 017: /* mem protection */ if (PROT) { /* enabled? */ @@ -1432,7 +1436,7 @@ case 034: /* IOT */ default: /* devices */ if (dev_tab[device]) /* defined? */ - iot_data = dev_tab[device] (pulse, iot_data); + iot_data = dev_tab[device] (device, pulse, iot_data); else reason = stop_inst; /* stop on flag */ break; } /* end switch device */ LAC = LAC | (iot_data & DMASK); @@ -1634,7 +1638,8 @@ return (((LAC & LINK) >> 1) | ((memm & 1) << 16) | will access absolute locations 00010-00017. Indirect addressing range is determined by autoincrementing. Any indirect can trigger a restore. - Memory protection is implemented for foreground/background operation. */ + Memory protection is implemented for foreground/background operation. + Read and write mask addresses to 17b except for XVM systems */ t_stat Read (int32 ma, int32 *dat, int32 cyc) { @@ -1643,7 +1648,7 @@ int32 pa; if (usmd) { /* user mode? */ if (XVM) pa = RelocXVM (ma, REL_R); /* XVM relocation? */ else if (RELOC) pa = Reloc15 (ma, REL_R); /* PDP-15 relocation? */ - else pa = Prot15 (ma, cyc == FE); /* just protection */ + else pa = Prot15 (ma, cyc == FE); /* PDP-15 prot, fetch only */ if (pa < 0) { /* error? */ *dat = 0; return MM_ERR; } } @@ -1661,7 +1666,7 @@ int32 pa; if (usmd) { /* user mode? */ if (XVM) pa = RelocXVM (ma, REL_W); /* XVM relocation? */ else if (RELOC) pa = Reloc15 (ma, REL_W); /* PDP-15 relocation? */ - else pa = Prot15 (ma, cyc != DF); /* just protection */ + else pa = Prot15 (ma, cyc != DF); /* PDP-15 prot, !defer */ if (pa < 0) return MM_ERR; } /* error? */ else pa = ma & AMASK; /* no prot or reloc */ if (MEM_ADDR_OK (pa)) M[pa] = dat & DMASK; /* valid mem? ok */ @@ -1673,8 +1678,9 @@ return MM_OK; t_stat Ia (int32 ma, int32 *ea, t_bool jmp) { -int32 t; +int32 gmode, t; int32 damask = memm? B_DAMASK: P_DAMASK; +static const int32 g_mask[4] = { MM_G_W0, MM_G_W1, MM_G_W2, MM_G_W3 }; t_stat sta = MM_OK; if ((ma & damask & ~07) == 010) { /* autoincrement? */ @@ -1688,8 +1694,10 @@ if (rest_pending) { /* restore pending? */ memm = (t >> 16) & 1; /* restore bank */ usmd = usmd_buf = (t >> 15) & 1; /* restore user */ emir_pending = rest_pending = 0; } -if (usmd && XVM && (MMR & MM_GM)) *ea = t; /* XVM G_mode? */ -else if ((ma & damask & ~07) == 010) *ea = t & AMASK; /* autoindex? */ +gmode = MM_GETGM (MMR); /* get G_mode */ +if (usmd && XVM && gmode) { /* XVM user mode? */ + *ea = t & g_mask[gmode]; } /* mask ia to size */ +else if ((ma & damask & ~07) == 010) *ea = t & DMASK; /* autoindex? */ else *ea = (PC & BLKMASK) | (t & IAMASK); /* within 32K */ return sta; } @@ -1745,13 +1753,11 @@ return pa; int32 RelocXVM (int32 ma, int32 rc) { int32 pa, gmode, slr; -static const int32 g_mask[4] = { MM_G_W0, MM_G_W1, MM_G_W2, MM_G_W3 }; static const int32 g_base[4] = { MM_G_B0, MM_G_B1, MM_G_B2, MM_G_B3 }; static const int32 slr_lnt[4] = { MM_SLR_L0, MM_SLR_L1, MM_SLR_L2, MM_SLR_L3 }; gmode = MM_GETGM (MMR); /* get G_mode */ slr = MM_GETSLR (MMR); /* get segment length */ -ma = ma & g_mask[gmode]; /* mask address */ if (MMR & MM_RDIS) pa = ma; /* reloc disabled? */ else if ((MMR & MM_SH) && /* shared enabled and */ (ma >= g_base[gmode]) && /* >= shared base and */ @@ -1884,7 +1890,7 @@ return SCPE_OK; /* CPU device handler - should never get here! */ -int32 bad_dev (int32 pulse, int32 AC) +int32 bad_dev (int32 dev, int32 pulse, int32 AC) { return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */ } diff --git a/PDP18B/pdp18b_defs.h b/PDP18B/pdp18b_defs.h index 120be26e..d53ffba5 100644 --- a/PDP18B/pdp18b_defs.h +++ b/PDP18B/pdp18b_defs.h @@ -1,6 +1,6 @@ /* pdp18b_defs.h: 18b PDP simulator definitions - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 14-Jan-04 RMS Revised IO device call interface 18-Oct-03 RMS Added DECtape off reel message 18-Jul-03 RMS Added FP15 support Added XVM support @@ -80,7 +81,7 @@ RB09 fixed head disk TC59 magnetic tape TC02/TU55 DECtape - LT09A second Teletype + LT09A additional Teletypes PDP15 128K KE15 EAE KSR-35 Teletype KA15 auto pri intr PC15 paper tape reader and punch @@ -91,7 +92,7 @@ XVM option RF15/RF09 fixed head disk TC59D magnetic tape TC15/TU56 DECtape - LT15 second Teletype + LT15/LT19 additional Teletypes ??Indicates not implemented. The PDP-4 manual refers to a memory ??extension control; there is no documentation on it. @@ -134,7 +135,7 @@ #define RF 0 /* fixed head disk */ #define MTA 0 /* magtape */ #define TC02 0 /* DECtape */ -#define TTY1 0 /* second Teletype */ +#define TTY1 4 /* second Teletype(s) */ #define BRMASK 0076000 /* bounds mask */ #elif defined (PDP15) #define ADDRSIZE 17 @@ -144,7 +145,7 @@ #define RP 0 /* disk pack */ #define MTA 0 /* magtape */ #define TC02 0 /* DECtape */ -#define TTY1 0 /* second Teletype */ +#define TTY1 16 /* second Teletype(s) */ #define BRMASK 0377400 /* bounds mask */ #define BRMASK_XVM 0777400 /* bounds mask, XVM */ #endif @@ -250,7 +251,7 @@ struct pdp18b_dib { uint32 dev; /* base dev number */ uint32 num; /* number of slots */ int32 (*iors)(void); /* IORS responder */ - int32 (*dsp[DEV_MAXBLK])(int32 pulse, int32 dat); + int32 (*dsp[DEV_MAXBLK])(int32 dev, int32 pulse, int32 dat); }; typedef struct pdp18b_dib DIB; @@ -312,7 +313,10 @@ typedef struct pdp18b_dib DIB; 35 LT15 TTI 3 PDP-15 only 36 - 37 - -*/ + + On the PDP-9, any API level active masks PI, and PI does not mask API. + On the PDP-15, only the hardware API levels active mask PI, and PI masks + the API software levels. */ #define API_ML0 0200 /* API masks: level 0 */ #define API_ML1 0100 diff --git a/PDP18B/pdp18b_diag.txt b/PDP18B/pdp18b_diag.txt new file mode 100644 index 00000000..0055c4ee --- /dev/null +++ b/PDP18B/pdp18b_diag.txt @@ -0,0 +1,58 @@ +Operating Instructions, PDP-15 diagnostics + +MAINDEC-15-D0A1-PH Instruction test 1 + +Read in: 200 +Start: 200 +Breakpoint: 7274 for one pass + +MAINDEC-15-D0A2-PH Instruction test 1A + +Read in: 200 +Start: 200 +Breakpoint: 4437 for one pass + +MAINDEC-15-D0AA-PB Index register test + +Read in: 17700 (binary tape, doesn't matter) +Start: 200 +Halts: at 214, set BANKM = 0 +Runs to: prints END at end of pass + +MAINDEC-15-D0BB-PH Instruction test 2 + +Read in: 200 +Start: 200 +SR: 1 to run clock test +Breakpoint: 6403 for one pass + +MAINDEC-15-D0CA-PH Memory address test + +Read in: 7200 +Start: 7200 +Breakpoint: 7577 for one pass + +MAINDEC-15-D0EA-PH JMP-Y interrupt test + +Read in: 7400 +Start: 7400 +Breakpoint: 7551 for one pass + +MAINDEC-15-D0FA-PH JMS-Y interrupt test + +Read in: 7400 +Start: 7400 +Breakpoint: 7577 for one pass + +MAINDEC-15-D0KA-PH ISZ test + +Read in: 200 +Start: 200 +Breakpoint: 7704 for one pass + +MAINDEC-15-D1CD-PB Extended memory test + +Read in: 200 (ignored, binary tape) +Start: 200 +Halts after printout, set SR = 30000 +Breakpoint: 563 for one pass \ No newline at end of file diff --git a/PDP18B/pdp18b_doc.txt b/PDP18B/pdp18b_doc.txt index f1428aa0..f17536ee 100644 --- a/PDP18B/pdp18b_doc.txt +++ b/PDP18B/pdp18b_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: 18b PDP Simulator Usage -Date: 25-Aug-2003 +Date: 4-Apr-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -107,7 +107,7 @@ PDP-9 CPU PDP-9 CPU with 32KW of memory - KX09A memory protection PTR,PTP PC09A paper tape reader/punch TTI,TTO KSR 33 console terminal - TTI1,TTO1 LT09A second console terminal + TTIX,TTOX 1-4 LT09A additional terminals LP9 LP09 line printer LPT Type 647E line printer CLK integral real-time clock @@ -126,7 +126,7 @@ PDP-15 CPU PDP-15 CPU with 32KW of memory FPP FP15 floating point processor PTR,PTP PC15 paper tape reader/punch TTI,TTO KSR 35 console terminal - TTI1,TTO1 LT15 second console terminal + TTIX,TTOX 1-16 LT15/LT19 additional terminals LP9 LP09 line printer LPT LP15 line printer CLK integral real-time clock @@ -154,7 +154,8 @@ The 18b PDP simulators implement several unique stop conditions: instruction execution - an FP15 instruction is decoded, the FP15 is disabled, and register STOP_FPP is set - - a simulated DECtape runs off the end of its real + - a simulated DECtape runs off the end of its real, and + register STOP_EOR is set The PDP-4 and PDP-7 LOAD command supports only "second stage" RIM format files (alternating DAC address instructions and data): @@ -532,52 +533,67 @@ The clock implements these registers: The real-time clock autocalibrates; the clock interval is adjusted up or down so that the clock tracks actual elapsed time. -2.3.7 Second Terminal (TTI1, TTO1) +2.3.7 Additional Terminals (TTIX, TTOX) -The second terminal consists of two independent devices, TTI1 and TTO1. -The second terminal performs input and output through a Telnet session -connected to a user-specified port. The ATTACH command specifies the -port to be used: +The additional terminals consist of two independent devices, TTIX and +TTOX. The entire set is modelled as a terminal multiplexor, with TTIX +as the master unit. The additional terminals perform input and output +through Telnet sessions connected to a user-specified port. The ATTACH +command specifies the port to be used: - ATTACH TTI1 set up listening port + ATTACH TTIX set up listening port where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. -Once TTI1 is attached and the simulator is running, the terminal listens -for a connection on the specified port. It assumes that the incoming -connection is a Telnet connection. The connection remain opens until -disconnected by the Telnet client, or by a DETACH TTI1 command. +The PDP-9 supports 1-4 additional terminals. The PDP-15 supports 1-16 +additional terminals. The number of additional terminals can be changed +with the command: -The second terminal (TTI1,TTO1) can be set to one of three modes: KSR, 7B, -or 8B. In KSR mode, lower case input and output characters are converted -automatically to upper case, the high order bit is forced to one on input, -and printing of ALTmode characters is supressed. In 7B mode, input and -output characters are masked to 7 bits. In 8B mode, characters are not -modified. Changing the mode of either device changes both. The default -mode is KSR. + SET TTIX LINES=n set number of lines to n -The SHOW TTI1 CONNECTIONS command displays the current connection to TTI1. -The SHOW TTI1 STATISTICS command displays statistics for the current connection. -The SET TTI1 DISCONNECT{=0} disconnects the current connection. +The default is one additional terminal. -The second terminal input implements these registers: +The additional terminals can be set to one of three modes: UC, 7B, or +8B. In KSR mode, lower case input and output characters are converted +automatically to upper case. In 7B mode, input and output characters +are masked to 7 bits. In 8B mode, characters are not modified. The +default mode is KSR. Finally, each line supports output logging. +The SET TTOXn LOG command enables logging on a line: + + SET TTOXn LOG=filename log output of line n to filename + +The SET TTOXn NOLOG command disables logging and closes the open log +file, if any. + +Once TTIX is attached and the simulator is running, the terminals listen +for connections on the specified port. They assume that the incoming +connections are Telnet connections. The connections remain open until +disconnected either by the Telnet client, a SET TTIX DISCONNECT command, +or a DETACH TTIX command. + +The SHOW TTIX CONNECTIONS command displays the current connections to the +extra terminals. The SHOW TTIX STATISTICS command displays statistics for +active connections. The SET TTIX DISCONNECT=linenumber disconnects the +specified line. + +The input device (TTIX) implements these registers: name size comments - BUF 8 last data item processed + BUF[0..3/15] 8 last character received + DONE 16 input ready flags, line 0 on right INT 1 interrupt pending flag - DONE 1 device done flag TIME 24 keyboard polling interval -The second terminal output implements these registers: +The output device (TTOX) implements these registers: name size comments - BUF 8 last data item processed + BUF[0..3/15] 8 last character transmitted + DONE 16 output ready flags, line 0 on right INT 1 interrupt pending flag - DONE 1 device done flag - TIME 24 time from I/O initiation to interrupt + TIME[0..3/15] 24 time from I/O initiation to interrupt 2.4 RP15/RP02 Disk Pack (RP) @@ -771,6 +787,7 @@ The DECtape controller implements these registers: all SUBSTATE 2 read/write command substate all POS[0:7] 32 position, in lines, units 0-7 all STATT[0:7] 18 unit state, units 0-7 + all STOP_OFFR 1 stop on off-reel error It is critically important to maintain certain timing relationships among the DECtape parameters, or the DECtape simulator will fail to diff --git a/PDP18B/pdp18b_drm.c b/PDP18B/pdp18b_drm.c index b00333dd..ef97ac7d 100644 --- a/PDP18B/pdp18b_drm.c +++ b/PDP18B/pdp18b_drm.c @@ -1,6 +1,6 @@ /* pdp18b_drm.c: drum/fixed head disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ drm (PDP-4,PDP-7) Type 24 serial drum + 14-Jan-04 RMS Revised IO device call interface 26-Oct-03 RMS Cleaned up buffer copy code 05-Dec-02 RMS Updated from Type 24 documentation 22-Nov-02 RMS Added PDP-4 support @@ -71,9 +72,9 @@ int32 drm_time = 10; /* inter-word time */ int32 drm_stopioe = 1; /* stop on error */ DEVICE drm_dev; -int32 drm60 (int32 pulse, int32 AC); -int32 drm61 (int32 pulse, int32 AC); -int32 drm62 (int32 pulse, int32 AC); +int32 drm60 (int32 dev, int32 pulse, int32 AC); +int32 drm61 (int32 dev, int32 pulse, int32 AC); +int32 drm62 (int32 dev, int32 pulse, int32 AC); int32 drm_iors (void); t_stat drm_svc (UNIT *uptr); t_stat drm_reset (DEVICE *dptr); @@ -117,7 +118,7 @@ DEVICE drm_dev = { /* IOT routines */ -int32 drm60 (int32 pulse, int32 AC) +int32 drm60 (int32 dev, int32 pulse, int32 AC) { if ((pulse & 027) == 06) { /* DRLR, DRLW */ drm_ma = AC & 0177777; /* load mem addr */ @@ -125,7 +126,7 @@ if ((pulse & 027) == 06) { /* DRLR, DRLW */ return AC; } -int32 drm61 (int32 pulse, int32 AC) +int32 drm61 (int32 dev, int32 pulse, int32 AC) { int32 t; @@ -142,7 +143,7 @@ if (pulse & 004) { /* DRSS */ return AC; } -int32 drm62 (int32 pulse, int32 AC) +int32 drm62 (int32 dev, int32 pulse, int32 AC) { int32 t; diff --git a/PDP18B/pdp18b_dt.c b/PDP18B/pdp18b_dt.c index 382aad93..153198b9 100644 --- a/PDP18B/pdp18b_dt.c +++ b/PDP18B/pdp18b_dt.c @@ -1,6 +1,6 @@ /* pdp18b_dt.c: 18b DECtape simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,6 +27,9 @@ (PDP-9) TC02/TU55 DECtape (PDP-15) TC15/TU56 DECtape + 25-Jan-04 RMS Revised for device debug support + 14-Jan-04 RMS Revised IO device call interface + Changed sim_fsize calling sequence, added STOP_OFFR 26-Oct-03 RMS Cleaned up buffer copy code 18-Oct-03 RMS Fixed reverse checksum in read all Added DECtape off reel message @@ -317,10 +320,11 @@ #define ABS(x) (((x) < 0)? (-(x)): (x)) extern int32 M[]; -extern int32 int_hwre[API_HLVL+1], dev_enb; +extern int32 int_hwre[API_HLVL+1]; extern UNIT cpu_unit; extern int32 sim_switches; extern int32 sim_is_running; +extern FILE *sim_deb; int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ @@ -328,15 +332,15 @@ int32 dtdb = 0; /* data buffer */ int32 dt_ltime = 12; /* interline time */ int32 dt_dctime = 40000; /* decel time */ int32 dt_substate = 0; -int32 dt_log = 0; int32 dt_logblk = 0; +int32 dt_stopoffr = 0; /* stop on off reel */ static const int32 map_unit[16] = { /* Type 550 unit map */ -1, 1, 2, 3, 4, 5, 6, 7, 0, -1, -1, -1, -1, -1, -1, -1 }; DEVICE dt_dev; -int32 dt75 (int32 pulse, int32 dat); -int32 dt76 (int32 pulse, int32 dat); +int32 dt75 (int32 dev, int32 pulse, int32 dat); +int32 dt76 (int32 dev, int32 pulse, int32 dat); int32 dt_iors (void); t_stat dt_svc (UNIT *uptr); t_stat dt_reset (DEVICE *dptr); @@ -400,7 +404,6 @@ REG dt_reg[] = { { DRDATA (LTIME, dt_ltime, 31), REG_NZ }, { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, { ORDATA (SUBSTATE, dt_substate, 2) }, - { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, { URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 0, DT_NUMDR, PV_LEFT | REG_RO) }, @@ -409,6 +412,7 @@ REG dt_reg[] = { { URDATA (LASTT, dt_unit[0].LASTT, 10, T_ADDR_W, 0, DT_NUMDR, REG_HRO) }, { ORDATA (DEVNO, dt_dib.dev, 6), REG_HRO }, + { FLDATA (STOP_OFFR, dt_stopoffr, 0) }, { NULL } }; MTAB dt_mod[] = { @@ -420,17 +424,25 @@ MTAB dt_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { 0 } }; +DEBTAB dt_deb[] = { + { "MOTION", LOG_MS }, + { "DATA", LOG_RW }, + { "READALL", LOG_RA }, + { "BLOCK", LOG_BL }, + { NULL, 0 } }; + DEVICE dt_dev = { "DT", dt_unit, dt_reg, dt_mod, DT_NUMDR, 8, 24, 1, 8, 18, NULL, NULL, &dt_reset, NULL, &dt_attach, &dt_detach, - &dt_dib, DEV_DISABLE }; + &dt_dib, DEV_DISABLE | DEV_DEBUG, 0, + dt_deb, NULL, NULL }; /* IOT routines */ #if defined (TC02) /* TC02/TC15 */ -int32 dt75 (int32 pulse, int32 dat) +int32 dt75 (int32 dev, int32 pulse, int32 dat) { int32 old_dtsa = dtsa, fnc; UNIT *uptr; @@ -462,7 +474,7 @@ if ((pulse & 067) == 063) /* DTEF!DTRB */ return dat; } -int32 dt76 (int32 pulse, int32 dat) +int32 dt76 (int32 dev, int32 pulse, int32 dat) { if ((pulse & 01) && (dtsb & DTB_DTF)) /* DTDF */ return IOT_SKP + dat; @@ -470,7 +482,7 @@ return dat; } #else /* Type 550 */ -int32 dt75 (int32 pulse, int32 dat) +int32 dt75 (int32 dev, int32 pulse, int32 dat) { if (((pulse & 041) == 001) && (dtsb & DTB_DTF)) /* MMDF */ dat = dat | IOT_SKP; @@ -486,7 +498,7 @@ DT_UPDINT; return dat; } -int32 dt76 (int32 pulse, int32 dat) +int32 dt76 (int32 dev, int32 pulse, int32 dat) { int32 fnc, mot, unum; UNIT *uptr = NULL; @@ -664,16 +676,16 @@ case DTS_OFR: /* off reel */ break; case FNC_MOVE: /* move */ dt_schedez (uptr, dir); /* sched end zone */ - if (dt_log & LOG_MS) printf ("[DT%d: moving %s]\n", unum, (dir? - "backward": "forward")); + 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 (dt_log & LOG_MS) printf ("[DT%d: searching %s]\n", unum, - (dir? "backward": "forward")); + 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 */ @@ -701,10 +713,11 @@ case FNC_WALL: /* write all */ else { newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE; if (!dir) newpos = newpos + (DT_WSIZE - 1); } - if ((dt_log & LOG_RA) || ((dt_log & LOG_BL) && (blk == dt_logblk))) - printf ("[DT%d: read all block %d %s%s\n", + if (DEBUG_PRI (dt_dev, LOG_RA) || + (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) + fprintf (sim_deb, ">>DT%d: read all block %d %s%s\n", unum, blk, (dir? "backward": "forward"), - ((dtsa & DTA_MODE)? " continuous]": "]")); + ((dtsa & DTA_MODE)? " continuous]": " ")); break; default: dt_seterr (uptr, DTB_SEL); /* bad state */ @@ -800,7 +813,8 @@ uint32 ba; switch (mot) { case DTS_DECF: case DTS_DECR: /* decelerating */ - if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */ + 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)); /* reversing */ @@ -821,7 +835,8 @@ default: /* other */ Off reel - detach unit (it must be deselected) */ -if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */ +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; } @@ -871,10 +886,11 @@ case FNC_READ: /* read */ if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } - if ((dt_log & LOG_RW) || ((dt_log & LOG_BL) && (blk == dt_logblk))) - printf ("[DT%d: reading block %d %s%s\n", + 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]": "]")); + ((dtsa & DTA_MODE)? " continuous": " ")); dt_substate = 0; /* fall through */ case 0: /* normal read */ M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ @@ -920,10 +936,11 @@ case FNC_WRIT: /* write */ if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } - if ((dt_log & LOG_RW) || ((dt_log & LOG_BL) && (blk == dt_logblk))) - printf ("[DT%d: writing block %d %s%s\n", unum, blk, + 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]": "]")); + ((dtsa & DTA_MODE)? " continuous": " ")); dt_substate = 0; /* fall through */ case 0: /* normal write */ M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ @@ -1245,7 +1262,7 @@ if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ else if (sim_switches & SWMASK ('S')) /* att 16b? */ uptr->flags = uptr->flags | UNIT_11FMT; else if (!(sim_switches & SWMASK ('T')) && /* autosize? */ - (sz = sim_fsize (cptr))) { + (sz = sim_fsize (uptr->fileref))) { if (sz == D8_FILSIZ) uptr->flags = uptr->flags | UNIT_8FMT; else if (sz == D11_FILSIZ) diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index 4b8eb99d..5d27437c 100644 --- a/PDP18B/pdp18b_fpp.c +++ b/PDP18B/pdp18b_fpp.c @@ -1,6 +1,6 @@ /* pdp18b_fpp.c: FP15 floating point processor simulator - Copyright (c) 2003, Robert M Supnik + Copyright (c) 2003-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -263,7 +263,7 @@ case FOP_MUL: /* multiply */ case FOP_DIV: /* divide */ if (sta = fp15_opnd (fir, ar, &fmb)) break; /* fetch op to FMB */ if (fir & FI_FP) /* fp? */ - sta = fp15_fadd (fir, &fma, &fmb, 1); /* yes, fp sub */ + sta = fp15_fdiv (fir, &fma, &fmb); /* yes, fp div */ else sta = fp15_idiv (fir, &fma, &fmb); /* no, int div */ break; @@ -271,7 +271,7 @@ case FOP_RDIV: /* reverse divide */ fmb = fma; /* FMB <- FMA */ if (sta = fp15_opnd (fir, ar, &fma)) break; /* fetch op to FMA */ if (fir & FI_FP) /* fp? */ - sta = fp15_fadd (fir, &fma, &fmb, 1); /* yes, fp sub */ + sta = fp15_fdiv (fir, &fma, &fmb); /* yes, fp div */ else sta = fp15_idiv (fir, &fma, &fmb); /* no, int div */ break; @@ -529,8 +529,7 @@ else if (((b->hi | b->lo) != 0) && (ediff <= 35)) { /* b!=0 && ~"small"? */ dp_rsh_1 (a, NULL); /* right shift */ a->exp = a->exp + 1; /* incr exponent */ if (!(ir & FI_NORND) && fguard) /* rounding? */ - dp_inc (a); - if (a->exp > 0377777) return FP_OVF; } } + dp_inc (a); } } } /* end if b != 0 */ fp15_asign (ir, a); /* adjust A sign */ return fp15_norm (ir, a, NULL, 0); /* norm, no round */ @@ -733,6 +732,11 @@ return; t_stat fp15_norm (int32 ir, UFP *a, UFP *b, t_bool rnd) { +a->hi = a->hi & UFP_FH_MASK; /* mask a */ +a->lo = a->lo & UFP_FL_MASK; +if (b) { /* if b, mask */ + b->hi = b->hi & UFP_FH_MASK; + b->lo = b->lo & UFP_FL_MASK; } if (!(ir & FI_NONORM)) { /* norm enabled? */ if ((a->hi | a->lo) || (b && (b->hi | b->lo))) { /* frac != 0? */ while ((a->hi & UFP_FH_NORM) == 0) { /* until norm */ diff --git a/PDP18B/pdp18b_lp.c b/PDP18B/pdp18b_lp.c index 3ef218a6..99b1c3f7 100644 --- a/PDP18B/pdp18b_lp.c +++ b/PDP18B/pdp18b_lp.c @@ -1,6 +1,6 @@ /* pdp18b_lp.c: 18b PDP's line printer simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,7 @@ lp09 (PDP-9,15) LP09 line printer lp15 (PDP-15) LP15 line printer + 14-Jan-04 RMS Revised IO device call interface 23-Jul-03 RMS Fixed overprint bug in Type 62 25-Apr-03 RMS Revised for extended file support 05-Feb-03 RMS Added LP09, fixed conditionalization @@ -75,8 +76,8 @@ static const char *lp62_cc[] = { "\f" }; DEVICE lp62_dev; -int32 lp62_65 (int32 pulse, int32 dat); -int32 lp62_66 (int32 pulse, int32 dat); +int32 lp62_65 (int32 dev, int32 pulse, int32 dat); +int32 lp62_66 (int32 dev, int32 pulse, int32 dat); int32 lp62_iors (void); t_stat lp62_svc (UNIT *uptr); t_stat lp62_reset (DEVICE *dptr); @@ -121,7 +122,7 @@ DEVICE lp62_dev = { /* IOT routines */ -int32 lp62_65 (int32 pulse, int32 dat) +int32 lp62_65 (int32 dev, int32 pulse, int32 dat) { int32 i; @@ -142,7 +143,7 @@ if (pulse & 04) { /* LPSE */ return dat; } -int32 lp62_66 (int32 pulse, int32 dat) +int32 lp62_66 (int32 dev, int32 pulse, int32 dat) { if ((pulse & 01) && TST_INT (LPTSPC)) /* LSSF */ dat = IOT_SKP | dat; @@ -239,8 +240,8 @@ static const char *lp647_cc[] = { "\f" }; DEVICE lp647_dev; -int32 lp647_65 (int32 pulse, int32 dat); -int32 lp647_66 (int32 pulse, int32 dat); +int32 lp647_65 (int32 dev, int32 pulse, int32 dat); +int32 lp647_66 (int32 dev, int32 pulse, int32 dat); int32 lp647_iors (void); t_stat lp647_svc (UNIT *uptr); t_stat lp647_reset (DEVICE *dptr); @@ -289,7 +290,7 @@ DEVICE lp647_dev = { /* IOT routines */ -int32 lp647_65 (int32 pulse, int32 dat) +int32 lp647_65 (int32 dev, int32 pulse, int32 dat) { int32 i, sb; @@ -331,7 +332,7 @@ if (pulse & 004) { /* LPDI */ return dat; } -int32 lp647_66 (int32 pulse, int32 dat) +int32 lp647_66 (int32 dev, int32 pulse, int32 dat) { if ((pulse & 01) && lp647_err) dat = IOT_SKP | dat; /* LPSE */ if (pulse & 02) { /* LPCF */ @@ -446,7 +447,7 @@ int32 lp09_ie = 1; /* int enable */ int32 lp09_stopioe = 0; DEVICE lp09_dev; -int32 lp09_66 (int32 pulse, int32 dat); +int32 lp09_66 (int32 dev, int32 pulse, int32 dat); int32 lp09_iors (void); t_stat lp09_svc (UNIT *uptr); t_stat lp09_reset (DEVICE *dptr); @@ -490,7 +491,7 @@ DEVICE lp09_dev = { /* IOT routines */ -int32 lp09_66 (int32 pulse, int32 dat) +int32 lp09_66 (int32 dev, int32 pulse, int32 dat) { int32 sb = pulse & 060; /* subopcode */ @@ -612,8 +613,8 @@ int32 lp15_bp = 0; char lp15_buf[LP15_BSIZE] = { 0 }; DEVICE lp15_dev; -int32 lp15_65 (int32 pulse, int32 dat); -int32 lp15_66 (int32 pulse, int32 dat); +int32 lp15_65 (int32 dev, int32 pulse, int32 dat); +int32 lp15_66 (int32 dev, int32 pulse, int32 dat); int32 lp15_iors (void); t_stat lp15_svc (UNIT *uptr); t_stat lp15_reset (DEVICE *dptr); @@ -660,7 +661,7 @@ DEVICE lp15_dev = { /* IOT routines */ -int32 lp15_65 (int32 pulse, int32 dat) +int32 lp15_65 (int32 dev, int32 pulse, int32 dat) { int32 header, sb; @@ -685,7 +686,7 @@ lp15_updsta (0); /* update status */ return dat; } -int32 lp15_66 (int32 pulse, int32 dat) +int32 lp15_66 (int32 dev, int32 pulse, int32 dat) { if (pulse == 021) lp15_sta = lp15_sta & ~STA_DON; /* LPCD */ if (pulse == 041) lp15_sta = 0; /* LPCF */ diff --git a/PDP18B/pdp18b_mt.c b/PDP18B/pdp18b_mt.c index 0796035d..f9bb8807 100644 --- a/PDP18B/pdp18b_mt.c +++ b/PDP18B/pdp18b_mt.c @@ -1,6 +1,6 @@ /* pdp18b_mt.c: 18b PDP magnetic tape simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ mt (PDP-9) TC59 magtape (PDP-15) TC59D magtape + 14-Jan-04 RMS Revised IO device call interface 25-Apr-03 RMS Revised for extended file support 28-Mar-03 RMS Added multiformat support 04-Mar-03 RMS Fixed bug in MTTR @@ -131,7 +132,7 @@ int32 mt_log = 0; uint8 *mtxb = NULL; /* transfer buffer */ DEVICE mt_dev; -int32 mt (int32 pulse, int32 dat); +int32 mt (int32 dev, int32 pulse, int32 dat); int32 mt_iors (void); t_stat mt_svc (UNIT *uptr); t_stat mt_reset (DEVICE *dptr); @@ -194,7 +195,7 @@ DEVICE mt_dev = { /* IOT routine */ -int32 mt (int32 pulse, int32 dat) +int32 mt (int32 dev, int32 pulse, int32 dat) { int32 f, sb; UNIT *uptr; diff --git a/PDP18B/pdp18b_rb.c b/PDP18B/pdp18b_rb.c index 839e1fcb..bfd5f9e4 100644 --- a/PDP18B/pdp18b_rb.c +++ b/PDP18B/pdp18b_rb.c @@ -1,6 +1,6 @@ /* pdp18b_rb.c: RB09 fixed head disk simulator - Copyright (c) 2003, Robert M Supnik + Copyright (c) 2003-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rb RB09 fixed head disk + 14-Jan-04 RMS Revised IO device call interface 26-Oct-03 RMS Cleaned up buffer copy code The RB09 is a head-per-track disk. It uses the single cycle data break @@ -89,7 +90,7 @@ int32 rb_burst = 1; /* burst mode flag */ int32 rb_stopioe = 1; /* stop on error */ DEVICE rb_dev; -int32 rb71 (int32 pulse, int32 AC); +int32 rb71 (int32 dev, int32 pulse, int32 AC); t_stat rb_svc (UNIT *uptr); t_stat rb_reset (DEVICE *dptr); int32 rb_updsta (int32 new); @@ -137,7 +138,7 @@ DEVICE rb_dev = { /* IOT routines */ -int32 rb71 (int32 pulse, int32 AC) +int32 rb71 (int32 dev, int32 pulse, int32 AC) { int32 tow, t, sb = pulse & 060; diff --git a/PDP18B/pdp18b_rf.c b/PDP18B/pdp18b_rf.c index ff7932f7..f528c6b7 100644 --- a/PDP18B/pdp18b_rf.c +++ b/PDP18B/pdp18b_rf.c @@ -1,6 +1,6 @@ /* pdp18b_rf.c: fixed head disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,8 @@ rf (PDP-9) RF09/RF09 (PDP-15) RF15/RS09 + 14-Jan-04 RMS Revised IO device call interface + 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 @@ -115,8 +117,8 @@ int32 rf_burst = 1; /* burst mode flag */ int32 rf_stopioe = 1; /* stop on error */ DEVICE rf_dev; -int32 rf70 (int32 pulse, int32 dat); -int32 rf72 (int32 pulse, int32 dat); +int32 rf70 (int32 dev, int32 pulse, int32 dat); +int32 rf72 (int32 dev, int32 pulse, int32 dat); int32 rf_iors (void); t_stat rf_svc (UNIT *uptr); t_stat rf_reset (DEVICE *dptr); @@ -174,7 +176,7 @@ DEVICE rf_dev = { /* IOT routines */ -int32 rf70 (int32 pulse, int32 dat) +int32 rf70 (int32 dev, int32 pulse, int32 dat) { int32 t, sb; @@ -217,7 +219,7 @@ rf_updsta (0); /* update status */ return dat; } -int32 rf72 (int32 pulse, int32 dat) +int32 rf72 (int32 dev, int32 pulse, int32 dat) { int32 sb = pulse & 060; @@ -311,14 +313,17 @@ t_stat rf_attach (UNIT *uptr, char *cptr) { uint32 p, sz; uint32 ds_bytes = RF_DKSIZE * sizeof (int32); +t_stat r; -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) { +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) { 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); +return SCPE_OK; } /* Change disk size */ diff --git a/PDP18B/pdp18b_rp.c b/PDP18B/pdp18b_rp.c index b4d739c9..2431dc39 100644 --- a/PDP18B/pdp18b_rp.c +++ b/PDP18B/pdp18b_rp.c @@ -1,6 +1,6 @@ /* pdp18b_rp.c: RP15/RP02 disk pack simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rp RP15/RP02 disk pack + 14-Jan-04 RMS Revised IO device call interface 06-Feb-03 RMS Revised IOT decoding, fixed bug in initiation 05-Oct-02 RMS Added DIB, device number support 06-Jan-02 RMS Revised enable/disable support @@ -144,8 +145,8 @@ int32 rp_swait = 10; /* seek time */ int32 rp_rwait = 10; /* rotate time */ DEVICE rp_dev; -int32 rp63 (int32 pulse, int32 dat); -int32 rp64 (int32 pulse, int32 dat); +int32 rp63 (int32 dev, int32 pulse, int32 dat); +int32 rp64 (int32 dev, int32 pulse, int32 dat); int32 rp_iors (void); t_stat rp_svc (UNIT *uptr); void rp_updsta (int32 newa, int32 newb); @@ -202,7 +203,7 @@ DEVICE rp_dev = { /* IOT routines */ -int32 rp63 (int32 pulse, int32 dat) +int32 rp63 (int32 dev, int32 pulse, int32 dat) { int32 sb = pulse & 060; /* subopcode */ @@ -244,7 +245,7 @@ return dat; /* IOT 64 */ -int32 rp64 (int32 pulse, int32 dat) +int32 rp64 (int32 dev, int32 pulse, int32 dat) { int32 u, f, c, sb; UNIT *uptr; diff --git a/PDP18B/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c index 213924bb..8d391714 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -1,6 +1,6 @@ /* pdp18b_stddev.c: 18b PDP's standard devices - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,6 +29,9 @@ tto teleprinter clk clock + 16-Feb-04 RMS Fixed bug in hardware read-in mode bootstrap + 14-Jan-04 RMS Revised IO device call interface + CAF does not turn off the clock 29-Dec-03 RMS Added console backpressure support 26-Jul-03 RMS Increased PTP, TTO timeouts for PDP-15 operating systems Added hardware read-in mode support for PDP-7/9/15 @@ -67,6 +70,7 @@ extern int32 M[]; extern int32 int_hwre[API_HLVL+1], PC, ASW; extern int32 sim_switches; +extern int32 sim_is_running; extern UNIT cpu_unit; int32 clk_state = 0; @@ -77,10 +81,10 @@ int32 tto_state = 0; int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = 16000; /* term mux poll */ -int32 ptr (int32 pulse, int32 dat); -int32 ptp (int32 pulse, int32 dat); -int32 tti (int32 pulse, int32 dat); -int32 tto (int32 pulse, int32 dat); +int32 ptr (int32 dev, int32 pulse, int32 dat); +int32 ptp (int32 dev, int32 pulse, int32 dat); +int32 tti (int32 dev, int32 pulse, int32 dat); +int32 tto (int32 dev, int32 pulse, int32 dat); int32 clk_iors (void); int32 ptr_iors (void); int32 ptp_iors (void); @@ -361,7 +365,7 @@ DEVICE tto_dev = { /* Clock: IOT routine */ -int32 clk (int32 pulse, int32 dat) +int32 clk (int32 dev, int32 pulse, int32 dat) { if (pulse & 001) { /* CLSF */ if (TST_INT (CLK)) dat = dat | IOT_SKP; } @@ -403,9 +407,10 @@ return (TST_INT (CLK)? IOS_CLK: 0); t_stat clk_reset (DEVICE *dptr) { CLR_INT (CLK); /* clear flag */ -clk_state = 0; /* clock off */ -sim_cancel (&clk_unit); /* stop clock */ tmxr_poll = clk_unit.wait; /* set mux poll */ +if (!sim_is_running) { /* RESET? */ + clk_state = 0; /* clock off */ + sim_cancel (&clk_unit); } /* stop clock */ return SCPE_OK; } @@ -429,7 +434,7 @@ return SCPE_OK; /* Paper tape reader: IOT routine */ -int32 ptr (int32 pulse, int32 dat) +int32 ptr (int32 dev, int32 pulse, int32 dat) { if (pulse & 001) { /* RSF */ if (TST_INT (PTR)) dat = dat | IOT_SKP; } @@ -531,12 +536,13 @@ return detach_unit (uptr); /* Hardware RIM loader routines, PDP-7/9/15 */ -int32 ptr_getw (FILE *fileref, int32 *hi) +int32 ptr_getw (UNIT *uptr, int32 *hi) { int32 word, bits, st, ch; word = st = bits = 0; -do { if ((ch = getc (fileref)) == EOF) return -1; +do { if ((ch = getc (uptr->fileref)) == EOF) return -1; + uptr->pos = uptr->pos + 1; if (ch & 0200) { word = (word << 6) | (ch & 077); bits = (bits << 1) | ((ch >> 6) & 1); @@ -546,12 +552,12 @@ if (hi != NULL) *hi = bits; return word; } -t_stat ptr_rim_load (FILE *fileref, int32 origin) +t_stat ptr_rim_load (UNIT *uptr, int32 origin) { int32 bits, val; for (;;) { /* word loop */ - if ((val = ptr_getw (fileref, &bits)) < 0) return SCPE_FMT; + if ((val = ptr_getw (uptr, &bits)) < 0) return SCPE_FMT; if (bits & 1) { /* end of tape? */ if ((val & 0760000) == OP_JMP) { PC = ((origin - 1) & 060000) | (val & 017777); @@ -714,7 +720,7 @@ extern int32 sim_switches; #if defined (PDP7) if (sim_switches & SWMASK ('H')) /* hardware RIM load? */ - return ptr_rim_load (ptr_unit.fileref, ASW); + return ptr_rim_load (&ptr_unit, ASW); #endif if (ptr_dib.dev != DEV_PTR) return STOP_NONSTD; /* non-std addr? */ if (MEMSIZE < 8192) mask = 0767777; /* 4k? */ @@ -733,14 +739,14 @@ return SCPE_OK; t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -return ptr_rim_load (ptr_unit.fileref, ASW); +return ptr_rim_load (&ptr_unit, ASW); } #endif /* Paper tape punch: IOT routine */ -int32 ptp (int32 pulse, int32 dat) +int32 ptp (int32 dev, int32 pulse, int32 dat) { if (pulse & 001) { /* PSF */ if (TST_INT (PTP)) dat = dat | IOT_SKP; } @@ -821,7 +827,7 @@ return detach_unit (uptr); /* Terminal input: IOT routine */ -int32 tti (int32 pulse, int32 dat) +int32 tti (int32 dev, int32 pulse, int32 dat) { if (pulse & 001) { /* KSF */ if (TST_INT (TTI)) dat = dat | IOT_SKP; } @@ -909,7 +915,7 @@ return SCPE_OK; /* Terminal output: IOT routine */ -int32 tto (int32 pulse, int32 dat) +int32 tto (int32 dev, int32 pulse, int32 dat) { if (pulse & 001) { /* TSF */ if (TST_INT (TTO)) dat = dat | IOT_SKP; } diff --git a/PDP18B/pdp18b_sys.c b/PDP18B/pdp18b_sys.c index 683966fe..fd3007de 100644 --- a/PDP18B/pdp18b_sys.c +++ b/PDP18B/pdp18b_sys.c @@ -1,6 +1,6 @@ /* pdp18b_sys.c: 18b PDP's simulator interface - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 09-Jan-04 RMS Fixed instruction table errors 18-Oct-03 RMS Added DECtape off reel message 30-Jul-03 RMS Fixed FPM class mask 18-Jul-03 RMS Added FP15 support @@ -366,6 +367,9 @@ static const int32 masks[] = { 0740700, 0760700, 0777700, 0777777, 0777777, 0777777 }; +/* If both NPN (clear AC) and NPI versions of an IOT are defined, + the NPN version must come first */ + static const char *opcode[] = { "CAL", "DAC", "JMS", "DZM", /* mem refs */ "LAC", "XOR", "ADD", "TAD", @@ -472,7 +476,7 @@ static const char *opcode[] = { #if defined (PDP15) "SPCO", "SKP15", "RES", "SBA", "DBA", "EBA", - "ORMM", "RDMM", "LDMM", "MPLR", + "RDMM", "ORMM", "LDMM", "MPLR", "ENB", "INH", "MPRC", "IPFH", "AAS", "PAX", "PAL", "AAC", "PXA", "AXS", "PXL", "PLA", @@ -670,7 +674,7 @@ static const int32 opc_val[] = { #if defined (RP) 0706301+I_NPI, 0706321+I_NPI, 0706341+I_NPI, 0706361+I_NPI, 0706312+I_NPN, 0706302+I_NPI, 0706332+I_NPN, 0706322+I_NPI, - 0706342+I_NPN, 0706352+I_NPI, + 0706352+I_NPN, 0706342+I_NPI, 0706304+I_NPI, 0706324+I_NPI, 0706344+I_NPI, 0706364+I_NPI, 0706411+I_NPN, 0706401+I_NPI, 0706421+I_NPI, 0706412+I_NPN, 0706402+I_NPI, 0706432+I_NPN, 0706422+I_NPI, @@ -703,7 +707,7 @@ static const int32 opc_val[] = { #if defined (PDP15) 0703341+I_NPI, 0707741+I_NPI, 0707742+I_NPI, 0707761+I_NPI, 0707762+I_NPI, 0707764+I_NPI, - 0700022+I_NPI, 0700032+I_NPN, 0700024+I_NPI, 0701724+I_NPI, + 0700032+I_NPN, 0700022+I_NPI, 0700024+I_NPI, 0701724+I_NPI, 0705521+I_NPI, 0705522+I_NPI, 0701722+I_NPI, 0701764+I_NPI, 0720000+I_XR9, 0721000+I_XR, 0722000+I_XR, 0723000+I_XR9, 0724000+I_XR, 0725000+I_XR9, 0726000+I_XR, 0730000+I_XR, diff --git a/PDP18B/pdp18b_tt1.c b/PDP18B/pdp18b_tt1.c index 9229bc3d..4da1c99d 100644 --- a/PDP18B/pdp18b_tt1.c +++ b/PDP18B/pdp18b_tt1.c @@ -1,6 +1,6 @@ -/* pdp18b_tt1.c: 18b PDP's second Teletype +/* pdp15_ttx.c: PDP-15 additional terminals simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,23 +23,14 @@ 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. - tti1 keyboard - tto1 teleprinter + ttix,ttox LT15/LT19 terminal input/output - 09-May-03 RMS Added network device flag - 22-Dec-02 RMS Added break support - 02-Nov-02 RMS Added 7B/8B support - 05-Oct-02 RMS Added DIB, device number support - 22-Aug-02 RMS Updated for changes to sim_tmxr - 30-May-02 RMS Widened POS to 32b - 06-Jan-02 RMS Added enable/disable support - 30-Dec-01 RMS Added show statistics, set disconnect - 30-Nov-01 RMS Added extended SET/SHOW support - 25-Nov-01 RMS Revised interrupt structure - 19-Sep-01 RMS Fixed typo - 17-Sep-01 RMS Changed to use terminal multiplexor library - 07-Sep-01 RMS Moved function prototypes - 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware + 14-Jan-04 RMS Cloned from pdp8_ttx.c + + This module implements 16 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 "pdp18b_defs.h" @@ -47,266 +38,400 @@ #include "sim_tmxr.h" #include +#if defined (PDP15) +#define TTX_MAXL 16 /* max number of lines */ +#elif defined (PDP9) +#define TTX_MAXL 4 +#else +#define TTX_MAXL 1 +#endif + #define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ #define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */ #define UNIT_8B (1 << UNIT_V_8B) #define UNIT_KSR (1 << UNIT_V_KSR) -extern int32 int_hwre[API_HLVL+1], dev_enb; -extern int32 tmxr_poll; /* calibrated poll */ -TMLN tt1_ldsc = { 0 }; /* line descriptors */ -TMXR tt_desc = { 1, 0, 0, &tt1_ldsc }; /* mux descriptor */ +uint32 ttix_done = 0; /* input flags */ +uint32 ttox_done = 0; /* output flags */ +uint8 ttix_buf[TTX_MAXL] = { 0 }; /* input buffers */ +uint8 ttox_buf[TTX_MAXL] = { 0 }; /* output buffers */ +TMLN ttx_ldsc[TTX_MAXL] = { 0 }; /* line descriptors */ +TMXR ttx_desc = { 1, 0, 0, ttx_ldsc }; /* mux descriptor */ +#define ttx_lines ttx_desc.lines /* current number of lines */ -DEVICE tti1_dev, tto1_dev; -int32 tti1 (int32 pulse, int32 dat); -int32 tto1 (int32 pulse, int32 dat); -t_stat tti1_svc (UNIT *uptr); -t_stat tto1_svc (UNIT *uptr); -t_stat tti1_reset (DEVICE *dptr); -t_stat tto1_reset (DEVICE *dptr); -t_stat tti1_attach (UNIT *uptr, char *cptr); -t_stat tti1_detach (UNIT *uptr); -t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc); -void tt1_enbdis (int32 dis); -t_stat tt1_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); +extern int32 int_hwre[API_HLVL+1]; +extern int32 tmxr_poll; +extern int32 stop_inst; + +DEVICE ttix_dev, ttox_dev; +int32 ttix (int32 dev, int32 pulse, int32 dat); +int32 ttox (int32 dev, int32 pulse, int32 dat); +t_stat ttix_svc (UNIT *uptr); +t_bool ttix_test_done (int32 ln); +void ttix_set_done (int32 ln); +void ttix_clr_done (int32 ln); +t_stat ttox_svc (UNIT *uptr); +t_bool ttox_test_done (int32 ln); +void ttox_set_done (int32 ln); +void ttox_clr_done (int32 ln); +int32 ttx_getln (int32 dev, int32 pulse); +t_stat ttx_attach (UNIT *uptr, char *cptr); +t_stat ttx_detach (UNIT *uptr); +t_stat ttx_reset (DEVICE *dptr); +void ttx_reset_ln (int32 i); +t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat ttx_vlines (UNIT *uptr, int32 val, char *cptr, void *desc); -/* TTI1 data structures +/* TTIx data structures - tti1_dev TTI1 device descriptor - tti1_unit TTI1 unit - tto1_mod TTI1 modifier list - tti1_reg TTI1 register list + ttix_dev TTIx device descriptor + ttix_unit TTIx unit descriptor + ttix_reg TTIx register list + ttix_mod TTIx modifiers list */ -DIB tti1_dib = { DEV_TTI1, 1, NULL, { &tti1 } }; +DIB ttix_dib = { DEV_TTO1, 8, NULL, + { &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix } }; -UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE+UNIT_KSR, 0), KBD_POLL_WAIT }; +UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; -REG tti1_reg[] = { - { ORDATA (BUF, tti1_unit.buf, 8) }, +REG ttx_nlreg = { DRDATA (NLINES, ttx_lines, 4), PV_LEFT }; + +REG ttix_reg[] = { + { BRDATA (BUF, ttix_buf, 8, 8, TTX_MAXL) }, + { ORDATA (DONE, ttix_done, TTX_MAXL) }, { FLDATA (INT, int_hwre[API_TTI1], INT_V_TTI1) }, - { FLDATA (DONE, int_hwre[API_TTI1], INT_V_TTI1) }, - { DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT }, - { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, - { ORDATA (DEVNO, tti1_dib.dev, 6), REG_HRO }, + { DRDATA (TIME, ttix_unit.wait, 24), REG_NZ + PV_LEFT }, + { ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO }, { NULL } }; -MTAB tti1_mod[] = { - { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tt1_set_mode }, - { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tt1_set_mode }, - { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tt1_set_mode }, - { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tti1_summ }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &tt_desc }, +MTAB ttix_mod[] = { + { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES", + &ttx_vlines, NULL, &ttx_nlreg }, + { 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, &tti1_show, NULL }, + NULL, &ttx_show, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tti1_show, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, + NULL, &ttx_show, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_devno, &show_devno, NULL }, + { 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 tti1_dev = { - "TTI1", &tti1_unit, tti1_reg, tti1_mod, + "TTIX", &ttix_unit, ttix_reg, ttix_mod, 1, 10, 31, 1, 8, 8, - &tmxr_ex, &tmxr_dep, &tti1_reset, - NULL, &tti1_attach, &tti1_detach, - &tti1_dib, DEV_NET | DEV_DISABLE }; + &tmxr_ex, &tmxr_dep, &ttx_reset, + NULL, &ttx_attach, &ttx_detach, + &ttix_dib, DEV_NET | DEV_DISABLE }; -/* TTO1 data structures +/* TTOx data structures - tto1_dev TTO1 device descriptor - tto1_unit TTO1 unit - tto1_mod TTO1 modifier list - tto1_reg TTO1 register list + ttox_dev TTOx device descriptor + ttox_unit TTOx unit descriptor + ttox_reg TTOx register list */ -DIB tto1_dib = { DEV_TTO1, 1, NULL, { &tto1 } }; +UNIT ttox_unit[] = { + { UDATA (&ttox_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT }, + { UDATA (&ttox_svc, UNIT_KSR+UNIT_DIS, 0), SERIAL_OUT_WAIT } }; -UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT }; - -REG tto1_reg[] = { - { ORDATA (BUF, tto1_unit.buf, 8) }, +REG ttox_reg[] = { + { BRDATA (BUF, ttox_buf, 8, 8, TTX_MAXL) }, + { ORDATA (DONE, ttox_done, TTX_MAXL) }, { FLDATA (INT, int_hwre[API_TTO1], INT_V_TTO1) }, - { FLDATA (DONE, int_hwre[API_TTO1], INT_V_TTO1) }, - { DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT }, - { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, - { ORDATA (DEVNO, tto1_dib.dev, 6), REG_HRO }, + { URDATA (TIME, ttox_unit[0].wait, 10, 24, 0, + TTX_MAXL, PV_LEFT) }, { NULL } }; -MTAB tto1_mod[] = { - { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tt1_set_mode }, - { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tt1_set_mode }, - { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tt1_set_mode }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, +MTAB ttox_mod[] = { + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", NULL }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , NULL }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , NULL }, { 0 } }; DEVICE tto1_dev = { - "TTO1", &tto1_unit, tto1_reg, tto1_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tto1_reset, + "TTOX", ttox_unit, ttox_reg, ttox_mod, + TTX_MAXL, 10, 31, 1, 8, 8, + NULL, NULL, &ttx_reset, NULL, NULL, NULL, - &tto1_dib, DEV_DISABLE }; + NULL, DEV_DISABLE }; /* Terminal input: IOT routine */ -int32 tti1 (int32 pulse, int32 dat) +int32 ttix (int32 dev, int32 pulse, int32 dat) { +int32 ln = ttx_getln (dev, pulse); /* line # */ + +if (ln > ttx_lines) return dat; if (pulse & 001) { /* KSF1 */ - if (TST_INT (TTI1)) dat = dat | IOT_SKP; } + if (ttix_test_done (ln)) dat = dat | IOT_SKP; } if (pulse & 002) { /* KRB1 */ - CLR_INT (TTI1); /* clear flag */ - dat= dat | tti1_unit.buf; } /* return buffer */ + ttix_clr_done (ln); /* clear flag */ + dat = dat | ttix_buf[ln]; } /* return buffer */ return dat; } /* Unit service */ -t_stat tti1_svc (UNIT *uptr) +t_stat ttix_svc (UNIT *uptr) { -int32 c, newln; +int32 ln, c, temp; -if (tt1_ldsc.conn) { /* connected? */ - tmxr_poll_rx (&tt_desc); /* poll for input */ - if (c = tmxr_getc_ln (&tt1_ldsc)) { /* get char */ - if (c & SCPE_BREAK) uptr->buf = 0; /* break? */ - else if (uptr->flags & UNIT_KSR) { /* KSR? */ - c = c & 0177; - if (islower (c)) c = toupper (c); - uptr->buf = c | 0200; } /* got char */ - else uptr->buf = c & ((tti1_unit.flags & UNIT_8B)? 0377: 0177); - SET_INT (TTI1); } /* set flag */ - sim_activate (uptr, uptr->wait); } /* continue poll */ -if (uptr->flags & UNIT_ATT) { /* attached? */ - newln = tmxr_poll_conn (&tt_desc); /* poll connect */ - if (newln >= 0) { /* got one? */ - sim_activate (&tti1_unit, tti1_unit.wait); - tt1_ldsc.rcve = 1; } /* rcv enabled */ - sim_activate (uptr, tmxr_poll); } /* sched poll */ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +sim_activate (uptr, tmxr_poll); /* continue poll */ +ln = tmxr_poll_conn (&ttx_desc); /* look for connect */ +if (ln >= 0) ttx_ldsc[ln].rcve = 1; /* got one? rcv enab */ +tmxr_poll_rx (&ttx_desc); /* poll for input */ +for (ln = 0; ln < TTX_MAXL; 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 if (ttox_unit[ln].flags & UNIT_KSR) { /* KSR? */ + c = temp & 0177; + if (islower (c)) c = toupper (c); + c = c | 0200; } + else c = temp & ((ttox_unit[ln].flags & UNIT_8B)? 0377: 0177); + ttix_buf[ln] = c; + ttix_set_done (ln); } } } return SCPE_OK; } -/* Reset routine */ +/* Interrupt handling routines */ -t_stat tti1_reset (DEVICE *dptr) +t_bool ttix_test_done (int32 ln) { -tt1_enbdis (dptr->flags & DEV_DIS); /* sync enables */ -tti1_unit.buf = 0; /* clear buffer */ -CLR_INT (TTI1); /* clear flag */ -if (tt1_ldsc.conn) { /* if conn, */ - sim_activate (&tti1_unit, tti1_unit.wait); /* activate, */ - tt1_ldsc.rcve = 1; } /* enable */ -else if (tti1_unit.flags & UNIT_ATT) /* if attached, */ - sim_activate (&tti1_unit, tmxr_poll); /* activate */ -else sim_cancel (&tti1_unit); /* else stop */ -return SCPE_OK; +if (ttix_done & (1 << ln)) return TRUE; +return FALSE; +} + +void ttix_set_done (int32 ln) +{ +ttix_done = ttix_done | (1 << ln); +SET_INT (TTI1); +return; +} + +void ttix_clr_done (int32 ln) +{ +ttix_done = ttix_done & ~(1 << ln); +if (ttix_done) { SET_INT (TTI1); } +else { CLR_INT (TTI1); } +return; } /* Terminal output: IOT routine */ -int32 tto1 (int32 pulse, int32 dat) +int32 ttox (int32 dev, int32 pulse, int32 dat) { +int32 ln = ttx_getln (dev, pulse); /* line # */ + +if (ln > ttx_lines) return dat; if (pulse & 001) { /* TSF */ - if (TST_INT (TTO1)) dat = dat | IOT_SKP; } -if (pulse & 002) CLR_INT (TTO1); /* clear flag */ + if (ttox_test_done (ln)) dat = dat | IOT_SKP; } +if (pulse & 002) ttox_clr_done (ln); /* clear flag */ if (pulse & 004) { /* load buffer */ - sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */ - tto1_unit.buf = dat & 0377; } /* load buffer */ + sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate unit */ + ttox_buf[ln] = dat & 0377; } /* load buffer */ return dat; } /* Unit service */ -t_stat tto1_svc (UNIT *uptr) +t_stat ttox_svc (UNIT *uptr) { -int32 c; +int32 c, ln = uptr - ttox_unit; /* line # */ -SET_INT (TTO1); /* set flag */ -c = tto1_unit.buf & 0177; -if (tt1_ldsc.conn) { /* connected? */ - if (tt1_ldsc.xmte) { /* tx enabled? */ - if (tto1_unit.flags & UNIT_KSR) { /* KSR? */ - c = c & 0177; +if (ttx_ldsc[ln].conn) { /* connected? */ + if (ttx_ldsc[ln].xmte) { /* tx enabled? */ + TMLN *lp = &ttx_ldsc[ln]; /* get line */ + if (ttox_unit[ln].flags & UNIT_KSR) { /* KSR mode? */ + c = ttox_buf[ln] & 0177; /* get char */ if (islower (c)) c = toupper (c); - if ((c < 007) || (c > 0137)) c = 0; } - else c = c & ((tto1_unit.flags & UNIT_8B)? 0377: 0177); - if (c) tmxr_putc_ln (&tt1_ldsc, c); /* output char */ - tmxr_poll_tx (&tt_desc); } /* poll xmt */ + if ((c < 007) || (c > 0137)) c = -1; } + else c = ttox_buf[ln] & ((ttox_unit[ln].flags & UNIT_8B)? 0377: 0177); + if (c >= 0) tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&ttx_desc); } /* poll xmt */ else { - tmxr_poll_tx (&tt_desc); /* poll xmt */ - sim_activate (&tto1_unit, tmxr_poll); /* wait */ + tmxr_poll_tx (&ttx_desc); /* poll xmt */ + sim_activate (uptr, ttox_unit[ln].wait); /* wait */ return SCPE_OK; } } +ttox_set_done (ln); /* set done */ return SCPE_OK; } +/* Interrupt handling routines */ + +t_bool ttox_test_done (int32 ln) +{ +if (ttox_done & (1 << ln)) return TRUE; +return FALSE; +} + +void ttox_set_done (int32 ln) +{ +ttox_done = ttox_done | (1 << ln); +SET_INT (TTO1); +return; +} + +void ttox_clr_done (int32 ln) +{ +ttox_done = ttox_done & ~(1 << ln); +if (ttox_done) { SET_INT (TTO1); } +else { CLR_INT (TTO1); } +return; +} + +/* Compute relative line number + + This algorithm does not assign contiguous line numbers of ascending + LT19's. Rather, line numbers follow a simple progression based on + the relative IOT number and the subdevice select */ + +int32 ttx_getln (int32 dev, int32 pulse) +{ +int32 rdno = ((dev - ttix_dib.dev) >> 1) & 3; + +#if defined (PDP15) /* PDP-15? */ +int32 sub = (pulse >> 4) & 3; +return (rdno * 4) + sub; /* use dev, subdev */ +#else /* others */ +return rdno; /* use dev only */ +#endif +} + /* Reset routine */ -t_stat tto1_reset (DEVICE *dptr) +t_stat ttx_reset (DEVICE *dptr) { -tt1_enbdis (dptr->flags & DEV_DIS); /* sync enables */ -tto1_unit.buf = 0; /* clear buffer */ -CLR_INT (TTO1); /* clear flag */ -sim_cancel (&tto1_unit); /* deactivate unit */ +int32 ln; + +if (dptr->flags & DEV_DIS) { /* sync enables */ + 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; } +if (ttix_unit.flags & UNIT_ATT) /* if attached, */ + sim_activate (&ttix_unit, tmxr_poll); /* activate */ +else sim_cancel (&ttix_unit); /* else stop */ +for (ln = 0; ln < TTX_MAXL; ln++) ttx_reset_ln (ln); /* for all lines */ return SCPE_OK; } -/* Attach routine */ +/* Reset line n */ -t_stat tti1_attach (UNIT *uptr, char *cptr) +void ttx_reset_ln (int32 ln) +{ +ttix_buf[ln] = 0; /* clear buf, */ +ttox_buf[ln] = 0; +ttix_clr_done (ln); /* clear done */ +ttox_clr_done (ln); +sim_cancel (&ttox_unit[ln]); /* stop poll */ +return; +} + +/* Attach master unit */ + +t_stat ttx_attach (UNIT *uptr, char *cptr) { t_stat r; -r = tmxr_attach (&tt_desc, uptr, cptr); /* attach */ +r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */ if (r != SCPE_OK) return r; /* error */ sim_activate (uptr, tmxr_poll); /* start poll */ return SCPE_OK; } -/* Detach routine */ +/* Detach master unit */ -t_stat tti1_detach (UNIT *uptr) +t_stat ttx_detach (UNIT *uptr) { +int32 i; t_stat r; -r = tmxr_detach (&tt_desc, uptr); /* detach */ -tt1_ldsc.rcve = 0; /* disable rcv */ +r = tmxr_detach (&ttx_desc, uptr); /* detach */ sim_cancel (uptr); /* stop poll */ +for (i = 0; i < TTX_MAXL; i++) ttx_ldsc[i].rcve = 0; /* disable rcv */ return r; } /* Show summary processor */ -t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc) { -if (tt1_ldsc.conn) fprintf (st, "connected"); -else fprintf (st, "disconnected"); +int32 i, t; + +for (i = t = 0; i < TTX_MAXL; 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 tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc) { -if (val) tmxr_fconns (st, &tt1_ldsc, -1); -else tmxr_fstats (st, &tt1_ldsc, -1); +int32 i; + +for (i = 0; (i < ttx_lines) && (ttx_ldsc[i].conn == 0); i++) ; +if (i < ttx_lines) { + 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 */ +/* Change number of lines */ -void tt1_enbdis (int32 dis) +t_stat ttx_vlines (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (dis) { - tti1_dev.flags = tto1_dev.flags | DEV_DIS; - tto1_dev.flags = tto1_dev.flags | DEV_DIS; } -else { tti1_dev.flags = tti1_dev.flags & ~DEV_DIS; - tto1_dev.flags = tto1_dev.flags & ~DEV_DIS; } -return; -} +int32 newln, i, t; +t_stat r; -t_stat tt1_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -tti1_unit.flags = (tti1_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; -tto1_unit.flags = (tto1_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +if (cptr == NULL) return SCPE_ARG; +newln = get_uint (cptr, 10, TTX_MAXL, &r); +if ((r != SCPE_OK) || (newln == ttx_lines)) return r; +if (newln == 0) return SCPE_ARG; +if (newln < ttx_lines) { + for (i = newln, t = 0; i < ttx_lines; i++) t = t | ttx_ldsc[i].conn; + if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) + return SCPE_OK; + for (i = newln; i < ttx_lines; i++) { + if (ttx_ldsc[i].conn) { + tmxr_linemsg (&ttx_ldsc[i], "\r\nOperator disconnected line\r\n"); + tmxr_reset_ln (&ttx_ldsc[i]); } /* reset line */ + ttox_unit[i].flags = ttox_unit[i].flags | UNIT_DIS; + ttx_reset_ln (i); } + } +else { for (i = ttx_lines; i < newln; i++) { + ttox_unit[i].flags = ttox_unit[i].flags & ~UNIT_DIS; + ttx_reset_ln (i); } + } +ttx_lines = newln; return SCPE_OK; } + + diff --git a/PDP8/pdp8_clk.c b/PDP8/pdp8_clk.c index 462de909..5361d9d0 100644 --- a/PDP8/pdp8_clk.c +++ b/PDP8/pdp8_clk.c @@ -1,6 +1,6 @@ /* pdp8_clk.c: PDP-8 real-time clock simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP8/pdp8_defs.h b/PDP8/pdp8_defs.h index 7d6c30b1..7ac1f8af 100644 --- a/PDP8/pdp8_defs.h +++ b/PDP8/pdp8_defs.h @@ -1,6 +1,6 @@ /* pdp8_defs.h: PDP-8 simulator definitions - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP8/pdp8_df.c b/PDP8/pdp8_df.c index c4e1db73..fca3496d 100644 --- a/PDP8/pdp8_df.c +++ b/PDP8/pdp8_df.c @@ -1,6 +1,6 @@ /* pdp8_df.c: DF32 fixed head disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ df DF32 fixed head disk + 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 @@ -327,14 +328,17 @@ t_stat df_attach (UNIT *uptr, char *cptr) { uint32 p, sz; uint32 ds_bytes = DF_DKSIZE * sizeof (int16); +t_stat r; -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) { +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) { 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); +return SCPE_OK; } /* Change disk size */ diff --git a/PDP8/pdp8_doc.txt b/PDP8/pdp8_doc.txt index 1e4018e6..3ea13e4c 100644 --- a/PDP8/pdp8_doc.txt +++ b/PDP8/pdp8_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: PDP-8 Simulator Usage -Date: 1-Feb-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,15 +36,21 @@ This memorandum documents the PDP-8 simulator. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/pdp8/ pdp8_defs.h @@ -381,10 +387,16 @@ where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. The additional terminals can be set to one of three modes: UC, 7B, or -8B. In KSR mode, lower case input and output characters are converted +8B. In UC mode, lower case input and output characters are converted automatically to upper case. In 7B mode, input and output characters are masked to 7 bits. In 8B mode, characters are not modified. The -default mode is UC. +default mode is UC. Finally, each line supports output logging. +The SET TTOXn LOG command enables logging on a line: + + SET TTOXn LOG=filename log output of line n to filename + +The SET TTOXLn NOLOG command disables logging and closes the open log +file, if any. Once TTIX is attached and the simulator is running, the terminals listen for connections on the specified port. They assume that the incoming @@ -466,6 +478,7 @@ The TD8E controller implements these registers: DCTIME 31 time to decelerate to a full stop POS[0:7] 32 position, in lines, units 0-7 STATT[0:7] 18 unit state, units 0-7 + STOP_OFFR 1 stop on off-reel error The LTIME parameter should not be changed, or OS/8 may fail to run correctly. The DCTIME parameter should always be at least 100 times @@ -745,6 +758,7 @@ The DECtape controller implements these registers: SUBSTATE 2 read/write command substate POS[0:7] 32 position, in lines, units 0-7 STATT[0:7] 31 unit state, units 0-7 + STOP_OFFR 1 stop on off-reel error It is critically important to maintain certain timing relationships among the DECtape parameters, or the DECtape simulator will fail to diff --git a/PDP8/pdp8_dt.c b/PDP8/pdp8_dt.c index c4d02b49..a8e55636 100644 --- a/PDP8/pdp8_dt.c +++ b/PDP8/pdp8_dt.c @@ -1,6 +1,6 @@ /* pdp8_dt.c: PDP-8 DECtape simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ dt TC08/TU56 DECtape + 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 @@ -250,8 +252,7 @@ #define LOG_MS 001 /* move, search */ #define LOG_RW 002 /* read, write */ -#define LOG_RA 004 /* read all */ -#define LOG_BL 010 /* block # lblk */ +#define LOG_BL 004 /* block # lblk */ #define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \ int_req = int_req | INT_DTA; \ @@ -262,14 +263,15 @@ 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_log = 0; /* debug */ int32 dt_logblk = 0; +int32 dt_stopoffr = 0; DEVICE dt_dev; int32 dt76 (int32 IR, int32 AC); @@ -330,7 +332,6 @@ REG dt_reg[] = { { DRDATA (LTIME, dt_ltime, 31), REG_NZ | PV_LEFT }, { DRDATA (DCTIME, dt_dctime, 31), REG_NZ | PV_LEFT }, { ORDATA (SUBSTATE, dt_substate, 2) }, - { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, { URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 0, DT_NUMDR, PV_LEFT | REG_RO) }, @@ -338,6 +339,7 @@ REG dt_reg[] = { 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 } }; @@ -351,12 +353,19 @@ MTAB dt_mod[] = { &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 }; + &dt_dib, DEV_DISABLE | DEV_DEBUG, 0, + dt_deb, NULL, NULL }; /* IOT routines */ @@ -536,16 +545,16 @@ case DTS_OFR: /* off reel */ break; case FNC_MOVE: /* move */ dt_schedez (uptr, dir); /* sched end zone */ - if (dt_log & LOG_MS) printf ("[DT%d: moving %s]\n", unum, (dir? - "backward": "forward")); + 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 (dt_log & LOG_MS) printf ("[DT%d: searching %s]\n", unum, - (dir? "backward": "forward")); + 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 */ @@ -654,7 +663,8 @@ uint32 ba; switch (mot) { case DTS_DECF: case DTS_DECR: /* decelerating */ - if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */ + 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 */ @@ -675,7 +685,8 @@ default: /* other */ Off reel - detach unit (it must be deselected) */ -if (dt_setpos (uptr)) return STOP_DTOFF; /* update pos */ +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; } @@ -720,10 +731,11 @@ case FNC_READ: /* read */ if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } - if ((dt_log & LOG_RW) || ((dt_log & LOG_BL) && (blk == dt_logblk))) - printf ("[DT%d: reading block %d %s%s\n", + 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]": "]")); + ((dtsa & DTA_MODE)? " continuous": " ")); dt_substate = 0; /* fall through */ case 0: /* normal read */ M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ @@ -769,10 +781,11 @@ case FNC_WRIT: /* write */ if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } - if ((dt_log & LOG_RW) || ((dt_log & LOG_BL) && (blk == dt_logblk))) - printf ("[DT%d: writing block %d %s%s\n", unum, blk, + 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]": "]")); + ((dtsa & DTA_MODE)? " continuous": " ")); dt_substate = 0; /* fall through */ case 0: /* normal write */ M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ @@ -1089,7 +1102,7 @@ if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ else if (sim_switches & SWMASK ('S')) /* att 16b? */ uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; else if (!(sim_switches & SWMASK ('R')) && /* autosize? */ - (sz = sim_fsize (cptr))) { + (sz = sim_fsize (uptr->fileref))) { if (sz == D11_FILSIZ) uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; else if (sz > D8_FILSIZ) diff --git a/PDP8/pdp8_lp.c b/PDP8/pdp8_lp.c index 48bda59f..5b4fcfce 100644 --- a/PDP8/pdp8_lp.c +++ b/PDP8/pdp8_lp.c @@ -1,6 +1,6 @@ /* pdp8_lp.c: PDP-8 line printer simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP8/pdp8_mt.c b/PDP8/pdp8_mt.c index 315105b8..88a87d08 100644 --- a/PDP8/pdp8_mt.c +++ b/PDP8/pdp8_mt.c @@ -1,6 +1,6 @@ /* pdp8_mt.c: PDP-8 magnetic tape simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP8/pdp8_pt.c b/PDP8/pdp8_pt.c index 92a39858..9c4a11fb 100644 --- a/PDP8/pdp8_pt.c +++ b/PDP8/pdp8_pt.c @@ -1,6 +1,6 @@ /* pdp8_pt.c: PDP-8 paper tape reader/punch simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP8/pdp8_rf.c b/PDP8/pdp8_rf.c index d6ee9e34..b0704bde 100644 --- a/PDP8/pdp8_rf.c +++ b/PDP8/pdp8_rf.c @@ -1,6 +1,6 @@ /* pdp8_rf.c: RF08 fixed head disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rf RF08 fixed head disk + 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 @@ -381,14 +382,17 @@ t_stat rf_attach (UNIT *uptr, char *cptr) { uint32 sz, p; uint32 ds_bytes = RF_DKSIZE * sizeof (int16); +t_stat r; -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) { +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) { 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); +return SCPE_OK; } /* Change disk size */ diff --git a/PDP8/pdp8_rk.c b/PDP8/pdp8_rk.c index 7273430e..6c4e5d78 100644 --- a/PDP8/pdp8_rk.c +++ b/PDP8/pdp8_rk.c @@ -1,6 +1,6 @@ /* pdp8_rk.c: RK8E cartridge disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -85,7 +85,7 @@ #define RKC_WALL 5 #define RKC_V_FUNC 9 #define RKC_IE 00400 /* interrupt enable */ -#define RKC_SKDN 00200 /* int on seek done */ +#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 diff --git a/PDP8/pdp8_rl.c b/PDP8/pdp8_rl.c index 69a91459..714775d6 100644 --- a/PDP8/pdp8_rl.c +++ b/PDP8/pdp8_rl.c @@ -1,6 +1,6 @@ /* pdp8_rl.c: RL8A cartridge disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rl RL8A cartridge disk + 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 @@ -523,8 +524,7 @@ 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 (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; /* seek to end */ -if ((p = ftell (uptr->fileref)) == 0) { /* new disk image? */ +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? */ diff --git a/PDP8/pdp8_rx.c b/PDP8/pdp8_rx.c index ac53b435..6cba46c4 100644 --- a/PDP8/pdp8_rx.c +++ b/PDP8/pdp8_rx.c @@ -1,6 +1,6 @@ /* pdp8_rx.c: RX8E/RX01, RX28/RX02 floppy disk simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rx RX8E/RX01, RX28/RX02 floppy disk + 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 @@ -523,12 +524,15 @@ return SCPE_OK; t_stat rx_attach (UNIT *uptr, char *cptr) { uint32 sz; +t_stat r; -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) { +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) { 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); +return SCPE_OK; } /* Set size routine */ diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index bb8268a1..7949773a 100644 --- a/PDP8/pdp8_sys.c +++ b/PDP8/pdp8_sys.c @@ -1,6 +1,6 @@ /* pdp8_sys.c: PDP-8 simulator interface - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP8/pdp8_td.c b/PDP8/pdp8_td.c index 40f20c6e..ac188a52 100644 --- a/PDP8/pdp8_td.c +++ b/PDP8/pdp8_td.c @@ -1,6 +1,6 @@ /* pdp8_td.c: PDP-8 simple DECtape controller (TD8E) simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,8 @@ td TD8E/TU56 DECtape + 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: @@ -183,6 +185,7 @@ 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; @@ -238,6 +241,7 @@ REG td_reg[] = { 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 } }; @@ -283,7 +287,7 @@ case 04: /* SDLC */ td_cmd = AC & TDC_MASK; /* update cmd */ if ((diff != 0) && (diff != TDC_RW)) { /* signif change? */ if (td_newsa (td_cmd)) /* new command */ - return AC | (STOP_DTOFF << IOT_V_REASON); } + return AC | (IORETURN (td_stopoffr, STOP_DTOFF) << IOT_V_REASON); } break; case 05: /* SDLD */ td_slf = 0; /* clear flags */ @@ -433,7 +437,8 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ switch (mot) { /* case on motion */ case STA_DEC: /* deceleration */ - if (td_setpos (uptr)) return STOP_DTOFF; /* update pos */ + 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 */ @@ -442,7 +447,8 @@ case STA_DEC: /* deceleration */ sim_activate (uptr, td_dctime - (td_dctime >> 2)); } return SCPE_OK; case STA_ACC: /* accelerating */ - if (td_setpos (uptr)) return STOP_DTOFF; /* update pos */ + 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 */ @@ -452,7 +458,7 @@ case STA_UTS: /* up to speed */ if (((int32) uptr->pos < 0) || /* off reel? */ (uptr->pos >= (((uint32) DTU_FWDEZ (uptr)) + DT_EZLIN))) { detach_unit (uptr); - return STOP_DTOFF; } + return IORETURN (td_stopoffr, STOP_DTOFF); } break; } /* check function */ /* At speed - process the current line @@ -707,7 +713,7 @@ if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ else if (sim_switches & SWMASK ('S')) /* att 16b? */ uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; else if (!(sim_switches & SWMASK ('R')) && /* autosize? */ - (sz = sim_fsize (cptr))) { + (sz = sim_fsize (uptr->fileref))) { if (sz == D11_FILSIZ) uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; else if (sz > D8_FILSIZ) diff --git a/PDP8/pdp8_tsc.c b/PDP8/pdp8_tsc.c index dd281784..21f90590 100644 --- a/PDP8/pdp8_tsc.c +++ b/PDP8/pdp8_tsc.c @@ -1,6 +1,6 @@ /* pdp8_tsc.c: PDP-8 ETOS timesharing option board (TSC8-75) - Copyright (c) 2003, Robert M Supnik + Copyright (c) 2003-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index ac6d3125..fd2cd250 100644 --- a/PDP8/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -1,6 +1,6 @@ /* pdp8_ttx.c: PDP-8 additional terminals simulator - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ ttix,ttox PT08/KL8JA terminal input/output + 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 @@ -62,8 +63,7 @@ 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 = { /* mux descriptor */ - TTX_LINES, 0, 0, &ttx_ldsc[0], &ttx_ldsc[1], &ttx_ldsc[2], &ttx_ldsc[3] }; +TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */ DEVICE ttix_dev, ttox_dev; int32 ttix (int32 IR, int32 AC); @@ -111,6 +111,10 @@ MTAB ttix_mod[] = { NULL, &ttx_show, NULL }, { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_dev, &show_dev, NULL }, + { 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 ttix_dev = { @@ -279,9 +283,9 @@ t_stat ttox_svc (UNIT *uptr) { int32 c, ln = uptr - ttox_unit; /* line # */ -if (ttx_desc.ldsc[ln]->conn) { /* connected? */ - if (ttx_desc.ldsc[ln]->xmte) { /* tx enabled? */ - TMLN *lp = ttx_desc.ldsc[ln]; /* get line */ +if (ttx_ldsc[ln].conn) { /* connected? */ + if (ttx_ldsc[ln].xmte) { /* tx enabled? */ + TMLN *lp = &ttx_ldsc[ln]; /* get line */ if (ttox_unit[ln].flags & UNIT_UC) { /* UC mode? */ c = ttox_buf[ln] & 0177; /* get char */ if (islower (c)) c = toupper (c); } @@ -337,7 +341,7 @@ t_stat r; r = tmxr_detach (&ttx_desc, uptr); /* detach */ for (i = 0; i < TTX_LINES; i++) { /* all lines, */ - ttx_desc.ldsc[i]->rcve = 0; /* disable rcv */ + ttx_ldsc[i].rcve = 0; /* disable rcv */ sim_cancel (&ttox_unit[i]); } /* stop poll */ return r; } diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index 2489cd13..84cac82c 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -1,6 +1,6 @@ /* sds_cpu.c: SDS 940 CPU simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_defs.h b/SDS/sds_defs.h index d6b6a549..aacdd26c 100644 --- a/SDS/sds_defs.h +++ b/SDS/sds_defs.h @@ -1,6 +1,6 @@ /* sds_defs.h: SDS 940 simulator definitions - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_doc.txt b/SDS/sds_doc.txt index 97ec45c8..207ad3d2 100644 --- a/SDS/sds_doc.txt +++ b/SDS/sds_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: SDS 940 Simulator Usage -Date: 15-Mar-2003 +Date: 15-Feb-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -36,15 +36,21 @@ This memorandum documents the SDS 940 simulator. 1. Simulator Files -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/sds/ sds_defs.h @@ -334,6 +340,13 @@ for other TCP/IP activities. Each line (each unit of MUXL) supports one option: UC, when set, causes lower case input characters to be automatically converted to upper case. +In addition, each line supports output logging. The SET MUXLn LOG command +enables logging on a line: + + SET MUXLn filename log output of line n to filename + +The SET MUXLn NOLOG command disables logging and closes the open log +file, if any. Once MUX is attached and the simulator is running, the multiplexor listens for connections on the specified port. It assumes that the incoming diff --git a/SDS/sds_drm.c b/SDS/sds_drm.c index 08007aba..825f4d67 100644 --- a/SDS/sds_drm.c +++ b/SDS/sds_drm.c @@ -1,6 +1,6 @@ /* sds_drm.c: SDS 940 Project Genie drum simulator - Copyright (c) 2002-2003, Robert M. Supnik + Copyright (c) 2002-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_dsk.c b/SDS/sds_dsk.c index adedeefa..ae303ede 100644 --- a/SDS/sds_dsk.c +++ b/SDS/sds_dsk.c @@ -1,6 +1,6 @@ /* sds_dsk.c: SDS 940 moving head disk simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_io.c b/SDS/sds_io.c index 702ea412..0298a659 100644 --- a/SDS/sds_io.c +++ b/SDS/sds_io.c @@ -1,6 +1,6 @@ /* sds_io.c: SDS 940 I/O simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_lp.c b/SDS/sds_lp.c index f3e4ffc5..880cfe11 100644 --- a/SDS/sds_lp.c +++ b/SDS/sds_lp.c @@ -1,6 +1,6 @@ /* sds_lp.c: SDS 940 line printer simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_mt.c b/SDS/sds_mt.c index 7d62a81d..0acfdf9f 100644 --- a/SDS/sds_mt.c +++ b/SDS/sds_mt.c @@ -1,6 +1,6 @@ /* sds_mt.c: SDS 940 magnetic tape simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_mux.c b/SDS/sds_mux.c index 65192e08..0c52473b 100644 --- a/SDS/sds_mux.c +++ b/SDS/sds_mux.c @@ -1,6 +1,6 @@ /* sds_mux.c: SDS 940 terminal multiplexor simulator - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ mux terminal multiplexor + 05-Jan-04 RMS Revised for tmxr library changes 09-May-03 RMS Added network device flag This module implements up to 32 individual serial interfaces, representing @@ -109,7 +110,7 @@ uint32 mux_scan = 0; /* scanner */ uint32 mux_slck = 0; /* scanner locked */ TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */ -TMXR mux_desc = { MUX_LINES, 0, 0, NULL }; /* mux descriptor */ +TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc }; /* mux descriptor */ t_stat mux (uint32 fnc, uint32 inst, uint32 *dat); t_stat muxi_svc (UNIT *uptr); @@ -211,6 +212,10 @@ UNIT muxl_unit[] = { MTAB muxl_mod[] = { { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", + &tmxr_set_log, &tmxr_show_log, &mux_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", + &tmxr_set_nolog, NULL, &mux_desc }, { 0 } }; REG muxl_reg[] = { @@ -285,7 +290,7 @@ if (PROJ_GENIE && ((*dat & POT_GLNE) == 0)) { /* Genie disable? */ mux_ldsc[ln].rcve = 0; } else if (!PROJ_GENIE && (*dat & POT_SCDT)) { /* SDS disable? */ if (mux_ldsc[ln].conn) { /* connected? */ - tmxr_msg (mux_ldsc[ln].conn, "\r\nLine hangup\r\n"); + tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n"); tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ mux_reset_ln (ln); /* reset state */ MUX_SETFLG (ln, MUX_FCRF); /* set carrier off */ @@ -396,9 +401,7 @@ if (mux_unit.flags & UNIT_ATT) { /* master att? */ t = sim_rtcn_init (mux_unit.wait, TMR_MUX); sim_activate (&mux_unit, t); } } /* activate */ else sim_cancel (&mux_unit); /* else stop */ -for (i = 0; i < MUX_LINES; i++) { - mux_desc.ldsc[i] = &mux_ldsc[i]; - mux_reset_ln (i); } +for (i = 0; i < MUX_LINES; i++) mux_reset_ln (i); for (i = 0; i < MUX_FLAGS; i++) MUX_CLRINT (i); /* clear all ints */ return SCPE_OK; } @@ -475,7 +478,7 @@ if (newln < MUX_NUMLIN) { return SCPE_OK; for (i = newln; i < MUX_NUMLIN; i++) { if (mux_ldsc[i].conn) { - tmxr_msg (mux_ldsc[i].conn, "\r\nOperator disconnected line\r\n"); + tmxr_linemsg (&mux_ldsc[i], "\r\nOperator disconnected line\r\n"); tmxr_reset_ln (&mux_ldsc[i]); } /* reset line */ muxl_unit[i].flags = muxl_unit[i].flags | UNIT_DIS; mux_reset_ln (i); } diff --git a/SDS/sds_rad.c b/SDS/sds_rad.c index 498f0dd7..45b3c3e4 100644 --- a/SDS/sds_rad.c +++ b/SDS/sds_rad.c @@ -1,6 +1,6 @@ /* sds_rad.c: SDS 940 fixed head disk simulator - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_stddev.c b/SDS/sds_stddev.c index 56049acb..d3a8ff36 100644 --- a/SDS/sds_stddev.c +++ b/SDS/sds_stddev.c @@ -1,6 +1,6 @@ /* sds_stddev.c: SDS 940 standard devices - Copyright (c) 2001-2003, Robert M. Supnik + Copyright (c) 2001-2004, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index 8ff8d2af..b522ece8 100644 --- a/SDS/sds_sys.c +++ b/SDS/sds_sys.c @@ -1,6 +1,6 @@ /* sds_sys.c: SDS 940 simulator interface - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/VAX/ka655x.bin b/VAX/ka655x.bin new file mode 100644 index 00000000..d15f41da Binary files /dev/null and b/VAX/ka655x.bin differ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index fd889c3b..df579873 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -25,6 +25,8 @@ cpu CVAX central processor + 25-Jan-04 RMS Removed local debug logging support + RMS,MP Added extended physical memory support 31-Dec-03 RMS Fixed bug in set_cpu_hist 21-Dec-03 RMS Added autoconfiguration controls 29-Oct-03 RMS Fixed WriteB declaration (found by Mark Pizzolato) @@ -146,8 +148,10 @@ #define OP_MEM -1 #define UNIT_V_CONH (UNIT_V_UF + 0) /* halt to console */ -#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy */ +#define UNIT_V_EXTM (UNIT_V_UF + 1) /* ext memory enable */ +#define UNIT_V_MSIZE (UNIT_V_UF + 2) /* dummy */ #define UNIT_CONH (1u << UNIT_V_CONH) +#define UNIT_EXTM (1u << UNIT_V_EXTM) #define UNIT_MSIZE (1u << UNIT_V_MSIZE) #define GET_CUR acc = ACC_MASK (PSL_GETCUR (PSL)) @@ -221,8 +225,8 @@ int32 dbg_stop = 0; int32 mchk_va, mchk_ref; /* mem ref param */ int32 ibufl, ibufh; /* prefetch buf */ int32 ibcnt, ppc; /* prefetch ctl */ -int32 cpu_log = 0; /* logging */ int32 autcon_enb = 1; /* autoconfig enable */ +int32 cpu_extmem = 0; /* extended memory */ jmp_buf save_env; REG *pcq_r = NULL; /* PC queue reg ptr */ int32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ @@ -335,6 +339,7 @@ t_stat cpu_boot (int32 unitno, DEVICE *dptr); t_stat cpu_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_extm (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_show_virt (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); @@ -349,7 +354,7 @@ int32 con_halt (int32 code, int32 cc); cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, INITMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_EXTM, INITMEMSIZE) }; REG cpu_reg[] = { { HRDATA (PC, R[nPC], 32) }, @@ -395,7 +400,6 @@ REG cpu_reg[] = { { FLDATA (CRDERR, crd_err, 0) }, { FLDATA (MEMERR, mem_err, 0) }, { FLDATA (HLTPIN, hlt_pin, 0) }, - { HRDATA (DBGLOG, cpu_log, 16), REG_HIDDEN }, { FLDATA (DBGSTOP, dbg_stop, 0), REG_HIDDEN }, { BRDATA (PCQ, pcq, 16, 32, PCQ_SIZE), REG_RO+REG_CIRC }, { HRDATA (PCQP, pcq_p, 6), REG_HRO }, @@ -405,10 +409,15 @@ REG cpu_reg[] = { { NULL } }; MTAB cpu_mod[] = { - { UNIT_MSIZE, (1u << 23), NULL, "8M", &cpu_set_size }, + { UNIT_EXTM, UNIT_EXTM, NULL, "EXTENDEDMEMORY", &cpu_set_extm }, + { UNIT_EXTM, 0, NULL, "NOEXTENDEDMEMORY", &cpu_set_extm }, { UNIT_MSIZE, (1u << 24), NULL, "16M", &cpu_set_size }, { UNIT_MSIZE, (1u << 25), NULL, "32M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 25) + (1u << 24), NULL, "48M", &cpu_set_size }, { UNIT_MSIZE, (1u << 26), NULL, "64M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 27), NULL, "128M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 28), NULL, "256M", &cpu_set_size }, + { UNIT_MSIZE, (1u << 29), NULL, "512M", &cpu_set_size }, { UNIT_CONH, 0, "HALT to SIMH", "SIMHALT", NULL }, { UNIT_CONH, UNIT_CONH, "HALT to console", "CONHALT", NULL }, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, @@ -422,12 +431,19 @@ MTAB cpu_mod[] = { { MTAB_XTD|MTAB_VDV, 0, NULL, "VIRTUAL", &cpu_show_virt }, { 0 } }; +DEBTAB cpu_deb[] = { + { "INTEXC", LOG_CPU_I }, + { "REI", LOG_CPU_R }, + { "CONTEXT", LOG_CPU_P }, + { NULL, 0 } }; + DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 16, 32, 1, 16, 8, &cpu_ex, &cpu_dep, &cpu_reset, &cpu_boot, NULL, NULL, - NULL, DEV_DYNM, &cpu_set_size }; + NULL, DEV_DYNM | DEV_DEBUG, 0, + cpu_deb, &cpu_set_size, NULL }; t_stat sim_instr (void) { @@ -437,6 +453,7 @@ int abortval; t_stat r; if ((r = build_dib_tab ()) != SCPE_OK) return r; /* build, chk dib_tab */ +cpu_extmem = cpu_unit.flags & UNIT_EXTM; /* external flag */ cc = PSL & CC_MASK; /* split PSL */ PSL = PSL & ~CC_MASK; in_ie = 0; /* not in exc */ @@ -2311,10 +2328,6 @@ JUMP (ROMBASE); /* PC = 20040000 */ return 0; /* new cc = 0 */ } -/* To do list: - Examine/deposit I/O -*/ - /* Reset */ t_stat cpu_reset (DEVICE *dptr) @@ -2359,10 +2372,16 @@ conpc = 0; conpsl = PSL_IS | PSL_IPL1F | CON_PWRUP; if (rom == NULL) return SCPE_IERR; if (*rom == 0) { /* no boot? */ - printf ("Loading boot code from ka655.bin\n"); - if (sim_log) fprintf (sim_log, - "Loading boot code from ka655.bin\n"); - r = load_cmd (0, "-R ka655.bin"); + if (cpu_unit.flags & UNIT_EXTM) { /* KA655X? */ + printf ("Loading boot code from ka655x.bin\n"); + if (sim_log) fprintf (sim_log, + "Loading boot code from ka655x.bin\n"); + r = load_cmd (0, "-R ka655x.bin"); } + else { /* KA655 */ + printf ("Loading boot code from ka655.bin\n"); + if (sim_log) fprintf (sim_log, + "Loading boot code from ka655.bin\n"); + r = load_cmd (0, "-R ka655.bin"); } if (r != SCPE_OK) return r; } return SCPE_OK; } @@ -2403,6 +2422,14 @@ if (ADDR_IS_ROM (addr)) { return SCPE_NXM; } +/* Enable/disable extended physical memory */ + +t_stat cpu_set_extm (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if ((val == 0) && (MEMSIZE > MAXMEMSIZE)) return SCPE_ARG; +return SCPE_OK; +} + /* Memory allocation */ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) @@ -2411,7 +2438,8 @@ int32 mc = 0; uint32 i, clim; uint32 *nM = NULL; -if ((val <= 0) || (val > MAXMEMSIZE)) return SCPE_ARG; +if ((val <= 0) || + (val > ((uptr->flags & UNIT_EXTM)? MAXMEMSIZE_X: MAXMEMSIZE))) return SCPE_ARG; for (i = val; i < MEMSIZE; i = i + 4) mc = mc | M[i >> 2]; if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) return SCPE_OK; diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index ad1f6c23..53585471 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -1,6 +1,6 @@ /* vax_cpu1.c: VAX complex instructions - Copyright (c) 1998-2003, Robert M Supnik + Copyright (c) 1998-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 27-Jan-04 RMS Added device logging support + Fixed EXTxV, INSV double register PC reference fault 30-Apr-02 RMS Fixed interrupt/exception handler to clear traps 17-Apr-02 RMS Fixed pos > 31 test in bit fields (should be unsigned) 14-Apr-02 RMS Fixed prv_mode handling for interrupts (found by Tim Stark) @@ -98,8 +100,8 @@ extern int32 in_ie; extern int32 mchk_va; extern int32 sim_interval; extern int32 ibcnt, ppc; -extern int32 cpu_log; -extern FILE *sim_log; +extern FILE *sim_deb; +extern DEVICE cpu_dev; extern int32 Read (uint32 va, int32 lnt, int32 acc); extern void Write (uint32 va, int32 val, int32 lnt, int32 acc); @@ -180,6 +182,8 @@ if (size == 0) return 0; /* size 0? field = 0 */ if (size > 32) RSVD_OPND_FAULT; /* size > 32? fault */ if (rn >= 0) { /* register? */ if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */ + if (((pos + size) > 32) && (rn >= nSP)) /* span 2 reg, PC? */ + RSVD_ADDR_FAULT; /* fault */ if (pos) wd = (wd >> pos) | (((uint32) vfldrp1) << (32 - pos)); } else { ba = wd + (pos >> 3); /* base byte addr */ pos = (pos & 07) | ((ba & 03) << 3); /* bit offset */ @@ -214,7 +218,7 @@ if (size > 32) RSVD_OPND_FAULT; /* size > 32? fault */ if (rn >= 0) { /* in registers? */ if (((uint32) pos) > 31) RSVD_OPND_FAULT; /* pos > 31? fault */ if ((pos + size) > 32) { /* span two reg? */ - if (rn >= nSP) RSVD_OPND_FAULT; /* if PC, fault */ + if (rn >= nSP) RSVD_ADDR_FAULT; /* if PC, fault */ mask = byte_mask[pos + size - 32]; /* insert fragment */ val = ins >> (32 - pos); R[rnplus1] = (vfldrp1 & ~mask) | (val & mask); } @@ -1032,7 +1036,7 @@ else { STK[oldcur] = SP; /* no, save cur stk */ if (ei > 0) PSL = newpsl | (ipl << PSL_V_IPL); /* if int, new IPL */ else PSL = newpsl | ((newpc & 1)? PSL_IPL1F: (oldpsl & PSL_IPL)) | (oldcur << PSL_V_PRV); -if (DBG_LOG (LOG_CPU_I)) fprintf (sim_log, +if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) fprintf (sim_deb, ">>IEX: PC=%08x, PSL=%08x, SP=%08x, VEC=%08x, nPSL=%08x, nSP=%08x\n", PC, oldpsl, oldsp, vec, PSL, SP); acc = ACC_MASK (KERN); /* new mode is kernel */ @@ -1122,14 +1126,14 @@ else { /* to k, skip 3,5,6 */ SP = SP + 8; /* pop stack */ if (PSL & PSL_IS) IS = SP; /* save stack */ else STK[oldcur] = SP; -if (DBG_LOG (LOG_CPU_R)) fprintf (sim_log, +if (DEBUG_PRI (cpu_dev, LOG_CPU_R)) fprintf (sim_deb, ">>REI: PC=%08x, PSL=%08x, SP=%08x, nPC=%08x, nPSL=%08x, nSP=%08x\n", PC, PSL, SP - 8, newpc, newpsl, ((newpsl & IS)? IS: STK[newcur])); PSL = (PSL & PSL_TP) | (newpsl & ~CC_MASK); /* set new PSL */ if (PSL & PSL_IS) SP = IS; /* set new stack */ else { SP = STK[newcur]; /* if ~IS, chk AST */ if (newcur >= ASTLVL) { - if (DBG_LOG (LOG_CPU_R)) fprintf (sim_log, + if (DEBUG_PRI (cpu_dev, LOG_CPU_R)) fprintf (sim_deb, ">>REI: AST delivered\n"); SISR = SISR | SISR_2; } } JUMP (newpc); /* set new PC */ @@ -1175,7 +1179,7 @@ P1BR = P1BR & BR_MASK; P1LR = P1LR & LR_MASK; zap_tb (0); /* clear process TB */ set_map_reg (); -if (DBG_LOG (LOG_CPU_P)) fprintf (sim_log, +if (DEBUG_PRI (cpu_dev, LOG_CPU_P)) fprintf (sim_deb, ">>LDP: PC=%08x, PSL=%08x, SP=%08x, nPC=%08x, nPSL=%08x, nSP=%08x\n", PC, PSL, SP, newpc, newpsl, KSP); if (PSL & PSL_IS) IS = SP; /* if istk, */ @@ -1195,7 +1199,7 @@ int32 savpc, savpsl, pcbpa; if (PSL & PSL_CUR) RSVD_INST_FAULT; /* must be kernel */ savpc = Read (SP, L_LONG, RA); /* pop PC, PSL */ savpsl = Read (SP + 4, L_LONG, RA); -if (DBG_LOG (LOG_CPU_P)) fprintf (sim_log, +if (DEBUG_PRI (cpu_dev, LOG_CPU_P)) fprintf (sim_deb, ">>SVP: PC=%08x, PSL=%08x, SP=%08x, oPC=%08x, oPSL=%08x\n", PC, PSL, SP, savpc, savpsl); if (PSL & PSL_IS) SP = SP + 8; /* int stack? */ diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index 6541c71f..dfed24ff 100644 --- a/VAX/vax_defs.h +++ b/VAX/vax_defs.h @@ -1,6 +1,6 @@ /* vax_defs.h: VAX architecture definitions file - Copyright (c) 1998-2003, Robert M Supnik + Copyright (c) 1998-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/VAX/vax_doc.txt b/VAX/vax_doc.txt index c821b221..2033a6b2 100644 --- a/VAX/vax_doc.txt +++ b/VAX/vax_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik Subj: VAX Simulator Usage -Date: 15-Dec-2003 +Date: 04-Apr-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -40,17 +40,23 @@ To compile the VAX, you must define VM_VAX and USE_INT64 as part of the compilat command line. To enable extended file support (files greater than 2GB), you must define USE_ADDR64 as part of the command line as well. -sim/ sim_defs.h +sim/ scp.h + sim_console.h + sim_defs.h sim_ether.h + sim_fio.h sim_rev.h sim_sock.h sim_tape.h + sim_timer.h sim_tmxr.h scp.c - scp_tty.c + sim_console.c sim_ether.c + sim_fio.c sim_sock.c sim_tape.c + sim_timer.c sim_tmxr.c sim/vax/ vax_defs.h @@ -72,11 +78,17 @@ sim/pdp11/ pdp11_mscp.h pdp11_lp.c pdp11_pt.c pdp11_rl.c + pdp11_ry.c pdp11_rq.c pdp11_tq.c pdp11_ts.c pdp11_xp.c +Additional files are: + +sim/vax/ ka655.bin standard boot ROM code + ka655x.bin extended memory boot ROM code + 2. VAX Features The VAX simulator is configured as follows: @@ -84,7 +96,8 @@ The VAX simulator is configured as follows: device simulates name(s) -CPU KA655 CPU with 16MB-64MB of memory +CPU KA655 CPU with 16MB-64MB of memory, or + "KA655X" CPU with 16MB-512MB of memory TLB translation buffer ROM read-only memory NVR non-volatile memory @@ -100,13 +113,15 @@ RQ RQDX3 MSCP controller with four drives RQB second RQDX3 MSCP controller with four drives RQC third RQDX3 MSCP controller with four drives RQD fourth RQDX3 MSCP controller with four drives +RY RXV21 floppy disk controller with two drives TS TSV11/TSV05 magnetic tape controller with one drive TQ TQK50 TMSCP magnetic tape controller with four drives XQ DELQA/DEQNA Ethernet controller XQB second DELQA/DEQNA Ethernet controller -The PTR, PTP, LPT, DZ, RL, RQ, RQB, RQC, RQD, TS, TQ, XQ, and XQB devices -can be set DISABLED. RQB, RQC, RQD, and XQB are disabled by default. +The PTR, PTP, LPT, DZ, RL, RQ, RQB, RQC, RQD, RY, TS, TQ, XQ, and XQB +devices can be set DISABLED. RQB, RQC, RQD, and XQB are disabled by +default. The VAX simulator implements several unique stop conditions: @@ -128,10 +143,15 @@ ROM, or the non-volatile memory. CPU options include the size of main memory and the treatment of the HALT instruction. + SET CPU EXTEND enable extended memory support + SET CPU NOEXTEND disable extended memory support SET CPU 16M set memory size = 16MB SET CPU 32M set memory size = 32MB SET CPU 48M set memory size = 48MB SET CPU 64M set memory size = 64MB + SET CPU 128M set memory size = 128MB + SET CPU 256M set memory size = 256MB + SET CPU 512M set memory size = 512MB SET CPU SIMHALT kernel HALT returns to simulator SET CPU CONHALT kernel HALT returns to boot ROM console @@ -139,16 +159,39 @@ The CPU implements a show command to display the I/O address map: SHOW CPU IOSPACE show I/O space address map -If memory size is being reduced, and the memory being truncated contains -non-zero data, the simulator asks for confirmation. Data in the truncated -portion of memory is lost. Initial memory size is 16MB. If the simulator -is running VMS, the operating system will not recognize memory size changes -until AUTOGEN is run. +Notes of the memory size: + +- The real KA655 CPU only supported 16MB to 64MB of memory. The simulator + provides a KA655"X" mode, which increases supported memory to 512MB. + Extended memory is enabled by default. If extended memory is enabled, + and memory size exceeds 64MB, the CPU will boot using special firmware + ka655x.bin. This firmware contains code to determine the size of extended + memory and set up the PFN bit map accordingly. Other than setting up + the PFN bootmap, the firmware does not recognize extended memory and + will behave as though memory size was 64MB. +- If memory size is being reduced, and the memory being truncated contains + non-zero data, the simulator asks for confirmation. Data in the truncated + portion of memory is lost. +- If the simulator is running VMS, the operating system may have a SYSGEN + parameter set called PHYSICXAL PAGES (viewable from "MCR SYSGEN SHOW + PHYSICALPAGES"). PHYSICALPAGES limits the maximum number of physical pages + of memory the OS will recognize. If it is set to a lower value than the + new extended memory size of the machine, then only the first PHYSICALPAGES + of memory will be recognized, otherwise the actual size of the extended + memory will be realized by VMS upon each boot. Some users and/or sites + may specify the PHYSICALPAGES parameter in the input file to AUTOGEN + (SYS$SYSTEM:MODPARAMS.DAT). If PHYSICALPAGES is specified there, it will + have to be adjusted before running AUTOGEN to recognize more memory. The + default value for PHYSICALPAGES is 1048576, which describes 512MB of RAM. + +Initial memory size is 16MB. Memory can be loaded with a binary byte stream using the LOAD command. -The LOAD command recognizes one switch: +The LOAD command recognizes three switch: - -o Origin argument follows file name + -o origin argument follows file name + -r load the boot ROM + -n load the non-volatile RAM The CPU supports the BOOT command and is the only VAX device to do so. Note that the behavior of the bootstrap depends on the capabilities of @@ -315,6 +358,7 @@ presense of other devices in the configuration: DZ11 all instances have floating addresses RL11 first instance has fixed address, rest floating + RX11/RX211 first instance has fixed address, second floating MSCP disk first instance has fixed address, rest floating TMSCP tape first instance has fixed address, rest floating @@ -516,6 +560,22 @@ may be incompatible with certain operating systems. The command forces output characters to be masked to 7 bits. +The DZ11 supports logging on a per-line basis. The command + + SET DZ LOG=line=filename + +enables logging for the specified line to the indicated file. The +command + + SET DZ NOLOG=line + +disables logging for the specified line and closes any open log file. +Finally, the command + + SHOW DZ LOG + +displays logging information for all DZ lines. + The terminal lines perform input and output through Telnet sessions connected to a user-specified port. The ATTACH command specifies the port to be used: @@ -687,7 +747,54 @@ Error handling is as follows: OS I/O error report error and stop -2.6 TSV11/TSV05 Magnetic Tape (TS) +2.6 RXV21/RX02 Floppy Disk (RY) + +RXV21 options include the ability to set units write enabled or write +locked, single or double density, or autosized: + + SET RYn LOCKED set unit n write locked + SET RYn WRITEENABLED set unit n write enabled + SET RYn SINGLE set unit n single density + SET RYn DOUBLE set unit n double density (default) + SET RYn AUTOSIZE set unit n autosized + +The RXV21 does not support the boot command. + +The RXV21 implements these registers: + + name size comments + + RYCS 16 status + RYBA 16 buffer address + RYWC 8 word count + RYDB 16 data buffer + RYES 12 error status + RYERR 8 error code + RYTA 8 current track + RYSA 8 current sector + STAPTR 4 controller state + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + TR 1 transfer ready flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + DONE 1 device done flag (CSR<5>) + CTIME 24 command completion time + STIME 24 seek time, per track + XTIME 24 transfer ready delay + STOP_IOE 1 stop on I/O error + SBUF[0:255] 8 sector buffer array + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + +RX02 data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. + +2.7 TSV11/TSV05 Magnetic Tape (TS) TS options include the ability to make the unit write enabled or write locked. @@ -735,7 +842,7 @@ Error handling is as follows: OS I/O error fatal tape error -2.7 TQK50 TMSCP Disk Controller (TQ) +2.8 TQK50 TMSCP Disk Controller (TQ) The TQ controller simulates the TQK50 TMSCP disk controller. TQ options include the ability to set units write enabled or write locked, and to @@ -805,7 +912,7 @@ Error handling is as follows: OS I/O error report error and stop -2.8 DELQA/DEQNA Qbus Ethernet Controllers (XQ, XQB) +2.9 DELQA/DEQNA Qbus Ethernet Controllers (XQ, XQB) The simulator implements two DELQA/DEQNA Qbus Ethernet controllers (XQ, XQB). Initially, XQ is enabled, and XQB is disabled. Options allow @@ -841,6 +948,18 @@ state of this switch. Note that only the DEQNA (or the DELQA in DEQNA- LOCK mode (=DEQNA)) supports the sanity timer - it is ignored by a DELQA in Normal mode, which uses switch S4 for a different purpose. + SET XQ POLL={DEFAULT|4..2500} + SHOW XQ POLL + +These commands change or display the service polling timer. The polling +timer is calibrated to run the service thread 200 times per second. This +value can be changed to accomodate particular system requirements for +more (or less) frequent polling. + + SHOW XQ STATS + +This command will display the accumulated statistics for the simulated +Ethernet controller. To access the network, the simulated Ethernet controller must be attached to a real Ethernet interface: @@ -855,7 +974,7 @@ The device list can be quite cryptic, depending on the host system, but is probably better than guessing. If you do not attach the device, the controller will behave as though the ethernet cable were unplugged. -XQ has the following registers: +XQ and XQB have the following registers: name size comments @@ -865,17 +984,18 @@ XQ has the following registers: SA3 16 station address word 3 SA4 16 station address word 4 SA5 16 station address word 5 + RBDL 32 receive buffer descriptor list + XBDL 32 trans(X)mit buffer descriptor list CSR 16 control status register VAR 16 vector address register - RBDL 32 receive buffer descriptor list - XBDL 32 trans(X)mit buffer descriptorlList + INT 1 interrupt request flag One final note: because of it's asynchronous nature, the XQ controller is not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers, nor the 10Mbit/sec of a standard Ethernet. Attach it to a Fast Ethernet (100 Mbit/sec) card, and "Feel the Power!" :-) -2.9 Symbolic Display and Input +2.10 Symbolic Display and Input The VAX simulator implements symbolic display and input. Display is controlled by command line switches: @@ -923,3 +1043,21 @@ l^d EF d - PC long PC relative If no override is given for a literal (s^ or i^) or for a displacement or PC relative addres (b^, w^, or l^), the simulator chooses the mode automatically. + +Appendix - The KA655"X" + +The real KA655 is limited to 64MB of memory, and the KA655 firmware is coded +to this limit. However, the VAX operating systems (VMS, Ultrix, NetBSD) +know very little about the hardware details. Instead, they take their memory +size information from the Restart Parameter Block (RPB). If the firmware +sets up an RPB for more than 64MB, the operating systems use the extra +memory without requiring source changes. + +In extended memory mode, the simulator implements an 18th CMCTL register. +This read-only register gives the size of main memory in MB. The extended +memory firmware (ka655x.bin) bootstrap code uses this to set up the RPB. +No other parts of the firmware are aware of extended memory; thus, all the +diagnostic and display commands operate only on the first 64MB of memory. + +If extended memory mode is disabled, the 18th CMCTL register is invisible, +and the simulator operates like a real KA655. diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index 483dd9df..94980a8d 100644 --- a/VAX/vax_fpa.c +++ b/VAX/vax_fpa.c @@ -1,6 +1,6 @@ /* vax_fpa.c - VAX floating point accelerator simulator - Copyright (c) 1998-2003, Robert M Supnik + Copyright (c) 1998-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/VAX/vax_io.c b/VAX/vax_io.c index afb62c04..13d64b69 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -1,6 +1,6 @@ /* vax_io.c: VAX Qbus IO simulator - Copyright (c) 1998-2003, Robert M Supnik + Copyright (c) 1998-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ qba Qbus adapter + 21-Mar-04 RMS Added RXV21 support 21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls 21-Nov-03 RMS Added check for interrupt slot conflict (found by Dave Hittner) 29-Oct-03 RMS Fixed WriteX declaration (found by Mark Pizzolato) @@ -927,7 +928,7 @@ struct auto_con auto_tab[AUTO_LNT + 1] = { { 0x7, 0x7 }, /* KW11C */ { 0x7, 0 }, /* reserved */ - { 0x7, 0x3 }, /* RX11/RX211 */ + { 0x7, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RX, { "RX", "RY" } }, { 0x7, 0x3 }, /* DR11W */ { 0x7, 0x3 }, /* DR11B */ { 0x7, 0x7 }, /* DMP11 */ diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index f0f7df43..4841019f 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -1,6 +1,6 @@ /* vax_mm.c - VAX memory management simulator - Copyright (c) 1998-2003, Robert M Supnik + Copyright (c) 1998-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/VAX/vax_sys.c b/VAX/vax_sys.c index 2933fd2e..961440ba 100644 --- a/VAX/vax_sys.c +++ b/VAX/vax_sys.c @@ -1,6 +1,6 @@ /* vax_sys.c: VAX simulator interface - Copyright (c) 1998-2003, Robert M Supnik + Copyright (c) 1998-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 21-Mar-04 RMS Added RXV21 support 06-May-03 RMS Added support for second DELQA 12-Oct-02 RMS Added multiple RQ controller support 10-Oct-02 RMS Added DELQA support @@ -47,6 +48,7 @@ extern DEVICE lpt_dev; extern DEVICE clk_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; extern DEVICE rl_dev; +extern DEVICE ry_dev; extern DEVICE ts_dev; extern DEVICE tq_dev; extern DEVICE dz_dev; @@ -107,6 +109,7 @@ DEVICE *sim_devices[] = { &rqb_dev, &rqc_dev, &rqd_dev, + &ry_dev, &ts_dev, &tq_dev, &xq_dev, diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index 77214ad1..b412650f 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -1,6 +1,6 @@ /* vax_sysreg.c: VAX system registers simulator - Copyright (c) 1998-2003, Robert M Supnik + Copyright (c) 1998-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -33,8 +33,9 @@ cso console storage output sysd system devices (SSC miscellany) - 7-Jun-03 MP Added calibrated delay to ROM reads (from Mark Pizzolato) - Fixed calibration problems interval timer (from Mark Pizzolato) + 23-Jan-04 MP Added extended physical memory support (Mark Pizzolato) + 07-Jun-03 MP Added calibrated delay to ROM reads (Mark Pizzolato) + Fixed calibration problems interval timer (Mark Pizzolato) 12-May-03 RMS Fixed compilation warnings from VC.Net 23-Apr-03 RMS Revised for 32b/64b t_addr 19-Aug-02 RMS Removed unused variables (found by David Hittner) @@ -65,7 +66,7 @@ #define CMCNF_RW (CMCNF_VLD | CMCNF_BA) /* read/write */ #define CMCNF_MASK (CMCNF_RW | CMCNF_SIG) #define MEM_BANK (1 << 22) /* bank size 4MB */ -#define MEM_SIG 0x17; /* ECC, 4 x 4MB */ +#define MEM_SIG (0x17) /* ECC, 4 x 4MB */ /* CMCTL error register */ @@ -169,6 +170,7 @@ extern int32 p1; extern int32 sim_switches; extern int32 MSER; extern int32 tmr_poll; +extern int32 cpu_extmem; uint32 *rom = NULL; /* boot ROM */ uint32 *nvr = NULL; /* non-volatile mem */ @@ -874,7 +876,10 @@ default: /* config reg */ case 16: /* err status */ return cmctl_reg[rg]; case 17: /* csr */ - return cmctl_reg[rg] & CMCSR_MASK; } + return cmctl_reg[rg] & CMCSR_MASK; +case 18: /* KA655X ext mem */ + if (cpu_extmem) return MEMSIZE; + MACH_CHECK (MCHK_READ); } return 0; } @@ -888,7 +893,8 @@ if (lnt < L_LONG) { /* LW write only */ switch (rg) { default: /* config reg */ if (val & CMCNF_SRQ) { /* sig request? */ - for (i = rg; i < (rg + 4); i++) { + int32 rg_g = rg & ~3; /* group of 4 */ + for (i = rg_g; i < (rg_g + 4); i++) { cmctl_reg[i] = cmctl_reg[i] & ~CMCNF_SIG; if (ADDR_IS_MEM (i * MEM_BANK)) cmctl_reg[i] = cmctl_reg[i] | MEM_SIG; } } @@ -899,7 +905,9 @@ case 16: /* err status */ break; case 17: /* csr */ cmctl_reg[rg] = val & CMCSR_MASK; - break; } + break; +case 18: + MACH_CHECK (MCHK_WRITE); } return; } diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index d2949416..749feb71 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 21-Mar-04 RMS Added RXV21 support + 25-Jan-04 RMS Removed local debug logging support + RMS,MP Added "KA655X" support 29-Dec-03 RMS Added Q18 definition for PDP11 compatibility 22-Dec-02 RMS Added BDR halt enable definition 11-Nov-02 RMS Added log bits for XQ @@ -33,13 +36,15 @@ 28-Apr-02 RMS Fixed DZV vector base and number of lines This file covers the KA65x ("Mayfair") series of CVAX-based Qbus systems. + The simulator defines an extended physical memory variant of the KA655, + called the KA655X. It has a maximum memory size of 512MB instead of 64MB. System memory map - 0000 0000 - 03FF FFFF main memory - 0400 0000 - 0FFF FFFF reserved - 1000 0000 - 13FF FFFF secondary cache diagnostic space - 1400 0000 - 1FFF FFFF reserved + 0000 0000 - 03FF FFFF main memory (KA655) + 0400 0000 - 0FFF FFFF reserved (KA655), main memory (KA655X) + 1000 0000 - 13FF FFFF cache diagnostic space (KA655), main memory (KA655X) + 1400 0000 - 1FFF FFFF reserved (KA655), main memory (KA655X) 2000 0000 - 2000 1FFF Qbus I/O page 2000 2000 - 2003 FFFF reserved @@ -81,9 +86,10 @@ /* Memory */ -#define MAXMEMWIDTH 26 /* max mem addr width */ +#define MAXMEMWIDTH 26 /* max mem, std KA655 */ #define MAXMEMSIZE (1 << MAXMEMWIDTH) /* max mem size */ -#define MAXMEMMASK (MAXMEMSIZE - 1) /* max mem addr mask */ +#define MAXMEMWIDTH_X 29 /* max mem, KA655X */ +#define MAXMEMSIZE_X (1 << MAXMEMWIDTH_X) #define INITMEMSIZE (1 << 24) /* initial memory size */ #define MEMSIZE (cpu_unit.capac) #define ADDR_IS_MEM(x) (((uint32) (x)) < MEMSIZE) @@ -148,7 +154,8 @@ /* CMCTL registers */ -#define CMCTLSIZE (18 << 2) /* 18 registers */ +/* #define CMCTLSIZE (18 << 2) /* 18 registers */ +#define CMCTLSIZE (19 << 2) /* KA655X extra reg */ #define CMCTLBASE (REGBASE + 0x100) /* CMCTL addr base */ /* SSC registers */ @@ -257,6 +264,10 @@ typedef struct pdp_dib DIB; #define IOLN_TQ 004 #define IOBA_RP (IOPAGEBASE + 016700) /* RP/RM */ #define IOLN_RP 054 +#define IOBA_RX (IOPAGEBASE + 017170) /* RXV11 */ +#define IOLN_RX 004 +#define IOBA_RY (IOPAGEBASE + 017170) /* RXV21 */ +#define IOLN_RY 004 #define IOBA_DBL (IOPAGEBASE + 017500) /* doorbell */ #define IOLN_DBL 002 #define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ @@ -298,6 +309,7 @@ typedef struct pdp_dib DIB; #define INT_V_CSO 6 #define INT_V_TMR0 7 /* SSC timers */ #define INT_V_TMR1 8 +#define INT_V_RY 9 /* RXV21 */ #define INT_CLK (1u << INT_V_CLK) #define INT_RQ (1u << INT_V_RQ) @@ -317,6 +329,7 @@ typedef struct pdp_dib DIB; #define INT_CSO (1u << INT_V_CSO) #define INT_TMR0 (1u << INT_V_TMR0) #define INT_TMR1 (1u << INT_V_TMR1) +#define INT_RY (1u << INT_V_RY) #define IPL_CLK (0x16 - IPL_HMIN) /* relative IPL */ #define IPL_RQ (0x15 - IPL_HMIN) @@ -327,6 +340,7 @@ typedef struct pdp_dib DIB; #define IPL_TS (0x15 - IPL_HMIN) #define IPL_TQ (0x15 - IPL_HMIN) #define IPL_XQ (0x15 - IPL_HMIN) +#define IPL_RY (0x15 - IPL_HMIN) #define IPL_TTI (0x14 - IPL_HMIN) #define IPL_TTO (0x14 - IPL_HMIN) #define IPL_PTR (0x14 - IPL_HMIN) @@ -354,6 +368,7 @@ typedef struct pdp_dib DIB; #define VEC_TS (VEC_Q + 0224) #define VEC_RP (VEC_Q + 0254) #define VEC_TQ (VEC_Q + 0260) +#define VEC_RY (VEC_Q + 0264) #define VEC_DZRX (VEC_Q + 0300) #define VEC_DZTX (VEC_Q + 0304) @@ -361,6 +376,7 @@ typedef struct pdp_dib DIB; #define RANK_DZ 8 #define RANK_RL 14 +#define RANK_RX 18 #define RANK_RQ 26 #define RANK_TQ 30 @@ -374,20 +390,9 @@ typedef struct pdp_dib DIB; /* Logging */ -#define LOG_CPU_I 0x0001 /* intexc */ -#define LOG_CPU_R 0x0002 /* REI */ -#define LOG_CPU_P 0x0004 /* context */ -#define LOG_CPU_H 0x0008 /* history */ -#define LOG_RP 0x0010 -#define LOG_TS 0x0020 -#define LOG_RQ 0x0040 -#define LOG_TQ 0x0080 -#define LOG_XQ0 0x0100 -#define LOG_XQ1 0x0200 -#define LOG_XQ2 0x0400 -#define LOG_XQ3 0x0800 - -#define DBG_LOG(x) (sim_log && (cpu_log & (x))) +#define LOG_CPU_I 0x1 /* intexc */ +#define LOG_CPU_R 0x2 /* REI */ +#define LOG_CPU_P 0x4 /* context */ /* Function prototypes for I/O */ diff --git a/build_mingw.bat b/build_mingw.bat index eaad7353..187cea2f 100644 --- a/build_mingw.bat +++ b/build_mingw.bat @@ -8,7 +8,7 @@ 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% -mkdir BIN +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/build_mingw_ether.bat b/build_mingw_ether.bat index 6d7b9282..15c9a7c1 100644 --- a/build_mingw_ether.bat +++ b/build_mingw_ether.bat @@ -9,7 +9,7 @@ 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% -mkdir BIN +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/descrip.mms b/descrip.mms index 7d56039a..3d032ced 100644 --- a/descrip.mms +++ b/descrip.mms @@ -21,6 +21,7 @@ # 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. @@ -117,15 +118,17 @@ CC = CC/DECC$(OUR_CC_FLAGS) @ 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)SCP_TTY.C,$(SIMH_DIR)SIM_SOCK.C,\ +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_TAPE.C,$(SIMH_DIR)SIM_FIO.C,\ + $(SIMH_DIR)SIM_TIMER.C # # VMS PCAP File Definitions. @@ -189,7 +192,7 @@ NOVA_SOURCE = $(NOVA_DIR)NOVA_SYS.C,$(NOVA_DIR)NOVA_CPU.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_TT1.C,$(NOVA_DIR)NOVA_QTY.C NOVA_OPTIONS = /INCLUDE=($(SIMH_DIR),$(NOVA_DIR))/DEFINE=($(CC_DEFS)) # @@ -201,7 +204,7 @@ ECLIPSE_SOURCE = $(NOVA_DIR)ECLIPSE_CPU.C,$(NOVA_DIR)ECLIPSE_TT.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_TT1.C,$(NOVA_DIR)NOVA_QTY.C ECLIPSE_OPTIONS = /INCLUDE=($(SIMH_DIR),$(NOVA_DIR))\ /DEFINE=($(CC_DEFS),"USE_INT64=1","ECLIPSE=1") @@ -213,6 +216,14 @@ 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 = /INCLUDE=($(SIMH_DIR),$(GRI_DIR))/DEFINE=($(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 = /INCLUDE=($(SIMH_DIR),$(LGP_DIR))/DEFINE=($(CC_DEFS)) + # # Honeywell 316/516 Simulator Definitions. # @@ -349,7 +360,7 @@ 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_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_LIB2 = $(LIB_DIR)PDP11L2-$(ARCH).OLB @@ -376,7 +387,7 @@ PDP10_SOURCE = $(PDP10_DIR)PDP10_FE.C,\ $(PDP11_DIR)PDP11_PT.C,$(PDP11_DIR)PDP11_DZ.C,\ $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_XU.C PDP10_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP10_DIR),$(PDP11_DIR))\ - /DEFINE=($(CC_DEFS),"USE_INT64=1","VM_PDP10=1") + /DEFINE=($(CC_DEFS),"USE_INT64=1","VM_PDP10=1"$(PCAP_DEFS)) # # IBM System 3 Simulator Definitions. @@ -407,10 +418,11 @@ VAX_SOURCE = $(VAX_DIR)VAX_CPU1.C,$(VAX_DIR)VAX_CPU.C,\ $(VAX_DIR)VAX_FPA.C,$(VAX_DIR)VAX_IO.C,\ $(VAX_DIR)VAX_MMU.C,$(VAX_DIR)VAX_STDDEV.C,\ $(VAX_DIR)VAX_SYS.C,$(VAX_DIR)VAX_SYSDEV.C,\ - $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.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_PT.C,$(PDP11_DIR)PDP11_XQ.C + $(PDP11_DIR)PDP11_PT.C,$(PDP11_DIR)PDP11_XQ.C,\ + $(PDP11_DIR)PDP11_RY.C VAX_OPTIONS = /INCLUDE=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEFINE=($(CC_DEFS),"VM_VAX=1"$(PCAP_DEFS)) @@ -418,12 +430,12 @@ VAX_OPTIONS = /INCLUDE=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR)$(PCAP_INC))\ # If we're not a VAX, Build Everything # .IFDEF MMSALPHA -ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ +ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 VAX SDS .ELSE # -# Else We Are On VAX And Build Everything EXCEPT The PDP-10 Since VAX -# Dosen't Have INT64 +# Else We Are On VAX And Build Everything EXCEPT The PDP-10 and the ECLIPSE +# Since VAX Dosen't Have INT64 # ALL : ALTAIR ALTAIRZ80 GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 VAX SDS @@ -516,6 +528,17 @@ $(GRI_LIB) : $(GRI_SOURCE) $ 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) - + /OBJECT=$(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. @@ -783,6 +806,10 @@ ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB) $(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. +# +.IFDEF MMSALPHA ECLIPSE : $(SIMH_LIB) $(ECLIPSE_LIB) $! $! Building The $(BIN_DIR)ECLIPSE-$(ARCH).EXE Simulator. @@ -791,6 +818,17 @@ ECLIPSE : $(SIMH_LIB) $(ECLIPSE_LIB) $ 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) $! @@ -801,6 +839,15 @@ GRI : $(SIMH_LIB) $(GRI_LIB) $(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)/OBJECT=$(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. @@ -922,13 +969,13 @@ PDP9 : $(SIMH_LIB) $(PDP9_LIB) # If Not On VAX, Build The PDP-10 Simulator. # .IFDEF MMSALPHA -PDP10 : $(SIMH_LIB) $(PDP10_LIB) +PDP10 : $(SIMH_LIB) $(PCAP_LIBD) $(PDP10_LIB) $(PCAP_EXECLET) $! $! Building The $(BIN_DIR)PDP10-$(ARCH).EXE Simulator. $! $ $(CC)$(PDP10_OPTIONS)/OBJECT=$(BLD_DIR) SCP.C $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP10-$(ARCH).EXE - - $(BLD_DIR)SCP.OBJ,$(PDP10_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $(BLD_DIR)SCP.OBJ,$(PDP10_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY$(PCAP_LIBR) $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* .ELSE # @@ -1003,4 +1050,4 @@ $(PCAP_VCMDIR)PCAPVCM.EXE : $(PCAP_VCM_SOURCES) $! $ @SYS$DISK:[.PCAP-VMS.PCAPVCM]BUILD_PCAPVCM $ DELETE/NOLOG/NOCONFIRM $(PCAP_VCMDIR)*.OBJ;*,$(PCAP_VCMDIR)*.MAP;* - + diff --git a/makefile b/makefile index 5c99827c..9be1acdf 100644 --- a/makefile +++ b/makefile @@ -6,19 +6,19 @@ ifeq ($(WIN32),) #Unix Environments ifeq ($(OSTYPE),solaris) -OS_CCDEFS = -lsocket -lnsl -I /usr/local/include -CC = gcc -O2 -g -lm $(OS_CCDEFS) -L /usr/local/lib -I . -D_GNU_SOURCE +OS_CCDEFS = -lsocket -lnsl -lpthread -D_GNU_SOURCE else -CC = gcc -O2 -lm -I . +OS_CCDEFS = -D_GNU_SOURCE endif +CC = gcc -std=c99 -O2 -g -lm $(OS_CCDEFS) -I . ifeq ($(USE_NETWORK),) else -NETWORK_OPT = -DUSE_NETWORK -lpcap +NETWORK_OPT = -DUSE_NETWORK -lpcap -isystem /usr/local/include -L /usr/local/lib endif else #Win32 Environments LDFLAGS = -lm -lwsock32 -CC = gcc -O0 -I. +CC = gcc -std=c99 -U__STRICT_ANSI__ -O0 -I. EXE = .exe ifeq ($(USE_NETWORK),) else @@ -31,8 +31,8 @@ endif # Common Libraries # BIN = BIN/ -SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c sim_ether.c sim_tape.c - +SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \ + sim_tmxr.c sim_ether.c sim_tape.c # @@ -48,7 +48,7 @@ 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_tt.c ${NOVAD}nova_tt1.c ${NOVAD}nova_qty.c NOVA_OPT = -I ${NOVAD} @@ -56,7 +56,7 @@ 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_clk.c ${NOVAD}nova_tt1.c ${NOVAD}nova_qty.c ECLIPSE_OPT = -I ${NOVAD} -DECLIPSE -DUSE_INT64 @@ -92,7 +92,7 @@ VAX = ${VAXD}vax_cpu1.c ${VAXD}vax_cpu.c ${VAXD}vax_fpa.c ${VAXD}vax_io.c \ ${VAXD}vax_sysdev.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_pt.c ${PDP11D}pdp11_xq.c + ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_xq.c ${PDP11D}pdp11_ry.c VAX_OPT = -DVM_VAX -DUSE_INT64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} @@ -103,7 +103,7 @@ PDP10 = ${PDP10D}pdp10_fe.c ${PDP11D}pdp11_dz.c ${PDP10D}pdp10_cpu.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} +PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} -I ${VAXD} ${NETWORK_OPT} @@ -208,6 +208,12 @@ 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 \ @@ -225,7 +231,7 @@ ALL = ${BIN}pdp1${EXE} ${BIN}pdp4${EXE} ${BIN}pdp7${EXE} ${BIN}pdp8${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}ibm1130${EXE} ${BIN}id16${EXE} \ - ${BIN}id32${EXE} ${BIN}sds${EXE} + ${BIN}id32${EXE} ${BIN}sds${EXE} ${BIN}lgp${EXE} all : ${ALL} @@ -332,6 +338,10 @@ ${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} @@ -342,5 +352,3 @@ ${BIN}id32${EXE} : ${ID32} ${SIM} ${BIN}sds${EXE} : ${SDS} ${SIM} ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ ${LDFLAGS} - - diff --git a/scp.c b/scp.c index 9c3e6aa5..0ae71abd 100644 --- a/scp.c +++ b/scp.c @@ -23,6 +23,19 @@ 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-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 @@ -120,8 +133,6 @@ #include "sim_defs.h" #include "sim_rev.h" -#include "sim_sock.h" -#include "sim_tmxr.h" #include #include @@ -151,13 +162,10 @@ #define SRBSIZ 1024 /* save/restore buffer */ #define SIM_BRK_INILNT 4096 /* bpt tbl length */ #define SIM_BRK_ALLTYP 0xFFFFFFFF -#define SIM_NTIMERS 8 /* # timers */ -#define SIM_TMAX 500 /* max timer makeup */ #define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \ sim_rtime = sim_rtime + ((uint32) (x - sim_interval)); \ x = sim_interval -#define print_val(a,b,c,d) fprint_val (stdout, (a), (b), (c), (d)) #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]) @@ -189,13 +197,6 @@ else if (sim_switches & SWMASK ('D')) val = 10; \ else if (sim_switches & SWMASK ('H')) val = 16; \ else val = dft; - -#if defined(VMS) -#define FOPEN(file_spec, mode) fopen (file_spec, mode, "ALQ=32", "DEQ=4096", \ - "MBF=6", "MBC=127", "FOP=cbt,tef", "ROP=rah,wbh", "CTX=stm") -#else -#define FOPEN(file_spec, mode) fopen (file_spec, mode) -#endif /* VM interface */ @@ -218,16 +219,8 @@ 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; - -/* External routines */ - -extern t_stat ttinit (void); -extern t_stat ttrunstate (void); -extern t_stat ttcmdstate (void); -extern t_stat ttclose (void); -extern t_stat sim_os_poll_kbd (void); -extern t_stat sim_os_putchar (int32 out); -extern uint32 sim_os_msec (void); +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 */ @@ -254,23 +247,28 @@ t_stat spawn_cmd (int32 flag, char *ptr); /* Set and show command processors */ -t_stat set_telnet (int32 flg, char *cptr); -t_stat set_notelnet (int32 flg, char *cptr); t_stat set_logon (int32 flag, char *cptr); t_stat set_logoff (int32 flag, char *cptr); -t_stat set_radix (DEVICE *dptr, UNIT *uptr, int32 flag); -t_stat set_devenbdis (DEVICE *dptr, UNIT *uptr, int32 flag); -t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag); +t_stat set_debon (int32 flag, char *cptr); +t_stat set_deboff (int32 flag, char *cptr); +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_onoff (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat ssh_break (FILE *st, char *cptr, int32 flg); -t_stat show_config (FILE *st, int32 flag, char *cptr); -t_stat show_queue (FILE *st, int32 flag, char *cptr); -t_stat show_time (FILE *st, int32 flag, char *cptr); -t_stat show_mod_names (FILE *st, int32 flag, char *cptr); -t_stat show_log_names (FILE *st, int32 flag, char *cptr); -t_stat show_log (FILE *st, int32 flag, char *cptr); -t_stat show_telnet (FILE *st, int32 flag, char *cptr); -t_stat show_version (FILE *st, int32 flag, char *cptr); -t_stat show_break (FILE *st, 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_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_debug (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); @@ -310,6 +308,7 @@ char *read_line (char *ptr, int32 size, FILE *stream); CTAB *find_ctab (CTAB *tab, char *gbuf); C1TAB *find_c1tab (C1TAB *tab, char *gbuf); CTAB *find_cmd (char *gbuf); +SHTAB *find_shtab (SHTAB *tab, char *gbuf); DEVICE *find_dev (char *ptr); DEVICE *find_unit (char *ptr, UNIT **uptr); REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); @@ -318,7 +317,6 @@ REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, char *cptr); t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr); -t_bool restore_skip_val (FILE *rfile); t_bool qdisable (DEVICE *dptr); t_stat attach_err (UNIT *uptr, t_stat stat); t_stat detach_all (int32 start_device, t_bool shutdown); @@ -353,24 +351,23 @@ int32 sim_brk_ins = 0; t_bool sim_brk_pend = FALSE; t_addr sim_brk_ploc = 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_end = 1; /* 1 = little */ +int32 sim_deb_close = 0; /* 1 = close debug */ FILE *sim_log = NULL; /* log file */ -unsigned char sim_flip[FLIP_SIZE]; +FILE *sim_deb = NULL; /* debug file */ -TMLN sim_con_ldsc = { 0 }; /* console line descr */ -TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */ -UNIT step_unit = { UDATA (&step_svc, 0, 0) }; +static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) }; /* Tables and strings */ -const char save_vercur[] = "V3.0"; +const char save_vercur[] = "V3.2"; +const char save_ver30[] = "V3.0"; const char save_ver210[] = "V2.10"; -const char save_ver26[] = "V2.6"; const char *scp_error_messages[] = { "Address space exceeded", "Unit not attached", @@ -412,7 +409,8 @@ const char *scp_error_messages[] = { "Internal error", "Invalid magtape record length", "Console Telnet connection lost", - "Console Telnet connection timed out" + "Console Telnet connection timed out", + "Console Telnet output stall" }; const size_t size_map[] = { sizeof (int8), @@ -498,25 +496,36 @@ static CTAB cmd_table[] = { "set nolog disable logging\n" "set telnet enable Telnet port for console\n" "set notelnet disable Telnet for console\n" + "set debug enable debug output to file\n" + "set nodebug disable debug output\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 ONLINE enable unit\n" "set OFFLINE disable unit\n" - "set | set device/unit parameter\n" + "set arg{,arg...} set unit parameters\n" }, { "SHOW", &show_cmd, 0, "sh{ow} br{eak} show breakpoints on address list\n" - "sh{ow} c{onfiguration} show configuration\n" - "sh{ow} d{evices} show devices\n" + "sh{ow} c{onfiguration} show configuration\n" + "sh{ow} deb{ug} show debugging output\n" + "sh{ow} dev{ices} show devices\n" "sh{ow} l{og} show log\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} te{lnet} show console Telnet status\n" "sh{ow} ti{me} show simulated time\n" - "sh{ow} ve{rsion} show simulator version\n" - "sh{ow} | show device parameters\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, 0, "do {arg,arg...} process command file\n" }, { "HELP", &help_cmd, 0, @@ -536,7 +545,6 @@ int32 i, sw; t_bool lookswitch; t_stat stat; CTAB *cmdp; -union {int32 i; char c[sizeof (int32)]; } end_test; #if defined (__MWERKS__) && defined (macintosh) argc = ccommand (&argv); @@ -562,8 +570,7 @@ for (i = 1; i < argc; i++) { /* loop thru args */ sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ if (sim_vm_init != NULL) (*sim_vm_init)(); /* call once only */ -end_test.i = 1; /* test endian-ness */ -sim_end = end_test.c[0]; +sim_finit (); /* init fio package */ stop_cpu = 0; sim_interval = 0; sim_time = sim_rtime = 0; @@ -573,7 +580,7 @@ sim_is_running = 0; sim_log = NULL; if (sim_emax <= 0) sim_emax = 1; -if ((stat = ttinit ()) != SCPE_OK) { +if ((stat = sim_ttinit ()) != SCPE_OK) { fprintf (stderr, "Fatal terminal initialization error\n%s\n", scp_error_messages[stat - SCPE_BASE]); return 0; } @@ -590,7 +597,7 @@ if ((stat = sim_brk_init ()) != SCPE_OK) { return 0; } if (!sim_quiet) { printf ("\n"); - show_version (stdout, 0, NULL); } + show_version (stdout, NULL, NULL, 0, NULL); } if (*cbuf) { /* cmd file arg? */ stat = do_cmd (1, cbuf); /* proc cmd file */ @@ -628,8 +635,9 @@ while (stat != SCPE_EXIT) { /* in case exit */ detach_all (0, TRUE); /* close files */ set_logoff (0, NULL); /* close log */ -set_notelnet (0, NULL); /* close Telnet */ -ttclose (); /* close console */ +set_deboff (0, NULL); /* close debug */ +sim_set_notelnet (0, NULL); /* close Telnet */ +sim_ttclose (); /* close console */ return 0; } @@ -792,23 +800,30 @@ UNIT *uptr; MTAB *mptr; CTAB *gcmdp; C1TAB *ctbr, *glbr; + static CTAB set_glob_tab[] = { - { "TELNET", &set_telnet, 0 }, - { "NOTELNET", &set_notelnet, 0 }, + { "TELNET", &sim_set_telnet, 0 }, + { "NOTELNET", &sim_set_notelnet, 0 }, { "LOG", &set_logon, 0 }, { "NOLOG", &set_logoff, 0 }, { "BREAK", &brk_cmd, SSH_ST }, + { "DEBUG", &set_debon, 0 }, + { "NODEBUG", &set_deboff, 0 }, { NULL, NULL, 0 } }; + static C1TAB set_dev_tab[] = { - { "OCTAL", &set_radix, 8 }, - { "DECIMAL", &set_radix, 10 }, - { "HEX", &set_radix, 16 }, - { "ENABLED", &set_devenbdis, 1 }, - { "DISABLED", &set_devenbdis, 0 }, + { "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[] = { - { "ONLINE", &set_onoff, 1 }, - { "OFFLINE", &set_onoff, 0 }, + { "ONLINE", &set_unit_onoff, 1 }, + { "OFFLINE", &set_unit_onoff, 0 }, { NULL, NULL, 0 } }; GET_SWITCHES (cptr); /* get switches */ @@ -829,7 +844,7 @@ 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 */ + cptr = get_glyph (svptr = cptr, gbuf, 0); /* get modifier */ if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) { if ((mptr->mstring) && /* match string */ @@ -866,7 +881,7 @@ while (*cptr != 0) { /* do all mods */ } /* end for */ if (!mptr || (mptr->mask == 0)) { /* no match? */ if (glbr = find_c1tab (ctbr, gbuf)) { /* global match? */ - r = glbr->action (dptr, uptr, glbr->arg); /* do global */ + 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 */ @@ -900,7 +915,7 @@ if (*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? */ set_logoff (0, NULL); /* close cur log */ -sim_log = FOPEN (gbuf, "a"); /* open 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 */ @@ -920,21 +935,23 @@ sim_log = NULL; return SCPE_OK; } -/* Set controller data radix routine */ +/* Set device data radix routine */ -t_stat set_radix (DEVICE *dptr, UNIT *uptr, int32 flag) +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 controller enabled/disabled routine */ +/* Set device enabled/disabled routine */ -t_stat set_devenbdis (DEVICE *dptr, UNIT *uptr, int32 flag) +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 */ @@ -952,8 +969,9 @@ else return SCPE_OK; /* Set unit online/offline routine */ -t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag) +t_stat set_unit_onoff (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; /* onl? enable */ else { if ((uptr->flags & UNIT_ATT) || /* offline */ @@ -962,18 +980,83 @@ else { if ((uptr->flags & UNIT_ATT) || /* offline */ return SCPE_OK; } +/* Debug on routine */ + +t_stat set_debon (int32 flag, char *cptr) +{ +char *tptr, gbuf[CBUFSIZE]; + +if (*cptr == 0) return SCPE_2FARG; /* need arg */ +tptr = get_glyph (cptr, gbuf, 0); /* get file name */ +if (*tptr != 0) return SCPE_2MARG; /* now eol? */ +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; +} + + /* Debug off routine */ + +t_stat 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; +} + +/* Device debug enable and disable 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? */ + if (dptr->debflags && flag) return SCPE_ARG; /* table or enable? */ + dptr->dctrl = flag; /* no table or disable */ + 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) { -int32 i, lvl; +int32 lvl; t_stat r; char gbuf[CBUFSIZE]; DEVICE *dptr; UNIT *uptr; MTAB *mptr; +SHTAB *shtb, *shptr; -static SHTAB show_table[] = { +static SHTAB show_glob_tab[] = { { "CONFIGURATION", &show_config, 0 }, { "DEVICES", &show_config, 1 }, { "QUEUE", &show_queue, 0 }, @@ -982,25 +1065,37 @@ static SHTAB show_table[] = { { "NAMES", &show_log_names, 0 }, { "VERSION", &show_version, 0 }, { "LOG", &show_log, 0 }, - { "TELNET", &show_telnet, 0 }, + { "TELNET", &sim_show_telnet, 0 }, { "BREAK", &show_break, 0 }, + { "DEBUG", &show_debug, 0 }, + { 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 */ -for (i = 0; show_table[i].name != NULL; i++) { /* find command */ - if (MATCH_CMD (gbuf, show_table[i].name) == 0) { - r = show_table[i].action (stdout, show_table[i].arg, cptr); - if (sim_log) show_table[i].action (sim_log, show_table[i].arg, cptr); - return r; } } +if (shptr = find_shtab (show_glob_tab, gbuf)) { /* global? */ + r = shptr->action (stdout, NULL, NULL, shptr->arg, cptr); + if (sim_log) shptr->action (sim_log, NULL, NULL, shptr->arg, cptr); + return r; } 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 */ @@ -1030,10 +1125,22 @@ while (*cptr != 0) { /* do all mods */ break; } /* end if */ } /* end for */ - if (mptr->mask == 0) return SCPE_ARG; /* any match? */ + if (mptr->mask == 0) { /* no match? */ + if (shptr = find_shtab (shtb, gbuf)) { /* global match? */ + shptr->action (stdout, dptr, uptr, shptr->arg, cptr); + if (sim_log) shptr->action (sim_log, 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 */ @@ -1104,7 +1211,7 @@ return; /* Show processors */ -t_stat show_version (FILE *st, int32 flag, char *cptr) +t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH; @@ -1113,7 +1220,7 @@ fprintf (st, "%s simulator V%d.%d-%d\n", sim_name, vmaj, vmin, vpat); return SCPE_OK; } -t_stat show_config (FILE *st, int32 flag, char *cptr) +t_stat show_config (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr) { int32 i; DEVICE *dptr; @@ -1125,18 +1232,25 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) return SCPE_OK; } -t_stat show_log_names (FILE *st, int32 flag, char *cptr) +t_stat show_log_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr) { int32 i; DEVICE *dptr; -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - if (dptr->lname) fprintf (st, "%s -> %s\n", - dptr->lname, dptr->name); } +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_queue (FILE *st, int32 flag, char *cptr) +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; @@ -1151,7 +1265,7 @@ 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 == &step_unit) fprintf (st, " Step timer"); + 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", @@ -1162,54 +1276,105 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) { return SCPE_OK; } -t_stat show_time (FILE *st, int32 flag, char *cptr) +t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { if (cptr && (*cptr != 0)) return SCPE_2MARG; fprintf (st, "Time: %.0f\n", sim_time); return SCPE_OK; } -t_stat show_log (FILE *st, int32 flag, char *cptr) +t_stat show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { if (cptr && (*cptr != 0)) return SCPE_2MARG; -if (sim_log) fprintf (st, "Logging enabled\n"); -else fprintf (st, "Logging disabled\n"); +if (sim_log) fputs ("Logging enabled\n", st); +else fputs ("Logging disabled\n", st); return SCPE_OK; } -t_stat show_break (FILE *st, int32 flag, char *cptr) +t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { t_stat r; -if (cptr && (*cptr != 0)) { /* more? */ - r = ssh_break (stdout, cptr, 1); - if (sim_log) ssh_break (sim_log, cptr, SSH_SH); } -else { r = sim_brk_showall (stdout, sim_switches); - if (sim_log) sim_brk_showall (sim_log,sim_switches); } +if (cptr && (*cptr != 0)) r = ssh_break (st, cptr, 1); /* more? */ +else r = sim_brk_showall (st, sim_switches); return r; } + +t_stat 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; +} + +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, int32 flag, char *cptr) +t_stat show_mod_names (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr) { -int32 i, any, enb; +int32 i; DEVICE *dptr; -MTAB *mptr; if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - 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 (!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"); } +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; } @@ -1269,7 +1434,7 @@ if (aptr = strchr (cptr, ';')) { /* ;action? */ *aptr++ = 0; } /* separate strings */ while (*cptr) { cptr = get_glyph (cptr, gbuf, ','); - tptr = get_range (gbuf, &lo, &hi, dptr->aradix, max, 0); + 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); @@ -1356,7 +1521,7 @@ 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 = FOPEN (gbuf, flag? "wb": "rb"); /* open for wr/rd */ +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 */ @@ -1408,24 +1573,25 @@ 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 = calloc (CBUFSIZE, sizeof (char)); /* alloc buf for name */ 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 = FOPEN (cptr, "rb"); /* open rd only */ + 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 = FOPEN (cptr, "rb+"); /* open r/w */ + uptr->fileref = sim_fopen (cptr, "rb+"); /* open r/w */ if (uptr->fileref == NULL) { /* open fail? */ if (errno == EROFS) { /* read only? */ if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ return attach_err (uptr, SCPE_NORO); /* no error */ - uptr->fileref = FOPEN (cptr, "rb"); /* open rd only */ + 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 */ @@ -1433,7 +1599,7 @@ else { /* normal */ else { /* doesn't exist */ if (sim_switches & SWMASK ('E')) /* must exist? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - uptr->fileref = FOPEN (cptr, "wb+"); /* open new file */ + 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)); } @@ -1446,7 +1612,7 @@ if (uptr->flags & UNIT_BUFABLE) { /* buffer? */ 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 = fxread (uptr->filebuf, SZ_D (dptr), /* read file */ + uptr->hwmark = sim_fread (uptr->filebuf, SZ_D (dptr), /* read file */ cap, uptr->fileref); uptr->flags = uptr->flags | UNIT_BUF; } /* set buffered */ uptr->flags = uptr->flags | UNIT_ATT; @@ -1539,7 +1705,7 @@ if (uptr->flags & UNIT_BUF) { if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { if (!sim_quiet) printf ("%s: writing buffer to file\n", sim_dname (dptr)); rewind (uptr->fileref); - fxwrite (uptr->filebuf, SZ_D (dptr), cap, 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 */ @@ -1627,7 +1793,7 @@ FILE *sfile; t_stat r; GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ -if ((sfile = FOPEN (cptr, "wb")) == NULL) return SCPE_OPENERR; +if ((sfile = sim_fopen (cptr, "wb")) == NULL) return SCPE_OPENERR; r = sim_save (sfile); fclose (sfile); return r; @@ -1647,13 +1813,13 @@ DEVICE *dptr; UNIT *uptr; REG *rptr; -#define WRITE_I(xx) fxwrite (&(xx), sizeof (xx), 1, sfile) +#define WRITE_I(xx) sim_fwrite (&(xx), sizeof (xx), 1, sfile) fputs (save_vercur, sfile); /* [V2.5] save format */ fputc ('\n', sfile); fputs (sim_name, sfile); /* sim name */ fputc ('\n', sfile); -WRITE_I (sim_time); /* sim time */ +fprintf (sfile, "%.0f\n", 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 */ @@ -1696,7 +1862,7 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */ WRITE_I (l); } /* write only count */ else { WRITE_I (l); /* block count */ - fxwrite (mbuf, sz, l, sfile); } + sim_fwrite (mbuf, sz, l, sfile); } } /* end for k */ free (mbuf); /* dealloc buffer */ } /* end if mem */ @@ -1732,7 +1898,7 @@ t_stat r; GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ -if ((rfile = FOPEN (cptr, "rb")) == NULL) return SCPE_OPENERR; +if ((rfile = sim_fopen (cptr, "rb")) == NULL) return SCPE_OPENERR; r = sim_rest (rfile); fclose (rfile); return r; @@ -1748,27 +1914,30 @@ t_addr k, high; t_value val, mask; t_stat r; size_t sz; -t_bool v30 = FALSE, v210 = FALSE; +t_bool v32 = FALSE, v30 = FALSE; 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 (fxread (&xx, sizeof (xx), 1, rfile) == 0) \ +#define READ_I(xx) if (sim_fread (&xx, sizeof (xx), 1, rfile) == 0) \ return SCPE_IOERR; READ_S (buf); /* [V2.5+] read version */ -if (strcmp (buf, save_vercur) == 0) v30 = v210 = TRUE; /* version 2.11? */ -else if (strcmp (buf, save_ver210) == 0) v210 = TRUE; /* version 2.10? */ -else if (strcmp (buf, save_ver26) != 0) { /* version 2.6? */ +if (strcmp (buf, save_vercur) == 0) v32 = v30 = TRUE; /* version 3.2? */ +else if (strcmp (buf, save_ver30) == 0) v30 = TRUE; /* version 3.0? */ +else if (strcmp (buf, save_ver210) != 0) { /* version 2.10? */ printf ("Invalid file version: %s\n", buf); /* no, unknown */ 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; } -READ_I (sim_time); /* sim time */ +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 */ @@ -1782,10 +1951,11 @@ for ( ;; ) { /* device loop */ deassign_device (dptr); /* delete old name */ if ((buf[0] != 0) && ((r = assign_device (dptr, buf)) != SCPE_OK)) return r; } - if (v210) { /* [V2.10+] */ - READ_I (flg); /* cont flags */ - dptr->flags = (dptr->flags & ~DEV_RFLAGS) | /* restore */ - (flg & DEV_RFLAGS); } + 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? */ @@ -1801,10 +1971,11 @@ for ( ;; ) { /* device loop */ if (v30) { /* [V3.0+] */ READ_I (uptr->u5); /* more dev specific */ READ_I (uptr->u6); } - if (v210) { /* [V2.10+] */ - READ_I (flg); /* unit flags */ - uptr->flags = (uptr->flags & ~UNIT_RFLAGS) | - (flg & UNIT_RFLAGS); } /* restore */ + READ_I (flg); /* [V2.10+] unit flags */ + 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 (!(dptr->flags & DEV_NET) || /* if not net dev or */ !(uptr->flags & UNIT_ATT) || /* not currently att */ @@ -1814,7 +1985,7 @@ for ( ;; ) { /* device loop */ if (buf[0] != 0) { /* any file? */ uptr->flags = uptr->flags & ~UNIT_DIS; sim_switches = SIM_SW_REST; /* attach/rest */ - if (v210 && (flg & UNIT_RO)) /* saved flgs & RO? */ + 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; } } @@ -1841,7 +2012,7 @@ for ( ;; ) { /* device loop */ for (k = 0; k < high; ) { /* loop thru mem */ READ_I (blkcnt); /* block count */ if (blkcnt < 0) limit = -blkcnt; /* compressed? */ - else limit = fxread (mbuf, sz, blkcnt, rfile); + 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? */ @@ -1856,21 +2027,15 @@ for ( ;; ) { /* device loop */ for ( ;; ) { /* register loop */ READ_S (buf); /* read reg name */ if (buf[0] == 0) break; /* last? */ - if (v210) { READ_I (depth); } /* [V2.10+] depth */ + 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); - if (v210) { /* [V2.10]+ */ - for (us = 0; us < depth; us++) { /* skip values */ - READ_I (val); } } - else { - READ_I (val); /* must be one val */ - if (!restore_skip_val (rfile)) /* grope for next reg */ - return SCPE_INCOMP; } /* err or eof? */ - continue; } /* pray! */ - if (v210 && (depth != rptr->depth)) /* [V2.10+] mismatch? */ + 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); - else depth = rptr->depth; /* depth validated */ mask = width_mask[rptr->width]; /* get mask */ for (us = 0; us < depth; us++) { /* loop thru values */ READ_I (val); /* read value */ @@ -1881,34 +2046,6 @@ for ( ;; ) { /* device loop */ } /* end device loop */ return SCPE_OK; } - -/* Restore skip values (pre V2.10) - - To find the next register name, sift through bytes looking for valid - upper case ASCII characters terminated by \n */ - -t_bool restore_skip_val (FILE *rfile) -{ -t_bool instr = FALSE; -char c; -int32 ic, pos; - -if ((ic = fgetc (rfile)) == EOF) return FALSE; /* one char */ -fseek (rfile, ftell (rfile) - 1, SEEK_SET); /* back up over */ -if ((ic & 0377) == '\n') return TRUE; /* immediate nl? */ -while ((ic = fgetc (rfile)) != EOF) { /* get char */ - c = ic & 0377; /* cut to 8b */ - if (isalnum (c) || (c == '*') || (c == '_')) { /* valid reg char? */ - if (!instr) pos = ftell (rfile) - 1; /* new? save pos */ - instr = TRUE; } - else { /* not ASCII */ - if ((c == '\n') && instr) { /* nl & in string? */ - fseek (rfile, pos, SEEK_SET); /* rewind file */ - return TRUE; } - instr = FALSE; } /* not in string */ - } /* end while */ -return FALSE; /* error */ -} /* Run, go, cont, step commands @@ -1921,26 +2058,32 @@ return FALSE; /* error */ t_stat run_cmd (int32 flag, char *cptr) { -char gbuf[CBUFSIZE]; +char *tptr, gbuf[CBUFSIZE]; uint32 i, j; -int32 step, unitno; +int32 unitno; +t_value pcv; t_stat r; DEVICE *dptr; UNIT *uptr; void int_handler (int signal); GET_SWITCHES (cptr); /* get switches */ -step = 0; +sim_step = 0; if (((flag == RU_RUN) || (flag == RU_GO)) && (*cptr != 0)) { /* run or go */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ - if ((r = dep_reg (0, gbuf, sim_PC, 0)) != SCPE_OK) return r; } + if (sim_vm_parse_addr) /* address parser? */ + pcv = sim_vm_parse_addr (sim_devices[0], gbuf, &tptr); + else pcv = strtotv (gbuf, &tptr, sim_PC->radix); + if ((tptr == gbuf) || (*tptr != 0) || + (pcv > width_mask[sim_PC->width])) return SCPE_ARG; + put_rval (sim_PC, 0, pcv); } if (flag == RU_STEP) { /* step */ - if (*cptr == 0) step = 1; + if (*cptr == 0) sim_step = 1; else { cptr = get_glyph (cptr, gbuf, 0); - step = (int32) get_uint (gbuf, 10, INT_MAX, &r); - if ((r != SCPE_OK) || (step == 0)) return SCPE_ARG; } } + sim_step = (int32) get_uint (gbuf, 10, INT_MAX, &r); + if ((r != SCPE_OK) || (sim_step <= 0)) return SCPE_ARG; } } if (flag == RU_BOOT) { /* boot */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ @@ -1968,25 +2111,25 @@ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { uptr = dptr->units + j; if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ)) - fseek_ext (uptr->fileref, uptr->pos, SEEK_SET); } } + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); } } stop_cpu = 0; if (signal (SIGINT, int_handler) == SIG_ERR) { /* set WRU */ return SCPE_SIGERR; } -if (ttrunstate () != SCPE_OK) { /* set console mode */ - ttcmdstate (); +if (sim_ttrun () != SCPE_OK) { /* set console mode */ + sim_ttcmd (); return SCPE_TTYERR; } if ((r = sim_check_console (30)) != SCPE_OK) { /* check console, error? */ - ttcmdstate (); + sim_ttcmd (); return r; } -if (step) sim_activate (&step_unit, step); /* set step timer */ +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 */ -ttcmdstate (); /* restore console */ +sim_ttcmd (); /* restore console */ signal (SIGINT, SIG_DFL); /* cancel WRU */ -sim_cancel (&step_unit); /* cancel step timer */ +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); } @@ -2000,7 +2143,7 @@ return SCPE_OK; /* Print stopped message */ -void fprint_stopped (FILE *stream, t_stat v) +void fprint_stopped (FILE *st, t_stat v) { int32 i; t_stat r; @@ -2008,11 +2151,12 @@ t_addr k; t_value pcval; DEVICE *dptr; -if (v >= SCPE_BASE) fprintf (stream, "\n%s, %s: ", +if (v >= SCPE_BASE) fprintf (st, "\n%s, %s: ", scp_error_messages[v - SCPE_BASE], sim_PC->name); -else fprintf (stream, "\n%s, %s: ", sim_stop_messages[v], sim_PC->name); +else fprintf (st, "\n%s, %s: ", sim_stop_messages[v], sim_PC->name); pcval = get_rval (sim_PC, 0); -fprint_val (stream, pcval, sim_PC->radix, sim_PC->width, +if (sim_vm_fprint_addr) sim_vm_fprint_addr (st, sim_devices[0], (t_addr) pcval); +else fprint_val (st, pcval, sim_PC->radix, sim_PC->width, sim_PC->flags & REG_FMT); if (((dptr = sim_devices[0]) != NULL) && (dptr->examine != NULL)) { for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; @@ -2020,29 +2164,31 @@ if (((dptr = sim_devices[0]) != NULL) && (dptr->examine != NULL)) { if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V'))) != SCPE_OK) break; } if ((r == SCPE_OK) || (i > 0)) { - fprintf (stream, " ("); - if (fprint_sym (stream, (t_addr) pcval, sim_eval, NULL, SWMASK('M')) > 0) - fprint_val (stream, sim_eval[0], dptr->dradix, + fprintf (st, " ("); + if (fprint_sym (st, (t_addr) pcval, sim_eval, NULL, SWMASK('M')) > 0) + fprint_val (st, sim_eval[0], dptr->dradix, dptr->dwidth, PV_RZRO); - fprintf (stream, ")"); } } -fprintf (stream, "\n"); + fprintf (st, ")"); } } +fprintf (st, "\n"); return; } /* Unit service for step timeout, originally scheduled by STEP n command - - Return step timeout SCP code, will cause simulation to stop -*/ + Return step timeout SCP code, will cause simulation to stop */ t_stat step_svc (UNIT *uptr) { return SCPE_STEP; } -/* Signal handler for ^C signal +/* Cancel scheduled step service */ - Set stop simulation flag -*/ +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) { @@ -2100,7 +2246,7 @@ for (;;) { /* loop through modifiers */ fclose (ofile); /* one per customer */ return SCPE_ARG; } cptr = get_glyph_nc (cptr + 1, gbuf, 0); - ofile = FOPEN (gbuf, "a"); /* open for append */ + ofile = sim_fopen (gbuf, "a"); /* open for append */ if (ofile == NULL) return SCPE_OPENERR; exd2f = TRUE; continue; } /* look for more */ @@ -2142,7 +2288,7 @@ for (gptr = gbuf, reason = SCPE_OK; highr = lowr; if (*tptr == '[') { if (lowr->depth <= 1) return SCPE_ARG; - tptr = get_range (tptr + 1, &low, &high, + tptr = get_range (NULL, tptr + 1, &low, &high, 10, lowr->depth - 1, ']'); if (tptr == NULL) return SCPE_ARG; } } if (*tptr && (*tptr++ != ',')) return SCPE_ARG; @@ -2150,7 +2296,7 @@ for (gptr = gbuf, reason = SCPE_OK; lowr, highr, (uint32) low, (uint32) high); continue; } - tptr = get_range (gptr, &low, &high, dptr->aradix, + tptr = get_range (dptr, gptr, &low, &high, dptr->aradix, (((uptr->capac == 0) || (flag == EX_E))? 0: uptr->capac - dptr->aincr), 0); if (tptr == NULL) return SCPE_ARG; @@ -2243,9 +2389,11 @@ if (rptr->depth > 1) fprintf (ofile, "%s[%d]: ", rptr->name, idx); else fprintf (ofile, "%s: ", rptr->name); if (!(flag & EX_E)) return SCPE_OK; GET_RADIX (rdx, rptr->radix); -if (rptr->flags & REG_VMIO) - fprint_sym (ofile, rdx, &val, NULL, REG_VMIO); -else fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT); +if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr) + sim_vm_fprint_addr (ofile, sim_devices[0], (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, " "); else fprintf (ofile, "\n"); return SCPE_OK; @@ -2309,7 +2457,7 @@ t_stat dep_reg (int32 flag, char *cptr, REG *rptr, uint32 idx) t_stat r; t_value val, mask; int32 rdx; -char gbuf[CBUFSIZE]; +char *tptr, gbuf[CBUFSIZE]; if ((cptr == NULL) || (rptr == NULL)) return SCPE_IERR; if (rptr->flags & REG_RO) return SCPE_RO; @@ -2320,10 +2468,14 @@ if (flag & EX_I) { if (*cptr == 0) return SCPE_OK; } /* success */ mask = width_mask[rptr->width]; GET_RADIX (rdx, rptr->radix); -if (rptr->flags & REG_VMIO) - r = parse_sym (cptr, rdx, NULL, &val, REG_VMIO); -else val = get_uint (cptr, rdx, mask, &r); -if (r != SCPE_OK) return SCPE_ARG; +if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr) { /* address form? */ + val = sim_vm_parse_addr (sim_devices[0], 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; @@ -2403,7 +2555,8 @@ t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr) t_stat reason; int32 rdx; -fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT); +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, ": "); if (!(flag & EX_E)) return SCPE_OK; @@ -2443,6 +2596,7 @@ for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) { 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; } @@ -2451,8 +2605,8 @@ for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) { if (uptr->flags & UNIT_BUF) { SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc); } else { - fseek_ext (uptr->fileref, sz * loc, SEEK_SET); - fxread (&sim_eval[i], sz, 1, uptr->fileref); + 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; @@ -2512,6 +2666,7 @@ for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) { 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); @@ -2520,8 +2675,8 @@ for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) { SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc); if (loc >= uptr->hwmark) uptr->hwmark = (uint32) loc + 1; } else { - fseek_ext (uptr->fileref, sz * loc, SEEK_SET); - fxwrite (&sim_eval[i], sz, 1, uptr->fileref); + 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; } } } } @@ -2671,10 +2826,11 @@ 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 = address radix + aradix = radix max = default high value term = terminating character, 0 if none Outputs: @@ -2682,8 +2838,8 @@ return val; NULL if error */ -char *get_range (char *cptr, t_addr *lo, t_addr *hi, uint32 rdx, - t_addr max, char term) +char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi, + uint32 rdx, t_addr max, char term) { char *tptr; @@ -2691,11 +2847,15 @@ if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) { /* ALL? */ tptr = cptr + strlen ("ALL"); *lo = 0; *hi = max; } -else { *lo = (t_addr) strtotv (cptr, &tptr, rdx); /* get low */ +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; - *hi = (t_addr) strtotv (cptr, &tptr, rdx); /* get high */ + 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? */ @@ -3301,166 +3461,6 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) cnt++; return cnt; } -/* 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 - using an intermediate buffer. -*/ - -size_t fxread (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 (sim_end || (size == sizeof (char))) - return fread (bptr, size, count, fptr); -if ((size == 0) || (count == 0)) return 0; -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; -dptr = bptr; /* init output ptr */ -for (i = nbuf; i > 0; i--) { - c = fread (sim_flip, size, (i == 1? lcnt: nelem), fptr); - if (c == 0) return total; - total = total + c; - for (j = 0, sptr = sim_flip; j < c; j++) { - for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; - dptr = dptr + size; } } -return total; -} - -size_t fxwrite (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 (sim_end || (size == sizeof (char))) - return fwrite (bptr, size, count, fptr); -if ((size == 0) || (count == 0)) return 0; -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 = bptr; /* init input ptr */ -for (i = nbuf; i > 0; i--) { - c = (i == 1)? lcnt: nelem; - for (j = 0, dptr = sim_flip; j < c; j++) { - 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 (char *cptr) -{ -FILE *fp; -uint32 sz; - -fp = fopen (cptr, "rb"); -if (fp == NULL) return 0; -fseek (fp, 0, SEEK_END); -sz = ftell (fp); -fclose (fp); -return sz; -} - -/* OS independent clock calibration package - - sim_rtc_init initialize calibration - sim_rtc_calb calibrate clock -*/ - -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 */ -extern t_bool rtc_avail; - -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); -} - /* Breakpoint package. This module replaces the VM-implemented one instruction breakpoint capability. @@ -3628,7 +3628,8 @@ if (sw == 0) sw = SIM_BRK_ALLTYP; if (!bp || (!(bp->typ & sw))) return SCPE_OK; dptr = sim_devices[0]; if (dptr == NULL) return SCPE_OK; -fprint_val (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); +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) { @@ -3707,112 +3708,146 @@ sim_brk_pend = FALSE; return; } -/* Telnet console package. +/* Debug printout routines, from Dave Hittner */ - 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. -*/ +const char* debug_bstates = "01_^"; +const char* debug_fmt = "DBG> %s %s: "; +int32 debug_unterm = 0; -/* Set console to Telnet port */ +/* Finds debug phrase matching bitmask from from device DEBTAB table */ -t_stat set_telnet (int32 flg, char *cptr) +static char* get_dbg_verb (uint32 dbits, DEVICE* dptr) { -if (*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 */ -} +static char* debtab_none = "DEBTAB_ISNULL"; +static char* debtab_nomatch = "DEBTAB_NOMATCH"; +int32 offset = 0; -/* Close console Telnet port */ +if (dptr->debflags == 0) return debtab_none; -t_stat 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 */ -} +/* Find matching words for bitmask */ -/* Show console Telnet status */ - -t_stat show_telnet (FILE *st, 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 */ +while (dptr->debflags[offset].name && (offset < 32)) { + if (dptr->debflags[offset].mask & dbits) + return dptr->debflags[offset].name; + offset++; } -return SCPE_TTMO; /* timed out */ +return debtab_nomatch; } -/* Poll for character */ +/* Prints standard debug prefix unless previous call unterminated */ -t_stat sim_poll_kbd (void) +static void sim_debug_prefix (uint32 dbits, DEVICE* dptr) { -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; +if (!debug_unterm) { + char* debug_type = get_dbg_verb (dbits, dptr); + fprintf(sim_deb, debug_fmt, dptr->name, debug_type); + } } -/* Output character */ +/* 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) */ -t_stat sim_putchar (int32 c) +void sim_debug_u16(uint32 dbits, DEVICE* dptr, const char* const* bitdefs, + uint16 before, uint16 after, int terminate) { -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; +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 */ + } } -t_stat sim_putchar_s (int32 c) +#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, ...) { -t_stat r; +if (sim_deb && (dptr->dctrl & dbits)) { -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 */ + char stackbuf[STACKBUFSIZE]; + int32 bufsize = sizeof(stackbuf); + char *buf = stackbuf; + va_list arglist; + int32 i, j, len; + + 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 = 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) fwrite (&buf[j], 1, i-j, sim_deb); + j = i; + fputc('\r', sim_deb); + } + } + if (i > j) 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/scp.h b/scp.h new file mode 100644 index 00000000..2154e7cd --- /dev/null +++ b/scp.h @@ -0,0 +1,63 @@ +/* sim_timer.h: simulator timer library headers + + Copyright (c) 1993-2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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-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 + +t_stat sim_process_event (void); +t_stat sim_activate (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); +char *sim_dname (DEVICE *dptr); +t_stat get_yn (char *ques, t_stat deflt); +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); +DEVICE *find_dev_from_unit (UNIT *uptr); +REG *find_reg (char *ptr, char **optr, DEVICE *dptr); +BRKTAB *sim_brk_fnd (t_addr loc); +t_bool sim_brk_test (t_addr bloc, int32 btyp); +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, ...); + +#endif diff --git a/scp_tty.c b/sim_console.c similarity index 65% rename from scp_tty.c rename to sim_console.c index fe4b7e19..f0e6771a 100644 --- a/scp_tty.c +++ b/sim_console.c @@ -1,6 +1,6 @@ -/* scp_tty.c: operating system-dependent I/O routines +/* sim_console.c: simulator console I/O library - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 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 @@ -45,34 +47,153 @@ This module implements the following routines to support terminal I/O: - ttinit - called once to get initial terminal state - ttrunstate - called to put terminal into run state - ttcmdstate - called to return terminal to command state - ttclose - called once before the simulator exits + 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_telnet - set console to Telnet port + sim_set_notelnet - close console Telnet port + sim_show_telnet - show console status + + 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 terminal + sim_os_putchar - output character to console - This module implements the following routines to support clock calibration: - - sim_os_msec - return elapsed time in msec - sim_os_sleep - sleep specified number of seconds - - Versions are included for VMS, Windows, OS/2, Macintosh, BSD UNIX, and POSIX UNIX. - The POSIX UNIX version works with LINUX. + The first group is OS-independent; the second group is OS-dependent. */ #include "sim_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + int32 sim_int_char = 005; /* interrupt character */ +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 FILE *sim_log; +/* 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 to Telnet port */ + +t_stat sim_set_telnet (int32 flg, char *cptr) +{ +if (*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 */ +} + /* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */ #if defined (VMS) -#define _SIM_IO_TTY_ 0 + #if defined(__VAX) #define sys$assign SYS$ASSIGN #define sys$qiow SYS$QIOW -#define sys$gettim SYS$GETTIM #endif #include @@ -82,22 +203,26 @@ extern FILE *sim_log; #include #include #include + #define EFN 0 unsigned int32 tty_chan = 0; + typedef struct { unsigned short sense_count; unsigned char sense_first_char; unsigned char sense_reserved; unsigned int32 stat; unsigned int32 stat2; } SENSE_BUF; + typedef struct { unsigned int16 status; unsigned int16 count; unsigned int32 dev_status; } IOSB; + SENSE_BUF cmd_mode = { 0 }; SENSE_BUF run_mode = { 0 }; -t_stat ttinit (void) +t_stat sim_ttinit (void) { unsigned int32 status; IOSB iosb; @@ -114,7 +239,7 @@ run_mode.stat2 = cmd_mode.stat2 | TT2$M_PASTHRU; return SCPE_OK; } -t_stat ttrunstate (void) +t_stat sim_ttrun (void) { unsigned int status; IOSB iosb; @@ -125,7 +250,7 @@ if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR; return SCPE_OK; } -t_stat ttcmdstate (void) +t_stat sim_ttcmd (void) { unsigned int status; IOSB iosb; @@ -136,9 +261,9 @@ if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR; return SCPE_OK; } -t_stat ttclose (void) +t_stat sim_ttclose (void) { -return ttcmdstate (); +return sim_ttcmd (); } t_stat sim_os_poll_kbd (void) @@ -171,49 +296,14 @@ 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 (sim_log) fputc (c, sim_log); if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTOERR; return SCPE_OK; } - -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; -} - -#endif /* Win32 routines */ -#if defined (_WIN32) -#define _SIM_IO_TTY_ 0 +#elif defined (_WIN32) + #include #include #include @@ -226,25 +316,25 @@ sim_win_ctlc = 1; return; } -t_stat ttinit (void) +t_stat sim_ttinit (void) { return SCPE_OK; } -t_stat ttrunstate (void) +t_stat sim_ttrun (void) { if (signal (SIGINT, win_handler) == SIG_ERR) return SCPE_SIGERR; SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); return SCPE_OK; } -t_stat ttcmdstate (void) +t_stat sim_ttcmd (void) { SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); return SCPE_OK; } -t_stat ttclose (void) +t_stat sim_ttclose (void) { return SCPE_OK; } @@ -257,7 +347,7 @@ if (sim_win_ctlc) { sim_win_ctlc = 0; signal (SIGINT, win_handler); return 003 | SCPE_KFLAG; } -if (!kbhit ()) return SCPE_OK; +if (!_kbhit ()) return SCPE_OK; c = _getch (); if ((c & 0177) == '\b') c = 0177; if ((c & 0177) == sim_int_char) return SCPE_STOP; @@ -266,49 +356,32 @@ return c | SCPE_KFLAG; t_stat sim_os_putchar (int32 c) { -if (c != 0177) { - _putch (c); - if (sim_log) fputc (c, sim_log); } +if (c != 0177) _putch (c); return SCPE_OK; } - -const t_bool rtc_avail = TRUE; - -uint32 sim_os_msec () -{ -return GetTickCount (); -} - -void sim_os_sleep (unsigned int sec) -{ -Sleep (sec * 1000); -return; -} - -#endif /* OS/2 routines, from Bruce Ray */ -#if defined (__OS2__) -#define _SIM_IO_TTY_ 0 +#elif defined (__OS2__) + #include -t_stat ttinit (void) +t_stat sim_ttinit (void) { return SCPE_OK; } -t_stat ttrunstate (void) +t_stat sim_ttrun (void) { return SCPE_OK; } -t_stat ttcmdstate (void) +t_stat sim_ttcmd (void) { return SCPE_OK; } -t_stat ttclose (void) +t_stat sim_ttclose (void) { return SCPE_OK; } @@ -328,28 +401,15 @@ t_stat sim_os_putchar (int32 c) { if (c != 0177) { putch (c); - fflush (stdout) ; - if (sim_log) fputc (c, sim_log); } + fflush (stdout); } return SCPE_OK; } - -const t_bool rtc_avail = FALSE; - -uint32 sim_os_msec () -{ -return 0; -} - -#endif -/* Metrowerks CodeWarrior Macintosh routines, from Louis Chretien, - Peter Schorn, and Ben Supnik -*/ +/* Metrowerks CodeWarrior Macintosh routines, from Louis Chretien and + Peter Schorn */ -#if defined (__MWERKS__) && defined (macintosh) -#define _SIM_IO_TTY_ 0 +#elif defined (__MWERKS__) && defined (macintosh) -#include #include #include #include @@ -367,13 +427,6 @@ void SIOUXUpdateMenuItems(void); void SIOUXUpdateScrollbar(void); int ps_kbhit(void); int ps_getch(void); -t_stat ttinit (void); -t_stat ttrunstate (void); -t_stat ttcmdstate (void); -t_stat ttclose (void); -uint32 sim_os_msec (void); -t_stat sim_os_poll_kbd (void); -t_stat sim_os_putchar (int32 c); extern char sim_name[]; extern pSIOUXWin SIOUXTextWindow; @@ -464,8 +517,8 @@ int ps_getch(void) { return c; } -t_stat ttinit (void) { -/* Note that this only works if the call to ttinit comes before any output to the console */ +t_stat sim_ttinit (void) { +/* Note that this only works if the call to sim_ttinit comes before any output to the console */ int i; char title[50] = " "; /* this blank will later be replaced by the number of characters */ unsigned char ptitle[50]; @@ -487,17 +540,17 @@ t_stat ttinit (void) { return SCPE_OK; } -t_stat ttrunstate (void) +t_stat sim_ttrun (void) { return SCPE_OK; } -t_stat ttcmdstate (void) +t_stat sim_ttcmd (void) { return SCPE_OK; } -t_stat ttclose (void) +t_stat sim_ttclose (void) { return SCPE_OK; } @@ -517,40 +570,16 @@ t_stat sim_os_putchar (int32 c) { if (c != 0177) { putchar (c); - fflush (stdout) ; - if (sim_log) fputc (c, sim_log); } + fflush (stdout); } return SCPE_OK; } - -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; -} - -#endif /* BSD UNIX routines */ -#if defined (BSDTTY) -#define _SIM_IO_TTY_ 0 +#elif defined (BSDTTY) + #include #include -#include #include struct sgttyb cmdtty,runtty; /* V6/V7 stty data */ @@ -558,7 +587,7 @@ struct tchars cmdtchars,runtchars; /* V7 editing */ struct ltchars cmdltchars,runltchars; /* 4.2 BSD editing */ int cmdfl,runfl; /* TTY flags */ -t_stat ttinit (void) +t_stat sim_ttinit (void) { cmdfl = fcntl (0, F_GETFL, 0); /* get old flags and status */ runfl = cmdfl | FNDELAY; @@ -582,7 +611,7 @@ runltchars.t_lnextc = 0xFF; return SCPE_OK; /* return success */ } -t_stat ttrunstate (void) +t_stat sim_ttrun (void) { runtchars.t_intrc = sim_int_char; /* in case changed */ fcntl (0, F_SETFL, runfl); /* non-block mode */ @@ -593,7 +622,7 @@ nice (10); /* lower priority */ return SCPE_OK; } -t_stat ttcmdstate (void) +t_stat sim_ttcmd (void) { nice (-10); /* restore priority */ fcntl (0, F_SETFL, cmdfl); /* block mode */ @@ -603,9 +632,9 @@ if (ioctl (0, TIOCSLTC, &cmdltchars) < 0) return SCPE_TTIERR; return SCPE_OK; } -t_stat ttclose (void) +t_stat sim_ttclose (void) { -return ttcmdstate (); +return sim_ttcmd (); } t_stat sim_os_poll_kbd (void) @@ -624,42 +653,20 @@ char c; c = out; write (1, &c, 1); -if (sim_log) fputc (c, sim_log); return SCPE_OK; } - -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 /* POSIX UNIX routines, from Leendert Van Doorn */ -#if !defined (_SIM_IO_TTY_) +#else + #include -#include #include struct termios cmdtty, runtty; static int prior_norm = 1; -t_stat ttinit (void) +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 */ @@ -699,7 +706,7 @@ runtty.c_cc[VSTATUS] = 0; return SCPE_OK; } -t_stat ttrunstate (void) +t_stat sim_ttrun (void) { if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */ runtty.c_cc[VINTR] = sim_int_char; /* in case changed */ @@ -711,7 +718,7 @@ if (prior_norm) { /* at normal pri? */ return SCPE_OK; } -t_stat ttcmdstate (void) +t_stat sim_ttcmd (void) { if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */ if (!prior_norm) { /* priority down? */ @@ -722,9 +729,9 @@ if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) return SCPE_TTIERR; return SCPE_OK; } -t_stat ttclose (void) +t_stat sim_ttclose (void) { -return ttcmdstate (); +return sim_ttcmd (); } t_stat sim_os_poll_kbd (void) @@ -743,142 +750,7 @@ char c; c = out; write (1, &c, 1); -if (sim_log) fputc (c, sim_log); return SCPE_OK; } -const t_bool rtc_avail = TRUE; - -uint32 sim_os_msec () -{ -struct timeval cur; -uint32 msec; - -gettimeofday (&cur, NULL); -msec = (((uint32) cur.tv_sec) * 1000) + (((uint32) cur.tv_usec) / 1000); -return msec; -} - -void sim_os_sleep (unsigned int sec) -{ -sleep (sec); -return; -} - -#endif - -/* Long seek routines */ - -#if defined (USE_INT64) && defined (USE_ADDR64) - -/* Alpha VMS */ - -#if defined (__ALPHA) && defined (VMS) /* Alpha VMS */ -#define _SIM_IO_FSEEK_EXT_ 0 - -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; } -} - -int fseek_ext (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_ 0 - -int fseek_ext (FILE *st, t_addr offset, int whence) -{ -return fseek (st, offset, whence); -} - -#endif - -/* Windows */ - -#if defined (_WIN32) -#define _SIM_IO_FSEEK_EXT_ 0 - -int fseek_ext (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 */ - -#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 fseek_ext (FILE *st, t_addr xpos, int origin) -{ -return fseek (st, (int32) xpos, origin); -} - -uint32 sim_taddr_64 = 0; -#else -uint32 sim_taddr_64 = 1; #endif diff --git a/sim_console.h b/sim_console.h new file mode 100644 index 00000000..c81905ce --- /dev/null +++ b/sim_console.h @@ -0,0 +1,46 @@ +/* sim_console.h: simulator console I/O library headers + + Copyright (c) 1993-2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 Removed timer routines, added Telnet console routines +*/ + +#ifndef _SIM_CONSOLE_H_ +#define _SIM_CONSOLE_H_ 0 + +t_stat sim_set_telnet (int32 flg, char *cptr); +t_stat sim_set_notelnet (int32 flag, char *cptr); +t_stat sim_show_telnet (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); + +#endif diff --git a/sim_defs.h b/sim_defs.h index 760418e6..5068f7d2 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 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 @@ -88,6 +90,7 @@ #include #include #include +#include #include #include #include @@ -247,6 +250,8 @@ struct sim_device { 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 */ @@ -258,14 +263,22 @@ struct sim_device { #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_UF 12 /* user flags */ +#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 */ @@ -299,7 +312,8 @@ struct sim_unit { /* Unit flags */ -#define UNIT_V_UF 12 /* device specific */ +#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 */ @@ -314,7 +328,9 @@ struct sim_unit { #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 */ @@ -337,7 +353,8 @@ struct sim_reg { #define REG_NZ 0020 /* must be non-zero */ #define REG_UNIT 0040 /* in unit struct */ #define REG_CIRC 0100 /* circular array */ -#define REG_VMIO 0200 /* use VM print/parse */ +#define REG_VMIO 0200 /* use VM data print/parse */ +#define REG_VMAD 0400 /* use VM addr print/parse */ #define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */ /* Command tables, base and alternate formats */ @@ -353,14 +370,15 @@ struct sim_ctab { struct sim_c1tab { char *name; /* name */ t_stat (*action)(struct sim_device *dptr, struct sim_unit *uptr, - int32 flag); /* action routine */ + int32 flag, char *cptr); /* action routine */ int32 arg; /* argument */ char *help; /* help string */ }; struct sim_shtab { char *name; /* name */ - t_stat (*action)(FILE *st, int32 flag, char *cptr); + t_stat (*action)(FILE *st, struct sim_device *dptr, + struct sim_unit *uptr, int32 flag, char *cptr); int32 arg; /* argument */ char *help; /* help string */ }; @@ -405,6 +423,17 @@ struct sim_brktab { 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 */ @@ -441,45 +470,13 @@ 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 */ -t_stat sim_process_event (void); -t_stat sim_activate (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); -size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr); -size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr); -int fseek_ext (FILE *st, t_addr xpos, int origin); -uint32 sim_fsize (char *cptr); -char *sim_dname (DEVICE *dptr); -t_stat get_yn (char *ques, t_stat deflt); -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 (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); -DEVICE *find_dev_from_unit (UNIT *uptr); -REG *find_reg (char *ptr, char **optr, DEVICE *dptr); -int32 sim_rtc_init (int32 time); -int32 sim_rtc_calb (int32 ticksper); -int32 sim_rtcn_init (int32 time, int32 tmr); -int32 sim_rtcn_calb (int32 time, int32 tmr); -t_stat sim_poll_kbd (void); -t_stat sim_putchar (int32 out); -t_stat sim_putchar_s (int32 out); -BRKTAB *sim_brk_fnd (t_addr loc); -t_bool sim_brk_test (t_addr bloc, int32 btyp); -void sim_os_sleep (unsigned int sec); -char *match_ext (char *fnam, char *ext); +#include "scp.h" +#include "sim_console.h" +#include "sim_timer.h" +#include "sim_fio.h" #endif diff --git a/sim_ether.c b/sim_ether.c index 78191bd0..438148a7 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1,6 +1,6 @@ /* sim_ether.c: OS-dependent network routines ------------------------------------------------------------------------------ - Copyright (c) 2002-2003, David T. Hittner + Copyright (c) 2002-2004, 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"), @@ -50,8 +50,104 @@ ------------------------------------------------------------------------------ + 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: + 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 @@ -130,25 +226,56 @@ extern FILE *sim_log; -/* 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 - -/* make common winpcap code a bit easier to read in this file */ -#if defined(_WIN32) || defined(VMS) -#define WIN_PCAP 1 -#define HAS_PCAP_SENDPACKET 1 -#define PCAP_READ_TIMEOUT -1 -#else -#define PCAP_READ_TIMEOUT 1 -#endif /*============================================================================*/ /* 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; imsg[12]; - uint32 crc = eth_crc32(0, packet->msg, packet->len); - eth_mac_fmt((ETH_MAC*)&packet->msg[0], dst); - eth_mac_fmt((ETH_MAC*)&packet->msg[6], src); - printf("Eth: %s dst: %s src: %s proto: 0x%04X len: %d crc: %X\r\n", - msg, dst, src, ntohs(*proto), packet->len, crc); - if (dmp) { - int i, same, group, sidx, oidx; - char outbuf[80], strbuf[18]; - static char hex[] = "0123456789ABCDEF"; - for (i=same=0; ilen; i += 16) { - if ((i > 0) && (0 == memcmp(&packet->msg[i], &packet->msg[i-16], 16))) { - ++same; - continue; + 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) { - printf("%04X thru %04X same as above\r\n", i-(16*same), i-1); - same = 0; - } - group = (((packet->len - i) > 16) ? 16 : (packet->len - i)); - for (sidx=oidx=0; sidxmsg[i+sidx]>>4)&0xf]; - outbuf[oidx++] = hex[packet->msg[i+sidx]&0xf]; - if (isprint(packet->msg[i+sidx])) - strbuf[sidx] = packet->msg[i+sidx]; - else - strbuf[sidx] = '.'; - } - outbuf[oidx] = '\0'; - strbuf[sidx] = '\0'; - printf("%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); } - if (same > 0) - printf("%04X thru %04X same as above\r\n", i-(16*same), packet->len-1); } } -void eth_packet_trace(ETH_PACK* packet, char* msg) +void eth_packet_trace(ETH_DEV* dev, const uint8 *msg, int len, char* txt) { - eth_packet_trace_ex(packet, msg, packet->len > 1514); + eth_packet_trace_ex(dev, msg, len, txt, len > ETH_MAX_PACKET); } char* eth_getname(int number, char* name) { -#define ETH_SUPPORTED_DEVICES 10 - ETH_LIST list[ETH_SUPPORTED_DEVICES]; - int count = eth_devices(ETH_SUPPORTED_DEVICES, list); + ETH_LIST list[ETH_MAX_DEVICE]; + int count = eth_devices(ETH_MAX_DEVICE, list); if (count < number) return 0; strcpy(name, list[number].name); @@ -278,12 +406,106 @@ void eth_zero(ETH_DEV* dev) dev->reflections = -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 = 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; + memcpy(item->packet.msg, pack->msg, pack->len); + item->packet.status = status; +} + /*============================================================================*/ /* Non-implemented versions */ /*============================================================================*/ #if !defined (USE_NETWORK) -t_stat eth_open (ETH_DEV* dev, char* name) +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;} @@ -295,7 +517,7 @@ 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 0;} + {return -1;} #else /* endif unimplemented */ /*============================================================================*/ @@ -303,17 +525,29 @@ int eth_devices (int max, ETH_LIST* dev) /* OpenVMS Alpha uses a WinPcap port and an associated execlet */ /*============================================================================*/ +#if defined (xBSD) && !defined(__APPLE__) +#include +#include +#endif /* xBSD */ + #include #include -#ifdef xBSD -#include -#endif /* xBSD */ + +/* 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, u_char* msg, int len) +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; @@ -323,7 +557,48 @@ int pcap_sendpacket(pcap_t* handle, u_char* msg, int len) } #endif /* !HAS_PCAP_SENDPACKET */ -t_stat eth_open(ETH_DEV* dev, char* name) +#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]; @@ -364,7 +639,11 @@ t_stat eth_open(ETH_DEV* dev, char* name) dev->name = malloc(strlen(savname)+1); strcpy(dev->name, savname); -#if defined (xBSD) + /* 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. */ { @@ -373,7 +652,19 @@ t_stat eth_open(ETH_DEV* dev, char* name) } #endif /* xBSD */ -#if !defined (WIN_PCAP) +#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"; @@ -381,21 +672,29 @@ t_stat eth_open(ETH_DEV* dev, char* name) 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_close(dev->handle); + 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); @@ -408,6 +707,7 @@ 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)); @@ -418,11 +718,27 @@ t_stat eth_reflect(ETH_DEV* dev, ETH_MAC mac) 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 */ - dev->reflections = 0; do { memset (&recv, 0, sizeof(ETH_PACK)); status = eth_read (dev, &recv, NULL); @@ -430,13 +746,7 @@ t_stat eth_reflect(ETH_DEV* dev, ETH_MAC mac) dev->reflections++; } while (recv.len > 0); -#ifdef ETH_DEBUG - { - char* msg = "Eth: reflections = %d\r\n"; - printf (msg, dev->reflections); - if (sim_log) fprintf (sim_log, msg, dev->reflections); - } -#endif + sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections); return dev->reflections; } @@ -452,10 +762,9 @@ t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) /* 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) */ -#ifdef ETH_DEBUG - eth_packet_trace (packet, "writing"); -#endif status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len); /* detect sending of decnet loopback packet */ @@ -468,13 +777,33 @@ t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) if (routine) (routine)(status); - return SCPE_OK; + 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)) { @@ -482,22 +811,41 @@ void eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* 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); + + 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); -#ifdef ETH_DEBUG - eth_packet_trace (dev->read_packet, "reading"); -#endif + 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 } } @@ -511,6 +859,7 @@ t_stat eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) /* make sure packet exists */ if (!packet) return SCPE_ARG; +#if !defined (USE_READER_THREAD) /* set read packet */ dev->read_packet = packet; packet->len = 0; @@ -522,6 +871,22 @@ t_stat eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) 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; } @@ -532,11 +897,13 @@ t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses, bpf_u_int32 bpf_subnet, bpf_netmask; char buf[110+66*ETH_FILTER_MAX]; char errbuf[PCAP_ERRBUF_SIZE]; - struct bpf_program bpf; char mac[20]; char* buf2; - char* msg; t_stat status; +#ifdef USE_BPF + struct bpf_program bpf; + char* msg; +#endif /* make sure device exists */ if (!dev) return SCPE_UNATT; @@ -547,27 +914,28 @@ t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses, else if (!addresses) return SCPE_ARG; - /* clear filter array */ - memset(dev->filter_address, 0, sizeof(dev->filter_address)); - /* 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; -#ifdef ETH_DEBUG - printf("Eth: Filter Set\r\n"); - for (i = 0; i < addr_count; i++) { - char mac[20]; - eth_mac_fmt(&dev->filter_address[i], mac); - printf(" Addr[%d]: %s\r\n", i, mac); + /* 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"); } - printf("%s%s\r\n", dev->all_multicast ? " All Multicast\r\n" : "", - dev->promiscuous ? " Promiscuous\r\n" : ""); -#endif /* test reflections */ if (dev->reflections == -1) @@ -633,18 +1001,15 @@ t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses, } } } - -#ifdef ETH_DEBUG - msg = "Eth: BPF string is: |%s|\r\n"; - printf (msg, buf); - if (sim_log) fprintf (sim_log, msg, buf); -#endif + 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)); @@ -663,13 +1028,14 @@ t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses, printf(msg, errbuf); if (sim_log) fprintf (sim_log, msg, errbuf); } else { -#if !defined (WIN_PCAP) +#ifdef USE_SETNONBLOCK /* set file non-blocking */ status = pcap_setnonblock (dev->handle, 1, errbuf); -#endif +#endif /* USE_SETNONBLOCK */ } pcap_freecode(&bpf); } +#endif /* USE_BPF */ return SCPE_OK; } @@ -688,11 +1054,6 @@ t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses, alternate methods to implement pcap_findalldevs(). However, this can get tricky, and would then result in a sort of deviant libpcap. - Additionally, we're really only interested in Ethernet LAN type - interfaces here. It would be nice if the flags provided by pcap_if_t - actually told us if an interface was a Point to Point or a LAN interface - and if it was an ethernet. This isn't implemented anywhere. - 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. @@ -700,6 +1061,20 @@ t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses, */ 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 +#endif + /* structure declarations */ #define ETH_PROMISC 1 /* promiscuous mode = true */ @@ -58,6 +107,7 @@ #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 DECNET_SELF_FRAME(dnet_mac, msg) \ ((memcmp(dnet_mac, msg , 6) == 0) && \ @@ -67,11 +117,12 @@ struct eth_packet { uint8 msg[1518]; int len; int used; + int status; }; -struct eth_message { - int type; - struct eth_packet pack; +struct eth_item { + int type; /* receive (0=setup, 1=loopback, 2=normal) */ + struct eth_packet packet; }; struct eth_queue { @@ -80,7 +131,8 @@ struct eth_queue { int head; int tail; int loss; - struct eth_message* arr; + int high; + struct eth_item* item; }; struct eth_list { @@ -94,6 +146,8 @@ 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 */ @@ -103,18 +157,27 @@ struct eth_device { 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 */ +#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 */ +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 */ @@ -126,7 +189,18 @@ t_stat eth_filter (ETH_DEV* dev, int addr_count, /* set filter on incoming pack ETH_BOOL promiscuous); int eth_devices (int max, ETH_LIST* dev); /* get ethernet devices on host */ +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 */ -void eth_packet_trace (ETH_PACK* packet, char* msg); /* trace ethernet packet */ +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/sim_fio.c b/sim_fio.c new file mode 100644 index 00000000..58f422a5 --- /dev/null +++ b/sim_fio.c @@ -0,0 +1,267 @@ +/* sim_fio.c: simulator file I/O library + + Copyright (c) 1993-2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 + + 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 + using 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, nelem, nbuf, lcnt, total; +int32 i, k; +unsigned char *sptr, *dptr; + +if (sim_end || (size == sizeof (char))) + return fread (bptr, size, count, fptr); +if ((size == 0) || (count == 0)) return 0; +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; +dptr = bptr; /* init output ptr */ +for (i = nbuf; i > 0; i--) { + c = fread (sim_flip, size, (i == 1? lcnt: nelem), fptr); + if (c == 0) return total; + total = total + c; + for (j = 0, sptr = sim_flip; j < c; j++) { + for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; + dptr = dptr + size; } } +return total; +} + +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 (sim_end || (size == sizeof (char))) + return fwrite (bptr, size, count, fptr); +if ((size == 0) || (count == 0)) return 0; +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 = bptr; /* init input ptr */ +for (i = nbuf; i > 0; i--) { + c = (i == 1)? lcnt: nelem; + for (j = 0, dptr = sim_flip; j < c; j++) { + 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 (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 (char *file, 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"); +#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; } +} + +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 */ + +#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/sim_fio.h b/sim_fio.h new file mode 100644 index 00000000..e9af1ca4 --- /dev/null +++ b/sim_fio.h @@ -0,0 +1,43 @@ +/* sim_fio.h: simulator file I/O library headers + + Copyright (c) 1993-2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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_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 (char *file, 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); + +#endif diff --git a/sim_rev.h b/sim_rev.h index 88276ca0..44aa4459 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -28,13 +28,100 @@ #define _SIM_REV_H_ 0 #define SIM_MAJOR 3 -#define SIM_MINOR 1 +#define SIM_MINOR 2 #define SIM_PATCH 0 -/* V3.1 revision history +/* V3.2 revision history patch date module(s) and fix(es) + 0 tbd 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 diff --git a/sim_sock.c b/sim_sock.c index 24691611..692b8e46 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -1,6 +1,6 @@ /* sim_sock.c: OS-dependent socket routines - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 09-Jan-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 @@ -182,7 +183,8 @@ SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr) int32 sta, err; #if defined (macintosh) socklen_t size; -#elif defined (_WIN32) || defined (__EMX__) || defined (__APPLE__) +#elif defined (_WIN32) || defined (__EMX__) || defined (__APPLE__) ||\ + (defined (__ALPHA) && defined (__unix__)) int size; #else size_t size; diff --git a/sim_sock.h b/sim_sock.h index 78dcc7a5..440b0c14 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -1,6 +1,6 @@ /* sim_sock.h: OS-dependent socket routines header file - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/sim_tape.c b/sim_tape.c index ecd38a58..83479b29 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -1,6 +1,6 @@ /* sim_tape.c: simulator tape support library - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ Ultimately, this will be a place to hide processing of various tape formats, as well as OS-specific direct hardware access. + 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 @@ -146,7 +147,7 @@ return SCPE_OK; read error unchanged, PNU set end of file/medium unchanged, PNU set tape mark updated - data record updated, fxread will read record forward + data record updated, sim_fread will read record forward */ t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc) @@ -157,11 +158,11 @@ t_tpclnt tpcbc; MT_CLR_PNU (uptr); if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */ -fseek_ext (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ +sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ switch (f) { /* switch on fmt */ case MTUF_F_STD: case MTUF_F_E11: - fxread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ + 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 */ @@ -176,7 +177,7 @@ case MTUF_F_STD: case MTUF_F_E11: break; case MTUF_F_TPC: - fxread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref); + 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 */ @@ -211,7 +212,7 @@ return MTSE_OK; end of file unchanged end of medium updated tape mark updated - data record updated, fxread will read record forward + data record updated, sim_fread will read record forward */ t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc) @@ -227,8 +228,8 @@ if (sim_tape_bot (uptr)) return MTSE_BOT; /* at BOT? */ switch (f) { /* switch on fmt */ case MTUF_F_STD: case MTUF_F_E11: - fseek_ext (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); - fxread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ + 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); @@ -238,20 +239,20 @@ case MTUF_F_STD: case MTUF_F_E11: 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); - fseek_ext (uptr->fileref, uptr->pos + sizeof (t_mtrlnt), SEEK_SET); + sim_fseek (uptr->fileref, uptr->pos + sizeof (t_mtrlnt), SEEK_SET); break; case MTUF_F_TPC: ppos = sim_tape_tpc_fnd (uptr, uptr->filebuf); /* find prev rec */ - fseek_ext (uptr->fileref, ppos, SEEK_SET); /* position */ - fxread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref); + 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? */ - fseek_ext (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET); + sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET); break; default: return MTSE_FMT; } @@ -292,7 +293,7 @@ if (rbc > max) { /* rec out of range? */ MT_SET_PNU (uptr); uptr->pos = opos; return MTSE_INVRL; } -i = fxread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ +i = sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ if (ferror (uptr->fileref)) { /* error? */ MT_SET_PNU (uptr); uptr->pos = opos; @@ -331,7 +332,7 @@ 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 = fxread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */ +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 */ @@ -361,14 +362,14 @@ 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? */ if (f == MTUF_F_STD) sbc = (bc + 1) & ~1; else sbc = bc; -if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */ -if (uptr->flags & MTUF_WRP) return MTSE_WRP; /* write prot? */ -fseek_ext (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ -fxwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref); -fxwrite (buf, sizeof (uint8), sbc, uptr->fileref); -fxwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref); +sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ +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); } @@ -382,9 +383,9 @@ 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 (uptr-> flags & MTUF_WRP) return MTSE_WRP; /* write prot? */ -fseek_ext (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ -fxwrite (&dat, sizeof (t_mtrlnt), 1, uptr->fileref); +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); } @@ -518,8 +519,8 @@ uint32 i, objc; if ((uptr == NULL) || (uptr->fileref == NULL)) return 0; for (objc = 0, tpos = 0;; ) { - fseek_ext (uptr->fileref, tpos, SEEK_SET); - i = fxread (&bc, sizeof (t_tpclnt), 1, uptr->fileref); + 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++; diff --git a/sim_tape.h b/sim_tape.h index 74d3f363..536552a0 100644 --- a/sim_tape.h +++ b/sim_tape.h @@ -1,6 +1,6 @@ /* sim_tape.h: simulator tape support library definitions - Copyright (c) 1993-2003, Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/sim_timer.c b/sim_timer.c new file mode 100644 index 00000000..c971afe5 --- /dev/null +++ b/sim_timer.c @@ -0,0 +1,247 @@ +/* sim_timer.c: simulator timer library + + Copyright (c) 1993-2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 + + 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 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 */ +const t_bool rtc_avail; + +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); +} + +/* 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 diff --git a/sim_timer.h b/sim_timer.h new file mode 100644 index 00000000..6c3a390e --- /dev/null +++ b/sim_timer.h @@ -0,0 +1,42 @@ +/* sim_timer.h: simulator timer library headers + + Copyright (c) 1993-2004, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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/sim_tmxr.c b/sim_tmxr.c index 16daf280..bacfd191 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -1,6 +1,6 @@ /* sim_tmxr.c: Telnet terminal multiplexor library - Copyright (c) 2001-2003, Robert M Supnik + Copyright (c) 2001-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,10 @@ 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, 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 @@ -37,6 +41,30 @@ 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" @@ -67,6 +95,9 @@ #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; @@ -98,13 +129,13 @@ static char mantra[] = { 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 */ + 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 = mp->ldsc + i; /* get line desc */ lp->conn = newsock; /* record connection */ lp->ipad = ipaddr; /* ip address */ lp->cnms = sim_os_msec (); /* time of conn */ @@ -115,9 +146,10 @@ if (newsock != INVALID_SOCKET) { /* got a live one? */ lp->xmte = 1; /* enable transmit */ lp->dstb = 0; /* default bin mode */ sim_write_sock (newsock, mantra, 15); - tmxr_msg (newsock, "\n\r\nConnected to the "); - tmxr_msg (newsock, sim_name); - tmxr_msg (newsock, " simulator\r\n\n"); + 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; @@ -127,6 +159,8 @@ return -1; 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; @@ -175,7 +209,7 @@ int32 i, nbytes, j; TMLN *lp; for (i = 0; i < mp->lines; i++) { /* loop thru lines */ - lp = mp->ldsc[i]; /* get line desc */ + lp = mp->ldsc + i; /* get line desc */ if (!lp->conn || !lp->rcve) continue; /* skip if !conn */ nbytes = 0; @@ -238,7 +272,7 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ } /* end else nbytes */ } /* end for lines */ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ - lp = mp->ldsc[i]; /* get line desc */ + lp = mp->ldsc + i; /* get line desc */ if (lp->rxbpi == lp->rxbpr) /* if buf empty, */ lp->rxbpi = lp->rxbpr = 0; /* reset pointers */ } /* end for */ @@ -274,14 +308,17 @@ return; 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 (lp->txbpi < (TMXR_MAXBUF - 1)) { /* room for char (+ IAC)? */ +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 - TMXR_GUARD)) /* near full? */ + 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 */ @@ -298,33 +335,58 @@ return SCPE_STALL; /* char not sent */ void tmxr_poll_tx (TMXR *mp) { -int32 i, nbytes, sbytes; +int32 i, nbytes; TMLN *lp; for (i = 0; i < mp->lines; i++) { /* loop thru lines */ - lp = mp->ldsc[i]; /* get line desc */ + lp = mp->ldsc + i; /* get line desc */ if (lp->conn == 0) continue; /* skip if !conn */ - nbytes = lp->txbpi - lp->txbpr; /* avail bytes */ - if (nbytes) { /* >0? write */ - sbytes = sim_write_sock (lp->conn, - &(lp->txb[lp->txbpr]), nbytes); - if (sbytes != SOCKET_ERROR) { /* update ptrs */ - lp->txbpr = lp->txbpr + sbytes; - lp->txcnt = lp->txcnt + sbytes; - nbytes = nbytes - sbytes; } - } - if (nbytes == 0) { /* buf empty? */ - lp->xmte = 1; /* enable this line */ - lp->txbpr = lp->txbpi = 0; } + 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); +return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? TMXR_MAXBUF: 0)); } /* Open master socket */ @@ -346,7 +408,7 @@ if (sim_log) fprintf (sim_log, 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 = mp->ldsc + i; lp->conn = lp->tsta = 0; lp->rxbpi = lp->rxbpr = 0; lp->txbpi = lp->txbpr = 0; @@ -383,11 +445,11 @@ int32 i; TMLN *lp; for (i = 0; i < mp->lines; i++) { /* loop thru conn */ - lp = mp->ldsc[i]; + lp = mp->ldsc + i; if (lp->conn) { - tmxr_msg (lp->conn, "\r\nDisconnected from the "); - tmxr_msg (lp->conn, sim_name); - tmxr_msg (lp->conn, " simulator\r\n\n"); + 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 */ @@ -419,7 +481,7 @@ t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) return SCPE_NOFNC; } -/* Output message */ +/* Output message to socket or line descriptor */ void tmxr_msg (SOCKET sock, char *msg) { @@ -427,6 +489,15 @@ 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) @@ -447,6 +518,7 @@ if (lp->conn) { 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; } @@ -483,9 +555,74 @@ if (cptr) { ln = (int32) get_uint (cptr, 10, mp->lines - 1, &r); if (r != SCPE_OK) return SCPE_ARG; } else ln = 0; -lp = mp->ldsc[ln]; +lp = mp->ldsc + ln; if (lp->conn) { - tmxr_msg (lp->conn, "\r\nOperator disconnected line\r\n\n"); + 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 = 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 = uptr - dptr->units; } /* implicit line # */ +if ((val < 0) || (val >= mp->lines)) return NULL; /* invalid line? */ +return mp->ldsc + val; /* line descriptor */ +} diff --git a/sim_tmxr.h b/sim_tmxr.h index 6ea650a9..ac692afd 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -26,6 +26,8 @@ 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 @@ -41,7 +43,6 @@ #define TMXR_VALID (1 << TMXR_V_VALID) #define TMXR_MAXBUF 256 /* buffer size */ #define TMXR_GUARD 12 /* buffer guard */ -#define TMXR_MAXLIN 64 /* max lines */ struct tmln { SOCKET conn; /* line conn */ @@ -57,6 +58,8 @@ struct tmln { 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 */ @@ -68,7 +71,7 @@ struct tmxr { int32 lines; /* # lines */ int32 port; /* listening port */ SOCKET master; /* master socket */ - TMLN *ldsc[TMXR_MAXLIN]; /* line descriptors */ + TMLN *ldsc; /* line descriptors */ }; typedef struct tmxr TMXR; @@ -86,8 +89,12 @@ 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); diff --git a/simh_doc.txt b/simh_doc.txt index 1e05a202..9669ec87 100644 --- a/simh_doc.txt +++ b/simh_doc.txt @@ -1,14 +1,14 @@ To: Users From: Bob Supnik -Subj: Simulator Usage, V3.1 -Date: 15-Dec-2003 +Subj: Simulator Usage, V3.2 +Date: 4-Apr-2004 COPYRIGHT NOTICE The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -35,7 +35,7 @@ This memorandum documents SIMH simulators. These simulators are freeware; refer to the license terms above for conditions of use. Support is not available. The best way to fix problems or add features is to read and modify the sources yourself. Alternately, you can send Internet mail to -bsupnik@us.inter.net, but a response is not guaranteed. +bob AT supnik DOT org, but a response is not guaranteed. The simulators use a common command interface. This memorandum describes the features of the command interface. The details of each simulator are @@ -47,8 +47,8 @@ documented in separate, machine-specific memoranda. The simulators have been tested on VAX VMS, Alpha VMS, Alpha UNIX, NetBSD, FreeBSD, OpenBSD, Linux, Solaris, Windows 9x/Me/NT/2000, MacOS 9 and X, and OS/2. Porting to other environments will require changes -to the operating system dependent code in scp_tty.c, scp_sock.c, and -sim_ether.c. +to the operating system dependent code in the SIMH libraries (sim_fio.c, +sim_timer.c, sim_console.c, sim_ether.c, sim_sock.c). The simulator sources are provided in a zip archive and are organized hierarchically. Source files for the simulator libraries are in the @@ -78,10 +78,12 @@ The simulators recognize or require a few compile-time #defines: defined on the command line: VM_PDP10 for the PDP-10; VM_PDP11 for the PDP-11; or VM_VAX for the VAX. -- The PDP-11 and VAX simulators optionally support Ethernet. To - include Ethernet emulation, USE_NETWORK must be defined as part - of the compilation command line. At present, Ethernet support is - available only on Windows, Linux, NetBSD, OpenBSD, and Alpha VMS. +- The PDP-11, PDP-11, and VAX simulators optionally support Ethernet. + To include Ethernet emulation, USE_NETWORK must be defined as part + of the compilation command line. At present, Ethernet support has + been tested only on Windows, Linux, NetBSD, OpenBSD, FreeBSD, + Solaris, and Alpha VMS, but it should work in any host environment + that supports the Pcap library (see the Ethernet readme file). - The PDP-11 and VAX simulators optionally support disks and serial devices files greater than 2GB. To include large device support, @@ -102,7 +104,7 @@ If no file is specified on the command line, the simulator looks for an startup file consisting of the simulator name (including its path components) plus the extension .ini. If a startup file is specified, either on the command line or implicitly via the .ini capability, it -ishould contain a series of non-interactive simulator command, one +should contain a series of non-interactive simulator command, one per line. These command can be used to set up standard parameters, for example, disk sizes. @@ -144,15 +146,15 @@ Examples: - PDP-11 under TERMIOS UNIX: - % cc -DVM_PDP11 pdp11_*.c scp*.c sim_*.c -lm -o pdp11 + % cc -DVM_PDP11 pdp11_*.c scp.c sim_*.c -lm -o pdp11 - PDP-9 under TERMIOS UNIX: - % cc -DPDP9 pdp18b_*.c scp*.c sim_*.c -lm -o pdp9 + % cc -DPDP9 pdp18b_*.c scp.c sim_*.c -lm -o pdp9 - PDP-10 under BSD terminal UNIX: - % cc -DVM_PDP10 -DUSE_INT64 -DBSDTTY pdp10_*.c scp*.c sim_*.c -lm -o pdp10 + % cc -DVM_PDP10 -DUSE_INT64 -DBSDTTY pdp10_*.c scp.c sim_*.c -lm -o pdp10 1.2 Compiling Under Windows @@ -223,8 +225,8 @@ build all the simulators from source. An example of hand compilation: - PDP-8 under VMS: - $ cc scp*.c,sim_*.c,[.pdp8]pdp8*.c - $ link/exec=pdp8 scp*.obj,sim_*.obj,[.pdp8]pdp8*.obj + $ cc scp.c,sim_*.c,[.pdp8]pdp8*.c + $ link/exec=pdp8 scp.obj,sim_*.obj,[.pdp8]pdp8*.obj 1.4 Compiling Under MacOS @@ -291,7 +293,8 @@ The types of formats supported are implementation specific. Options The SAVE command (abbreviation SA) save the complete state of the simulator to a file. This includes the contents of main memory and -all registers, and the I/O connections of devices: +all registers, and the I/O connections of devices except network +devices (such as Ethernet controllers and terminal multiplexors): sim> save (cr) @@ -317,8 +320,8 @@ does not clear main memory or affect I/O connections. 3.4 Connecting and Disconnecting Devices -Except for main memory, simulated unit address spaces are simulated -as unstructured binary disk files in the host file system. Before +Except for main memory and network devices, units are simulated as +unstructured binary disk files in the host file system. Before using a simulated unit, the user must specify the file to be accessed by that unit. The ATTACH (abbreviation AT) command associates a unit and a file: @@ -366,8 +369,13 @@ master unit with a TCP/IP port: The port is a decimal number between 1 and 65535 and should not used by standard TCP/IP protocols. +For Ethernet emulators, the ATTACH command associates the simulated +Ethernet with a physical Ethernet device: + + sim> ATTACH (cr) + The DETACH (abbreviation DET) command breaks the association between -a unit and a file, or between a unit and a port: +a unit and a file, port, or network device: sim> DETACH ALL(cr) -- detach all units sim> DETACH (cr) -- detach specified unit @@ -492,7 +500,7 @@ is supplied, one instruction is executed. The BOOT command (abbreviated BO) bootstraps the device and unit given by its argument. If no unit is supplied, unit 0 is bootstrapped. The -specified unit must be attached to a file. +specified unit must be attached. 3.7 Stopping Programs @@ -530,7 +538,7 @@ for execution, R for read, W for write, etc). At the moment, most simulators support only E (execution) breakpoints. Associated with a breakpoint is a count and, optionally, one or more -actions. Each time the breakpoint is sprung, the associated count is +actions. Each time the breakpoint is taken, the associated count is decremented. If the count is less than or equal to 0, the breakpoint occurs; otherwise, it is deferred. When the breakpoint occurs, the optional actions are automatically executed. @@ -601,7 +609,9 @@ the last RUN command. The SHOW command shows the status of the named simulated device. SHOW shows the value of the named -parameter, if it can display a value. +parameter, if it can display a value. All devices implement parameters +RADIX (the display radix), MODIFIERS (list of valid modifiers), and +NAMES (logical name). The SHOW command shows the status of the named simulated unit. SHOW shows the value of the named parameter, if @@ -637,11 +647,15 @@ Logical names must be unique within a simulator (that is, they cannot be the same as an existing device name). To assign a logical name to a device: - sim> ASSIGN device log-name -- assign log-name to device + sim> ASSIGN -- assign log-name to device To remove a logical name: - sim> DEASSIGN device -- remove logical name + sim> DEASSIGN -- remove logical name + +To show the current logical name assignment: + + sim> SHOW NAMES -- show logical name, if any To show all logical names: @@ -694,7 +708,34 @@ commands: sim> HELP -- print all HELP messages sim> HELP -- print HELP for command -3.15 Exiting The Simulator +3.15 Controlling Debugging + +Some simulated devices may provide debug printouts to help in diagnosing +complicated problems. Debug output may be sent to a variety of places, +or disabled entirely: + + sim> SET DEBUG STDOUT -- direct debug output to stdout + sim> SET DEBUG STDERR -- direct debug output to stderr + sim> SET DEBUG LOG -- direct debug output to log file + sim> SET DEBUG -- direct debug output to file + sim> SET NODEBUG -- disable debug output + +If debug output is enabled, individual devices can be controlled with the +SET command. If a device has only a single debug flag: + + sim> SET DEBUG -- enable device debug output + sim> SET NODEBUG -- disable device debug output + +If the device has individual, named debug flags: + + sim> SET DEBUG=n1,n2,... -- enable device debug flags n1, n2, ... + sim> SET NODEBUG=n1,n2,... -- disable device debug flags n1, n2, ... + sim> SET NODEBUG -- disable all device debug flags + +If debug output is directed to stdout, it will be intermixed with normal +simulator output. + +3.16 Exiting The Simulator EXIT (synonyms QUIT and BYE) returns control to the operating system. @@ -720,7 +761,7 @@ written. 3. Magnetic Tapes Magnetic tapes are represented as unstructured binary files of 8b data -items. Each record consists of a 32b record header, in little endian +items. Each record starts with a 32b record header, in little endian format. If the record header is not a special header, it is followed by n 8b bytes of data, followed by a repeat of the 32b record header. A 1 in the high order bit of the record header indicates an error in @@ -730,8 +771,8 @@ length; the pad byte is undefined. Special record headers occur only once and have no data. The currently defined special headers are: - 0x00000000 file mark (not repeated) - 0xFFFFFFFF end of medium (not repeated) + 0x00000000 file mark + 0xFFFFFFFF end of medium Magnetic tapes are endian independent and consistent across simulator families. A magtape produced by the Nova simulator will appear to @@ -764,7 +805,7 @@ DECtapes use 1474 blocks of 129 16b words. Each 16b word contains 12b and OS/8 DECtape dumps contain only 128 words per block. A utility, DTOS8CVT.C, is provided to convert OS/8 DECtape dumps to simulator format. -A known problem in DECtape format is that when a block is recorded in +A known issue in DECtape format is that when a block is recorded in one direction and read in the other, the bits in a word are scrambled (to the complement obverse). The PDP-11 deals with this problem by performing an automatic complement obverse on reverse writes and reads. @@ -842,6 +883,24 @@ drum - - - - h DECtape - - - - - mag tape - - d y h + system LGP-30 1130 +device +CPU h y +FPU - - +CIS - - +console h y +paper tape h - +card reader - y +line printer - y +clock - - +extra terminal - - +hard disk - y +fixed disk - - +floppy disk - - +drum - - +DECtape - - +mag tape - - + legend: y = runs operating system or sample program d = runs diagnostics h = runs hand-generated test cases @@ -853,6 +912,17 @@ Revision History (covering Rev 2.0 to present) Starting with Rev 2.7, detailed revision histories can be found in file sim_rev.c. +Rev 3.2, Feb, 04 + Added LGP-30/LGP-21 simulator + Added global SHOW modifier capability + Added global SET DEBUG modifier + Added global SHOW DEBUG,RADIX,MODIFIERS,NAME modifiers + Added VAX extended physical memory support (Mark Pizzolato) + Added VAX RXV21 support + Revised terminal multiplexor library to support variable + number of lines per multiplexor + Added PDP-15 LT19 support (1-16 terminals) + Rev 3.1, Dec, 03 Added Alpha/VMS, FreeBSD, Mac OS/X Ethernet library support Added Eclipse floating point and interval timer support diff --git a/simh_faq.txt b/simh_faq.txt index 009bde9c..ce447e3d 100644 --- a/simh_faq.txt +++ b/simh_faq.txt @@ -1,4 +1,4 @@ -SIMH FAQ, 31-Dec-2003 +SIMH FAQ, 31-Mar-2004 1 General @@ -148,6 +148,7 @@ SIMH simulates the following computer systems: Interdata Corporation 16b systems, 7/32, 8/32 Scientific Data Systems SDS-940 MITS Altair 8080, Altair Z80 + Royal-Mcbee LGP-30, LGP-21 The documentation contains more details on supported models and peripherals. @@ -169,7 +170,7 @@ The documentation contains more details on supported models and peripherals. Linux gcc requires libpcap for Ethernet support Tru64 UNIX DEC C no Ethernet support AIX no Ethernet support - Solaris no Ethernet support + Solaris requires libpcap for Ethernet support HP/UX no Ethernet support NetBSD gcc requires libpcap for Ethernet support OpenBSD gcc requires libpcap for Ethernet support @@ -199,8 +200,8 @@ The simplest way is to download the pre-compiled binaries. Unzip these into the directory where you want to run SIMH. You can then run whichever binary that you want. -If you want to run the VAX emulator, you will also need the KA655.bin file from -the source kit. +If you want to run the VAX emulator, you will also need files ka655.bin and +ka655x.bin from the source kit. -------------------------------------------------------------------------------- @@ -363,7 +364,7 @@ use the various network copy programs (FTP, DECNET) to transfer files. 2.9 Can I connect real devices on the host computer to SIMH? -Not yet. +At the moment, Ethernet is the only supported real device. -------------------------------------------------------------------------------- @@ -429,9 +430,8 @@ completing the current instruction. SIMH is released whenever a significant number of new features, or important bug fixes, has accumulated. This has averaged every 4-8 -weeks. The major version number has not been changed since the -addition of symbolic debugging and won't be changed unless the -internals of SCP change dramatically. The minor version number +weeks. The major version number only changes when there is a major +restructuring of SIMH's internal structures. The minor version number is changed when the format of the save/restore file must be updated. ================================================================================ diff --git a/simh_swre.txt b/simh_swre.txt index 2606d76c..eba0731a 100644 --- a/simh_swre.txt +++ b/simh_swre.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: Sample Software Packages -Date: 15-Sep-2003 +Date: 15-Jan-2004 This memorandum documents the sample software packages available to run with the SIMH simulators. Many of these packages are available under @@ -10,8 +10,8 @@ software. The following copyright notice applies to both the SIMH source and binary: - Original code published in 1993-2003, written by Robert M Supnik - Copyright (c) 1993-2003, Robert M Supnik + Original code published in 1993-2004, written by Robert M Supnik + Copyright (c) 1993-2004, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),