From e6c94e9466e75aa5de2e0278d56c9aa13cd74170 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 29 Feb 2012 07:08:02 -0800 Subject: [PATCH 001/112] Add some polish to build messages --- makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/makefile b/makefile index 3abeb767..a211e432 100644 --- a/makefile +++ b/makefile @@ -117,10 +117,16 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) # building the pdp11, or any vax simulator could use networking support ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) NETWORK_USEFUL = true + ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) + BUILD_MULTIPLE = (s) + else + BUILD_SINGLE := $(MAKECMDGOALS) $(BUILD_SINGLE) + endif else ifeq ($(MAKECMDGOALS),) # default target is all NETWORK_USEFUL = true + BUILD_MULTIPLE = (s) endif endif ifneq (,$(NETWORK_USEFUL)) @@ -134,12 +140,12 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) NETWORK_CCDEFS = -DUSE_SHARED $(info using libpcap: $(call find_include,pcap)) endif - $(info *** Simulator(s) being built with networking support using) + $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) $(info *** $(OSTYPE) provided libpcap components) else NETWORK_CCDEFS = -DUSE_SHARED $(info using libpcap: $(call find_include,pcap)) - $(info *** Simulator(s) being built with networking support using) + $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) $(info *** $(OSTYPE) provided libpcap components) endif else @@ -153,7 +159,7 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) NETWORK_CCDEFS := -DUSE_NETWORK -isystem $(dir $(call find_include,pcap)) $(call find_lib,pcap) $(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap)) $(info *** Warning ***) - $(info *** Warning *** Simulator(s) being built with networking support using) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) $(info *** Warning *** libpcap components from www.tcpdump.org.) $(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap) $(info *** Warning *** components for simh networking. For best results, with) @@ -189,7 +195,7 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif else $(info *** Warning ***) - $(info *** Warning *** Simulator(s) are being built WITHOUT networking support) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) are being built WITHOUT networking support) $(info *** Warning ***) $(info *** Warning *** To build simulator(s) with networking support you should install) $(info *** Warning *** the libpcap-dev package from your $(OSTYPE) distribution) From 8e76a8d0818bf72c665cfc000e79b4b4f6ce0a44 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 2 Mar 2012 13:27:20 -0800 Subject: [PATCH 002/112] Fixed cygwin build and execution issue, mostly from Tony Nicholson Fixed OS/X build issues from Tony Nickolson Fixed OS/X tap networking startup Added cygwin host NIC hardware address determination Made *nix host NIC hardware address determination more robust --- 0readme_ethernet.txt | 43 ++++++++---- makefile | 144 +++++++++++++++++++++++-------------- sim_ether.c | 164 ++++++++++++++++++++++++++++++------------- sim_ether.h | 16 ++++- 4 files changed, 249 insertions(+), 118 deletions(-) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 6916cfac..841079e2 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -129,17 +129,17 @@ OSX (Snow Leopard) based internal network so a host and guest can communicate directly. Download the install package from: - http://sourceforge.net/projects/tuntaposx/files/tuntap/20090913/tuntap_20090913.tar.gz + http://sourceforge.net/projects/tuntaposx/files/tuntap/20111101/tuntap_20111101.tar.gz Expand the tarball to a directory. - Invoke the package installer tuntap_20090913.pkg + Invoke the package installer tuntap_20111101.pkg Click through the various prompts accepting things and eventually installing the package. # Build and Run simulator and: sim> attach xq tap:tap0 sim> ! ifconfig tap0 192.168.6.1 netmask 255.255.255.0 - Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1 + Simulated system uses IP address 192.168.6.2 and host uses 192.168.6.1 and things work. You must run as root for this to work. @@ -180,7 +180,8 @@ Windows notes: and the user must be an Administrator on the machine to do so. If you need to run as an unprivileged user, you must set the "npf" driver to autostart. Current WinPcap installers provide an option to configure this at - installation time. + installation time, so if that choice is made, then there is no need for + administrator privileged to run simulators with network support. Building on Windows: @@ -189,10 +190,10 @@ Building on Windows: Express 2008 or 2010 interactive development environments, read the file ".\Visual Studio Projects\0ReadMe_Projects.txt" for details about the required dependencies. Alternatively, you can build simh with networking - support using the MinGW GCC compiler environment. Both the Visual C++ - and MinGW build environments require WinPcap and Posix packages being - available. These should be located in a directory structure parallel to - the current simulator source directory. + support using the MinGW GCC compiler environment or the cygwin environment. + Each of these Visual C++, MinGW and cygwin build environments require + WinPcap and Posix packages being available. These should be located in a + directory structure parallel to the current simulator source directory. For Example, the directory structure should look like: @@ -243,7 +244,9 @@ for details. packets through the driver. a) For Windows systems this means having administrator privileges to start the "npf" driver. The current WinPcap installer offers an - option to autostart the "npf" driver when the system boots. + option to autostart the "npf" driver when the system boots. + Starting the "npf" driver at boot time means that simulators do + not need to run with administrator privileges. b) For more recent Linux systems, The concepts leveraging "Filesystem Capabilities" can be used to specifically grant the simh binary the needed privileges to access the network. The article at: @@ -264,7 +267,7 @@ for details. (possibly at system boot time), using the TAP devices can be done without root privileges. -Building on Linux, {Free|Net|Open}BSD, OS/X, Un*x: +Building on Linux, {Free|Net|Open}BSD, OS/X, Solaris, other *nix: 1. Get/make/install the libpcap-dev package for your operating system. Sources: All : http://www.tcpdump.org/ @@ -290,10 +293,16 @@ Building on Linux, {Free|Net|Open}BSD, OS/X, Un*x: 2. If you install the vendor supplied libpcap-dev package then the simh makefile will automatically use the vendor supplied library without any additional arguments. If you have downloaded and built libpcap from - www.tcpdump.org, then you can force its use during a build by typing - 'make USE_NETWORK=1' + www.tcpdump.org, then the existing makefile will detect that this is + the case and try to use that. - 3. Build it! + 3. The makefile defaults to building simulators with network support which + dynamically load the libpcap library. This means that the same simulator + binaries will run on any system whether or not libpcap is installed. If + you want to force direct libpcap linking during a build you do so by + typing 'make USE_NETWORK=1' + + 4. Build it! ------------------------------------------------------------------------------- @@ -404,6 +413,14 @@ Dave Change Log =============================================================================== + 01-Mar-12 AGN Added support for building using Cygwin on Windows + 01-Mar-12 MP Made host NIC address detection more robust on *nix platforms + and mad it work when compiling under Cygwin + 29-Feb-12 MP Fixed MAC Address Conflict detection support + 28-Feb-12 MP Fixed overrun bug in eth_devices which caused SEGFAULTs + 28-Feb-12 MP Fixed internal loopback processing to only respond to loopback + packets addressed to the physical MAC or appropriate Multicast + or Broadcast addresses. 17-Nov-11 MP Added dynamic loading of libpcap on *nix platforms 30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking 29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX diff --git a/makefile b/makefile index a211e432..4ac68fbb 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,5 @@ # -# This GMU make makefile has been tested on: +# This GNU make makefile has been tested on: # Linux (x86 & Sparc) # OS X # Solaris (x86 & Sparc) @@ -12,9 +12,9 @@ # Android targeted builds should invoke GNU make with GCC=agcc on # the command line. # -# In general, the logic below will detect and build with the available -# features which the host build environment provides. -# +# In general, the logic below will detect and build with the available +# features which the host build environment provides. +# # Dynamic loading of libpcap is the default behavior if pcap.h is # available at build time. Direct calls to libpcap can be enabled # if GNU make is invoked with USE_NETWORK=1 on the command line. @@ -29,15 +29,21 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) GCC = gcc endif OSTYPE = $(shell uname) + # OSNAME is used in messages to indicate the source of libpcap components OSNAME = $(OSTYPE) ifeq (SunOS,$(OSTYPE)) TEST = /bin/test else TEST = test endif + ifeq (CYGWIN,$(findstring CYGWIN,$(OSTYPE))) # uname returns CYGWIN_NT-n.n-ver + OSTYPE = cygwin + OSNAME = windows-build + endif + PCAPLIB = pcap ifeq (agcc,$(findstring agcc,$(GCC))) # Android target build? OS_CCDEFS = -D_GNU_SOURCE -DSIM_ASYNCH_IO - OS_LDFLAGS = -lm + OS_LDFLAGS = -lm else # Non-Android Builds INCPATH:=/usr/include LIBPATH:=/usr/lib @@ -64,26 +70,36 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) OS_LDFLAGS += -L/opt/sfw/lib -R/opt/sfw/lib endif else - LDSEARCH :=$(shell ldconfig -r | grep 'search directories' | awk '{print $$3}' | sed 's/:/ /g') - ifneq (,$(LDSEARCH)) - LIBPATH := $(LDSEARCH) - endif - ifeq (usrpkglib,$(shell if $(TEST) -d /usr/pkg/lib; then echo usrpkglib; fi)) - LIBPATH += /usr/pkg/lib - OS_LDFLAGS += -L/usr/pkg/lib -R/usr/pkg/lib - endif - ifneq (,$(findstring NetBSD,$(OSTYPE))$(findstring FreeBSD,$(OSTYPE))) - LIBEXT = so - else + ifeq (cygwin,$(OSTYPE)) + # use 0readme_ethernet.txt documented Windows pcap build components + INCPATH += ../windows-build/winpcap/WpdPack/include + LIBPATH += ../windows-build/winpcap/WpdPack/lib + PCAPLIB = wpcap LIBEXT = a + else + LDSEARCH :=$(shell ldconfig -r | grep 'search directories' | awk '{print $$3}' | sed 's/:/ /g') + ifneq (,$(LDSEARCH)) + LIBPATH := $(LDSEARCH) + endif + ifeq (usrpkglib,$(shell if $(TEST) -d /usr/pkg/lib; then echo usrpkglib; fi)) + LIBPATH += /usr/pkg/lib + OS_LDFLAGS += -L/usr/pkg/lib -R/usr/pkg/lib + endif + ifneq (,$(findstring NetBSD,$(OSTYPE))$(findstring FreeBSD,$(OSTYPE))) + LIBEXT = so + else + LIBEXT = a + endif endif endif endif endif endif $(info lib paths are: $(LIBPATH)) - ifeq (cygwin,$(findstring cygwin,$(OSTYPE))) - OS_CCDEFS += -O2 + ifeq (cygwin,$(OSTYPE)) + # gcc optimization seems to be broken in Cygwin's gcc 4.5.3 + # (vax780 won't boot VMS 4.7 unless -O2 removed) + #OS_CCDEFS += -O2 endif find_lib = $(strip $(firstword $(foreach dir,$(strip $(LIBPATH)),$(wildcard $(dir)/lib$(1).$(LIBEXT))))) find_include = $(strip $(firstword $(foreach dir,$(strip $(INCPATH)),$(wildcard $(dir)/$(1).h)))) @@ -92,13 +108,13 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) $(info using libm: $(call find_lib,m)) endif ifneq (,$(call find_lib,rt)) - OS_LDFLAGS += -lrt + OS_LDFLAGS += -lrt $(info using librt: $(call find_lib,rt)) endif ifneq (,$(call find_lib,pthread)) ifneq (,$(call find_include,pthread)) - OS_CCDEFS += -DSIM_ASYNCH_IO -DUSE_READER_THREAD - OS_LDFLAGS += -lpthread + OS_CCDEFS += -DSIM_ASYNCH_IO -DUSE_READER_THREAD + OS_LDFLAGS += -lpthread $(info using libpthread: $(call find_lib,pthread) $(call find_include,pthread)) endif endif @@ -131,43 +147,61 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif ifneq (,$(NETWORK_USEFUL)) ifneq (,$(call find_include,pcap)) - ifneq (,$(call find_lib,pcap)) + ifneq (,$(call find_lib,$(PCAPLIB))) ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line - NETWORK_CCDEFS = -DUSE_NETWORK - NETWORK_LDFLAGS = -lpcap - $(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap)) + NETWORK_CCDEFS = -DUSE_NETWORK -I$(dir $(call find_include,pcap)) + ifeq (cygwin,$(OSTYPE)) + # cygwin has no ldconfig so explicitly specify pcap object library + NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) + else + NETWORK_LDFLAGS = -l$(PCAPLIB) + endif + $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) else # default build uses dynamic libpcap - NETWORK_CCDEFS = -DUSE_SHARED + NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(info using libpcap: $(call find_include,pcap)) endif + $(info ***) $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) - $(info *** $(OSTYPE) provided libpcap components) + $(info *** $(OSNAME) provided libpcap components) + $(info ***) else - NETWORK_CCDEFS = -DUSE_SHARED + NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(info using libpcap: $(call find_include,pcap)) + $(info ***) $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) - $(info *** $(OSTYPE) provided libpcap components) + $(info *** $(OSNAME) provided libpcap components) + $(info ***) endif else - # Look for package built from tcpdump.org sources with default install target + # Look for package built from tcpdump.org sources with default install target (or cygwin winpcap) LIBPATH += /usr/local/lib INCPATH += /usr/local/include LIBEXTSAVE := $(LIBEXT) LIBEXT = a - ifneq (,$(call find_lib,pcap)) + ifneq (,$(call find_lib,$(PCAPLIB))) ifneq (,$(call find_include,pcap)) - NETWORK_CCDEFS := -DUSE_NETWORK -isystem $(dir $(call find_include,pcap)) $(call find_lib,pcap) - $(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap)) - $(info *** Warning ***) - $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) - $(info *** Warning *** libpcap components from www.tcpdump.org.) - $(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap) - $(info *** Warning *** components for simh networking. For best results, with) - $(info *** Warning *** simh networking, it is recommended that you install the) - $(info *** Warning *** libpcap-dev package from your $(OSTYPE) distribution) - $(info *** Warning ***) + $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) + ifeq (cygwin,$(OSTYPE)) + NETWORK_CCDEFS = -DUSE_NETWORK -I$(dir $(call find_include,pcap)) + NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) + $(info ***) + $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) + $(info *** libpcap components located in the cygwin directories.) + $(info ***) + else + NETWORK_CCDEFS := -DUSE_NETWORK -isystem $(dir $(call find_include,pcap)) $(call find_lib,$(PCAPLIB)) + $(info *** Warning ***) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) + $(info *** Warning *** libpcap components from www.tcpdump.org.) + $(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap) + $(info *** Warning *** components for simh networking. For best results, with) + $(info *** Warning *** simh networking, it is recommended that you install the) + $(info *** Warning *** libpcap-dev package from your $(OSTYPE) distribution) + $(info *** Warning ***) + endif else - $(error using libpcap: $(call find_lib,pcap) missing pcap.h) + $(error using libpcap: $(call find_lib,$(PCAPLIB)) missing pcap.h) endif LIBEXT = $(LIBEXTSAVE) endif @@ -197,8 +231,9 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) $(info *** Warning ***) $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) are being built WITHOUT networking support) $(info *** Warning ***) - $(info *** Warning *** To build simulator(s) with networking support you should install) - $(info *** Warning *** the libpcap-dev package from your $(OSTYPE) distribution) + $(info *** Warning *** To build simulator(s) with networking support you should read) + $(info *** Warning *** 0readme_ethernet.txt and follow the instructions regarding the ) + $(info *** Warning *** needed libpcap components for your $(OSTYPE) platform) $(info *** Warning ***) endif NETWORK_OPT = $(NETWORK_CCDEFS) @@ -223,16 +258,16 @@ else endif ifeq (pcap,$(shell if exist ..\windows-build\winpcap\Wpdpack\include\pcap.h echo pcap)) PCAP_CCDEFS = -I../windows-build/winpcap/Wpdpack/include -I$(GCC_Path)..\include\ddk -DUSE_SHARED - NETWORK_LDFLAGS = + NETWORK_LDFLAGS = NETWORK_OPT = -DUSE_SHARED else ifeq (pcap,$(shell if exist $(dir $(GCC_Path))..\include\pcap.h echo pcap)) - PCAP_CCDEFS = -DUSE_SHARED -I$(GCC_Path)..\include\ddk - NETWORK_LDFLAGS = + PCAP_CCDEFS = -DUSE_SHARED -I$(GCC_Path)..\include\ddk + NETWORK_LDFLAGS = NETWORK_OPT = -DUSE_SHARED endif endif - OS_CCDEFS = -fms-extensions -O2 $(PTHREADS_CCDEFS) $(PCAP_CCDEFS) + OS_CCDEFS = -fms-extensions -O2 $(PTHREADS_CCDEFS) $(PCAP_CCDEFS) OS_LDFLAGS = -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) EXE = .exe ifneq (binexists,$(shell if exist BIN echo binexists)) @@ -247,10 +282,12 @@ ifneq ($(DONT_USE_ROMS),) else BUILD_ROMS = ${BIN}BuildROMs${EXE} endif - +ifneq ($(DONT_USE_READER_THREAD),) + NETWORK_OPT += -DDONT_USE_READER_THREAD +endif CC = $(GCC) -std=c99 -U__STRICT_ANSI__ -g -I . $(OS_CCDEFS) $(ROMS_OPT) -LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) +LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) # # Common Libraries @@ -499,7 +536,7 @@ else if exist BIN rmdir BIN endif -${BIN}BuildROMs${EXE} : +${BIN}BuildROMs${EXE} : ${MKDIRBIN} ifeq (agcc,$(findstring agcc,$(firstword $(CC)))) gcc $(wordlist 2,1000,${CC}) sim_BuildROMs.c -o $@ @@ -509,6 +546,9 @@ endif ifeq ($(WIN32),) $@ ${RM} $@ + ifeq (Darwin,$(OSTYPE)) # remove Xcode's debugging symbols folder too + ${RM} -rf $@.dSYM + endif else $(@D)\$(@F) del $(@D)\$(@F) @@ -639,7 +679,7 @@ ${BIN}altair${EXE} : ${ALTAIR} ${SIM} altairz80 : ${BIN}altairz80${EXE} -${BIN}altairz80${EXE} : ${ALTAIRZ80} ${SIM} +${BIN}altairz80${EXE} : ${ALTAIRZ80} ${SIM} ${MKDIRBIN} ${CC} ${ALTAIRZ80} ${SIM} ${ALTAIRZ80_OPT} -o $@ ${LDFLAGS} diff --git a/sim_ether.c b/sim_ether.c index 3cc40ace..78cf7fc4 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -129,7 +129,7 @@ likely run faster (given that modern host CPUs are multi-core and have someplace to do this work in parallel). MUST_DO_SELECT - Specifies that, when USE_READER_THREAD is active, - select() should be used to determin when available + select() should be used to determine 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 @@ -163,6 +163,12 @@ Modification history: + 01-Mar-12 MP Made host NIC address determination on *nix platforms more + robust. + 01-Mar-12 MP Added host NIC address determination work when building + under Cygwin + 01-Mar-12 AGN Add conditionals for Cygwin dynamic loading of wpcap.dll + 01-Mar-12 AGN Specify the full /usr/lib for dlopen under Apple Mac OS X. 17-Nov-11 MP Added dynamic loading of libpcap on *nix platforms 30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking 29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX @@ -193,11 +199,11 @@ network traffic from the host and/or from hosts on the LAN. These new TOE features are: LSO (Large Send Offload) and Jumbo packet fragmentation support. These features allow a simulated network - device to suuport traffic when a host leverages a NIC's Large + device to support traffic when a host leverages a NIC's Large Send Offload capabilities to fregment and/or segment outgoing network traffic. Additionally a simulated network device can reasonably exist on a LAN which is configured to use Jumbo frames. - 21-May-10 MP Added functionslity to fixup IP header checksums to accomodate + 21-May-10 MP Added functionality to fixup IP header checksums to accomodate packets from a host with a NIC which has TOE (TCP Offload Engine) enabled which is expected to implement the checksum computations in hardware. Since we catch packets before they arrive at the @@ -817,14 +823,14 @@ void eth_show_dev (FILE* st, ETH_DEV* dev) #include #endif -#if defined(USE_SHARED) && (defined(_WIN32) || defined(HAVE_DLOPEN)) -/* Dynamic DLL loading technique and modified source comes from - Etherial/WireShark capture_pcap.c */ - #ifdef HAVE_DLOPEN #include #endif +#if defined(USE_SHARED) && (defined(_WIN32) || defined(HAVE_DLOPEN)) +/* Dynamic DLL loading technique and modified source comes from + Etherial/WireShark capture_pcap.c */ + /* Dynamic DLL load variables */ #ifdef _WIN32 static HINSTANCE hLib = 0; /* handle to DLL */ @@ -833,15 +839,17 @@ static void *hLib = 0; /* handle to Library */ #endif static int lib_loaded = 0; /* 0=not loaded, 1=loaded, 2=library load failed, 3=Func load failed */ static char* lib_name = -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) "wpcap.dll"; +#elif defined(__APPLE__) + "/usr/lib/libpcap.A.dylib"; #else #define __STR_QUOTE(tok) #tok #define __STR(tok) __STR_QUOTE(tok) "libpcap." __STR(HAVE_DLOPEN); #endif static char* no_pcap = -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) "wpcap load failure"; #else "libpcap load failure"; @@ -862,7 +870,9 @@ static pcap_t* (*p_pcap_open_live) (const char *, int, int, int, char *); static int (*p_pcap_setmintocopy) (pcap_t* handle, int); static HANDLE (*p_pcap_getevent) (pcap_t *); #else +#ifdef MUST_DO_SELECT static int (*p_pcap_get_selectable_fd) (pcap_t *); +#endif static int (*p_pcap_fileno) (pcap_t *); #endif static int (*p_pcap_sendpacket) (pcap_t* handle, const u_char* msg, int len); @@ -933,7 +943,9 @@ int load_pcap(void) { load_function("pcap_setmintocopy", (void**) &p_pcap_setmintocopy); load_function("pcap_getevent", (void**) &p_pcap_getevent); #else +#ifdef MUST_DO_SELECT load_function("pcap_get_selectable_fd", (void**) &p_pcap_get_selectable_fd); +#endif load_function("pcap_fileno", (void**) &p_pcap_fileno); #endif load_function("pcap_sendpacket", (void**) &p_pcap_sendpacket); @@ -1054,6 +1066,7 @@ HANDLE pcap_getevent(pcap_t* a) { } #else +#ifdef MUST_DO_SELECT int pcap_get_selectable_fd(pcap_t* a) { if (load_pcap() != 0) { return p_pcap_get_selectable_fd(a); @@ -1061,6 +1074,7 @@ int pcap_get_selectable_fd(pcap_t* a) { return 0; } } +#endif int pcap_fileno(pcap_t * a) { if (load_pcap() != 0) { @@ -1112,32 +1126,57 @@ int pcap_sendpacket(pcap_t* handle, const u_char* msg, int len) } #endif /* !HAS_PCAP_SENDPACKET */ -#ifdef _WIN32 -#include -#include +#if defined(_WIN32) || defined(__CYGWIN__) +/* extracted from WinPcap's Packet32.h */ +struct _PACKET_OID_DATA { + uint32 Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + uint32 Length; ///< Length of the data field + uint8 Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; +typedef void **LPADAPTER; +#define OID_802_3_CURRENT_ADDRESS 0x01010102 /* Extracted from ntddmdis.h */ -static int pcap_mac_if_win32(char *AdapterName, UCHAR MACAddress[6]) +static int pcap_mac_if_win32(char *AdapterName, unsigned char MACAddress[6]) { LPADAPTER lpAdapter; PPACKET_OID_DATA OidData; - BOOLEAN Status; + int Status; int ReturnValue; +#ifdef _WIN32 HINSTANCE hDll; /* handle to DLL */ - LPADAPTER (*p_PacketOpenAdapter)(PCHAR AdapterName); - VOID (*p_PacketCloseAdapter)(LPADAPTER lpAdapter); - BOOLEAN (*p_PacketRequest)(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +#else + static void *hDll = NULL; /* handle to Library */ + typedef int BOOLEAN; +#endif + LPADAPTER (*p_PacketOpenAdapter)(char *AdapterName); + void (*p_PacketCloseAdapter)(LPADAPTER lpAdapter); + int (*p_PacketRequest)(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); - hDll = LoadLibrary(TEXT("packet.dll")); +#ifdef _WIN32 + hDll = LoadLibraryA("packet.dll"); p_PacketOpenAdapter = (void *)GetProcAddress(hDll, "PacketOpenAdapter"); p_PacketCloseAdapter = (void *)GetProcAddress(hDll, "PacketCloseAdapter"); p_PacketRequest = (void *)GetProcAddress(hDll, "PacketRequest"); +#else + hDll = dlopen("packet.dll", RTLD_NOW); + p_PacketOpenAdapter = (void *)dlsym(hDll, "PacketOpenAdapter"); + p_PacketCloseAdapter = (void *)dlsym(hDll, "PacketCloseAdapter"); + p_PacketRequest = (void *)dlsym(hDll, "PacketRequest"); +#endif /* Open the selected adapter */ lpAdapter = p_PacketOpenAdapter(AdapterName); - if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE)) { - FreeLibrary(hDll); + if (!lpAdapter || (*lpAdapter == (void *)-1)) { +#ifdef _WIN32 + FreeLibrary(hDll); +#else + dlclose(hDll); +#endif return -1; } @@ -1146,7 +1185,11 @@ static int pcap_mac_if_win32(char *AdapterName, UCHAR MACAddress[6]) OidData = malloc(6 + sizeof(PACKET_OID_DATA)); if (OidData == NULL) { p_PacketCloseAdapter(lpAdapter); +#ifdef _WIN32 FreeLibrary(hDll); +#else + dlclose(hDll); +#endif return -1; } @@ -1166,7 +1209,11 @@ static int pcap_mac_if_win32(char *AdapterName, UCHAR MACAddress[6]) free(OidData); p_PacketCloseAdapter(lpAdapter); +#ifdef _WIN32 FreeLibrary(hDll); +#else + dlclose(hDll); +#endif return ReturnValue; } #endif @@ -1175,44 +1222,55 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname) { memset(&dev->host_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr)); dev->have_host_nic_phy_addr = 0; -#ifdef _WIN32 - if (!pcap_mac_if_win32(devname, (UCHAR *)&dev->host_nic_phy_hw_addr)) +#if defined(_WIN32) || defined(__CYGWIN__) + if (!pcap_mac_if_win32(devname, dev->host_nic_phy_hw_addr)) dev->have_host_nic_phy_addr = 1; -#elif !defined (__VMS) +#elif !defined (__VMS) && !defined(__CYGWIN__) if (1) { char command[1024]; FILE *f; + int i; + char *patterns[] = { + "grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]", + "egrep [0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]", + NULL}; if (0 == strncmp("vde:", devname, 4)) return; memset(command, 0, sizeof(command)); - snprintf(command, sizeof(command)-1, "ifconfig %s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F] >NIC.hwaddr", devname); - system(command); - if (f = fopen("NIC.hwaddr", "r")) { - if (fgets(command, sizeof(command)-1, f)) { - char *p1, *p2; - - p1 = strchr(command, ':'); - while (p1) { - p2 = strchr(p1+1, ':'); - if (p2 == p1+3) { - int mac_bytes[6]; - if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) { - dev->host_nic_phy_hw_addr[0] = mac_bytes[0]; - dev->host_nic_phy_hw_addr[1] = mac_bytes[1]; - dev->host_nic_phy_hw_addr[2] = mac_bytes[2]; - dev->host_nic_phy_hw_addr[3] = mac_bytes[3]; - dev->host_nic_phy_hw_addr[4] = mac_bytes[4]; - dev->host_nic_phy_hw_addr[5] = mac_bytes[5]; - dev->have_host_nic_phy_addr = 1; + for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) { + snprintf(command, sizeof(command)-1, "ifconfig %s | %s >NIC.hwaddr", devname, patterns[i]); + system(command); + if (f = fopen("NIC.hwaddr", "r")) { + while (0 == dev->have_host_nic_phy_addr) { + if (fgets(command, sizeof(command)-1, f)) { + char *p1, *p2; + + p1 = strchr(command, ':'); + while (p1) { + p2 = strchr(p1+1, ':'); + if (p2 <= p1+3) { + int mac_bytes[6]; + if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) { + dev->host_nic_phy_hw_addr[0] = mac_bytes[0]; + dev->host_nic_phy_hw_addr[1] = mac_bytes[1]; + dev->host_nic_phy_hw_addr[2] = mac_bytes[2]; + dev->host_nic_phy_hw_addr[3] = mac_bytes[3]; + dev->host_nic_phy_hw_addr[4] = mac_bytes[4]; + dev->host_nic_phy_hw_addr[5] = mac_bytes[5]; + dev->have_host_nic_phy_addr = 1; + } + break; + } + p1 = p2; } - break; } - p1 = p2; + else + break; } + fclose(f); + remove("NIC.hwaddr"); } - fclose(f); - remove("NIC.hwaddr"); } } #endif @@ -1523,11 +1581,14 @@ if (0 == strncmp("tap:", savname, 4)) { memset (&ifr, 0, sizeof(ifr)); ifr.ifr_addr.sa_family = AF_INET; - strncpy(ifr.ifr_name, savname+4, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, savname, sizeof(ifr.ifr_name)); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) { ifr.ifr_flags |= IFF_UP; - ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr); + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr)) { + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + close(tun); + } } close(s); } @@ -1798,9 +1859,12 @@ eth_filter(dev, 1, (ETH_MAC *)mac, 0, 0); status = _eth_write (dev, &send, NULL); if (status != SCPE_OK) { char *msg; - msg = "Eth: Error Transmitting packet: %s\r\n" + msg = (dev->eth_api == ETH_API_PCAP) ? + "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 your OS vendor or www.tcpdump.org\r\n"; + "which is at least 0.9 from your OS vendor or www.tcpdump.org\r\n" : + "Eth: Error Transmitting packet: %s\r\n" + "You may need to run as root.\r\n"; printf(msg, strerror(errno)); if (sim_log) fprintf (sim_log, msg, strerror(errno)); return status; diff --git a/sim_ether.h b/sim_ether.h index 29c9e7a8..571b75a8 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -28,6 +28,7 @@ Modification history: + 01-Mar-12 AGN Cygwin doesn't have non-blocking pcap I/O pcap (it uses WinPcap) 17-Nov-11 MP Added dynamic loading of libpcap on *nix platforms 30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking 18-Apr-11 MP Fixed race condition with self loopback packets in @@ -72,16 +73,25 @@ #if defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__) #define xBSD 1 #endif -#if !defined(__FreeBSD__) && !defined(_WIN32) && !defined(VMS) +#if !defined(__FreeBSD__) && !defined(_WIN32) && !defined(VMS) && !defined(__CYGWIN__) && !defined(__APPLE__) #define USE_SETNONBLOCK 1 #endif +/* cygwin dowsn't have the right features to use the threaded network I/O */ +#if defined(__CYGWIN__) +#define DONT_USE_READER_THREAD +#endif + #if (((defined(__sun__) && defined(__i386__)) || defined(__linux)) && !defined(DONT_USE_READER_THREAD)) #define USE_READER_THREAD 1 #endif +#if defined(DONT_USE_READER_THREAD) +#undef USE_READER_THREAD +#endif + /* make common winpcap code a bit easier to read in this file */ -#if defined(_WIN32) || defined(VMS) +#if defined(_WIN32) || defined(VMS) || defined(__CYGWIN__) #define PCAP_READ_TIMEOUT -1 #else #define PCAP_READ_TIMEOUT 1 @@ -94,7 +104,7 @@ #endif /* USE_SETNONBLOCK */ #undef PCAP_READ_TIMEOUT #define PCAP_READ_TIMEOUT 15 -#if (!defined (xBSD) && !defined(_WIN32) && !defined(VMS)) || defined (USE_TAP_NETWORK) || defined (USE_VDE_NETWORK) +#if (!defined (xBSD) && !defined(_WIN32) && !defined(VMS) && !defined(__CYGWIN__)) || defined (USE_TAP_NETWORK) || defined (USE_VDE_NETWORK) #define MUST_DO_SELECT 1 #endif #endif /* USE_READER_THREAD */ From 1d5dc21dcc95c68df57f7513931b1a5bdae34d86 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 9 Mar 2012 09:14:34 -0800 Subject: [PATCH 003/112] Enable Maximum compiler optimization for release build of VAX simulators this produces a net gain of 20% more instructions executed per second --- Visual Studio Projects/VAX.vcproj | 4 ++++ Visual Studio Projects/VAX780.vcproj | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Visual Studio Projects/VAX.vcproj b/Visual Studio Projects/VAX.vcproj index 13136d28..3aaebaa1 100644 --- a/Visual Studio Projects/VAX.vcproj +++ b/Visual Studio Projects/VAX.vcproj @@ -134,11 +134,13 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" OmitFramePointers="true" + WholeProgramOptimization="true" AdditionalIncludeDirectories="./;../;../VAX/;../pdp11/;"../../windows-build/winpcap/Wpdpack/Include";"../../windows-build/pthreads"" PreprocessorDefinitions="USE_INT64;USE_ADDR64;VM_VAX;USE_SHARED;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;PTW32_STATIC_LIB;USE_READER_THREAD;SIM_ASYNCH_IO" KeepComments="false" StringPooling="true" RuntimeLibrary="0" + BufferSecurityCheck="false" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" @@ -166,6 +168,7 @@ SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" + LinkTimeCodeGeneration="1" RandomizedBaseAddress="1" DataExecutionPrevention="0" TargetMachine="1" @@ -260,6 +263,7 @@ > diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj index a2425a5f..fdb15cc3 100644 --- a/Visual Studio Projects/VAX780.vcproj +++ b/Visual Studio Projects/VAX780.vcproj @@ -133,10 +133,12 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" OmitFramePointers="true" + WholeProgramOptimization="true" AdditionalIncludeDirectories="./;../;../VAX/;../pdp11/;"../../windows-build/winpcap/Wpdpack/Include";"../../windows-build/pthreads"" PreprocessorDefinitions="USE_INT64;USE_ADDR64;VM_VAX;VAX_780;USE_SHARED;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;PTW32_STATIC_LIB;USE_READER_THREAD;SIM_ASYNCH_IO" StringPooling="true" RuntimeLibrary="0" + BufferSecurityCheck="false" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" @@ -164,6 +166,7 @@ SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" + LinkTimeCodeGeneration="1" RandomizedBaseAddress="1" DataExecutionPrevention="0" TargetMachine="1" @@ -270,6 +273,7 @@ > From 57c961f99a11ca2182847196c46b799410718294 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 12 Mar 2012 06:58:47 -0700 Subject: [PATCH 004/112] Made references to disk capacity consistent with respect to the units they are kept in (i.e. Words or Bytes). --- sim_disk.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/sim_disk.c b/sim_disk.c index 96679193..fbe23452 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -93,6 +93,7 @@ struct disk_context { DEVICE *dptr; /* Device for unit (access to debug flags) */ uint32 dbit; /* debugging bit */ uint32 sector_size; /* Disk Sector Size (of the pseudo disk) */ + uint32 capac_factor; /* Units of Capacity (2 = word, 1 = byte) */ uint32 xfer_element_size; /* Disk Bus Transfer size (1 - byte, 2 - word, 4 - longword) */ uint32 storage_sector_size;/* Sector size of the containing storage */ uint32 removable; /* Removable device flag */ @@ -333,12 +334,17 @@ return SCPE_OK; t_stat sim_disk_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc) { +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +char *cap_units = "B"; + +if (ctx->capac_factor == 2) + cap_units = "W"; if (uptr->capac) { if (uptr->capac >= (t_addr) 1000000) - fprintf (st, "capacity=%dMB", (uint32) (uptr->capac / ((t_addr) 1000000))); + fprintf (st, "capacity=%dM%s", (uint32) (uptr->capac / ((t_addr) 1000000)), cap_units); else if (uptr->capac >= (t_addr) 1000) - fprintf (st, "capacity=%dKB", (uint32) (uptr->capac / ((t_addr) 1000))); - else fprintf (st, "capacity=%dB", (uint32) uptr->capac); + fprintf (st, "capacity=%dK%s", (uint32) (uptr->capac / ((t_addr) 1000)), cap_units); + else fprintf (st, "capacity=%d%S", (uint32) uptr->capac, cap_units); } else fprintf (st, "undefined capacity"); return SCPE_OK; @@ -487,7 +493,7 @@ t_seccnt sread; sim_debug (ctx->dbit, ctx->dptr, "sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); if ((sects == 1) && /* Single sector reads */ - (lba >= uptr->capac/ctx->sector_size)) { /* beyond the end of the disk */ + (lba >= (uptr->capac*ctx->capac_factor)/ctx->sector_size)) {/* beyond the end of the disk */ memset (buf, '\0', ctx->sector_size); /* are bad block management efforts - zero buffer */ if (sectsread) *sectsread = 1; @@ -817,7 +823,7 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop } if (!sim_quiet) printf ("%s%d: creating new virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf); - vhd = sim_vhd_disk_create (gbuf, uptr->capac); + vhd = sim_vhd_disk_create (gbuf, uptr->capac*ctx->capac_factor); if (!vhd) { if (!sim_quiet) printf ("%s%d: can't create virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf); @@ -827,7 +833,7 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop uint8 *copy_buf = malloc (1024*1024); t_lba lba; t_seccnt sectors_per_buffer = (t_seccnt)((1024*1024)/sector_size); - t_lba total_sectors = (t_lba)(uptr->capac/sector_size); + t_lba total_sectors = (t_lba)((uptr->capac*ctx->capac_factor)/sector_size); t_seccnt sects = sectors_per_buffer; if (!copy_buf) { @@ -895,6 +901,7 @@ if ((uptr->filename == NULL) || (uptr->disk_ctx == NULL)) return _err_return (uptr, SCPE_MEM); strncpy (uptr->filename, cptr, CBUFSIZE); /* save name */ ctx->sector_size = (uint32)sector_size; /* save sector_size */ +ctx->capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */ ctx->xfer_element_size = (uint32)xfer_element_size; /* save xfer_element_size */ ctx->dptr = dptr; /* save DEVICE pointer */ ctx->dbit = dbit; /* save debug bit */ @@ -927,7 +934,7 @@ else { /* normal */ if (sim_switches & SWMASK ('E')) /* must exist? */ return _err_return (uptr, SCPE_OPENERR); /* yes, error */ if (create_function) - uptr->fileref = create_function (cptr, uptr->capac);/* create new file */ + uptr->fileref = create_function (cptr, uptr->capac*ctx->capac_factor);/* create new file */ else uptr->fileref = open_function (cptr, "wb+");/* open new file */ if (uptr->fileref == NULL) /* open fail? */ @@ -973,7 +980,7 @@ if (created) { if (secbuf == NULL) r = SCPE_MEM; if (r == SCPE_OK) - r = sim_disk_wrsect (uptr, (t_lba)((uptr->capac - ctx->sector_size)/ctx->sector_size), secbuf, NULL, 1); /* Write Last Sector */ + r = sim_disk_wrsect (uptr, (t_lba)(((uptr->capac*ctx->capac_factor) - ctx->sector_size)/ctx->sector_size), secbuf, NULL, 1); /* Write Last Sector */ if (r == SCPE_OK) r = sim_disk_wrsect (uptr, (t_lba)(0), secbuf, NULL, 1); /* Write First Sector */ free (secbuf); @@ -989,19 +996,19 @@ if (created) { capac = size_function (uptr->fileref); if (capac && (capac != (t_addr)-1)) if (dontautosize) { - if ((capac < uptr->capac) && (DKUF_F_STD != DK_GET_FMT (uptr))) { + if ((capac < (uptr->capac*ctx->capac_factor)) && (DKUF_F_STD != DK_GET_FMT (uptr))) { if (!sim_quiet) { printf ("%s%d: non expandable disk %s is smaller than simulated device (", sim_dname (dptr), (int)(uptr-dptr->units), cptr); - fprint_val (stdout, capac, 10, T_ADDR_W, PV_LEFT); - printf (" < "); + fprint_val (stdout, capac/ctx->capac_factor, 10, T_ADDR_W, PV_LEFT); + printf ("%s < ", (ctx->capac_factor == 2) ? "W" : ""); fprint_val (stdout, uptr->capac, 10, T_ADDR_W, PV_LEFT); - printf (")\n"); + printf ("%s)\n", (ctx->capac_factor == 2) ? "W" : ""); } } } else - if ((capac > uptr->capac) || (DKUF_F_STD != DK_GET_FMT (uptr))) - uptr->capac = capac; + if ((capac > (uptr->capac*ctx->capac_factor)) || (DKUF_F_STD != DK_GET_FMT (uptr))) + uptr->capac = capac/ctx->capac_factor; #if defined (SIM_ASYNCH_IO) sim_disk_set_async (uptr, 0); @@ -1082,7 +1089,6 @@ return SCPE_OK; t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec) { struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; -DEVICE *dptr; int32 i; t_addr da; int32 wds = ctx->sector_size/sizeof (uint16); @@ -1094,9 +1100,7 @@ if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; if (uptr->flags & UNIT_RO) return SCPE_RO; -if ((dptr = find_dev_from_unit (uptr)) == NULL) - return SCPE_NOATT; -if ((dptr->dwidth / dptr->aincr) <= 8) /* Must be Word oriented Capacity */ +if (ctx->capac_factor != 2) /* Must be Word oriented Capacity */ return SCPE_IERR; if (!get_yn ("Overwrite last track? [N]", FALSE)) return SCPE_OK; From f07f08b877bc2e28d0bb8cc4bb1d5e5a7f31b497 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 13 Mar 2012 06:53:36 -0700 Subject: [PATCH 005/112] Proper declarations to avoid compiler warnings --- VAX/vax780_uba.c | 2 +- VAX/vax_io.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VAX/vax780_uba.c b/VAX/vax780_uba.c index 16e2e910..cbbf0c74 100644 --- a/VAX/vax780_uba.c +++ b/VAX/vax780_uba.c @@ -214,7 +214,7 @@ t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); /* Unibus interrupt request to interrupt action map */ -int32 (*int_ack[IPL_HLVL][32])(); /* int ack routines */ +int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */ /* Unibus interrupt request to vector map */ diff --git a/VAX/vax_io.c b/VAX/vax_io.c index a52d93ea..d0646c3f 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -188,7 +188,7 @@ t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); /* Interrupt request to interrupt action map */ -int32 (*int_ack[IPL_HLVL][32])(); /* int ack routines */ +int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */ /* Interrupt request to vector map */ From e61d00d539f0775a1f381b59b6e108840e8221ae Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 13 Mar 2012 07:07:28 -0700 Subject: [PATCH 006/112] Added compiler optimizations to gcc builds --- makefile | 57 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/makefile b/makefile index 4ac68fbb..c9c01950 100644 --- a/makefile +++ b/makefile @@ -19,11 +19,30 @@ # available at build time. Direct calls to libpcap can be enabled # if GNU make is invoked with USE_NETWORK=1 on the command line. # +# The default build will build compiler optimized binaries. +# If debugging is desired, then GNU make can be invoked with +# DEBUG=1 on the command line. +# # Internal ROM support can be disabled if GNU make is invoked with # DONT_USE_ROMS=1 on the command line. # # CC Command (and platform available options). (Poor man's autoconf) # +# building the pdp11, or any vax simulator could use networking support +ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) + NETWORK_USEFUL = true + ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) + BUILD_MULTIPLE = (s) + else + BUILD_SINGLE := $(MAKECMDGOALS) $(BUILD_SINGLE) + endif +else + ifeq ($(MAKECMDGOALS),) + # default target is all + NETWORK_USEFUL = true + BUILD_MULTIPLE = (s) + endif +endif ifeq ($(WIN32),) #*nix Environments (&& cygwin) ifeq ($(GCC),) GCC = gcc @@ -96,11 +115,6 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif endif $(info lib paths are: $(LIBPATH)) - ifeq (cygwin,$(OSTYPE)) - # gcc optimization seems to be broken in Cygwin's gcc 4.5.3 - # (vax780 won't boot VMS 4.7 unless -O2 removed) - #OS_CCDEFS += -O2 - endif find_lib = $(strip $(firstword $(foreach dir,$(strip $(LIBPATH)),$(wildcard $(dir)/lib$(1).$(LIBEXT))))) find_include = $(strip $(firstword $(foreach dir,$(strip $(INCPATH)),$(wildcard $(dir)/$(1).h)))) ifneq (,$(call find_lib,m)) @@ -130,21 +144,6 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif endif endif - # building the pdp11, or any vax simulator could use networking support - ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) - NETWORK_USEFUL = true - ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) - BUILD_MULTIPLE = (s) - else - BUILD_SINGLE := $(MAKECMDGOALS) $(BUILD_SINGLE) - endif - else - ifeq ($(MAKECMDGOALS),) - # default target is all - NETWORK_USEFUL = true - BUILD_MULTIPLE = (s) - endif - endif ifneq (,$(NETWORK_USEFUL)) ifneq (,$(call find_include,pcap)) ifneq (,$(call find_lib,$(PCAPLIB))) @@ -267,7 +266,7 @@ else NETWORK_OPT = -DUSE_SHARED endif endif - OS_CCDEFS = -fms-extensions -O2 $(PTHREADS_CCDEFS) $(PCAP_CCDEFS) + OS_CCDEFS = -fms-extensions $(PTHREADS_CCDEFS) $(PCAP_CCDEFS) OS_LDFLAGS = -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) EXE = .exe ifneq (binexists,$(shell if exist BIN echo binexists)) @@ -277,6 +276,18 @@ else NETWORK_OPT = -DUSE_SHARED endif endif +ifneq ($(DEBUG),) + CFLAGS_G = -g -ggdb -g3 + CFLAGS_O = -O0 + BUILD_FEATURES = debugging support +else + CFLAGS_O = -O2 -flto -finline-functions -fgcse-after-reload -fpredictive-commoning -fipa-cp-clone -fno-unsafe-loop-optimizations -fno-strict-overflow + LDFLAGS_O = -flto -fwhole-program + BUILD_FEATURES = compiler optimizations and no debugging support +endif +$(info ***) +$(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with $(BUILD_FEATURES).) +$(info ***) ifneq ($(DONT_USE_ROMS),) ROMS_OPT = -DDONT_USE_INTERNAL_ROM else @@ -286,8 +297,8 @@ ifneq ($(DONT_USE_READER_THREAD),) NETWORK_OPT += -DDONT_USE_READER_THREAD endif -CC = $(GCC) -std=c99 -U__STRICT_ANSI__ -g -I . $(OS_CCDEFS) $(ROMS_OPT) -LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) +CC = $(GCC) -std=c99 -U__STRICT_ANSI__ $(CFLAGS_G) $(CFLAGS_O) -I . $(OS_CCDEFS) $(ROMS_OPT) +LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) $(LDFLAGS_O) # # Common Libraries From b3102ea86a5f3a1ccb9d509f3fff26a10afecd5c Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 14 Mar 2012 09:09:25 -0700 Subject: [PATCH 007/112] Foxed size units (words or bytes) consistency issues when creating disks. --- sim_disk.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sim_disk.c b/sim_disk.c index fbe23452..8e3090c4 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -806,6 +806,7 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop FILE *vhd; int saved_sim_switches = sim_switches; int32 saved_sim_quiet = sim_quiet; + uint32 capac_factor; t_stat r; sim_switches = sim_switches & ~(SWMASK ('C')); @@ -823,7 +824,8 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop } if (!sim_quiet) printf ("%s%d: creating new virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf); - vhd = sim_vhd_disk_create (gbuf, uptr->capac*ctx->capac_factor); + capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (word: 2, byte: 1) */ + vhd = sim_vhd_disk_create (gbuf, uptr->capac*capac_factor); if (!vhd) { if (!sim_quiet) printf ("%s%d: can't create virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf); @@ -833,7 +835,7 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop uint8 *copy_buf = malloc (1024*1024); t_lba lba; t_seccnt sectors_per_buffer = (t_seccnt)((1024*1024)/sector_size); - t_lba total_sectors = (t_lba)((uptr->capac*ctx->capac_factor)/sector_size); + t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/sector_size); t_seccnt sects = sectors_per_buffer; if (!copy_buf) { From eb0f027c4757006c58b0368880750f4fdfee54ab Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 14 Mar 2012 17:21:15 -0700 Subject: [PATCH 008/112] Cleanup Compiler warning. --- VAX/vax_cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 87492442..af9f1c5c 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -509,7 +509,7 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { volatile int32 opc, cc; /* used by setjmp */ -int32 acc; /* set by setjmp */ +volatile int32 acc; /* set by setjmp */ int abortval; t_stat r; From cf8c54184d361f421359cac4b925d1812a6796e7 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 14 Mar 2012 17:47:20 -0700 Subject: [PATCH 009/112] Cleaned up build status messages --- makefile | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/makefile b/makefile index c9c01950..c337767f 100644 --- a/makefile +++ b/makefile @@ -156,21 +156,16 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) NETWORK_LDFLAGS = -l$(PCAPLIB) endif $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) + NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components else # default build uses dynamic libpcap NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(info using libpcap: $(call find_include,pcap)) + NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components endif - $(info ***) - $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) - $(info *** $(OSNAME) provided libpcap components) - $(info ***) else NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) + NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components $(info using libpcap: $(call find_include,pcap)) - $(info ***) - $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) - $(info *** $(OSNAME) provided libpcap components) - $(info ***) endif else # Look for package built from tcpdump.org sources with default install target (or cygwin winpcap) @@ -184,12 +179,10 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) ifeq (cygwin,$(OSTYPE)) NETWORK_CCDEFS = -DUSE_NETWORK -I$(dir $(call find_include,pcap)) NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) - $(info ***) - $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) - $(info *** libpcap components located in the cygwin directories.) - $(info ***) + NETWORK_FEATURES = - static networking support using libpcap components located in the cygwin directories else NETWORK_CCDEFS := -DUSE_NETWORK -isystem $(dir $(call find_include,pcap)) $(call find_lib,$(PCAPLIB)) + NETWORK_FEATURES = - networking support using libpcap components from www.tcpdump.org $(info *** Warning ***) $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) $(info *** Warning *** libpcap components from www.tcpdump.org.) @@ -227,11 +220,12 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP endif else + NETWORK_FEATURES = - WITHOUT networking support $(info *** Warning ***) $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) are being built WITHOUT networking support) $(info *** Warning ***) $(info *** Warning *** To build simulator(s) with networking support you should read) - $(info *** Warning *** 0readme_ethernet.txt and follow the instructions regarding the ) + $(info *** Warning *** 0readme_ethernet.txt and follow the instructions regarding the) $(info *** Warning *** needed libpcap components for your $(OSTYPE) platform) $(info *** Warning ***) endif @@ -259,11 +253,13 @@ else PCAP_CCDEFS = -I../windows-build/winpcap/Wpdpack/include -I$(GCC_Path)..\include\ddk -DUSE_SHARED NETWORK_LDFLAGS = NETWORK_OPT = -DUSE_SHARED + NETWORK_FEATURES = - dynamic networking support using windows-build provided libpcap components else ifeq (pcap,$(shell if exist $(dir $(GCC_Path))..\include\pcap.h echo pcap)) PCAP_CCDEFS = -DUSE_SHARED -I$(GCC_Path)..\include\ddk NETWORK_LDFLAGS = NETWORK_OPT = -DUSE_SHARED + NETWORK_FEATURES = - dynamic networking support using libpcap components found in the MinGW directories endif endif OS_CCDEFS = -fms-extensions $(PTHREADS_CCDEFS) $(PCAP_CCDEFS) @@ -279,14 +275,16 @@ endif ifneq ($(DEBUG),) CFLAGS_G = -g -ggdb -g3 CFLAGS_O = -O0 - BUILD_FEATURES = debugging support + BUILD_FEATURES = - debugging support else CFLAGS_O = -O2 -flto -finline-functions -fgcse-after-reload -fpredictive-commoning -fipa-cp-clone -fno-unsafe-loop-optimizations -fno-strict-overflow LDFLAGS_O = -flto -fwhole-program - BUILD_FEATURES = compiler optimizations and no debugging support + BUILD_FEATURES = - compiler optimizations and no debugging support endif $(info ***) -$(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with $(BUILD_FEATURES).) +$(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with:) +$(info *** $(BUILD_FEATURES).) +$(info *** $(NETWORK_FEATURES).) $(info ***) ifneq ($(DONT_USE_ROMS),) ROMS_OPT = -DDONT_USE_INTERNAL_ROM From e04a987353c43c9d2dac9098df81e692b6ab5bee Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 18 Mar 2012 16:47:58 -0700 Subject: [PATCH 010/112] Added makefile option to compile without asynchronouos I/O support (invoke make with NOASYNCH=1) --- makefile | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/makefile b/makefile index c337767f..4e2b65c0 100644 --- a/makefile +++ b/makefile @@ -26,6 +26,9 @@ # Internal ROM support can be disabled if GNU make is invoked with # DONT_USE_ROMS=1 on the command line. # +# Asynchronous I/O support can be disabled if GNU make is invoked with +# NOASYNCH=1 on the command line. +# # CC Command (and platform available options). (Poor man's autoconf) # # building the pdp11, or any vax simulator could use networking support @@ -61,7 +64,10 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif PCAPLIB = pcap ifeq (agcc,$(findstring agcc,$(GCC))) # Android target build? - OS_CCDEFS = -D_GNU_SOURCE -DSIM_ASYNCH_IO + OS_CCDEFS = -D_GNU_SOURCE + ifeq (,$(NOASYNCH)) + OS_CCDEFS += -DSIM_ASYNCH_IO + endif OS_LDFLAGS = -lm else # Non-Android Builds INCPATH:=/usr/include @@ -127,7 +133,10 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif ifneq (,$(call find_lib,pthread)) ifneq (,$(call find_include,pthread)) - OS_CCDEFS += -DSIM_ASYNCH_IO -DUSE_READER_THREAD + OS_CCDEFS += -DUSE_READER_THREAD + ifeq (,$(NOASYNCH)) + OS_CCDEFS += -DSIM_ASYNCH_IO + endif OS_LDFLAGS += -lpthread $(info using libpthread: $(call find_lib,pthread) $(call find_include,pthread)) endif @@ -238,15 +247,19 @@ else #Win32 Environments (via MinGW32) GCC = gcc GCC_Path := $(dir $(shell where gcc.exe)) - ifeq ($(NOASYNCH),) - ifeq (pthreads,$(shell if exist ..\windows-build\pthreads\Pre-built.2\include\pthread.h echo pthreads)) - PTHREADS_CCDEFS = -DSIM_ASYNCH_IO -DUSE_READER_THREAD -DPTW32_STATIC_LIB -I../windows-build/pthreads/Pre-built.2/include - PTHREADS_LDFLAGS = -lpthreadGC2 -L..\windows-build\pthreads\Pre-built.2\lib - else - ifeq (pthreads,$(shell if exist $(dir $(GCC_Path))..\include\pthread.h echo pthreads)) - PTHREADS_CCDEFS = -DSIM_ASYNCH_IO -DUSE_READER_THREAD - PTHREADS_LDFLAGS = -lpthread - endif + ifeq (pthreads,$(shell if exist ..\windows-build\pthreads\Pre-built.2\include\pthread.h echo pthreads)) + PTHREADS_CCDEFS = -DUSE_READER_THREAD -DPTW32_STATIC_LIB -I../windows-build/pthreads/Pre-built.2/include + ifeq (,$(NOASYNCH)) + PTHREADS_CCDEFS += -DSIM_ASYNCH_IO + endif + PTHREADS_LDFLAGS = -lpthreadGC2 -L..\windows-build\pthreads\Pre-built.2\lib + else + ifeq (pthreads,$(shell if exist $(dir $(GCC_Path))..\include\pthread.h echo pthreads)) + PTHREADS_CCDEFS = -DUSE_READER_THREAD + ifeq (,$(NOASYNCH)) + PTHREADS_CCDEFS += -DSIM_ASYNCH_IO + endif + PTHREADS_LDFLAGS = -lpthread endif endif ifeq (pcap,$(shell if exist ..\windows-build\winpcap\Wpdpack\include\pcap.h echo pcap)) From fffad7c20e284dca83953ab9860eeba4866e0291 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 19 Mar 2012 16:05:24 -0700 Subject: [PATCH 011/112] Merge changes from v3.9-0 rc1 --- 0readme_38.txt | 80 - 0readme_39.txt | 184 + AltairZ80/altairz80_cpu.c | 37 +- AltairZ80/altairz80_cpu_nommu.c | 2 +- AltairZ80/altairz80_defs.h | 4 +- AltairZ80/altairz80_doc.pdf | Bin 416146 -> 507457 bytes AltairZ80/altairz80_dsk.c | 135 +- AltairZ80/altairz80_hdsk.c | 65 +- AltairZ80/altairz80_net.c | 17 +- AltairZ80/altairz80_sio.c | 420 ++- AltairZ80/altairz80_sys.c | 2 +- AltairZ80/i8272.c | 226 +- AltairZ80/insnsa.c | 4443 ----------------------- AltairZ80/mfdc.c | 46 +- AltairZ80/n8vem.c | 60 +- AltairZ80/s100_64fdc.c | 101 +- AltairZ80/s100_adcs6.c | 129 +- AltairZ80/s100_disk1a.c | 35 +- AltairZ80/s100_disk2.c | 122 +- AltairZ80/s100_disk3.c | 115 +- AltairZ80/s100_fif.c | 2 +- AltairZ80/s100_hdc1001.c | 90 +- AltairZ80/s100_if3.c | 58 +- AltairZ80/s100_mdriveh.c | 22 +- AltairZ80/s100_mdsad.c | 172 +- AltairZ80/s100_scp300f.c | 48 +- AltairZ80/s100_selchan.c | 18 +- AltairZ80/s100_ss1.c | 118 +- AltairZ80/sim_imd.c | 16 +- AltairZ80/vfdhd.c | 55 +- AltairZ80/wd179x.c | 251 +- HP2100/hp2100_baci.c | 421 +-- HP2100/hp2100_bugfixes.txt | 618 +++- HP2100/hp2100_cpu.c | 1650 +++++---- HP2100/hp2100_cpu.h | 37 +- HP2100/hp2100_cpu0.c | 16 +- HP2100/hp2100_cpu6.c | 15 +- HP2100/hp2100_defs.h | 339 +- HP2100/hp2100_dp.c | 494 +-- HP2100/hp2100_dq.c | 407 ++- HP2100/hp2100_dr.c | 264 +- HP2100/hp2100_ds.c | 314 +- HP2100/hp2100_fp1.c | 57 +- HP2100/hp2100_ipl.c | 533 +-- HP2100/hp2100_lps.c | 338 +- HP2100/hp2100_lpt.c | 171 +- HP2100/hp2100_mpx.c | 283 +- HP2100/hp2100_ms.c | 490 +-- HP2100/hp2100_mt.c | 326 +- HP2100/hp2100_mux.c | 654 ++-- HP2100/hp2100_pif.c | 190 +- HP2100/hp2100_stddev.c | 603 +-- HP2100/hp2100_sys.c | 27 +- I1401/i1401_cpu.c | 1 + I1401/i1401_iq.c | 4 +- I7094/i7094_clk.c | 13 +- I7094/i7094_com_old.c | 1179 ------ I7094/i7094_cpu.c | 135 +- I7094/i7094_cpu1.c | 51 +- I7094/i7094_cpu1_old.c | 887 ----- I7094/i7094_cpu_old.c | 2439 ------------- I7094/i7094_defs.h | 5 +- I7094/i7094_drm.c | 88 +- I7094/i7094_mt_old.c | 861 ----- I7094/i7094_sys.c | 9 +- I7094/i7094_sys_old.c | 748 ---- LGP/lgp_defs.h | 1 - PDP10/pdp10_sys.c | 5 +- PDP11/pdp11_dc.c | 5 +- PDP11/pdp11_dl.c | 5 +- PDP11/pdp11_io.c | 2 +- PDP11/pdp11_rl.c | 856 ++++- PDP11/pdp11_rq.c | 4 +- PDP11/pdp11_rx.c | 13 +- PDP11/pdp11_ry.c | 13 +- PDP11/pdp11_tq.c | 13 +- VAX/vax780_bug_history.txt | 5 + VAX/vax780_syslist.c | 2 +- VAX/vax_cpu.c | 6 +- VAX/vax_cpu1.c | 7 +- VAX/vax_defs.h | 3 +- VAX/vax_fpa.c | 45 +- VAX/vax_octa.c | 24 +- VAX/vax_syslist.c | 2 +- Visual Studio Projects/AltairZ80.vcproj | 4 - alpha/alpha_500au_syslist.c | 49 + alpha/alpha_cpu.c | 1865 ++++++++++ alpha/alpha_defs.h | 457 +++ alpha/alpha_ev5_cons.c | 143 + alpha/alpha_ev5_defs.h | 428 +++ alpha/alpha_ev5_pal.c | 961 +++++ alpha/alpha_ev5_tlb.c | 566 +++ alpha/alpha_fpi.c | 776 ++++ alpha/alpha_fpv.c | 457 +++ alpha/alpha_io.c | 214 ++ alpha/alpha_mmu.c | 308 ++ alpha/alpha_sys.c | 814 +++++ alpha/alpha_sys_defs.h | 43 + alpha/old_pal/alpha_pal_defs.h | 208 ++ alpha/old_pal/alpha_pal_unix.c | 702 ++++ alpha/old_pal/alpha_pal_vms.c | 1780 +++++++++ doc/gri_doc.doc | Bin 0 -> 54784 bytes doc/h316_doc.doc | Bin 0 -> 82432 bytes doc/hp2100_doc.doc | Bin 0 -> 166400 bytes doc/i1401_doc.doc | Bin 0 -> 65024 bytes doc/i1620_doc.doc | Bin 0 -> 68096 bytes doc/i7094_doc.doc | Bin 0 -> 89600 bytes doc/id_doc.doc | Bin 0 -> 116224 bytes doc/lgp_doc.doc | Bin 0 -> 58880 bytes doc/nova_doc.doc | Bin 0 -> 86528 bytes doc/pdp10_doc.doc | Bin 0 -> 84480 bytes doc/pdp11_doc.doc | Bin 0 -> 231424 bytes doc/pdp18b_doc.doc | Bin 0 -> 118784 bytes doc/pdp1_doc.doc | Bin 0 -> 83456 bytes doc/pdp8_doc.doc | Bin 0 -> 109056 bytes doc/sds_doc.doc | Bin 0 -> 74240 bytes doc/simh_doc.doc | Bin 0 -> 198144 bytes doc/simh_faq.doc | Bin 0 -> 85504 bytes doc/simh_swre.doc | Bin 0 -> 101376 bytes doc/vax780_doc.doc | Bin 0 -> 125440 bytes doc/vax_doc.doc | Bin 0 -> 123392 bytes makefile | 88 +- scp.c | 18 +- sigma/Design Notes on the Sigma 7.doc | Bin 0 -> 25088 bytes sigma/sigma_bugs.txt | 149 + sigma/sigma_cis.c | 990 +++++ sigma/sigma_coc.c | 620 ++++ sigma/sigma_cpu.c | 2848 +++++++++++++++ sigma/sigma_defs.h | 478 +++ sigma/sigma_dk.c | 470 +++ sigma/sigma_doc.doc | Bin 0 -> 90624 bytes sigma/sigma_dp.c | 1278 +++++++ sigma/sigma_fp.c | 421 +++ sigma/sigma_io.c | 1497 ++++++++ sigma/sigma_io_defs.h | 276 ++ sigma/sigma_lp.c | 529 +++ sigma/sigma_map.c | 591 +++ sigma/sigma_mt.c | 645 ++++ sigma/sigma_pt.c | 297 ++ sigma/sigma_rad.c | 532 +++ sigma/sigma_rtc.c | 267 ++ sigma/sigma_sys.c | 613 ++++ sigma/sigma_tt.c | 331 ++ sim_rev.h | 94 +- sim_timer.c | 8 +- 145 files changed, 29917 insertions(+), 15649 deletions(-) delete mode 100644 0readme_38.txt create mode 100644 0readme_39.txt delete mode 100644 AltairZ80/insnsa.c delete mode 100644 I7094/i7094_com_old.c delete mode 100644 I7094/i7094_cpu1_old.c delete mode 100644 I7094/i7094_cpu_old.c delete mode 100644 I7094/i7094_mt_old.c delete mode 100644 I7094/i7094_sys_old.c create mode 100644 alpha/alpha_500au_syslist.c create mode 100644 alpha/alpha_cpu.c create mode 100644 alpha/alpha_defs.h create mode 100644 alpha/alpha_ev5_cons.c create mode 100644 alpha/alpha_ev5_defs.h create mode 100644 alpha/alpha_ev5_pal.c create mode 100644 alpha/alpha_ev5_tlb.c create mode 100644 alpha/alpha_fpi.c create mode 100644 alpha/alpha_fpv.c create mode 100644 alpha/alpha_io.c create mode 100644 alpha/alpha_mmu.c create mode 100644 alpha/alpha_sys.c create mode 100644 alpha/alpha_sys_defs.h create mode 100644 alpha/old_pal/alpha_pal_defs.h create mode 100644 alpha/old_pal/alpha_pal_unix.c create mode 100644 alpha/old_pal/alpha_pal_vms.c create mode 100644 doc/gri_doc.doc create mode 100644 doc/h316_doc.doc create mode 100644 doc/hp2100_doc.doc create mode 100644 doc/i1401_doc.doc create mode 100644 doc/i1620_doc.doc create mode 100644 doc/i7094_doc.doc create mode 100644 doc/id_doc.doc create mode 100644 doc/lgp_doc.doc create mode 100644 doc/nova_doc.doc create mode 100644 doc/pdp10_doc.doc create mode 100644 doc/pdp11_doc.doc create mode 100644 doc/pdp18b_doc.doc create mode 100644 doc/pdp1_doc.doc create mode 100644 doc/pdp8_doc.doc create mode 100644 doc/sds_doc.doc create mode 100644 doc/simh_doc.doc create mode 100644 doc/simh_faq.doc create mode 100644 doc/simh_swre.doc create mode 100644 doc/vax780_doc.doc create mode 100644 doc/vax_doc.doc create mode 100644 sigma/Design Notes on the Sigma 7.doc create mode 100644 sigma/sigma_bugs.txt create mode 100644 sigma/sigma_cis.c create mode 100644 sigma/sigma_coc.c create mode 100644 sigma/sigma_cpu.c create mode 100644 sigma/sigma_defs.h create mode 100644 sigma/sigma_dk.c create mode 100644 sigma/sigma_doc.doc create mode 100644 sigma/sigma_dp.c create mode 100644 sigma/sigma_fp.c create mode 100644 sigma/sigma_io.c create mode 100644 sigma/sigma_io_defs.h create mode 100644 sigma/sigma_lp.c create mode 100644 sigma/sigma_map.c create mode 100644 sigma/sigma_mt.c create mode 100644 sigma/sigma_pt.c create mode 100644 sigma/sigma_rad.c create mode 100644 sigma/sigma_rtc.c create mode 100644 sigma/sigma_sys.c create mode 100644 sigma/sigma_tt.c diff --git a/0readme_38.txt b/0readme_38.txt deleted file mode 100644 index 5ed20e65..00000000 --- a/0readme_38.txt +++ /dev/null @@ -1,80 +0,0 @@ -Notes For V3.8 - - -The makefile now works for Linux and most Unix's. However, for Solaris -and MacOS, you must first export the OSTYPE environment variable: - -> export OSTYPE -> make - -Otherwise, you will get build errors. - - -1. New Features - -1.1 3.8-0 - -1.1.1 SCP and Libraries - -- BREAK, NOBREAK, and SHOW BREAK with no argument will set, clear, and - show (respectively) a breakpoint at the current PC. - -1.1.2 GRI - -- Added support for the GRI-99 processor. - -1.1.3 HP2100 - -- Added support for the BACI terminal interface. -- Added support for RTE OS/VMA/EMA, SIGNAL, VIS firmware extensions. - -1.1.4 Nova - -- Added support for 64KW memory (implemented in third-party CPU's). - -1.1.5 PDP-11 - -- Added support for DC11, RC11, KE11A, KG11A. -- Added modem control support for DL11. -- Added ASCII character support for all 8b devices. - -1.2 3.8-1 - -1.2.1 SCP and libraries - -- Added capability to set line connection order for terminal multiplexers. - -1.2.2 HP2100 - -- Added support for 12620A/12936A privileged interrupt fence. -- Added support for 12792C eight-channel asynchronous multiplexer. - -1.3 3.8-2 - -1.3.1 SCP and libraries - -- Added line history capability for *nix hosts. -- Added "SHOW SHOW" and "SHOW SHOW" commands. - -1.3.2 1401 - -- Added "no rewind" option to magtape boot. - -1.3.3 PDP-11 - -- Added RD32 support to RQ -- Added debug support to RL - -1.3.4 PDP-8 - -- Added FPP support (many thanks to Rick Murphy for debugging the code) - -1.3.5 VAX-11/780 - -- Added AUTORESTART switch support, and VMS REBOOT command support - - -2. Bugs Fixed - -Please see the revision history on http://simh.trailing-edge.com or -in the source module sim_rev.h. diff --git a/0readme_39.txt b/0readme_39.txt new file mode 100644 index 00000000..d3c8fbc0 --- /dev/null +++ b/0readme_39.txt @@ -0,0 +1,184 @@ +Notes For V3.9 + + +The makefile now works for Linux and most Unix's. However, for Solaris +and MacOS, you must first export the OSTYPE environment variable: + +> export OSTYPE +> make + +Otherwise, you will get build errors. + + +1. New Features + +1.1 3.9-0 + +1.1.1 SCP and libraries + + - added *nix READLINE support (Mark Pizzolato) + - added "SHOW SHOW" and "SHOW SHOW" commands (Mark Pizzolato) + - added support for BREAK key on Windows (Mark Pizzolato) + + +1.1.2 PDP-8 + + - floating point processor is now enabled + +2. Bugs Fixed + +Please see the revision history on http://simh.trailing-edge.com or +in the source module sim_rev.h. + +3. Status Report + +This is the last release of SimH for which I will be sole editor. After this +release, the source is moving to a public repository: + + + +under the general editorship of Dave Hittner and Mark Pizzolato. The status +of the individual simulators is as follows: + +3.1 PDP-1 + +Stable and working; runs available software. + +3.2 PDP-4/7/9/15 + +Stable and working; runs available software. + +3.3 PDP-8 + +Stable and working; runs available software. + +3.4 PDP-10 [KS-10 only] + +Stable and working; runs available software. + +3.5 PDP-11 + +Stable and working; runs available system software. The emulation of individual +models has numerous errors of detail, which prevents many diagnostics from +running correctly. + +3.6 VAX-11/780 + +Stable and working; runs available software. + +3.7 MicroVAX 3900 (VAX) + +Stable and working; runs available software. Thanks to the kind generosity of +Camiel Vanderhoeven, this simulator has been verified with AXE, the VAX +architectural exerciser. + +3.8 Nova + +Stable and working; runs available software. + +3.9 Eclipse + +Stable and working, but not really supported. There is no Eclipse-specific +software available under a hobbyist license. + +3.10 Interdata 16b + +Stable and working, but no software for it has been found, other than +diagnostics. + +3.11 Interdata 32b + +Stable and working; runs 32b UNIX and diagnostics. + +3.12 IBM 1401 + +Stable and working; runs available software. + +3.13 IBM 1620 + +Hand debug only. No software for it has been found or tested. + +3.14 IBM 7094 + +Stable and working as a stock system; runs IBSYS. The CTSS extensions +have not been debugged. + +3.15 IBM S/3 + +Stable and working, but not really supported. Runs available software. + +3.16 IBM 1130 + +Stable and working; runs available software. Supported and edited by +Brian Knittel. + +3.17 HP 2100/1000 + +Stable and working; runs available software. Supported and edited by +Dave Bryan. + +3.18 Honeywell 316/516 + +Stable and working; runs available software. + +3.19 GRI-909/99 + +Hand debug only. No software for it has been found or tested. + +3.20 SDS-940 + +Hand debug only, and a few diagnostics. + +3.21 LGP-30 + +Unfinished; hand debug only. Does not run available software, probably +due to my misunderstanding of the LGP-30 operational procedures. + +3.22 Altair (original 8080 version) + +Stable and working, but not really supported. Runs available software. + +3.23 AltairZ80 (Z80 version) + +Stable and working; runs available software. Supported and edited by +Peter Schorn. + +3.24 SWTP 6800 + +Stable and working; runs available software. Supported and edited by +Bill Beech + +3.25 Sigma 32b + +Incomplete; more work is needed on the peripherals for accuracy. + +3.26 Alpha + +Incomplete; essentially just an EV-5 (21164) chip emulator. + +4. Suggestions for Future Work + +4.1 General Structure + + - Multi-threading, to allow true concurrency between SCP and the simulator + - Graphics device support, particularly for the PDP-1 and PDP-11 + +4.2 Current Simulators + + - PDP-1 graphics, to run Space War + - PDP-11 GT40 graphics, to run Lunar Lander + - PDP-15 MUMPS-15 + - Interdata native OS debug, both 16b and 32b + - SDS 940 timesharing operating system debug + - IBM 7094 CTSS feature debug and operating system debug + - IBM 1620 debug and software + - GRI-909 software + - Sigma 32b completion and debug + - LGP-30 debug + +4.3 Possible Future Simulators + + - Data General MV8000 (if a hobbyist license can be obtained for AOS) + - Alpha simulator + - HP 3000 (16b) simulator with MPE + diff --git a/AltairZ80/altairz80_cpu.c b/AltairZ80/altairz80_cpu.c index 5c19ed64..7b4e7a5c 100644 --- a/AltairZ80/altairz80_cpu.c +++ b/AltairZ80/altairz80_cpu.c @@ -1,6 +1,6 @@ /* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -191,6 +191,8 @@ uint8 GetByteDMA(const uint32 Addr); void PutByteDMA(const uint32 Addr, const uint32 Value); int32 getBankSelect(void); void setBankSelect(const int32 b); +uint32 getClockFrequency(void); +void setClockFrequency(const uint32 Value); uint32 getCommon(void); t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag); uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, @@ -1867,6 +1869,17 @@ t_stat sim_instr (void) { return result; } +static int32 clockHasChanged = FALSE; + +uint32 getClockFrequency(void) { + return clockFrequency; +} + +void setClockFrequency(const uint32 Value) { + clockFrequency = Value; + clockHasChanged = TRUE; +} + static t_stat sim_instr_mmu (void) { extern int32 sim_interval; extern t_bool sim_brk_pend[SIM_BKPT_N_SPC]; @@ -1916,22 +1929,29 @@ static t_stat sim_instr_mmu (void) { startTime = sim_os_msec(); tStatesInSlice = sliceLength*clockFrequency; } - else { /* make sure that sim_os_msec() is not called later */ + else /* make sure that sim_os_msec() is not called later */ clockFrequency = startTime = tStatesInSlice = 0; - } /* main instruction fetch/decode loop */ while (switch_cpu_now == TRUE) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ #if !UNIX_PLATFORM - if ((reason = sim_os_poll_kbd()) == SCPE_STOP) { /* poll on platforms without reliable signalling */ + if ((reason = sim_os_poll_kbd()) == SCPE_STOP) /* poll on platforms without reliable signalling */ break; - } #endif - if ( (reason = sim_process_event()) ) + if ((reason = sim_process_event())) break; - else - specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ; + if (clockHasChanged) { + clockHasChanged = FALSE; + 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; + } + specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ; } if (specialProcessing) { /* quick check for special processing */ @@ -6442,6 +6462,7 @@ static void cpu_clear(void) { mmu_table[i] = EMPTY_PAGE; if (cpu_unit.flags & UNIT_CPU_ALTAIRROM) install_ALTAIRbootROM(); + clockHasChanged = FALSE; } static t_stat cpu_clear_command(UNIT *uptr, int32 value, char *cptr, void *desc) { diff --git a/AltairZ80/altairz80_cpu_nommu.c b/AltairZ80/altairz80_cpu_nommu.c index fa1a9221..a390ca4b 100644 --- a/AltairZ80/altairz80_cpu_nommu.c +++ b/AltairZ80/altairz80_cpu_nommu.c @@ -1,6 +1,6 @@ /* altairz80_cpu_opt.c: MITS Altair CPU (8080 and Z80) - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn 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/AltairZ80/altairz80_defs.h b/AltairZ80/altairz80_defs.h index c16f7121..162fd7c9 100644 --- a/AltairZ80/altairz80_defs.h +++ b/AltairZ80/altairz80_defs.h @@ -1,6 +1,6 @@ /* altairz80_defs.h: MITS Altair simulator definitions - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -43,7 +43,7 @@ #define RESOURCE_TYPE_MEMORY 1 #define RESOURCE_TYPE_IO 2 -#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ +#define NUM_OF_DSK 16 /* NUM_OF_DSK must be power of two */ #define LDA_INSTRUCTION 0x3e /* op-code for LD A,<8-bit value> instruction */ #define UNIT_NO_OFFSET_1 0x37 /* LD A, */ #define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | */ diff --git a/AltairZ80/altairz80_doc.pdf b/AltairZ80/altairz80_doc.pdf index 1d9f22d9814301a3fed9d345b8d1bd1d78f5718b..a09c74bd4789a93d959b385203c8eeb2d6055f09 100644 GIT binary patch literal 507457 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℘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

(|5V%n*3>;& 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%0DV?Ock#pV(vQ%OB~6R2}mJ| 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 literal 416146 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

Y@89G7#ML&X&)5gyGvw_ElF$Jq>7&nhM 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

YYkpg#1uI%td7gULc%H~@Hj|=Eq3DIA1 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%0AW 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 D*h)3a diff --git a/AltairZ80/altairz80_dsk.c b/AltairZ80/altairz80_dsk.c index 070b8b6f..4c7e9742 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-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -152,18 +152,20 @@ void install_ALTAIRbootROM(void); /* currently selected drive (values are 0 .. NUM_OF_DSK) current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */ static int32 current_disk = NUM_OF_DSK; -static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, + MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, + MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS }; static int32 in9_count = 0; static int32 in9_message = FALSE; static int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */ static int32 warnLevelDSK = 3; -static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static int32 warnDSK10 = 0; static int32 warnDSK11 = 0; static int32 warnDSK12 = 0; @@ -215,7 +217,15 @@ static UNIT dsk_unit[] = { { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, }; static REG dsk_reg[] = { @@ -244,10 +254,6 @@ static MTAB dsk_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if (dsk_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB dsk_dt[] = { { "IN", IN_MSG }, @@ -262,7 +268,7 @@ static DEBTAB dsk_dt[] = { DEVICE dsk_dev = { "DSK", dsk_unit, dsk_reg, dsk_mod, - 8, 10, 31, 1, 8, 8, + NUM_OF_DSK, 10, 31, 1, 8, 8, NULL, NULL, &dsk_reset, &dsk_boot, NULL, NULL, NULL, (DEV_DISABLE | DEV_DEBUG), 0, @@ -281,6 +287,11 @@ static t_stat dsk_reset(DEVICE *dptr) { for (i = 0; i < NUM_OF_DSK; i++) { warnLock[i] = 0; warnAttached[i] = 0; + current_track[i] = 0; + current_sector[i] = 0; + current_byte[i] = 0; + current_flag[i] = 0; + tracks[i] = MAX_TRACKS; } warnDSK10 = 0; warnDSK11 = 0; @@ -332,23 +343,30 @@ static void writebuf(void) { dskbuf[i++] = 0; uptr = dsk_dev.units + current_disk; if (((uptr -> flags) & UNIT_DSK_WLK) == 0) { /* write enabled */ - TRACE_PRINT(WRITE_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x0a (WRITE) D%d T%d S%d" NLP, current_disk, PCX, - current_disk, current_track[current_disk], current_sector[current_disk])); + sim_debug(WRITE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " OUT 0x0a (WRITE) D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); if (dskseek(uptr)) { - printf("DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d" NLP, current_disk, - PCX, current_disk, current_track[current_disk], current_sector[current_disk]); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); } rtn = sim_fwrite(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); if (rtn != DSK_SECTSIZE) { - printf("DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d" NLP, current_disk, - PCX, current_track[current_disk], current_sector[current_disk], rtn); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d\n", + current_disk, PCX, current_track[current_disk], + current_sector[current_disk], rtn); } } else if ( (dsk_dev.dctrl & VERBOSE_MSG) && (warnLock[current_disk] < warnLevelDSK) ) { /* write locked - print warning message if required */ warnLock[current_disk]++; -/*05*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt to write to locked DSK%d - ignored." NLP, - current_disk, PCX, current_disk); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " Attempt to write to locked DSK%d - ignored.\n", + current_disk, PCX, current_disk); } current_flag[current_disk] &= 0xfe; /* ENWD off */ current_byte[current_disk] = 0xff; @@ -381,8 +399,10 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK10 < warnLevelDSK)) { warnDSK10++; -/*01*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of IN 0x08 on unattached disk - ignored." NLP, - current_disk, PCX); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT + " Attempt of IN 0x08 on unattached disk - ignored.\n", + current_disk, PCX); } return 0xff; /* no drive selected - can do nothing */ } @@ -392,14 +412,16 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { /* OUT: Controller set/reset/enable/disable */ if (dirty) /* implies that current_disk < NUM_OF_DSK */ writebuf(); - TRACE_PRINT(OUT_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x08: %x" NLP, current_disk, PCX, data)); + sim_debug(OUT_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x08: %x\n", current_disk, PCX, 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 ( (dsk_dev.dctrl & VERBOSE_MSG) && (warnAttached[current_disk] < warnLevelDSK) ) { warnAttached[current_disk]++; -/*02*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt to select unattached DSK%d - ignored." NLP, - current_disk, PCX, current_disk); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT + " Attempt to select unattached DSK%d - ignored.\n", + current_disk, PCX, current_disk); } current_disk = NUM_OF_DSK; } @@ -407,8 +429,8 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { current_sector[current_disk] = 0xff; /* reset internal counters */ current_byte[current_disk] = 0xff; current_flag[current_disk] = data & 0x80 ? 0 /* disable drive */ : - (current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ : - 0x1a); /* enable: head move true */ + (current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ : + 0x1a); /* enable: head move true */ } return 0; /* ignored since OUT */ } @@ -419,8 +441,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK11 < warnLevelDSK)) { warnDSK11++; -/*03*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of %s 0x09 on unattached disk - ignored." NLP, - current_disk, PCX, selectInOut(io)); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT + " Attempt of %s 0x09 on unattached disk - ignored.\n", + current_disk, PCX, selectInOut(io)); } return 0; /* no drive selected - can do nothing */ } @@ -430,10 +454,11 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { in9_count++; if ((dsk_dev.dctrl & SECTOR_STUCK_MSG) && (in9_count > 2 * DSK_SECT) && (!in9_message)) { in9_message = TRUE; - printf("DSK%i: " ADDRESS_FORMAT " Looping on sector find." NLP, - current_disk, PCX); + sim_debug(SECTOR_STUCK_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " Looping on sector find.\n", + current_disk, PCX); } - TRACE_PRINT(IN_MSG, ("DSK%i: " ADDRESS_FORMAT " IN 0x09" NLP, current_disk, PCX)); + sim_debug(IN_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " IN 0x09\n", current_disk, PCX); if (dirty) /* implies that current_disk < NUM_OF_DSK */ writebuf(); if (current_flag[current_disk] & 0x04) { /* head loaded? */ @@ -442,7 +467,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { current_sector[current_disk] = 0; current_byte[current_disk] = 0xff; return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */ - | 0xc0); /* set on 'unused' bits */ + | 0xc0); /* set on 'unused' bits */ } else return 0; /* head not loaded - return 0 */ } @@ -450,12 +475,12 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { in9_count = 0; /* drive functions */ - TRACE_PRINT(OUT_MSG, ("DSK%i: " ADDRESS_FORMAT " OUT 0x09: %x" NLP, current_disk, PCX, data)); + sim_debug(OUT_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x09: %x\n", current_disk, PCX, data); if (data & 0x01) { /* step head in */ - if ((dsk_dev.dctrl & TRACK_STUCK_MSG) && (current_track[current_disk] == (tracks[current_disk] - 1))) { - printf("DSK%i: " ADDRESS_FORMAT " Unnecessary step in." NLP, - current_disk, PCX); - } + if (current_track[current_disk] == (tracks[current_disk] - 1)) + sim_debug(TRACK_STUCK_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " Unnecessary step in.\n", + current_disk, PCX); current_track[current_disk]++; if (current_track[current_disk] > (tracks[current_disk] - 1)) current_track[current_disk] = (tracks[current_disk] - 1); @@ -466,9 +491,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { } if (data & 0x02) { /* step head out */ - if ((dsk_dev.dctrl & TRACK_STUCK_MSG) && (current_track[current_disk] == 0)) { - printf("DSK%i: " ADDRESS_FORMAT " Unnecessary step out." NLP, current_disk, PCX); - } + if (current_track[current_disk] == 0) + sim_debug(TRACK_STUCK_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " Unnecessary step out.\n", + current_disk, PCX); current_track[current_disk]--; if (current_track[current_disk] < 0) { current_track[current_disk] = 0; @@ -513,8 +539,10 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; -/*04*/ printf("DSK%i: " ADDRESS_FORMAT " Attempt of %s 0x0a on unattached disk - ignored." NLP, - current_disk, PCX, selectInOut(io)); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT + " Attempt of %s 0x0a on unattached disk - ignored.\n", + current_disk, PCX, selectInOut(io)); } return 0; } @@ -525,24 +553,29 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { if (io == 0) { if (current_byte[current_disk] >= DSK_SECTSIZE) { /* physically read the sector */ - TRACE_PRINT(READ_MSG, - ("DSK%i: " ADDRESS_FORMAT " IN 0x0a (READ) D%d T%d S%d" NLP, current_disk, - PCX, current_disk, current_track[current_disk], current_sector[current_disk])); + sim_debug(READ_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " IN 0x0a (READ) D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); for (i = 0; i < DSK_SECTSIZE; i++) dskbuf[i] = 0; if (dskseek(uptr)) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; - printf("DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d" NLP, current_disk, - PCX, current_disk, current_track[current_disk], current_sector[current_disk]); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); } } rtn = sim_fread(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); if (rtn != DSK_SECTSIZE) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; - printf("DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d" NLP, current_disk, - PCX, current_disk, current_track[current_disk], current_sector[current_disk]); + sim_debug(VERBOSE_MSG, &dsk_dev, + "DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d\n", + current_disk, PCX, current_disk, + current_track[current_disk], current_sector[current_disk]); } } current_byte[current_disk] = 0; diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index e90bc90e..085b17e5 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-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -248,10 +248,6 @@ static MTAB hdsk_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if (hdsk_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB hdsk_dt[] = { { "READ", READ_MSG }, @@ -552,32 +548,37 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { static int32 checkParameters(void) { UNIT *uptr; if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i does not exist, will use HDSK0 instead." NLP, - selectedDisk, PCX, selectedDisk)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Disk %i does not exist, will use HDSK0 instead.\n", + selectedDisk, PCX, selectedDisk); selectedDisk = 0; } uptr = &hdsk_dev.units[selectedDisk]; if ((hdsk_dev.units[selectedDisk].flags & UNIT_ATT) == 0) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i is not attached." NLP, - selectedDisk, PCX, selectedDisk)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Disk %i is not attached.\n", selectedDisk, PCX, selectedDisk); return FALSE; /* cannot read or write */ } if ((selectedSector < 0) || (selectedSector >= uptr -> HDSK_SECTORS_PER_TRACK)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Constraint violation 0 <= Sector=%02d < %d, will use sector 0 instead." NLP, - selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Constraint violation 0 <= Sector=%02d < %d, will use sector 0 instead.\n", + selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK); selectedSector = 0; } if ((selectedTrack < 0) || (selectedTrack >= uptr -> HDSK_NUMBER_OF_TRACKS)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Constraint violation 0 <= Track=%04d < %04d, will use track 0 instead." NLP, - selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Constraint violation 0 <= Track=%04d < %04d, will use track 0 instead.\n", + selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS); selectedTrack = 0; } selectedDMA &= ADDRMASK; - if ((hdsk_dev.dctrl & READ_MSG) && (hdskLastCommand == HDSK_READ)) - printf("HDSK%d " ADDRESS_FORMAT " Read Track=%04d Sector=%02d Len=%04d DMA=%04x" NLP, + if (hdskLastCommand == HDSK_READ) + sim_debug(READ_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT + " Read Track=%04d Sector=%02d Len=%04d DMA=%04x\n", selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); - if ((hdsk_dev.dctrl & WRITE_MSG) && (hdskLastCommand == HDSK_WRITE)) - printf("HDSK%d " ADDRESS_FORMAT " Write Track=%04d Sector=%02d Len=%04d DMA=%04x" NLP, + if (hdskLastCommand == HDSK_WRITE) + sim_debug(WRITE_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT + " Write Track=%04d Sector=%02d Len=%04d DMA=%04x\n", selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); return TRUE; } @@ -592,8 +593,9 @@ static int32 doSeek(void) { if (sim_fseek(uptr -> fileref, sectorSize * (uptr -> HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) + dpb[uptr -> HDSK_FORMAT_TYPE].offset, SEEK_SET)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not access Sector=%02d[=%02d] Track=%04d." NLP, - selectedDisk, PCX, selectedSector, hostSector, selectedTrack)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not access Sector=%02d[=%02d] Track=%04d.\n", + selectedDisk, PCX, selectedSector, hostSector, selectedTrack); return CPM_ERROR; } return CPM_OK; @@ -611,8 +613,9 @@ static int32 doRead(void) { if (sim_fread(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref) != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) hdskbuf[i] = CPM_EMPTY; - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not read Sector=%02d Track=%04d." NLP, - selectedDisk, PCX, selectedSector, selectedTrack)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not read Sector=%02d Track=%04d.\n", + selectedDisk, PCX, selectedSector, selectedTrack); return CPM_OK; /* allows the creation of empty hard disks */ } for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) @@ -632,14 +635,16 @@ static int32 doWrite(void) { hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref); if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d Result=%d." NLP, - selectedDisk, PCX, selectedSector, selectedTrack, (int)rtn)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not write Sector=%02d Track=%04d Result=%zd.\n", + selectedDisk, PCX, selectedSector, selectedTrack, rtn); return CPM_ERROR; } } else { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write to locked disk Sector=%02d Track=%04d." NLP, - selectedDisk, PCX, selectedSector, selectedTrack)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not write to locked disk Sector=%02d Track=%04d.\n", + selectedDisk, PCX, selectedSector, selectedTrack); return CPM_ERROR; } return CPM_OK; @@ -660,8 +665,9 @@ static int32 hdsk_in(const int32 port) { hdskLastCommand = HDSK_NONE; return parameterBlock[parameterCount - 1]; } - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal IN command detected (port=%03xh, cmd=%d, pos=%d)." NLP, - selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).\n", + selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition); return CPM_OK; } @@ -745,8 +751,9 @@ static int32 hdsk_out(const int32 port, const int32 data) { if ((HDSK_RESET <= data) && (data <= HDSK_PARAM)) hdskLastCommand = data; else { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal OUT command detected (port=%03xh, cmd=%d)." NLP, - selectedDisk, PCX, port, data)); + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Illegal OUT command detected (port=%03xh, cmd=%d).\n", + selectedDisk, PCX, port, data); hdskLastCommand = HDSK_RESET; } hdskCommandPosition = 0; diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index c4fa016c..fa5e5103 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -1,6 +1,6 @@ /* altairz80_net.c: networking capability - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -96,10 +96,6 @@ static MTAB net_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if (net_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB net_dt[] = { { "ACCEPT", ACCEPT_MSG }, @@ -215,7 +211,7 @@ static t_stat net_svc(UNIT *uptr) { s = sim_accept_conn(serviceDescriptor[1].masterSocket, NULL); if (s != INVALID_SOCKET) { serviceDescriptor[i].ioSocket = s; - TRACE_PRINT(ACCEPT_MSG, ("NET: " ADDRESS_FORMAT " Accepted connection %i with socket %i." NLP, PCX, i, s)); + sim_debug(ACCEPT_MSG, &net_dev, "NET: " ADDRESS_FORMAT " Accepted connection %i with socket %i.\n", PCX, i, s); } } } @@ -232,8 +228,7 @@ static t_stat net_svc(UNIT *uptr) { r = sim_read_sock(serviceDescriptor[i].ioSocket, svcBuffer, BUFFER_LENGTH - serviceDescriptor[i].inputSize); if (r == -1) { - TRACE_PRINT(DROP_MSG, ("NET: " ADDRESS_FORMAT " Drop connection %i with socket %i." NLP, - PCX, i, serviceDescriptor[i].ioSocket)); + sim_debug(DROP_MSG, &net_dev, "NET: " ADDRESS_FORMAT " Drop connection %i with socket %i.\n", PCX, i, serviceDescriptor[i].ioSocket); sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); serviceDescriptor[i].ioSocket = 0; serviceDescriptor_reset(i); @@ -303,8 +298,7 @@ int32 netData(const int32 port, const int32 io, const int32 data) { serviceDescriptor[i].inputPosRead = 0; serviceDescriptor[i].inputSize--; } - TRACE_PRINT(IN_MSG, ("NET: " ADDRESS_FORMAT " IN(%i)=%03xh (%c)" NLP, PCX, port, (result & 0xff), - (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?')); + sim_debug(IN_MSG, &net_dev, "NET: " ADDRESS_FORMAT " IN(%i)=%03xh (%c)\n", PCX, port, (result & 0xff), (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'); return result; } else { /* OUT */ @@ -319,8 +313,7 @@ int32 netData(const int32 port, const int32 io, const int32 data) { serviceDescriptor[i].outputPosWrite = 0; serviceDescriptor[i].outputSize++; } - TRACE_PRINT(OUT_MSG, ("NET: " ADDRESS_FORMAT " OUT(%i)=%03xh (%c)" NLP, PCX, port, data, - (32 <= data) && (data <= 127) ? data : '?')); + sim_debug(OUT_MSG, &net_dev, "NET: " ADDRESS_FORMAT " OUT(%i)=%03xh (%c)\n", PCX, port, data, (32 <= data) && (data <= 127) ? data : '?'); return 0; } } diff --git a/AltairZ80/altairz80_sio.c b/AltairZ80/altairz80_sio.c index 6249546d..94a35f81 100644 --- a/AltairZ80/altairz80_sio.c +++ b/AltairZ80/altairz80_sio.c @@ -1,6 +1,6 @@ /* altairz80_sio.c: MITS Altair serial I/O card - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -62,6 +62,23 @@ #include #endif +uint8 *URLContents(const char *URL, uint32 *length); +#ifndef URL_READER_SUPPORT +#define RESULT_BUFFER_LENGTH 1024 +#define RESULT_LEAD_IN "URL is not supported on this platform. START URL \"" +#define RESULT_LEAD_OUT "\" URL END." +uint8 *URLContents(const char *URL, uint32 *length) { + char str[RESULT_BUFFER_LENGTH] = RESULT_LEAD_IN; + char *result; + strncat(str, URL, RESULT_BUFFER_LENGTH - strlen(RESULT_LEAD_IN) - strlen(RESULT_LEAD_OUT) - 1); + strcat(str, RESULT_LEAD_OUT); + result = malloc(strlen(str)); + strcpy(result, str); + *length = strlen(str); + return (uint8*)result; +} +#endif + /* Debug flags */ #define IN_MSG (1 << 0) #define OUT_MSG (1 << 1) @@ -143,6 +160,8 @@ extern uint32 getCommon(void); extern uint8 GetBYTEWrapper(const uint32 Addr); extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern uint32 getClockFrequency(void); +extern void setClockFrequency(const uint32 Value); extern int32 chiptype; extern const t_bool rtc_avail; @@ -154,10 +173,6 @@ extern UNIT cpu_unit; extern volatile int32 stop_cpu; extern int32 sim_interval; -#define TRACE_PRINT(device, level, args) if (device.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB generic_dt[] = { { "IN", IN_MSG }, @@ -213,6 +228,11 @@ static int32 lastCPMStatus = 0; /* result of last attachCPM comm static int32 lastCommand = 0; /* most recent command processed on port 0xfeh */ static int32 getCommonPos = 0; /* determines state for sending the 'common' register */ +/* CPU Clock Frequency related */ +static uint32 newClockFrequency; +static int32 setClockFrequencyPos = 0; /* determines state for sending the clock frequency */ +static int32 getClockFrequencyPos = 0; /* determines state for receiving the clock frequency */ + /* support for wild card expansion */ #if UNIX_PLATFORM static glob_t globS; @@ -437,7 +457,7 @@ static void pollConnection(void) { /* reset routines */ static t_stat sio_reset(DEVICE *dptr) { int32 i; - TRACE_PRINT(sio_dev, VERBOSE_MSG, ("SIO: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT " Reset\n", PCX); sio_unit.u3 = FALSE; /* no character in terminal input buffer */ sio_unit.buf = 0; resetSIOWarningFlags(); @@ -452,7 +472,7 @@ static t_stat sio_reset(DEVICE *dptr) { } static t_stat ptr_reset(DEVICE *dptr) { - TRACE_PRINT(ptr_dev, VERBOSE_MSG, ("PTR: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT " Reset\n", PCX); resetSIOWarningFlags(); ptr_unit.u3 = FALSE; /* End Of File not yet reached */ ptr_unit.buf = 0; @@ -464,7 +484,7 @@ static t_stat ptr_reset(DEVICE *dptr) { } static t_stat ptp_reset(DEVICE *dptr) { - TRACE_PRINT(ptp_dev, VERBOSE_MSG, ("PTP: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(VERBOSE_MSG, &ptp_dev, "PTP: " ADDRESS_FORMAT " Reset\n", PCX); resetSIOWarningFlags(); sim_map_resource(0x12, 1, RESOURCE_TYPE_IO, &sio1s, dptr->flags & DEV_DIS); sim_map_resource(0x13, 1, RESOURCE_TYPE_IO, &sio1d, dptr->flags & DEV_DIS); @@ -506,10 +526,10 @@ typedef struct { int32 sio_can_read; /* bit mask to indicate that one can read from this port */ int32 sio_cannot_read; /* bit mask to indicate that one cannot read from this port */ int32 sio_can_write; /* bit mask to indicate that one can write to this port */ - t_bool hasReset; /* TRUE iff SIO has reset command */ + int32 hasReset; /* TRUE iff SIO has reset command */ int32 sio_reset; /* reset command */ - t_bool hasOUT; /* TRUE iff port supports OUT command */ - t_bool isBuiltin; /* TRUE iff mapping is built in */ + int32 hasOUT; /* TRUE iff port supports OUT command */ + int32 isBuiltin; /* TRUE iff mapping is built in */ } SIO_PORT_INFO; static SIO_PORT_INFO port_table[PORT_TABLE_SIZE] = { @@ -677,18 +697,20 @@ static int32 sio0sCore(const int32 port, const int32 io, const int32 data) { if (spi.hasReset && (data == spi.sio_reset)) { /* reset command */ if (!sio_unit.u4) /* only reset for regular console I/O */ sio_unit.u3 = FALSE; /* indicate that no character is available */ - TRACE_PRINT(sio_dev, CMD_MSG, - ("\tSIO_S: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data)); + sim_debug(CMD_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT + " Command OUT(0x%03x) = 0x%02x\n", PCX, port, data); } return 0x00; /* ignored since OUT */ } int32 sio0s(const int32 port, const int32 io, const int32 data) { const int32 result = sio0sCore(port, io, data); - if ((io == 0) && (sio_dev.dctrl & IN_MSG)) - printf("\tSIO_S: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x" NLP, PCX, port, result); - else if ((io) && (sio_dev.dctrl & OUT_MSG)) - printf("\tSIO_S: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x" NLP, PCX, port, data); + if (io == 0) + sim_debug(IN_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT + " IN(0x%03x) = 0x%02x\n", PCX, port, result); + else if (io) + sim_debug(OUT_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT + " OUT(0x%03x) = 0x%02x\n", PCX, port, data); return result; } @@ -701,8 +723,9 @@ static int32 sio0dCore(const int32 port, const int32 io, const int32 data) { if (io == 0) { /* IN */ if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4)) return mapCharacter(tmxr_getc_ln(&TerminalLines[spi.terminalLine])); - if ((!sio_unit.u3) && (sio_dev.dctrl & BUFFER_EMPTY_MSG)) - printf("\tSIO_D: " ADDRESS_FORMAT " IN(0x%03x) for empty character buffer" NLP, PCX, port); + if (!sio_unit.u3) + sim_debug(BUFFER_EMPTY_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT + " IN(0x%03x) for empty character buffer\n", PCX, port); sio_unit.u3 = FALSE; /* no character is available any more */ return mapCharacter(sio_unit.buf); /* return previous character */ } /* OUT follows, no fall-through from IN */ @@ -730,10 +753,12 @@ static char* printable(char* result, int32 data, const int32 isIn) { int32 sio0d(const int32 port, const int32 io, const int32 data) { char buffer[8]; const int32 result = sio0dCore(port, io, data); - if ((io == 0) && (sio_dev.dctrl & IN_MSG)) - printf("\tSIO_D: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x%s" NLP, PCX, port, result, printable(buffer, result, TRUE)); - else if ((io) && (sio_dev.dctrl & OUT_MSG)) - printf("\tSIO_D: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x%s" NLP, PCX, port, data, printable(buffer, data, FALSE)); + if (io == 0) + sim_debug(IN_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT + " IN(0x%03x) = 0x%02x%s\n", PCX, port, result, printable(buffer, result, TRUE)); + else if (io) + sim_debug(OUT_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT + " OUT(0x%03x) = 0x%02x%s\n", PCX, port, data, printable(buffer, data, FALSE)); return result; } @@ -746,7 +771,8 @@ static int32 sio1sCore(const int32 port, const int32 io, const int32 data) { if ((ptr_unit.flags & UNIT_ATT) == 0) { /* PTR is not attached */ if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*06*/ printf("PTR: " ADDRESS_FORMAT " Attempt to test status of unattached PTR[0x%02x]. 0x02 returned." NLP, PCX, port); +/*06*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT + " Attempt to test status of unattached PTR[0x%02x]. 0x02 returned.\n", PCX, port); } return SIO_CAN_WRITE; } @@ -756,18 +782,26 @@ static int32 sio1sCore(const int32 port, const int32 io, const int32 data) { } /* OUT follows */ if (data == SIO_RESET) { ptr_unit.u3 = FALSE; /* reset EOF indicator */ - TRACE_PRINT(ptr_dev, CMD_MSG, - ("PTR: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data)); + sim_debug(CMD_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT + " Command OUT(0x%03x) = 0x%02x\n", PCX, port, data); } return 0x00; /* ignored since OUT */ } int32 sio1s(const int32 port, const int32 io, const int32 data) { const int32 result = sio1sCore(port, io, data); - if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG))) - printf("PTP/PTR_S: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result); - else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG))) - printf("PTP/PTR_S: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data); + if (io == 0) { + sim_debug(IN_MSG, &ptr_dev, "PTR_S: " ADDRESS_FORMAT + " IN(0x%02x) = 0x%02x\n", PCX, port, result); + sim_debug(IN_MSG, &ptp_dev, "PTP_S: " ADDRESS_FORMAT + " IN(0x%02x) = 0x%02x\n", PCX, port, result); + } + else if (io) { + sim_debug(OUT_MSG, &ptr_dev, "PTR_S: " ADDRESS_FORMAT + " OUT(0x%02x) = 0x%02x\n", PCX, port, data); + sim_debug(OUT_MSG, &ptp_dev, "PTP_S: " ADDRESS_FORMAT + " OUT(0x%02x) = 0x%02x\n", PCX, port, data); + } return result; } @@ -778,14 +812,16 @@ static int32 sio1dCore(const int32 port, const int32 io, const int32 data) { if (ptr_unit.u3) { /* EOF reached, no more data available */ if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnPTREOF < warnLevelSIO)) { warnPTREOF++; -/*07*/ printf("PTR: " ADDRESS_FORMAT " PTR[0x%02x] attempted to read past EOF. 0x00 returned." NLP, PCX, port); +/*07*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT + " PTR[0x%02x] attempted to read past EOF. 0x00 returned.\n", PCX, port); } return 0x00; } if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */ if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*08*/ printf("PTR: " ADDRESS_FORMAT " Attempt to read from unattached PTR[0x%02x]. 0x00 returned." NLP, PCX, port); +/*08*/ sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT + " Attempt to read from unattached PTR[0x%02x]. 0x00 returned.\n", PCX, port); } return 0x00; } @@ -800,17 +836,26 @@ static int32 sio1dCore(const int32 port, const int32 io, const int32 data) { /* else ignore data */ else if ((ptp_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTP < warnLevelSIO)) { warnUnattachedPTP++; -/*09*/ printf("PTP: " ADDRESS_FORMAT " Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored." NLP, PCX, data, port); +/*09*/ sim_debug(VERBOSE_MSG, &ptp_dev, "PTP: " ADDRESS_FORMAT + " Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored.\n", PCX, data, port); } return 0x00; /* ignored since OUT */ } int32 sio1d(const int32 port, const int32 io, const int32 data) { const int32 result = sio1dCore(port, io, data); - if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG))) - printf("PTP/PTR_D: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result); - else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG))) - printf("PTP/PTR_D: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data); + if (io == 0) { + sim_debug(IN_MSG, &ptr_dev, "PTR_D: " ADDRESS_FORMAT + " IN(0x%02x) = 0x%02x\n", PCX, port, result); + sim_debug(IN_MSG, &ptp_dev, "PTP_D: " ADDRESS_FORMAT + " IN(0x%02x) = 0x%02x\n", PCX, port, result); + } + else if (io) { + sim_debug(OUT_MSG, &ptr_dev, "PTR_D: " ADDRESS_FORMAT + " OUT(0x%02x) = 0x%02x\n", PCX, port, data); + sim_debug(OUT_MSG, &ptp_dev, "PTP_D: " ADDRESS_FORMAT + " OUT(0x%02x) = 0x%02x\n", PCX, port, data); + } return result; } @@ -962,9 +1007,13 @@ int32 nulldev(const int32 port, const int32 io, const int32 data) { if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) { warnUnassignedPort++; if (io == 0) - printf("SIO: " ADDRESS_FORMAT " Attempt to input from unassigned port 0x%04x - ignored." NLP, PCX, port); + sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT + " Attempt to input from unassigned port 0x%04x - ignored.\n", + PCX, port); else - printf("SIO: " ADDRESS_FORMAT " Attempt to output 0x%02x to unassigned port 0x%04x - ignored." NLP, PCX, data, port); + sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT + " Attempt to output 0x%02x to unassigned port 0x%04x - ignored.\n", + PCX, data, port); } return io == 0 ? 0xff : 0; } @@ -1010,7 +1059,17 @@ static int32 fromBCD(const int32 x) { Note: The calling program must request all bytes of the result. Otherwise the pseudo device is left in an undefined state. - 4) Commands requiring parameters and returning results do not exist currently. + 4) For commands that do require parameters and return results + ld a, + out (0feh),a + ld a, + out (0feh),a + ld a, + out (0feh),a + ... ; send all parameters + in a,(0feh) ; contains first byte of result + in a,(0feh) ; contains second byte of result + ... */ @@ -1044,12 +1103,14 @@ enum simhPseudoDeviceCommands { /* do not change order or remove commands, add o readStopWatchCmd, /* 26 read the millisecond stop watch */ SIMHSleepCmd, /* 27 let SIMH sleep for SIMHSleep microseconds */ getHostOSPathSeparatorCmd, /* 28 obtain the file path separator of the OS under which SIMH runs */ - getHostFilenamesCmd /* 29 perform wildcard expansion and obtain list of file names */ + getHostFilenamesCmd, /* 29 perform wildcard expansion and obtain list of file names */ + readURLCmd, /* 30 read the contents of an URL */ + getCPUClockFrequency, /* 31 get the clock frequency of the CPU */ + setCPUClockFrequency, /* 32 set the clock frequency of the CPU */ + kSimhPseudoDeviceCommands }; -static int32 lastSIMHCommand = getHostFilenamesCmd; - -static char *cmdNames[] = { +static char *cmdNames[kSimhPseudoDeviceCommands] = { "printTime", "startTimer", "stopTimer", @@ -1079,7 +1140,10 @@ static char *cmdNames[] = { "readStopWatch", "SIMHSleep", "getHostOSPathSeparator", - "getHostFilenames" + "getHostFilenames", + "readURL", + "getCPUClockFrequency", + "setCPUClockFrequency", }; #define CPM_COMMAND_LINE_LENGTH 128 @@ -1087,7 +1151,16 @@ static char *cmdNames[] = { static uint32 markTime[TIMER_STACK_LIMIT]; /* timer stack */ static struct tm currentTime; static int32 currentTimeValid = FALSE; -static char version[] = "SIMH003"; +static char version[] = "SIMH004"; + +#define URL_MAX_LENGTH 1024 +static uint32 urlPointer; +static char urlStore[URL_MAX_LENGTH]; +static uint8 *urlResult = NULL; +static uint32 resultLength; +static uint32 resultPointer; +static int32 showAvailability; +static int32 isInReadPhase; static t_stat simh_dev_reset(DEVICE *dptr) { sim_map_resource(0xfe, 1, RESOURCE_TYPE_IO, &simh_dev, dptr->flags & DEV_DIS); @@ -1107,14 +1180,21 @@ static t_stat simh_dev_reset(DEVICE *dptr) { lastCommand = 0; lastCPMStatus = SCPE_OK; timerInterrupt = FALSE; + urlPointer = 0; + getClockFrequencyPos = 0; + setClockFrequencyPos = 0; + if (urlResult != NULL) { + free(urlResult); + urlResult = NULL; + } if (simh_unit.flags & UNIT_SIMH_TIMERON) simh_dev_set_timeron(NULL, 0, NULL, NULL); return SCPE_OK; } static void warnNoRealTimeClock(void) { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Sorry - no real time clock available." NLP, PCX)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Sorry - no real time clock available.\n", PCX); } static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) { @@ -1142,11 +1222,11 @@ static t_stat simh_svc(UNIT *uptr) { else { uint32 newTimeOfNextInterrupt = now + timerDelta - (now - timeOfNextInterrupt) % timerDelta; if (newTimeOfNextInterrupt != timeOfNextInterrupt + timerDelta) { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Timer interrupts skipped %i. Delta %i. Expect %i. Got %i." NLP, PCX, - (newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1, - timerDelta, - timeOfNextInterrupt + timerDelta - now, newTimeOfNextInterrupt - now)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Timer interrupts skipped %i. Delta %i. Expect %i. Got %i.\n", + PCX, (newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1, + timerDelta, timeOfNextInterrupt + timerDelta - now, + newTimeOfNextInterrupt - now); } timeOfNextInterrupt = newTimeOfNextInterrupt; } @@ -1187,8 +1267,10 @@ static void attachCPM(UNIT *uptr) { /* 'C' option makes sure that file is properly truncated if it had existed before */ sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ lastCPMStatus = attach_unit(uptr, cpmCommandLine); - if ((lastCPMStatus != SCPE_OK) && (simh_device.dctrl & VERBOSE_MSG)) - printf("SIMH: " ADDRESS_FORMAT " Cannot open '%s' (%s)." NLP, PCX, cpmCommandLine, sim_error_text(lastCPMStatus)); + if (lastCPMStatus != SCPE_OK) + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Cannot open '%s' (%s).\n", PCX, cpmCommandLine, + sim_error_text(lastCPMStatus)); } /* setClockZSDOSAdr points to 6 byte block in M: YY MM DD HH MM SS in BCD notation */ @@ -1234,6 +1316,25 @@ static void setClockCPM3(void) { static int32 simh_in(const int32 port) { int32 result = 0; switch(lastCommand) { + case readURLCmd: + if (isInReadPhase) { + if (showAvailability) { + if (resultPointer < resultLength) + result = 1; + else { + if (urlResult != NULL) + free(urlResult); + urlResult = NULL; + lastCommand = 0; + } + } + else if (resultPointer < resultLength) + result = urlResult[resultPointer++]; + showAvailability = 1 - showAvailability; + } + else + lastCommand = 0; + break; case getHostFilenamesCmd: #if UNIX_PLATFORM @@ -1358,8 +1459,8 @@ static int32 simh_in(const int32 port) { result = getBankSelect(); else { result = 0; - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Get selected bank ignored for non-banked memory." NLP, PCX)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Get selected bank ignored for non-banked memory.\n", PCX); } lastCommand = 0; break; @@ -1375,6 +1476,17 @@ static int32 simh_in(const int32 port) { } break; + case getCPUClockFrequency: + if (getClockFrequencyPos == 0) { + result = getClockFrequency() & 0xff; + getClockFrequencyPos = 1; + } + else { + result = (getClockFrequency() >> 8) & 0xff; + getClockFrequencyPos = lastCommand = 0; + } + break; + case hasBankedMemoryCmd: result = cpu_unit.flags & UNIT_CPU_BANKED ? MAXBANKS : 0; lastCommand = 0; @@ -1402,9 +1514,9 @@ static int32 simh_in(const int32 port) { break; default: - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Undefined IN from SIMH pseudo device on port %03xh ignored." NLP, - PCX, port)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Undefined IN from SIMH pseudo device on port %03xh ignored.\n", + PCX, port); result = lastCommand = 0; } return result; @@ -1427,7 +1539,26 @@ void do_SIMH_sleep(void) { static int32 simh_out(const int32 port, const int32 data) { time_t now; switch(lastCommand) { - + case readURLCmd: + if (isInReadPhase) + lastCommand = 0; + else { + if (data) { + if (urlPointer < URL_MAX_LENGTH - 1) + urlStore[urlPointer++] = data & 0xff; + } + else { + if (urlResult != NULL) + free(urlResult); + urlStore[urlPointer] = 0; + urlResult = URLContents(urlStore, &resultLength); + urlPointer = resultPointer = 0; + showAvailability = 1; + isInReadPhase = TRUE; + } + } + break; + case setClockZSDOSCmd: if (setClockZSDOSPos == 0) { setClockZSDOSAdr = data; @@ -1439,7 +1570,7 @@ static int32 simh_out(const int32 port, const int32 data) { setClockZSDOSPos = lastCommand = 0; } break; - + case setClockCPM3Cmd: if (setClockCPM3Pos == 0) { setClockCPM3Adr = data; @@ -1451,18 +1582,28 @@ static int32 simh_out(const int32 port, const int32 data) { setClockCPM3Pos = lastCommand = 0; } break; - + + case setCPUClockFrequency: + if (setClockFrequencyPos == 0) { + newClockFrequency = data; + setClockFrequencyPos = 1; + } + else { + setClockFrequency((data << 8) | newClockFrequency); + setClockFrequencyPos = lastCommand = 0; + } + break; + case setBankSelectCmd: if (cpu_unit.flags & UNIT_CPU_BANKED) setBankSelect(data & BANKMASK); - else { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Set selected bank to %i ignored for non-banked memory." - NLP, PCX, data & 3)); - } + else + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Set selected bank to %i ignored for non-banked memory.\n", + PCX, data & 3); lastCommand = 0; break; - + case setTimerDeltaCmd: if (setTimerDeltaPos == 0) { timerDelta = data; @@ -1473,13 +1614,13 @@ static int32 simh_out(const int32 port, const int32 data) { setTimerDeltaPos = lastCommand = 0; if (timerDelta == 0) { timerDelta = DEFAULT_TIMER_DELTA; - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Timer delta set to 0 ms ignored. Using %i ms instead." - NLP, PCX, DEFAULT_TIMER_DELTA)); + sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Timer delta set to 0 ms ignored. Using %i ms instead.\n", + PCX, DEFAULT_TIMER_DELTA); } } break; - + case setTimerInterruptAdrCmd: if (setTimerInterruptAdrPos == 0) { timerInterruptHandler = data; @@ -1490,15 +1631,21 @@ static int32 simh_out(const int32 port, const int32 data) { setTimerInterruptAdrPos = lastCommand = 0; } break; - - default: - TRACE_PRINT(simh_device, CMD_MSG, - ("SIMH: " ADDRESS_FORMAT " CMD(0x%02x) <- %i (0x%02x, '%s')" NLP, PCX, port, data, data, - (0 <= data) && (data <= lastSIMHCommand) ? cmdNames[data] : "Unknown command")); - + + default: /* lastCommand not yet set */ + sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " CMD(0x%02x) <- %i (0x%02x, '%s')\n", + PCX, port, data, data, + (0 <= data) && (data < kSimhPseudoDeviceCommands) ? + cmdNames[data] : "Unknown command"); + lastCommand = data; switch(data) { - + case readURLCmd: + urlPointer = 0; + isInReadPhase = FALSE; + break; + case getHostFilenamesCmd: #if UNIX_PLATFORM if (!globValid) { @@ -1507,9 +1654,10 @@ static int32 simh_out(const int32 port, const int32 data) { createCPMCommandLine(); globError = glob(cpmCommandLine, GLOB_ERR, NULL, &globS); if (globError) { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %i." - NLP, PCX, cpmCommandLine, globError)); + sim_debug(VERBOSE_MSG, &simh_device, + "SIMH: " ADDRESS_FORMAT + " Cannot expand '%s'. Error is %i.\n", + PCX, cpmCommandLine, globError); globfree(&globS); globValid = FALSE; } @@ -1523,36 +1671,37 @@ static int32 simh_out(const int32 port, const int32 data) { setLastPathSeparator(); hFind = FindFirstFile(cpmCommandLine, &FindFileData); if (hFind == INVALID_HANDLE_VALUE) { - TRACE_PRINT(simh_device, VERBOSE_MSG, - ("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %lu." - NLP, PCX, cpmCommandLine, GetLastError())); + sim_debug(VERBOSE_MSG, &simh_device, + "SIMH: " ADDRESS_FORMAT + " Cannot expand '%s'. Error is %lu.\n", + PCX, cpmCommandLine, GetLastError()); globValid = FALSE; } } #endif break; - + case SIMHSleepCmd: do_SIMH_sleep(); break; - + case printTimeCmd: /* print time */ if (rtc_avail) printf("SIMH: " ADDRESS_FORMAT " Current time in milliseconds = %d." NLP, PCX, sim_os_msec()); else warnNoRealTimeClock(); break; - + case startTimerCmd: /* create a new timer on top of stack */ if (rtc_avail) if (markTimeSP < TIMER_STACK_LIMIT) markTime[markTimeSP++] = sim_os_msec(); else printf("SIMH: " ADDRESS_FORMAT " Timer stack overflow." NLP, PCX); - else - warnNoRealTimeClock(); + else + warnNoRealTimeClock(); break; - + case stopTimerCmd: /* stop timer on top of stack and show time difference */ if (rtc_avail) if (markTimeSP > 0) { @@ -1561,26 +1710,26 @@ static int32 simh_out(const int32 port, const int32 data) { } else printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX); - else - warnNoRealTimeClock(); + else + warnNoRealTimeClock(); break; - + case resetPTRCmd: /* reset ptr device */ ptr_reset(&ptr_dev); break; - + case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */ attachCPM(&ptr_unit); break; - + case detachPTRCmd: /* detach ptr */ detach_unit(&ptr_unit); break; - + case getSIMHVersionCmd: versionPos = 0; break; - + case getClockZSDOSCmd: time(&now); now += ClockZSDOSDelta; @@ -1588,11 +1737,11 @@ static int32 simh_out(const int32 port, const int32 data) { currentTimeValid = TRUE; getClockZSDOSPos = 0; break; - + case setClockZSDOSCmd: setClockZSDOSPos = 0; break; - + case getClockCPM3Cmd: time(&now); now += ClockCPM3Delta; @@ -1601,18 +1750,29 @@ static int32 simh_out(const int32 port, const int32 data) { daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY); getClockCPM3Pos = 0; break; - + case setClockCPM3Cmd: setClockCPM3Pos = 0; break; - + + case getCommonCmd: + getCommonPos = 0; + break; + + case getCPUClockFrequency: + getClockFrequencyPos = 0; + break; + + case setCPUClockFrequency: + setClockFrequencyPos = 0; + break; + case getBankSelectCmd: case setBankSelectCmd: - case getCommonCmd: case hasBankedMemoryCmd: case getHostOSPathSeparatorCmd: break; - + case resetSIMHInterfaceCmd: markTimeSP = 0; lastCommand = 0; @@ -1630,7 +1790,7 @@ static int32 simh_out(const int32 port, const int32 data) { } #endif break; - + case showTimerCmd: /* show time difference to timer on top of stack */ if (rtc_avail) if (markTimeSP > 0) { @@ -1639,60 +1799,60 @@ static int32 simh_out(const int32 port, const int32 data) { } else printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX); - else - warnNoRealTimeClock(); + else + warnNoRealTimeClock(); break; - + case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */ attachCPM(&ptp_unit); break; - + case detachPTPCmd: /* detach ptp */ detach_unit(&ptp_unit); break; - + case setZ80CPUCmd: chiptype = CHIP_TYPE_Z80; break; - + case set8080CPUCmd: chiptype = CHIP_TYPE_8080; break; - + case startTimerInterruptsCmd: if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) { timerInterrupt = FALSE; simh_unit.flags |= UNIT_SIMH_TIMERON; } break; - + case stopTimerInterruptsCmd: simh_unit.flags &= ~UNIT_SIMH_TIMERON; simh_dev_set_timeroff(NULL, 0, NULL, NULL); break; - + case setTimerDeltaCmd: setTimerDeltaPos = 0; break; - + case setTimerInterruptAdrCmd: setTimerInterruptAdrPos = 0; break; - + case resetStopWatchCmd: stopWatchNow = rtc_avail ? sim_os_msec() : 0; break; - + case readStopWatchCmd: getStopWatchDeltaPos = 0; stopWatchDelta = rtc_avail ? sim_os_msec() - stopWatchNow : 0; break; - + default: - TRACE_PRINT(simh_device, CMD_MSG, - ("SIMH: " ADDRESS_FORMAT " Unknown command (%i) to SIMH pseudo device on port %03xh ignored." - NLP, PCX, data, port)); - } + sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " Unknown command (%i) to SIMH pseudo device on port %03xh ignored.\n", + PCX, data, port); + } } return 0x00; /* ignored, since OUT */ } @@ -1702,15 +1862,17 @@ int32 simh_dev(const int32 port, const int32 io, const int32 data) { int32 result = 0; if (io == 0) { result = simh_in(port); - TRACE_PRINT(simh_device, IN_MSG, - ("SIMH: " ADDRESS_FORMAT " IN(0x%02x) -> %i (0x%02x, '%c')" NLP, PCX, port, result, result, - (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?')); + sim_debug(IN_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " IN(0x%02x) -> %i (0x%02x, '%c')\n", PCX, + port, result, result, + (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'); } else { - TRACE_PRINT(simh_device, OUT_MSG, - ("SIMH: " ADDRESS_FORMAT " OUT(0x%02x) <- %i (0x%02x, '%c')" NLP, PCX, port, data, data, - (32 <= (data & 0xff)) && ((data & 0xff) <= 127) ? (data & 0xff) : '?')); + sim_debug(OUT_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT + " OUT(0x%02x) <- %i (0x%02x, '%c')\n", PCX, + port, data, data, + (32 <= (data & 0xff)) && ((data & 0xff) <= 127) ? (data & 0xff) : '?'); simh_out(port, data); } return result; diff --git a/AltairZ80/altairz80_sys.c b/AltairZ80/altairz80_sys.c index f02b826f..6a4f8985 100644 --- a/AltairZ80/altairz80_sys.c +++ b/AltairZ80/altairz80_sys.c @@ -1,6 +1,6 @@ /* altairz80_sys.c: MITS Altair system interface - Copyright (c) 2002-2010, Peter Schorn + Copyright (c) 2002-2011, Peter Schorn 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/AltairZ80/i8272.c b/AltairZ80/i8272.c index 0d21de52..b02fa450 100644 --- a/AltairZ80/i8272.c +++ b/AltairZ80/i8272.c @@ -202,11 +202,6 @@ static MTAB i8272_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(i8272_dev.dctrl & level) { \ - printf args; \ - } - - /* Debug Flags */ static DEBTAB i8272_dt[] = { { "ERROR", ERROR_MSG }, @@ -427,26 +422,32 @@ uint8 I8272_Read(const uint32 Addr) cData |= ~I8272_MSR_FDC_BUSY; } #endif /* 0 hharte */ - TRACE_PRINT(STATUS_MSG, ("I8272: " ADDRESS_FORMAT " RD FDC MSR = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " RD FDC MSR = 0x%02x\n", PCX, cData); break; case I8272_FDC_DATA: if(i8272_info->fdc_phase == DATA_PHASE) { cData = i8272_info->result[i8272_info->result_index]; - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " RD Data, phase=%d, [%d]=0x%02x" NLP, PCX, i8272_info->fdc_phase, i8272_info->result_index, cData)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " RD Data, phase=%d, [%d]=0x%02x\n", + PCX, i8272_info->fdc_phase, i8272_info->result_index, cData); i8272_irq = 0; i8272_info->result_index ++; if(i8272_info->result_index == i8272_info->result_len) { - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " result phase complete." NLP, PCX)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " result phase complete.\n", PCX); i8272_info->fdc_phase = CMD_PHASE; } } else { cData = i8272_info->result[0]; /* hack, in theory any value should be ok but this makes "format" work */ - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " error, reading data register when not in data phase. " - "Returning 0x%02x" NLP, PCX, cData)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " error, reading data register when not in data phase. " + "Returning 0x%02x\n", PCX, cData); } break; default: - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " Cannot read register %x" NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Cannot read register %x\n", PCX, Addr); cData = 0xFF; } @@ -475,8 +476,8 @@ static char *messages[0x20] = { uint8 I8272_Write(const uint32 Addr, uint8 cData) { I8272_DRIVE_INFO *pDrive; - uint32 flags = 0; - uint32 readlen; + unsigned int flags = 0; + unsigned int readlen; uint8 disk_read = 0; int32 i; @@ -488,19 +489,20 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) switch(Addr & 0x3) { case I8272_FDC_MSR: - TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " WR Drive Select Reg=%02x" NLP, - PCX, cData)); + sim_debug(WR_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " WR Drive Select Reg=%02x\n", PCX, cData); break; case I8272_FDC_DATA: i8272_info->fdc_msr &= 0xF0; - TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " WR Data, phase=%d, index=%d" NLP, - PCX, i8272_info->fdc_phase, i8272_info->cmd_index)); + sim_debug(VERBOSE_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " WR Data, phase=%d, index=%d\n", + PCX, i8272_info->fdc_phase, i8272_info->cmd_index); if(i8272_info->fdc_phase == CMD_PHASE) { i8272_info->cmd[i8272_info->cmd_index] = cData; if(i8272_info->cmd_index == 0) { - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " CMD=0x%02x[%s]" NLP, - PCX, cData & 0x1F, messages[cData & 0x1F])); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " CMD=0x%02x[%s]\n", PCX, cData & 0x1F, messages[cData & 0x1F]); I8272_Setup_Cmd(cData & 0x1F); } i8272_info->cmd_index ++; @@ -537,14 +539,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->fdc_seek_end = 0; } if(pDrive->track != i8272_info->cmd[2]) { - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT - " ERROR: CMD=0x%02x[%s]: Drive: %d, Command wants track %d, but positioner is on track %d." NLP, - PCX, - i8272_info->cmd[0] & 0x1F, - messages[i8272_info->cmd[0] & 0x1F], - i8272_info->sel_drive, - i8272_info->cmd[2], - pDrive->track)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " ERROR: CMD=0x%02x[%s]: Drive: %d, Command wants track %d, " + "but positioner is on track %d.\n", + PCX, i8272_info->cmd[0] & 0x1F, + messages[i8272_info->cmd[0] & 0x1F], + i8272_info->sel_drive, i8272_info->cmd[2], pDrive->track); } pDrive->track = i8272_info->cmd[2]; @@ -552,30 +552,31 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->fdc_sector = i8272_info->cmd[4]; i8272_info->fdc_sec_len = i8272_info->cmd[5]; if(i8272_info->fdc_sec_len > I8272_MAX_N) { - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size %d [N=%d]. Reset to %d [N=%d]." NLP, - PCX, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sec_len, - 128 << I8272_MAX_N, I8272_MAX_N)); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Illegal sector size %d [N=%d]. Reset to %d [N=%d].\n", + PCX, 128 << i8272_info->fdc_sec_len, + i8272_info->fdc_sec_len, 128 << I8272_MAX_N, I8272_MAX_N); i8272_info->fdc_sec_len = I8272_MAX_N; } i8272_info->fdc_eot = i8272_info->cmd[6]; i8272_info->fdc_gpl = i8272_info->cmd[7]; i8272_info->fdc_dtl = i8272_info->cmd[8]; - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT - " CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, EOT=%02x, GPL=%02x, DTL=%02x" NLP, - PCX, - i8272_info->cmd[0] & 0x1F, - messages[i8272_info->cmd[0] & 0x1F], - i8272_info->sel_drive, - i8272_info->fdc_mt ? "Multi" : "Single", - i8272_info->fdc_mfm ? "MFM" : "FM", - pDrive->track, - i8272_info->fdc_head, - i8272_info->fdc_sector, - i8272_info->fdc_sec_len, - i8272_info->fdc_eot, - i8272_info->fdc_gpl, - i8272_info->fdc_dtl)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, " + "EOT=%02x, GPL=%02x, DTL=%02x\n", PCX, + i8272_info->cmd[0] & 0x1F, + messages[i8272_info->cmd[0] & 0x1F], + i8272_info->sel_drive, + i8272_info->fdc_mt ? "Multi" : "Single", + i8272_info->fdc_mfm ? "MFM" : "FM", + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sector, + i8272_info->fdc_sec_len, + i8272_info->fdc_eot, + i8272_info->fdc_gpl, + i8272_info->fdc_dtl); i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03); @@ -613,8 +614,9 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) /* READID to detect non-standard disk formats. */ i8272_info->fdc_sector = pDrive->imd->track[pDrive->track][i8272_info->fdc_hds].start_sector; if((i8272_info->fdc_sec_len == 0xF8) || (i8272_info->fdc_sec_len > I8272_MAX_N)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size N=%d. Reset to 0." NLP, - PCX, i8272_info->fdc_sec_len)); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Illegal sector size N=%d. Reset to 0.\n", + PCX, i8272_info->fdc_sec_len); i8272_info->fdc_sec_len = 0; return 0xFF; } @@ -642,8 +644,9 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) pDrive->track = 0; i8272_info->fdc_phase = CMD_PHASE; /* No result phase */ i8272_info->fdc_seek_end = 1; - TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT " Recalibrate: Drive 0x%02x" NLP, - PCX, i8272_info->sel_drive)); + sim_debug(SEEK_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Recalibrate: Drive 0x%02x\n", + PCX, i8272_info->sel_drive); break; case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; @@ -662,25 +665,27 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) } i8272_info->fdc_sec_len = i8272_info->cmd[2]; if(i8272_info->fdc_sec_len > I8272_MAX_N) { - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector size %d [N=%d]. Reset to %d [N=%d]." NLP, - PCX, 128 << i8272_info->fdc_sec_len, i8272_info->fdc_sec_len, - 128 << I8272_MAX_N, I8272_MAX_N)); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Illegal sector size %d [N=%d]. Reset to %d [N=%d].\n", + PCX, 128 << i8272_info->fdc_sec_len, + i8272_info->fdc_sec_len, 128 << I8272_MAX_N, I8272_MAX_N); i8272_info->fdc_sec_len = I8272_MAX_N; } i8272_info->fdc_sc = i8272_info->cmd[3]; i8272_info->fdc_gpl = i8272_info->cmd[4]; i8272_info->fdc_fillbyte = i8272_info->cmd[5]; - TRACE_PRINT(FMT_MSG, ("I8272: " ADDRESS_FORMAT " Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x" NLP, - PCX, - i8272_info->sel_drive, - i8272_info->fdc_mfm ? "MFM" : "FM", - pDrive->track, - i8272_info->fdc_head, - i8272_info->fdc_sec_len, - i8272_info->fdc_sc, - i8272_info->fdc_gpl, - i8272_info->fdc_fillbyte)); + sim_debug(FMT_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x\n", + PCX, + i8272_info->sel_drive, + i8272_info->fdc_mfm ? "MFM" : "FM", + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sec_len, + i8272_info->fdc_sc, + i8272_info->fdc_gpl, + i8272_info->fdc_fillbyte); i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 0x03); @@ -698,7 +703,8 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->result[6] = i8272_info->fdc_sec_len; break; case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Interrupt Status" NLP, PCX)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Sense Interrupt Status\n", PCX); i8272_info->result[0] = i8272_info->fdc_seek_end ? 0x20 : 0x00; /* SEEK_END */ i8272_info->result[0] |= i8272_info->sel_drive; i8272_info->result[1] = pDrive->track; @@ -710,12 +716,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->fdc_hlt = ((i8272_info->cmd[2] & 0xFE) >> 1) * 2; i8272_info->fdc_nd = (i8272_info->cmd[2] & 0x01); i8272_info->fdc_phase = CMD_PHASE; /* No result phase */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s" NLP, - PCX, - i8272_info->fdc_srt, - i8272_info->fdc_hut, - i8272_info->fdc_hlt, - i8272_info->fdc_nd ? "NON-DMA" : "DMA")); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s\n", + PCX, i8272_info->fdc_srt, + i8272_info->fdc_hut, + i8272_info->fdc_hlt, + i8272_info->fdc_nd ? "NON-DMA" : "DMA"); break; case I8272_SENSE_DRIVE_STATUS: /* Setup Status3 Byte */ i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; @@ -735,8 +741,8 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) i8272_info->result[0] |= (i8272_info->fdc_hds & 1) << 2; i8272_info->result[0] |= (i8272_info->sel_drive & 0x03); i8272_info->result[0] |= (pDrive->track == 0) ? DRIVE_STATUS_TRACK0 : 0x00; /* Track 0 */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Drive Status = 0x%02x" NLP, - PCX, i8272_info->result[0])); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Sense Drive Status = 0x%02x\n", PCX, i8272_info->result[0]); break; case I8272_SEEK: /* SEEK */ i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7; @@ -752,15 +758,15 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) pDrive->track = i8272_info->cmd[2]; i8272_info->fdc_head = i8272_info->fdc_hds; /*AGN seek should save the head */ i8272_info->fdc_seek_end = 1; - TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT - " Seek Drive: %d, %s %s, C=%d. Skip Deleted Data=%s Head Select=%s" NLP, - PCX, - i8272_info->sel_drive, - i8272_info->fdc_mt ? "Multi" : "Single", - i8272_info->fdc_mfm ? "MFM" : "FM", - i8272_info->cmd[2], - i8272_info->fdc_sk ? "True" : "False", - i8272_info->fdc_hds ? "True" : "False")); + sim_debug(SEEK_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Seek Drive: %d, %s %s, C=%d. Skip Deleted Data=%s Head Select=%s\n", + PCX, + i8272_info->sel_drive, + i8272_info->fdc_mt ? "Multi" : "Single", + i8272_info->fdc_mfm ? "MFM" : "FM", + i8272_info->cmd[2], + i8272_info->fdc_sk ? "True" : "False", + i8272_info->fdc_hds ? "True" : "False"); break; default: /* INVALID */ break; @@ -777,10 +783,11 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) case I8272_WRITE_DATA: case I8272_WRITE_DELETED_DATA: for(;i8272_info->fdc_sector<=i8272_info->fdc_eot;i8272_info->fdc_sector++) { - TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " %s Data, sector: %d sector len=%d" NLP, - PCX, disk_read ? "RD" : "WR", - i8272_info->fdc_sector, - 128 << i8272_info->fdc_sec_len)); + sim_debug(RD_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " %s Data, sector: %d sector len=%d\n", + PCX, disk_read ? "RD" : "WR", + i8272_info->fdc_sector, + 128 << i8272_info->fdc_sec_len); if(pDrive->imd == NULL) { printf(".imd is NULL!" NLP); @@ -799,20 +806,21 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) PutByteDMA(i8272_info->fdc_dma_addr, sdata.raw[i]); i8272_info->fdc_dma_addr++; } - TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " T:%d/H:%d/S:%d/L:%4d: Data transferred to RAM at 0x%06x" NLP, - PCX, - pDrive->track, - i8272_info->fdc_head, - i8272_info->fdc_sector, - 128 << i8272_info->fdc_sec_len, - i8272_info->fdc_dma_addr - i)); + sim_debug(RD_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " T:%d/H:%d/S:%d/L:%4d: Data transferred to RAM at 0x%06x\n", + PCX, pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sector, + 128 << i8272_info->fdc_sec_len, + i8272_info->fdc_dma_addr - i); } else { /* Write */ for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) { sdata.raw[i] = GetByteDMA(i8272_info->fdc_dma_addr); i8272_info->fdc_dma_addr++; } - TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " Data transferred from RAM at 0x%06x" NLP, - PCX, i8272_info->fdc_dma_addr)); + sim_debug(WR_DATA_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Data transferred from RAM at 0x%06x\n", + PCX, i8272_info->fdc_dma_addr); sectWrite(pDrive->imd, pDrive->track, i8272_info->fdc_head, @@ -829,14 +837,12 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) break; case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ for(i8272_info->fdc_sector = 1;i8272_info->fdc_sector<=i8272_info->fdc_sc;i8272_info->fdc_sector++) { - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Format Track %d, Sector=%d, len=%d" NLP, - PCX, - pDrive->track, - i8272_info->fdc_sector, - 128 << i8272_info->fdc_sec_len)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Format Track %d, Sector=%d, len=%d\n", PCX, pDrive->track, i8272_info->fdc_sector, 128 << i8272_info->fdc_sec_len); if(i8272_info->fdc_sectorcount >= I8272_MAX_SECTOR) { - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " Illegal sector count" NLP, PCX)); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Illegal sector count\n", PCX); i8272_info->fdc_sectorcount = 0; } i8272_info->fdc_sectormap[i8272_info->fdc_sectorcount] = i8272_info->fdc_sector; @@ -862,16 +868,20 @@ uint8 I8272_Write(const uint32 Addr, uint8 cData) case I8272_SCAN_LOW_EQUAL: /* SCAN LOW OR EQUAL */ case I8272_SCAN_HIGH_EQUAL: /* SCAN HIGH OR EQUAL */ case I8272_SCAN_EQUAL: /* SCAN EQUAL */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Scan Data" NLP, - PCX)); - TRACE_PRINT(ERROR_MSG, ("I8272: " ADDRESS_FORMAT " ERROR: Scan not implemented." NLP, PCX)); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " Scan Data\n", PCX); + sim_debug(ERROR_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " ERROR: Scan not implemented.\n", PCX); break; case I8272_READ_ID: /* READ ID */ - TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT - " READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x C=%d H=%d R=%02x N=%d" - NLP, PCX, i8272_info->sel_drive, i8272_info->result[0], - i8272_info->result[1],i8272_info->result[2],i8272_info->result[3], - i8272_info->result[4],i8272_info->result[5],i8272_info->result[6])); + sim_debug(CMD_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT + " READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x " + "C=%d H=%d R=%02x N=%d\n", PCX, + i8272_info->sel_drive, + i8272_info->result[0], i8272_info->result[1], + i8272_info->result[2], i8272_info->result[3], + i8272_info->result[4], i8272_info->result[5], + i8272_info->result[6]); break; default: @@ -956,7 +966,7 @@ extern void raise_disk1a_interrupt(void); static void raise_i8272_interrupt(void) { - TRACE_PRINT(IRQ_MSG, ("I8272: " ADDRESS_FORMAT " FDC Interrupt" NLP, PCX)); + sim_debug(IRQ_MSG, &i8272_dev, "I8272: " ADDRESS_FORMAT " FDC Interrupt\n", PCX); i8272_irq = 1; raise_disk1a_interrupt(); } diff --git a/AltairZ80/insnsa.c b/AltairZ80/insnsa.c deleted file mode 100644 index ba4d70d7..00000000 --- a/AltairZ80/insnsa.c +++ /dev/null @@ -1,4443 +0,0 @@ -/* This file auto-generated from insns.dat by insns.pl - don't edit it */ - -#include "nasm.h" -#include "insns.h" - -static struct itemplate instrux_AAA[] = { - {I_AAA, 0, {0,0,0}, "\1\x37", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_AAD[] = { - {I_AAD, 0, {0,0,0}, "\2\xD5\x0A", IF_8086}, - {I_AAD, 1, {IMMEDIATE,0,0}, "\1\xD5\24", IF_8086|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_AAM[] = { - {I_AAM, 0, {0,0,0}, "\2\xD4\x0A", IF_8086}, - {I_AAM, 1, {IMMEDIATE,0,0}, "\1\xD4\24", IF_8086|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_AAS[] = { - {I_AAS, 0, {0,0,0}, "\1\x3F", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADC[] = { - {I_ADC, 2, {MEMORY,REG8,0}, "\300\1\x10\101", IF_8086|IF_SM}, - {I_ADC, 2, {REG8,REG8,0}, "\1\x10\101", IF_8086}, - {I_ADC, 2, {MEMORY,REG16,0}, "\320\300\1\x11\101", IF_8086|IF_SM}, - {I_ADC, 2, {REG16,REG16,0}, "\320\1\x11\101", IF_8086}, - {I_ADC, 2, {MEMORY,REG32,0}, "\321\300\1\x11\101", IF_386|IF_SM}, - {I_ADC, 2, {REG32,REG32,0}, "\321\1\x11\101", IF_386}, - {I_ADC, 2, {REG8,MEMORY,0}, "\301\1\x12\110", IF_8086|IF_SM}, - {I_ADC, 2, {REG8,REG8,0}, "\1\x12\110", IF_8086}, - {I_ADC, 2, {REG16,MEMORY,0}, "\320\301\1\x13\110", IF_8086|IF_SM}, - {I_ADC, 2, {REG16,REG16,0}, "\320\1\x13\110", IF_8086}, - {I_ADC, 2, {REG32,MEMORY,0}, "\321\301\1\x13\110", IF_386|IF_SM}, - {I_ADC, 2, {REG32,REG32,0}, "\321\1\x13\110", IF_386}, - {I_ADC, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\202\15", IF_8086}, - {I_ADC, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\202\15", IF_386}, - {I_ADC, 2, {REG_AL,IMMEDIATE,0}, "\1\x14\21", IF_8086|IF_SM}, - {I_ADC, 2, {REG_AX,SBYTE,0}, "\320\1\x83\202\15", IF_8086|IF_SM}, - {I_ADC, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x15\31", IF_8086|IF_SM}, - {I_ADC, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\202\15", IF_386|IF_SM}, - {I_ADC, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x15\41", IF_386|IF_SM}, - {I_ADC, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\202\21", IF_8086|IF_SM}, - {I_ADC, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\202\131", IF_8086|IF_SM}, - {I_ADC, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\202\141", IF_386|IF_SM}, - {I_ADC, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\202\21", IF_8086|IF_SM}, - {I_ADC, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\202\131", IF_8086|IF_SM}, - {I_ADC, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\202\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADD[] = { - {I_ADD, 2, {MEMORY,REG8,0}, "\300\17\101", IF_8086|IF_SM}, - {I_ADD, 2, {REG8,REG8,0}, "\17\101", IF_8086}, - {I_ADD, 2, {MEMORY,REG16,0}, "\320\300\1\x01\101", IF_8086|IF_SM}, - {I_ADD, 2, {REG16,REG16,0}, "\320\1\x01\101", IF_8086}, - {I_ADD, 2, {MEMORY,REG32,0}, "\321\300\1\x01\101", IF_386|IF_SM}, - {I_ADD, 2, {REG32,REG32,0}, "\321\1\x01\101", IF_386}, - {I_ADD, 2, {REG8,MEMORY,0}, "\301\1\x02\110", IF_8086|IF_SM}, - {I_ADD, 2, {REG8,REG8,0}, "\1\x02\110", IF_8086}, - {I_ADD, 2, {REG16,MEMORY,0}, "\320\301\1\x03\110", IF_8086|IF_SM}, - {I_ADD, 2, {REG16,REG16,0}, "\320\1\x03\110", IF_8086}, - {I_ADD, 2, {REG32,MEMORY,0}, "\321\301\1\x03\110", IF_386|IF_SM}, - {I_ADD, 2, {REG32,REG32,0}, "\321\1\x03\110", IF_386}, - {I_ADD, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\200\15", IF_8086}, - {I_ADD, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\200\15", IF_386}, - {I_ADD, 2, {REG_AL,IMMEDIATE,0}, "\1\x04\21", IF_8086|IF_SM}, - {I_ADD, 2, {REG_AX,SBYTE,0}, "\320\1\x83\200\15", IF_8086|IF_SM}, - {I_ADD, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x05\31", IF_8086|IF_SM}, - {I_ADD, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\200\15", IF_386|IF_SM}, - {I_ADD, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x05\41", IF_386|IF_SM}, - {I_ADD, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\200\21", IF_8086|IF_SM}, - {I_ADD, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\200\131", IF_8086|IF_SM}, - {I_ADD, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\200\141", IF_386|IF_SM}, - {I_ADD, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\200\21", IF_8086|IF_SM}, - {I_ADD, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\200\131", IF_8086|IF_SM}, - {I_ADD, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\200\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDPD[] = { - {I_ADDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, - {I_ADDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x58\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDPS[] = { - {I_ADDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x58\110", IF_KATMAI|IF_SSE}, - {I_ADDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x58\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDSD[] = { - {I_ADDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, - {I_ADDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDSS[] = { - {I_ADDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x58\110", IF_KATMAI|IF_SSE}, - {I_ADDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x58\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDSUBPD[] = { - {I_ADDSUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD0\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_ADDSUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD0\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ADDSUBPS[] = { - {I_ADDSUBPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\xD0\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_ADDSUBPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\xD0\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_AND[] = { - {I_AND, 2, {MEMORY,REG8,0}, "\300\1\x20\101", IF_8086|IF_SM}, - {I_AND, 2, {REG8,REG8,0}, "\1\x20\101", IF_8086}, - {I_AND, 2, {MEMORY,REG16,0}, "\320\300\1\x21\101", IF_8086|IF_SM}, - {I_AND, 2, {REG16,REG16,0}, "\320\1\x21\101", IF_8086}, - {I_AND, 2, {MEMORY,REG32,0}, "\321\300\1\x21\101", IF_386|IF_SM}, - {I_AND, 2, {REG32,REG32,0}, "\321\1\x21\101", IF_386}, - {I_AND, 2, {REG8,MEMORY,0}, "\301\1\x22\110", IF_8086|IF_SM}, - {I_AND, 2, {REG8,REG8,0}, "\1\x22\110", IF_8086}, - {I_AND, 2, {REG16,MEMORY,0}, "\320\301\1\x23\110", IF_8086|IF_SM}, - {I_AND, 2, {REG16,REG16,0}, "\320\1\x23\110", IF_8086}, - {I_AND, 2, {REG32,MEMORY,0}, "\321\301\1\x23\110", IF_386|IF_SM}, - {I_AND, 2, {REG32,REG32,0}, "\321\1\x23\110", IF_386}, - {I_AND, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\204\15", IF_8086}, - {I_AND, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\204\15", IF_386}, - {I_AND, 2, {REG_AL,IMMEDIATE,0}, "\1\x24\21", IF_8086|IF_SM}, - {I_AND, 2, {REG_AX,SBYTE,0}, "\320\1\x83\204\15", IF_8086|IF_SM}, - {I_AND, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x25\31", IF_8086|IF_SM}, - {I_AND, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\204\15", IF_386|IF_SM}, - {I_AND, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x25\41", IF_386|IF_SM}, - {I_AND, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\204\21", IF_8086|IF_SM}, - {I_AND, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\204\131", IF_8086|IF_SM}, - {I_AND, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\204\141", IF_386|IF_SM}, - {I_AND, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\204\21", IF_8086|IF_SM}, - {I_AND, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\204\131", IF_8086|IF_SM}, - {I_AND, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\204\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ANDNPD[] = { - {I_ANDNPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x55\110", IF_WILLAMETTE|IF_SSE2}, - {I_ANDNPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x55\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ANDNPS[] = { - {I_ANDNPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x55\110", IF_KATMAI|IF_SSE}, - {I_ANDNPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x55\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ANDPD[] = { - {I_ANDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x54\110", IF_WILLAMETTE|IF_SSE2}, - {I_ANDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x54\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ANDPS[] = { - {I_ANDPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x54\110", IF_KATMAI|IF_SSE}, - {I_ANDPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x54\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ARPL[] = { - {I_ARPL, 2, {MEMORY,REG16,0}, "\300\1\x63\101", IF_286|IF_PROT|IF_SM}, - {I_ARPL, 2, {REG16,REG16,0}, "\1\x63\101", IF_286|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BOUND[] = { - {I_BOUND, 2, {REG16,MEMORY,0}, "\320\301\1\x62\110", IF_186}, - {I_BOUND, 2, {REG32,MEMORY,0}, "\321\301\1\x62\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BSF[] = { - {I_BSF, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBC\110", IF_386|IF_SM}, - {I_BSF, 2, {REG16,REG16,0}, "\320\2\x0F\xBC\110", IF_386}, - {I_BSF, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xBC\110", IF_386|IF_SM}, - {I_BSF, 2, {REG32,REG32,0}, "\321\2\x0F\xBC\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BSR[] = { - {I_BSR, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBD\110", IF_386|IF_SM}, - {I_BSR, 2, {REG16,REG16,0}, "\320\2\x0F\xBD\110", IF_386}, - {I_BSR, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xBD\110", IF_386|IF_SM}, - {I_BSR, 2, {REG32,REG32,0}, "\321\2\x0F\xBD\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BSWAP[] = { - {I_BSWAP, 1, {REG32,0,0}, "\321\1\x0F\10\xC8", IF_486}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BT[] = { - {I_BT, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA3\101", IF_386|IF_SM}, - {I_BT, 2, {REG16,REG16,0}, "\320\2\x0F\xA3\101", IF_386}, - {I_BT, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA3\101", IF_386|IF_SM}, - {I_BT, 2, {REG32,REG32,0}, "\321\2\x0F\xA3\101", IF_386}, - {I_BT, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\204\25", IF_386|IF_SB}, - {I_BT, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\204\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BTC[] = { - {I_BTC, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xBB\101", IF_386|IF_SM}, - {I_BTC, 2, {REG16,REG16,0}, "\320\2\x0F\xBB\101", IF_386}, - {I_BTC, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xBB\101", IF_386|IF_SM}, - {I_BTC, 2, {REG32,REG32,0}, "\321\2\x0F\xBB\101", IF_386}, - {I_BTC, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\207\25", IF_386|IF_SB}, - {I_BTC, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\207\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BTR[] = { - {I_BTR, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xB3\101", IF_386|IF_SM}, - {I_BTR, 2, {REG16,REG16,0}, "\320\2\x0F\xB3\101", IF_386}, - {I_BTR, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xB3\101", IF_386|IF_SM}, - {I_BTR, 2, {REG32,REG32,0}, "\321\2\x0F\xB3\101", IF_386}, - {I_BTR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\206\25", IF_386|IF_SB}, - {I_BTR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\206\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_BTS[] = { - {I_BTS, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xAB\101", IF_386|IF_SM}, - {I_BTS, 2, {REG16,REG16,0}, "\320\2\x0F\xAB\101", IF_386}, - {I_BTS, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xAB\101", IF_386|IF_SM}, - {I_BTS, 2, {REG32,REG32,0}, "\321\2\x0F\xAB\101", IF_386}, - {I_BTS, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\205\25", IF_386|IF_SB}, - {I_BTS, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\205\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CALL[] = { - {I_CALL, 1, {IMMEDIATE,0,0}, "\322\1\xE8\64", IF_8086}, - {I_CALL, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\xE8\64", IF_8086}, - {I_CALL, 1, {IMMEDIATE|FAR,0,0}, "\322\1\x9A\34\37", IF_8086}, - {I_CALL, 1, {IMMEDIATE|BITS16,0,0}, "\320\1\xE8\64", IF_8086}, - {I_CALL, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\xE8\64", IF_8086}, - {I_CALL, 1, {IMMEDIATE|BITS16|FAR,0,0}, "\320\1\x9A\34\37", IF_8086}, - {I_CALL, 1, {IMMEDIATE|BITS32,0,0}, "\321\1\xE8\64", IF_386}, - {I_CALL, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\xE8\64", IF_386}, - {I_CALL, 1, {IMMEDIATE|BITS32|FAR,0,0}, "\321\1\x9A\34\37", IF_386}, - {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\322\1\x9A\35\30", IF_8086}, - {I_CALL, 2, {IMMEDIATE|BITS16|COLON,IMMEDIATE,0}, "\320\1\x9A\31\30", IF_8086}, - {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS16,0}, "\320\1\x9A\31\30", IF_8086}, - {I_CALL, 2, {IMMEDIATE|BITS32|COLON,IMMEDIATE,0}, "\321\1\x9A\41\30", IF_386}, - {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS32,0}, "\321\1\x9A\41\30", IF_386}, - {I_CALL, 1, {MEMORY|FAR,0,0}, "\322\300\1\xFF\203", IF_8086}, - {I_CALL, 1, {MEMORY|BITS16|FAR,0,0}, "\320\300\1\xFF\203", IF_8086}, - {I_CALL, 1, {MEMORY|BITS32|FAR,0,0}, "\321\300\1\xFF\203", IF_386}, - {I_CALL, 1, {MEMORY|NEAR,0,0}, "\322\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {MEMORY|BITS16|NEAR,0,0}, "\320\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {MEMORY|BITS32|NEAR,0,0}, "\321\300\1\xFF\202", IF_386}, - {I_CALL, 1, {REG16,0,0}, "\320\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {REG32,0,0}, "\321\300\1\xFF\202", IF_386}, - {I_CALL, 1, {MEMORY,0,0}, "\322\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {MEMORY|BITS16,0,0}, "\320\300\1\xFF\202", IF_8086}, - {I_CALL, 1, {MEMORY|BITS32,0,0}, "\321\300\1\xFF\202", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CBW[] = { - {I_CBW, 0, {0,0,0}, "\320\1\x98", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CDQ[] = { - {I_CDQ, 0, {0,0,0}, "\321\1\x99", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLC[] = { - {I_CLC, 0, {0,0,0}, "\1\xF8", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLD[] = { - {I_CLD, 0, {0,0,0}, "\1\xFC", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLFLUSH[] = { - {I_CLFLUSH, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\207", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLI[] = { - {I_CLI, 0, {0,0,0}, "\1\xFA", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CLTS[] = { - {I_CLTS, 0, {0,0,0}, "\2\x0F\x06", IF_286|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMC[] = { - {I_CMC, 0, {0,0,0}, "\1\xF5", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMP[] = { - {I_CMP, 2, {MEMORY,REG8,0}, "\300\1\x38\101", IF_8086|IF_SM}, - {I_CMP, 2, {REG8,REG8,0}, "\1\x38\101", IF_8086}, - {I_CMP, 2, {MEMORY,REG16,0}, "\320\300\1\x39\101", IF_8086|IF_SM}, - {I_CMP, 2, {REG16,REG16,0}, "\320\1\x39\101", IF_8086}, - {I_CMP, 2, {MEMORY,REG32,0}, "\321\300\1\x39\101", IF_386|IF_SM}, - {I_CMP, 2, {REG32,REG32,0}, "\321\1\x39\101", IF_386}, - {I_CMP, 2, {REG8,MEMORY,0}, "\301\1\x3A\110", IF_8086|IF_SM}, - {I_CMP, 2, {REG8,REG8,0}, "\1\x3A\110", IF_8086}, - {I_CMP, 2, {REG16,MEMORY,0}, "\320\301\1\x3B\110", IF_8086|IF_SM}, - {I_CMP, 2, {REG16,REG16,0}, "\320\1\x3B\110", IF_8086}, - {I_CMP, 2, {REG32,MEMORY,0}, "\321\301\1\x3B\110", IF_386|IF_SM}, - {I_CMP, 2, {REG32,REG32,0}, "\321\1\x3B\110", IF_386}, - {I_CMP, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\207\15", IF_8086}, - {I_CMP, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\207\15", IF_386}, - {I_CMP, 2, {REG_AL,IMMEDIATE,0}, "\1\x3C\21", IF_8086|IF_SM}, - {I_CMP, 2, {REG_AX,SBYTE,0}, "\320\1\x83\207\15", IF_8086|IF_SM}, - {I_CMP, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x3D\31", IF_8086|IF_SM}, - {I_CMP, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\207\15", IF_386|IF_SM}, - {I_CMP, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x3D\41", IF_386|IF_SM}, - {I_CMP, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\207\21", IF_8086|IF_SM}, - {I_CMP, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\207\131", IF_8086|IF_SM}, - {I_CMP, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\207\141", IF_386|IF_SM}, - {I_CMP, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\207\21", IF_8086|IF_SM}, - {I_CMP, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\207\131", IF_8086|IF_SM}, - {I_CMP, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\207\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPEQPD[] = { - {I_CMPEQPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPEQPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPEQPS[] = { - {I_CMPEQPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, - {I_CMPEQPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPEQSD[] = { - {I_CMPEQSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, - {I_CMPEQSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPEQSS[] = { - {I_CMPEQSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, - {I_CMPEQSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLEPD[] = { - {I_CMPLEPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPLEPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLEPS[] = { - {I_CMPLEPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, - {I_CMPLEPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLESD[] = { - {I_CMPLESD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, - {I_CMPLESD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLESS[] = { - {I_CMPLESS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, - {I_CMPLESS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLTPD[] = { - {I_CMPLTPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPLTPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLTPS[] = { - {I_CMPLTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, - {I_CMPLTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLTSD[] = { - {I_CMPLTSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, - {I_CMPLTSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPLTSS[] = { - {I_CMPLTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, - {I_CMPLTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNEQPD[] = { - {I_CMPNEQPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPNEQPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNEQPS[] = { - {I_CMPNEQPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, - {I_CMPNEQPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNEQSD[] = { - {I_CMPNEQSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, - {I_CMPNEQSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNEQSS[] = { - {I_CMPNEQSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, - {I_CMPNEQSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLEPD[] = { - {I_CMPNLEPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPNLEPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLEPS[] = { - {I_CMPNLEPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, - {I_CMPNLEPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLESD[] = { - {I_CMPNLESD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, - {I_CMPNLESD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLESS[] = { - {I_CMPNLESS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, - {I_CMPNLESS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLTPD[] = { - {I_CMPNLTPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPNLTPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLTPS[] = { - {I_CMPNLTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, - {I_CMPNLTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLTSD[] = { - {I_CMPNLTSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, - {I_CMPNLTSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPNLTSS[] = { - {I_CMPNLTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, - {I_CMPNLTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPORDPD[] = { - {I_CMPORDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPORDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPORDPS[] = { - {I_CMPORDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, - {I_CMPORDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPORDSD[] = { - {I_CMPORDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, - {I_CMPORDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPORDSS[] = { - {I_CMPORDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, - {I_CMPORDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPPD[] = { - {I_CMPPD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\3\x66\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_CMPPD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\3\x66\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPPS[] = { - {I_CMPPS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - {I_CMPPS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPSB[] = { - {I_CMPSB, 0, {0,0,0}, "\332\1\xA6", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPSD[] = { - {I_CMPSD, 0, {0,0,0}, "\332\321\1\xA7", IF_386}, - {I_CMPSD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\3\xF2\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_CMPSD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\3\xF2\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPSS[] = { - {I_CMPSS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\333\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - {I_CMPSS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\333\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPSW[] = { - {I_CMPSW, 0, {0,0,0}, "\332\320\1\xA7", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPUNORDPD[] = { - {I_CMPUNORDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_CMPUNORDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPUNORDPS[] = { - {I_CMPUNORDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, - {I_CMPUNORDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPUNORDSD[] = { - {I_CMPUNORDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, - {I_CMPUNORDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPUNORDSS[] = { - {I_CMPUNORDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, - {I_CMPUNORDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPXCHG[] = { - {I_CMPXCHG, 2, {MEMORY,REG8,0}, "\300\2\x0F\xB0\101", IF_PENT|IF_SM}, - {I_CMPXCHG, 2, {REG8,REG8,0}, "\2\x0F\xB0\101", IF_PENT}, - {I_CMPXCHG, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xB1\101", IF_PENT|IF_SM}, - {I_CMPXCHG, 2, {REG16,REG16,0}, "\320\2\x0F\xB1\101", IF_PENT}, - {I_CMPXCHG, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xB1\101", IF_PENT|IF_SM}, - {I_CMPXCHG, 2, {REG32,REG32,0}, "\321\2\x0F\xB1\101", IF_PENT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPXCHG486[] = { - {I_CMPXCHG486, 2, {MEMORY,REG8,0}, "\300\2\x0F\xA6\101", IF_486|IF_SM|IF_UNDOC}, - {I_CMPXCHG486, 2, {REG8,REG8,0}, "\2\x0F\xA6\101", IF_486|IF_UNDOC}, - {I_CMPXCHG486, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA7\101", IF_486|IF_SM|IF_UNDOC}, - {I_CMPXCHG486, 2, {REG16,REG16,0}, "\320\2\x0F\xA7\101", IF_486|IF_UNDOC}, - {I_CMPXCHG486, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA7\101", IF_486|IF_SM|IF_UNDOC}, - {I_CMPXCHG486, 2, {REG32,REG32,0}, "\321\2\x0F\xA7\101", IF_486|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMPXCHG8B[] = { - {I_CMPXCHG8B, 1, {MEMORY,0,0}, "\300\2\x0F\xC7\201", IF_PENT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_COMISD[] = { - {I_COMISD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x2F\110", IF_WILLAMETTE|IF_SSE2}, - {I_COMISD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x2F\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_COMISS[] = { - {I_COMISS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x2F\110", IF_KATMAI|IF_SSE}, - {I_COMISS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x2F\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CPUID[] = { - {I_CPUID, 0, {0,0,0}, "\2\x0F\xA2", IF_PENT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTDQ2PD[] = { - {I_CVTDQ2PD, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTDQ2PD, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTDQ2PS[] = { - {I_CVTDQ2PS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTDQ2PS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPD2DQ[] = { - {I_CVTPD2DQ, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPD2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPD2PI[] = { - {I_CVTPD2PI, 2, {MMXREG,XMMREG,0}, "\3\x66\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPD2PI, 2, {MMXREG,MEMORY,0}, "\301\3\x66\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPD2PS[] = { - {I_CVTPD2PS, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPD2PS, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPI2PD[] = { - {I_CVTPI2PD, 2, {XMMREG,MMXREG,0}, "\3\x66\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPI2PD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPI2PS[] = { - {I_CVTPI2PS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_MMX}, - {I_CVTPI2PS, 2, {XMMREG,MMXREG,0}, "\331\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPS2DQ[] = { - {I_CVTPS2DQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPS2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPS2PD[] = { - {I_CVTPS2PD, 2, {XMMREG,XMMREG,0}, "\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTPS2PD, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTPS2PI[] = { - {I_CVTPS2PI, 2, {MMXREG,MEMORY,0}, "\301\331\2\x0F\x2D\110", IF_KATMAI|IF_SSE|IF_MMX}, - {I_CVTPS2PI, 2, {MMXREG,XMMREG,0}, "\331\2\x0F\x2D\110", IF_KATMAI|IF_SSE|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSD2SI[] = { - {I_CVTSD2SI, 2, {REG32,XMMREG,0}, "\3\xF2\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTSD2SI, 2, {REG32,MEMORY,0}, "\301\3\xF2\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSD2SS[] = { - {I_CVTSD2SS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTSD2SS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSI2SD[] = { - {I_CVTSI2SD, 2, {XMMREG,REG32,0}, "\3\xF2\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTSI2SD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSI2SS[] = { - {I_CVTSI2SS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_SD|IF_AR1}, - {I_CVTSI2SS, 2, {XMMREG,REG32,0}, "\333\2\x0F\x2A\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSS2SD[] = { - {I_CVTSS2SD, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTSS2SD, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTSS2SI[] = { - {I_CVTSS2SI, 2, {REG32,MEMORY,0}, "\301\333\2\x0F\x2D\110", IF_KATMAI|IF_SSE}, - {I_CVTSS2SI, 2, {REG32,XMMREG,0}, "\333\2\x0F\x2D\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTPD2DQ[] = { - {I_CVTTPD2DQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTTPD2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTPD2PI[] = { - {I_CVTTPD2PI, 2, {MMXREG,XMMREG,0}, "\3\x66\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTTPD2PI, 2, {MMXREG,MEMORY,0}, "\301\3\x66\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTPS2DQ[] = { - {I_CVTTPS2DQ, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTTPS2DQ, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTPS2PI[] = { - {I_CVTTPS2PI, 2, {MMXREG,MEMORY,0}, "\301\331\2\x0F\x2C\110", IF_KATMAI|IF_SSE|IF_MMX}, - {I_CVTTPS2PI, 2, {MMXREG,XMMREG,0}, "\331\2\x0F\x2C\110", IF_KATMAI|IF_SSE|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTSD2SI[] = { - {I_CVTTSD2SI, 2, {REG32,XMMREG,0}, "\3\xF2\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, - {I_CVTTSD2SI, 2, {REG32,MEMORY,0}, "\301\3\xF2\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CVTTSS2SI[] = { - {I_CVTTSS2SI, 2, {REG32,MEMORY,0}, "\301\333\2\x0F\x2C\110", IF_KATMAI|IF_SSE}, - {I_CVTTSS2SI, 2, {REG32,XMMREG,0}, "\333\2\x0F\x2C\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CWD[] = { - {I_CWD, 0, {0,0,0}, "\320\1\x99", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CWDE[] = { - {I_CWDE, 0, {0,0,0}, "\321\1\x98", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DAA[] = { - {I_DAA, 0, {0,0,0}, "\1\x27", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DAS[] = { - {I_DAS, 0, {0,0,0}, "\1\x2F", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DB[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_DD[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_DEC[] = { - {I_DEC, 1, {REG16,0,0}, "\320\10\x48", IF_8086}, - {I_DEC, 1, {REG32,0,0}, "\321\10\x48", IF_386}, - {I_DEC, 1, {REGMEM|BITS8,0,0}, "\300\1\xFE\201", IF_8086}, - {I_DEC, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\201", IF_8086}, - {I_DEC, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\201", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIV[] = { - {I_DIV, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\206", IF_8086}, - {I_DIV, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\206", IF_8086}, - {I_DIV, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\206", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIVPD[] = { - {I_DIVPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, - {I_DIVPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIVPS[] = { - {I_DIVPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, - {I_DIVPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIVSD[] = { - {I_DIVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, - {I_DIVSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DIVSS[] = { - {I_DIVSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, - {I_DIVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_DQ[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_DT[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_DW[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_EMMS[] = { - {I_EMMS, 0, {0,0,0}, "\2\x0F\x77", IF_PENT|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ENTER[] = { - {I_ENTER, 2, {IMMEDIATE,IMMEDIATE,0}, "\1\xC8\30\25", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_EQU[] = { - {I_EQU, 1, {IMMEDIATE,0,0}, "\0", IF_8086}, - {I_EQU, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\0", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_F2XM1[] = { - {I_F2XM1, 0, {0,0,0}, "\2\xD9\xF0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FABS[] = { - {I_FABS, 0, {0,0,0}, "\2\xD9\xE1", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FADD[] = { - {I_FADD, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\200", IF_8086|IF_FPU}, - {I_FADD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\200", IF_8086|IF_FPU}, - {I_FADD, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xC0", IF_8086|IF_FPU}, - {I_FADD, 1, {FPUREG,0,0}, "\1\xD8\10\xC0", IF_8086|IF_FPU}, - {I_FADD, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xC0", IF_8086|IF_FPU}, - {I_FADD, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xC0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FADDP[] = { - {I_FADDP, 1, {FPUREG,0,0}, "\1\xDE\10\xC0", IF_8086|IF_FPU}, - {I_FADDP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xC0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FBLD[] = { - {I_FBLD, 1, {MEMORY|BITS80,0,0}, "\300\1\xDF\204", IF_8086|IF_FPU}, - {I_FBLD, 1, {MEMORY,0,0}, "\300\1\xDF\204", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FBSTP[] = { - {I_FBSTP, 1, {MEMORY|BITS80,0,0}, "\300\1\xDF\206", IF_8086|IF_FPU}, - {I_FBSTP, 1, {MEMORY,0,0}, "\300\1\xDF\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCHS[] = { - {I_FCHS, 0, {0,0,0}, "\2\xD9\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCLEX[] = { - {I_FCLEX, 0, {0,0,0}, "\3\x9B\xDB\xE2", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVB[] = { - {I_FCMOVB, 1, {FPUREG,0,0}, "\1\xDA\10\xC0", IF_P6|IF_FPU}, - {I_FCMOVB, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xC0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVBE[] = { - {I_FCMOVBE, 1, {FPUREG,0,0}, "\1\xDA\10\xD0", IF_P6|IF_FPU}, - {I_FCMOVBE, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xD0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVE[] = { - {I_FCMOVE, 1, {FPUREG,0,0}, "\1\xDA\10\xC8", IF_P6|IF_FPU}, - {I_FCMOVE, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xC8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVNB[] = { - {I_FCMOVNB, 1, {FPUREG,0,0}, "\1\xDB\10\xC0", IF_P6|IF_FPU}, - {I_FCMOVNB, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xC0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVNBE[] = { - {I_FCMOVNBE, 1, {FPUREG,0,0}, "\1\xDB\10\xD0", IF_P6|IF_FPU}, - {I_FCMOVNBE, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xD0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVNE[] = { - {I_FCMOVNE, 1, {FPUREG,0,0}, "\1\xDB\10\xC8", IF_P6|IF_FPU}, - {I_FCMOVNE, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xC8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVNU[] = { - {I_FCMOVNU, 1, {FPUREG,0,0}, "\1\xDB\10\xD8", IF_P6|IF_FPU}, - {I_FCMOVNU, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xD8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCMOVU[] = { - {I_FCMOVU, 1, {FPUREG,0,0}, "\1\xDA\10\xD8", IF_P6|IF_FPU}, - {I_FCMOVU, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xD8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOM[] = { - {I_FCOM, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\202", IF_8086|IF_FPU}, - {I_FCOM, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\202", IF_8086|IF_FPU}, - {I_FCOM, 1, {FPUREG,0,0}, "\1\xD8\10\xD0", IF_8086|IF_FPU}, - {I_FCOM, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xD0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOMI[] = { - {I_FCOMI, 1, {FPUREG,0,0}, "\1\xDB\10\xF0", IF_P6|IF_FPU}, - {I_FCOMI, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xF0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOMIP[] = { - {I_FCOMIP, 1, {FPUREG,0,0}, "\1\xDF\10\xF0", IF_P6|IF_FPU}, - {I_FCOMIP, 2, {FPU0,FPUREG,0}, "\1\xDF\11\xF0", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOMP[] = { - {I_FCOMP, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\203", IF_8086|IF_FPU}, - {I_FCOMP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\203", IF_8086|IF_FPU}, - {I_FCOMP, 1, {FPUREG,0,0}, "\1\xD8\10\xD8", IF_8086|IF_FPU}, - {I_FCOMP, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xD8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOMPP[] = { - {I_FCOMPP, 0, {0,0,0}, "\2\xDE\xD9", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FCOS[] = { - {I_FCOS, 0, {0,0,0}, "\2\xD9\xFF", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDECSTP[] = { - {I_FDECSTP, 0, {0,0,0}, "\2\xD9\xF6", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDISI[] = { - {I_FDISI, 0, {0,0,0}, "\3\x9B\xDB\xE1", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDIV[] = { - {I_FDIV, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\206", IF_8086|IF_FPU}, - {I_FDIV, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\206", IF_8086|IF_FPU}, - {I_FDIV, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xF8", IF_8086|IF_FPU}, - {I_FDIV, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xF8", IF_8086|IF_FPU}, - {I_FDIV, 1, {FPUREG,0,0}, "\1\xD8\10\xF0", IF_8086|IF_FPU}, - {I_FDIV, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xF0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDIVP[] = { - {I_FDIVP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xF8", IF_8086|IF_FPU}, - {I_FDIVP, 1, {FPUREG,0,0}, "\1\xDE\10\xF8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDIVR[] = { - {I_FDIVR, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\207", IF_8086|IF_FPU}, - {I_FDIVR, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\207", IF_8086|IF_FPU}, - {I_FDIVR, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xF0", IF_8086|IF_FPU}, - {I_FDIVR, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xF0", IF_8086|IF_FPU}, - {I_FDIVR, 1, {FPUREG,0,0}, "\1\xD8\10\xF8", IF_8086|IF_FPU}, - {I_FDIVR, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xF8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FDIVRP[] = { - {I_FDIVRP, 1, {FPUREG,0,0}, "\1\xDE\10\xF0", IF_8086|IF_FPU}, - {I_FDIVRP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xF0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FEMMS[] = { - {I_FEMMS, 0, {0,0,0}, "\2\x0F\x0E", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FENI[] = { - {I_FENI, 0, {0,0,0}, "\3\x9B\xDB\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FFREE[] = { - {I_FFREE, 1, {FPUREG,0,0}, "\1\xDD\10\xC0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FFREEP[] = { - {I_FFREEP, 1, {FPUREG,0,0}, "\1\xDF\10\xC0", IF_286|IF_FPU|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIADD[] = { - {I_FIADD, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\200", IF_8086|IF_FPU}, - {I_FIADD, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\200", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FICOM[] = { - {I_FICOM, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\202", IF_8086|IF_FPU}, - {I_FICOM, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\202", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FICOMP[] = { - {I_FICOMP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\203", IF_8086|IF_FPU}, - {I_FICOMP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\203", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIDIV[] = { - {I_FIDIV, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\206", IF_8086|IF_FPU}, - {I_FIDIV, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIDIVR[] = { - {I_FIDIVR, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\207", IF_8086|IF_FPU}, - {I_FIDIVR, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\207", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FILD[] = { - {I_FILD, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\200", IF_8086|IF_FPU}, - {I_FILD, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\200", IF_8086|IF_FPU}, - {I_FILD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\205", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIMUL[] = { - {I_FIMUL, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\201", IF_8086|IF_FPU}, - {I_FIMUL, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\201", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FINCSTP[] = { - {I_FINCSTP, 0, {0,0,0}, "\2\xD9\xF7", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FINIT[] = { - {I_FINIT, 0, {0,0,0}, "\3\x9B\xDB\xE3", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FIST[] = { - {I_FIST, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\202", IF_8086|IF_FPU}, - {I_FIST, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\202", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FISTP[] = { - {I_FISTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\203", IF_8086|IF_FPU}, - {I_FISTP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\203", IF_8086|IF_FPU}, - {I_FISTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\207", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FISTTP[] = { - {I_FISTTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDD\201", IF_PRESCOTT|IF_FPU}, - {I_FISTTP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDB\201", IF_PRESCOTT|IF_FPU}, - {I_FISTTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\201", IF_PRESCOTT|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FISUB[] = { - {I_FISUB, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\204", IF_8086|IF_FPU}, - {I_FISUB, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\204", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FISUBR[] = { - {I_FISUBR, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\205", IF_8086|IF_FPU}, - {I_FISUBR, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\205", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLD[] = { - {I_FLD, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\200", IF_8086|IF_FPU}, - {I_FLD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\200", IF_8086|IF_FPU}, - {I_FLD, 1, {MEMORY|BITS80,0,0}, "\300\1\xDB\205", IF_8086|IF_FPU}, - {I_FLD, 1, {FPUREG,0,0}, "\1\xD9\10\xC0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLD1[] = { - {I_FLD1, 0, {0,0,0}, "\2\xD9\xE8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDCW[] = { - {I_FLDCW, 1, {MEMORY,0,0}, "\300\1\xD9\205", IF_8086|IF_FPU|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDENV[] = { - {I_FLDENV, 1, {MEMORY,0,0}, "\300\1\xD9\204", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDL2E[] = { - {I_FLDL2E, 0, {0,0,0}, "\2\xD9\xEA", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDL2T[] = { - {I_FLDL2T, 0, {0,0,0}, "\2\xD9\xE9", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDLG2[] = { - {I_FLDLG2, 0, {0,0,0}, "\2\xD9\xEC", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDLN2[] = { - {I_FLDLN2, 0, {0,0,0}, "\2\xD9\xED", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDPI[] = { - {I_FLDPI, 0, {0,0,0}, "\2\xD9\xEB", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FLDZ[] = { - {I_FLDZ, 0, {0,0,0}, "\2\xD9\xEE", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FMUL[] = { - {I_FMUL, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\201", IF_8086|IF_FPU}, - {I_FMUL, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\201", IF_8086|IF_FPU}, - {I_FMUL, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xC8", IF_8086|IF_FPU}, - {I_FMUL, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xC8", IF_8086|IF_FPU}, - {I_FMUL, 1, {FPUREG,0,0}, "\1\xD8\10\xC8", IF_8086|IF_FPU}, - {I_FMUL, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xC8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FMULP[] = { - {I_FMULP, 1, {FPUREG,0,0}, "\1\xDE\10\xC8", IF_8086|IF_FPU}, - {I_FMULP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xC8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNCLEX[] = { - {I_FNCLEX, 0, {0,0,0}, "\2\xDB\xE2", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNDISI[] = { - {I_FNDISI, 0, {0,0,0}, "\2\xDB\xE1", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNENI[] = { - {I_FNENI, 0, {0,0,0}, "\2\xDB\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNINIT[] = { - {I_FNINIT, 0, {0,0,0}, "\2\xDB\xE3", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNOP[] = { - {I_FNOP, 0, {0,0,0}, "\2\xD9\xD0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNSAVE[] = { - {I_FNSAVE, 1, {MEMORY,0,0}, "\300\1\xDD\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNSTCW[] = { - {I_FNSTCW, 1, {MEMORY,0,0}, "\300\1\xD9\207", IF_8086|IF_FPU|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNSTENV[] = { - {I_FNSTENV, 1, {MEMORY,0,0}, "\300\1\xD9\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FNSTSW[] = { - {I_FNSTSW, 1, {MEMORY,0,0}, "\300\1\xDD\207", IF_8086|IF_FPU|IF_SW}, - {I_FNSTSW, 1, {REG_AX,0,0}, "\2\xDF\xE0", IF_286|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FPATAN[] = { - {I_FPATAN, 0, {0,0,0}, "\2\xD9\xF3", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FPREM[] = { - {I_FPREM, 0, {0,0,0}, "\2\xD9\xF8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FPREM1[] = { - {I_FPREM1, 0, {0,0,0}, "\2\xD9\xF5", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FPTAN[] = { - {I_FPTAN, 0, {0,0,0}, "\2\xD9\xF2", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FRNDINT[] = { - {I_FRNDINT, 0, {0,0,0}, "\2\xD9\xFC", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FRSTOR[] = { - {I_FRSTOR, 1, {MEMORY,0,0}, "\300\1\xDD\204", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSAVE[] = { - {I_FSAVE, 1, {MEMORY,0,0}, "\300\2\x9B\xDD\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSCALE[] = { - {I_FSCALE, 0, {0,0,0}, "\2\xD9\xFD", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSETPM[] = { - {I_FSETPM, 0, {0,0,0}, "\2\xDB\xE4", IF_286|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSIN[] = { - {I_FSIN, 0, {0,0,0}, "\2\xD9\xFE", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSINCOS[] = { - {I_FSINCOS, 0, {0,0,0}, "\2\xD9\xFB", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSQRT[] = { - {I_FSQRT, 0, {0,0,0}, "\2\xD9\xFA", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FST[] = { - {I_FST, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\202", IF_8086|IF_FPU}, - {I_FST, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\202", IF_8086|IF_FPU}, - {I_FST, 1, {FPUREG,0,0}, "\1\xDD\10\xD0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSTCW[] = { - {I_FSTCW, 1, {MEMORY,0,0}, "\300\2\x9B\xD9\207", IF_8086|IF_FPU|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSTENV[] = { - {I_FSTENV, 1, {MEMORY,0,0}, "\300\2\x9B\xD9\206", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSTP[] = { - {I_FSTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\203", IF_8086|IF_FPU}, - {I_FSTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\203", IF_8086|IF_FPU}, - {I_FSTP, 1, {MEMORY|BITS80,0,0}, "\300\1\xDB\207", IF_8086|IF_FPU}, - {I_FSTP, 1, {FPUREG,0,0}, "\1\xDD\10\xD8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSTSW[] = { - {I_FSTSW, 1, {MEMORY,0,0}, "\300\2\x9B\xDD\207", IF_8086|IF_FPU|IF_SW}, - {I_FSTSW, 1, {REG_AX,0,0}, "\3\x9B\xDF\xE0", IF_286|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSUB[] = { - {I_FSUB, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\204", IF_8086|IF_FPU}, - {I_FSUB, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\204", IF_8086|IF_FPU}, - {I_FSUB, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xE8", IF_8086|IF_FPU}, - {I_FSUB, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xE8", IF_8086|IF_FPU}, - {I_FSUB, 1, {FPUREG,0,0}, "\1\xD8\10\xE0", IF_8086|IF_FPU}, - {I_FSUB, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSUBP[] = { - {I_FSUBP, 1, {FPUREG,0,0}, "\1\xDE\10\xE8", IF_8086|IF_FPU}, - {I_FSUBP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xE8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSUBR[] = { - {I_FSUBR, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\205", IF_8086|IF_FPU}, - {I_FSUBR, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\205", IF_8086|IF_FPU}, - {I_FSUBR, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xE0", IF_8086|IF_FPU}, - {I_FSUBR, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xE0", IF_8086|IF_FPU}, - {I_FSUBR, 1, {FPUREG,0,0}, "\1\xD8\10\xE8", IF_8086|IF_FPU}, - {I_FSUBR, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xE8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FSUBRP[] = { - {I_FSUBRP, 1, {FPUREG,0,0}, "\1\xDE\10\xE0", IF_8086|IF_FPU}, - {I_FSUBRP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xE0", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FTST[] = { - {I_FTST, 0, {0,0,0}, "\2\xD9\xE4", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOM[] = { - {I_FUCOM, 1, {FPUREG,0,0}, "\1\xDD\10\xE0", IF_386|IF_FPU}, - {I_FUCOM, 2, {FPU0,FPUREG,0}, "\1\xDD\11\xE0", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOMI[] = { - {I_FUCOMI, 1, {FPUREG,0,0}, "\1\xDB\10\xE8", IF_P6|IF_FPU}, - {I_FUCOMI, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xE8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOMIP[] = { - {I_FUCOMIP, 1, {FPUREG,0,0}, "\1\xDF\10\xE8", IF_P6|IF_FPU}, - {I_FUCOMIP, 2, {FPU0,FPUREG,0}, "\1\xDF\11\xE8", IF_P6|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOMP[] = { - {I_FUCOMP, 1, {FPUREG,0,0}, "\1\xDD\10\xE8", IF_386|IF_FPU}, - {I_FUCOMP, 2, {FPU0,FPUREG,0}, "\1\xDD\11\xE8", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FUCOMPP[] = { - {I_FUCOMPP, 0, {0,0,0}, "\2\xDA\xE9", IF_386|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FWAIT[] = { - {I_FWAIT, 0, {0,0,0}, "\1\x9B", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXAM[] = { - {I_FXAM, 0, {0,0,0}, "\2\xD9\xE5", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXCH[] = { - {I_FXCH, 0, {0,0,0}, "\2\xD9\xC9", IF_8086|IF_FPU}, - {I_FXCH, 1, {FPUREG,0,0}, "\1\xD9\10\xC8", IF_8086|IF_FPU}, - {I_FXCH, 2, {FPUREG,FPU0,0}, "\1\xD9\10\xC8", IF_8086|IF_FPU}, - {I_FXCH, 2, {FPU0,FPUREG,0}, "\1\xD9\11\xC8", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXRSTOR[] = { - {I_FXRSTOR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\201", IF_P6|IF_SSE|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXSAVE[] = { - {I_FXSAVE, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\200", IF_P6|IF_SSE|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FXTRACT[] = { - {I_FXTRACT, 0, {0,0,0}, "\2\xD9\xF4", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FYL2X[] = { - {I_FYL2X, 0, {0,0,0}, "\2\xD9\xF1", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_FYL2XP1[] = { - {I_FYL2XP1, 0, {0,0,0}, "\2\xD9\xF9", IF_8086|IF_FPU}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HADDPD[] = { - {I_HADDPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x7C\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_HADDPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7C\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HADDPS[] = { - {I_HADDPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x7C\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_HADDPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x7C\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HLT[] = { - {I_HLT, 0, {0,0,0}, "\1\xF4", IF_8086|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HSUBPD[] = { - {I_HSUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x7D\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_HSUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7D\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_HSUBPS[] = { - {I_HSUBPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x7D\110", IF_PRESCOTT|IF_SSE3|IF_SM}, - {I_HSUBPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x7D\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IBTS[] = { - {I_IBTS, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA7\101", IF_386|IF_SW|IF_UNDOC}, - {I_IBTS, 2, {REG16,REG16,0}, "\320\2\x0F\xA7\101", IF_386|IF_UNDOC}, - {I_IBTS, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA7\101", IF_386|IF_SD|IF_UNDOC}, - {I_IBTS, 2, {REG32,REG32,0}, "\321\2\x0F\xA7\101", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ICEBP[] = { - {I_ICEBP, 0, {0,0,0}, "\1\xF1", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IDIV[] = { - {I_IDIV, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\207", IF_8086}, - {I_IDIV, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\207", IF_8086}, - {I_IDIV, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\207", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IMUL[] = { - {I_IMUL, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\205", IF_8086}, - {I_IMUL, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\205", IF_8086}, - {I_IMUL, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\205", IF_386}, - {I_IMUL, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xAF\110", IF_386|IF_SM}, - {I_IMUL, 2, {REG16,REG16,0}, "\320\2\x0F\xAF\110", IF_386}, - {I_IMUL, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xAF\110", IF_386|IF_SM}, - {I_IMUL, 2, {REG32,REG32,0}, "\321\2\x0F\xAF\110", IF_386}, - {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE|BITS8}, "\320\301\1\x6B\110\16", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,MEMORY,SBYTE}, "\320\301\1\x6B\110\16", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE|BITS16}, "\320\301\1\x69\110\32", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE}, "\320\301\135\1\x69\110\132", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,REG16,IMMEDIATE|BITS8}, "\320\1\x6B\110\16", IF_186}, - {I_IMUL, 3, {REG16,REG16,SBYTE}, "\320\1\x6B\110\16", IF_186|IF_SM}, - {I_IMUL, 3, {REG16,REG16,IMMEDIATE|BITS16}, "\320\1\x69\110\32", IF_186}, - {I_IMUL, 3, {REG16,REG16,IMMEDIATE}, "\320\135\1\x69\110\132", IF_186|IF_SM}, - {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE|BITS8}, "\321\301\1\x6B\110\16", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,MEMORY,SBYTE}, "\321\301\1\x6B\110\16", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE|BITS32}, "\321\301\1\x69\110\42", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE}, "\321\301\145\1\x69\110\142", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,REG32,IMMEDIATE|BITS8}, "\321\1\x6B\110\16", IF_386}, - {I_IMUL, 3, {REG32,REG32,SBYTE}, "\321\1\x6B\110\16", IF_386|IF_SM}, - {I_IMUL, 3, {REG32,REG32,IMMEDIATE|BITS32}, "\321\1\x69\110\42", IF_386}, - {I_IMUL, 3, {REG32,REG32,IMMEDIATE}, "\321\145\1\x69\110\142", IF_386|IF_SM}, - {I_IMUL, 2, {REG16,IMMEDIATE|BITS8,0}, "\320\1\x6B\100\15", IF_186}, - {I_IMUL, 2, {REG16,SBYTE,0}, "\320\1\x6B\100\15", IF_186|IF_SM}, - {I_IMUL, 2, {REG16,IMMEDIATE|BITS16,0}, "\320\1\x69\100\31", IF_186}, - {I_IMUL, 2, {REG16,IMMEDIATE,0}, "\320\134\1\x69\100\131", IF_186|IF_SM}, - {I_IMUL, 2, {REG32,IMMEDIATE|BITS8,0}, "\321\1\x6B\100\15", IF_386}, - {I_IMUL, 2, {REG32,SBYTE,0}, "\321\1\x6B\100\15", IF_386|IF_SM}, - {I_IMUL, 2, {REG32,IMMEDIATE|BITS32,0}, "\321\1\x69\100\41", IF_386}, - {I_IMUL, 2, {REG32,IMMEDIATE,0}, "\321\144\1\x69\100\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IN[] = { - {I_IN, 2, {REG_AL,IMMEDIATE,0}, "\1\xE4\25", IF_8086|IF_SB}, - {I_IN, 2, {REG_AX,IMMEDIATE,0}, "\320\1\xE5\25", IF_8086|IF_SB}, - {I_IN, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\xE5\25", IF_386|IF_SB}, - {I_IN, 2, {REG_AL,REG_DX,0}, "\1\xEC", IF_8086}, - {I_IN, 2, {REG_AX,REG_DX,0}, "\320\1\xED", IF_8086}, - {I_IN, 2, {REG_EAX,REG_DX,0}, "\321\1\xED", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INC[] = { - {I_INC, 1, {REG16,0,0}, "\320\10\x40", IF_8086}, - {I_INC, 1, {REG32,0,0}, "\321\10\x40", IF_386}, - {I_INC, 1, {REGMEM|BITS8,0,0}, "\300\1\xFE\200", IF_8086}, - {I_INC, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\200", IF_8086}, - {I_INC, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\200", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INCBIN[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_INSB[] = { - {I_INSB, 0, {0,0,0}, "\1\x6C", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INSD[] = { - {I_INSD, 0, {0,0,0}, "\321\1\x6D", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INSW[] = { - {I_INSW, 0, {0,0,0}, "\320\1\x6D", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT[] = { - {I_INT, 1, {IMMEDIATE,0,0}, "\1\xCD\24", IF_8086|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT01[] = { - {I_INT01, 0, {0,0,0}, "\1\xF1", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT03[] = { - {I_INT03, 0, {0,0,0}, "\1\xCC", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT1[] = { - {I_INT1, 0, {0,0,0}, "\1\xF1", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INT3[] = { - {I_INT3, 0, {0,0,0}, "\1\xCC", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INTO[] = { - {I_INTO, 0, {0,0,0}, "\1\xCE", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INVD[] = { - {I_INVD, 0, {0,0,0}, "\2\x0F\x08", IF_486|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_INVLPG[] = { - {I_INVLPG, 1, {MEMORY,0,0}, "\300\2\x0F\x01\207", IF_486|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IRET[] = { - {I_IRET, 0, {0,0,0}, "\322\1\xCF", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IRETD[] = { - {I_IRETD, 0, {0,0,0}, "\321\1\xCF", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_IRETW[] = { - {I_IRETW, 0, {0,0,0}, "\320\1\xCF", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_JCXZ[] = { - {I_JCXZ, 1, {IMMEDIATE,0,0}, "\310\1\xE3\50", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_JECXZ[] = { - {I_JECXZ, 1, {IMMEDIATE,0,0}, "\311\1\xE3\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_JMP[] = { - {I_JMP, 1, {IMMEDIATE|SHORT,0,0}, "\1\xEB\50", IF_8086}, - {I_JMP, 1, {IMMEDIATE,0,0}, "\371\1\xEB\50", IF_8086}, - {I_JMP, 1, {IMMEDIATE,0,0}, "\322\1\xE9\64", IF_8086}, - {I_JMP, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\xE9\64", IF_8086}, - {I_JMP, 1, {IMMEDIATE|FAR,0,0}, "\322\1\xEA\34\37", IF_8086}, - {I_JMP, 1, {IMMEDIATE|BITS16,0,0}, "\320\1\xE9\64", IF_8086}, - {I_JMP, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\xE9\64", IF_8086}, - {I_JMP, 1, {IMMEDIATE|BITS16|FAR,0,0}, "\320\1\xEA\34\37", IF_8086}, - {I_JMP, 1, {IMMEDIATE|BITS32,0,0}, "\321\1\xE9\64", IF_386}, - {I_JMP, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\xE9\64", IF_386}, - {I_JMP, 1, {IMMEDIATE|BITS32|FAR,0,0}, "\321\1\xEA\34\37", IF_386}, - {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\322\1\xEA\35\30", IF_8086}, - {I_JMP, 2, {IMMEDIATE|BITS16|COLON,IMMEDIATE,0}, "\320\1\xEA\31\30", IF_8086}, - {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS16,0}, "\320\1\xEA\31\30", IF_8086}, - {I_JMP, 2, {IMMEDIATE|BITS32|COLON,IMMEDIATE,0}, "\321\1\xEA\41\30", IF_386}, - {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS32,0}, "\321\1\xEA\41\30", IF_386}, - {I_JMP, 1, {MEMORY|FAR,0,0}, "\322\300\1\xFF\205", IF_8086}, - {I_JMP, 1, {MEMORY|BITS16|FAR,0,0}, "\320\300\1\xFF\205", IF_8086}, - {I_JMP, 1, {MEMORY|BITS32|FAR,0,0}, "\321\300\1\xFF\205", IF_386}, - {I_JMP, 1, {MEMORY|NEAR,0,0}, "\322\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {MEMORY|BITS16|NEAR,0,0}, "\320\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {MEMORY|BITS32|NEAR,0,0}, "\321\300\1\xFF\204", IF_386}, - {I_JMP, 1, {REG16,0,0}, "\320\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {REG32,0,0}, "\321\300\1\xFF\204", IF_386}, - {I_JMP, 1, {MEMORY,0,0}, "\322\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {MEMORY|BITS16,0,0}, "\320\300\1\xFF\204", IF_8086}, - {I_JMP, 1, {MEMORY|BITS32,0,0}, "\321\300\1\xFF\204", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_JMPE[] = { - {I_JMPE, 1, {IMMEDIATE,0,0}, "\322\2\x0F\xB8\64", IF_IA64}, - {I_JMPE, 1, {IMMEDIATE|BITS16,0,0}, "\320\2\x0F\xB8\64", IF_IA64}, - {I_JMPE, 1, {IMMEDIATE|BITS32,0,0}, "\321\2\x0F\xB8\64", IF_IA64}, - {I_JMPE, 1, {REGMEM|BITS16,0,0}, "\320\2\x0F\x00\206", IF_IA64}, - {I_JMPE, 1, {REGMEM|BITS32,0,0}, "\321\2\x0F\x00\206", IF_IA64}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LAHF[] = { - {I_LAHF, 0, {0,0,0}, "\1\x9F", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LAR[] = { - {I_LAR, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x02\110", IF_286|IF_PROT|IF_SM}, - {I_LAR, 2, {REG16,REG16,0}, "\320\2\x0F\x02\110", IF_286|IF_PROT}, - {I_LAR, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x02\110", IF_386|IF_PROT|IF_SM}, - {I_LAR, 2, {REG32,REG32,0}, "\321\2\x0F\x02\110", IF_386|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LDDQU[] = { - {I_LDDQU, 2, {XMMREG,MEMORY,0}, "\3\xF2\x0F\xF0\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LDMXCSR[] = { - {I_LDMXCSR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\202", IF_KATMAI|IF_SSE|IF_SD}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LDS[] = { - {I_LDS, 2, {REG16,MEMORY,0}, "\320\301\1\xC5\110", IF_8086}, - {I_LDS, 2, {REG32,MEMORY,0}, "\321\301\1\xC5\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LEA[] = { - {I_LEA, 2, {REG16,MEMORY,0}, "\320\301\1\x8D\110", IF_8086}, - {I_LEA, 2, {REG32,MEMORY,0}, "\321\301\1\x8D\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LEAVE[] = { - {I_LEAVE, 0, {0,0,0}, "\1\xC9", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LES[] = { - {I_LES, 2, {REG16,MEMORY,0}, "\320\301\1\xC4\110", IF_8086}, - {I_LES, 2, {REG32,MEMORY,0}, "\321\301\1\xC4\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LFENCE[] = { - {I_LFENCE, 0, {0,0,0}, "\3\x0F\xAE\xE8", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LFS[] = { - {I_LFS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB4\110", IF_386}, - {I_LFS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB4\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LGDT[] = { - {I_LGDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\202", IF_286|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LGS[] = { - {I_LGS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB5\110", IF_386}, - {I_LGS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB5\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LIDT[] = { - {I_LIDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\203", IF_286|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LLDT[] = { - {I_LLDT, 1, {MEMORY,0,0}, "\300\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, - {I_LLDT, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, - {I_LLDT, 1, {REG16,0,0}, "\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LMSW[] = { - {I_LMSW, 1, {MEMORY,0,0}, "\300\2\x0F\x01\206", IF_286|IF_PRIV}, - {I_LMSW, 1, {MEMORY|BITS16,0,0}, "\300\2\x0F\x01\206", IF_286|IF_PRIV}, - {I_LMSW, 1, {REG16,0,0}, "\2\x0F\x01\206", IF_286|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOADALL[] = { - {I_LOADALL, 0, {0,0,0}, "\2\x0F\x07", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOADALL286[] = { - {I_LOADALL286, 0, {0,0,0}, "\2\x0F\x05", IF_286|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LODSB[] = { - {I_LODSB, 0, {0,0,0}, "\1\xAC", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LODSD[] = { - {I_LODSD, 0, {0,0,0}, "\321\1\xAD", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LODSW[] = { - {I_LODSW, 0, {0,0,0}, "\320\1\xAD", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOP[] = { - {I_LOOP, 1, {IMMEDIATE,0,0}, "\312\1\xE2\50", IF_8086}, - {I_LOOP, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE2\50", IF_8086}, - {I_LOOP, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE2\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOPE[] = { - {I_LOOPE, 1, {IMMEDIATE,0,0}, "\312\1\xE1\50", IF_8086}, - {I_LOOPE, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE1\50", IF_8086}, - {I_LOOPE, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE1\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOPNE[] = { - {I_LOOPNE, 1, {IMMEDIATE,0,0}, "\312\1\xE0\50", IF_8086}, - {I_LOOPNE, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE0\50", IF_8086}, - {I_LOOPNE, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE0\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOPNZ[] = { - {I_LOOPNZ, 1, {IMMEDIATE,0,0}, "\312\1\xE0\50", IF_8086}, - {I_LOOPNZ, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE0\50", IF_8086}, - {I_LOOPNZ, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE0\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LOOPZ[] = { - {I_LOOPZ, 1, {IMMEDIATE,0,0}, "\312\1\xE1\50", IF_8086}, - {I_LOOPZ, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE1\50", IF_8086}, - {I_LOOPZ, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE1\50", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LSL[] = { - {I_LSL, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x03\110", IF_286|IF_PROT|IF_SM}, - {I_LSL, 2, {REG16,REG16,0}, "\320\2\x0F\x03\110", IF_286|IF_PROT}, - {I_LSL, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x03\110", IF_386|IF_PROT|IF_SM}, - {I_LSL, 2, {REG32,REG32,0}, "\321\2\x0F\x03\110", IF_386|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LSS[] = { - {I_LSS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB2\110", IF_386}, - {I_LSS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB2\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_LTR[] = { - {I_LTR, 1, {MEMORY,0,0}, "\300\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, - {I_LTR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, - {I_LTR, 1, {REG16,0,0}, "\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MASKMOVDQU[] = { - {I_MASKMOVDQU, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF7\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MASKMOVQ[] = { - {I_MASKMOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF7\110", IF_KATMAI|IF_MMX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MAXPD[] = { - {I_MAXPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, - {I_MAXPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MAXPS[] = { - {I_MAXPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, - {I_MAXPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MAXSD[] = { - {I_MAXSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, - {I_MAXSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MAXSS[] = { - {I_MAXSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, - {I_MAXSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MFENCE[] = { - {I_MFENCE, 0, {0,0,0}, "\3\x0F\xAE\xF0", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MINPD[] = { - {I_MINPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, - {I_MINPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MINPS[] = { - {I_MINPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, - {I_MINPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MINSD[] = { - {I_MINSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, - {I_MINSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MINSS[] = { - {I_MINSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, - {I_MINSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MONITOR[] = { - {I_MONITOR, 0, {0,0,0}, "\3\x0F\x01\xC8", IF_PRESCOTT}, - {I_MONITOR, 3, {REG_EAX,REG_ECX,REG_EDX}, "\3\x0F\x01\xC8", IF_PRESCOTT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOV[] = { - {I_MOV, 2, {MEMORY,REG_SREG,0}, "\300\1\x8C\101", IF_8086|IF_SM}, - {I_MOV, 2, {REG16,REG_SREG,0}, "\320\1\x8C\101", IF_8086}, - {I_MOV, 2, {REG32,REG_SREG,0}, "\321\1\x8C\101", IF_386}, - {I_MOV, 2, {REG_SREG,MEMORY,0}, "\301\1\x8E\110", IF_8086|IF_SM}, - {I_MOV, 2, {REG_SREG,REG16,0}, "\1\x8E\110", IF_8086}, - {I_MOV, 2, {REG_SREG,REG32,0}, "\1\x8E\110", IF_386}, - {I_MOV, 2, {REG_AL,MEM_OFFS,0}, "\301\1\xA0\45", IF_8086|IF_SM}, - {I_MOV, 2, {REG_AX,MEM_OFFS,0}, "\301\320\1\xA1\45", IF_8086|IF_SM}, - {I_MOV, 2, {REG_EAX,MEM_OFFS,0}, "\301\321\1\xA1\45", IF_386|IF_SM}, - {I_MOV, 2, {MEM_OFFS,REG_AL,0}, "\300\1\xA2\44", IF_8086|IF_SM}, - {I_MOV, 2, {MEM_OFFS,REG_AX,0}, "\300\320\1\xA3\44", IF_8086|IF_SM}, - {I_MOV, 2, {MEM_OFFS,REG_EAX,0}, "\300\321\1\xA3\44", IF_386|IF_SM}, - {I_MOV, 2, {REG32,REG_CREG,0}, "\2\x0F\x20\101", IF_386|IF_PRIV}, - {I_MOV, 2, {REG32,REG_DREG,0}, "\2\x0F\x21\101", IF_386|IF_PRIV}, - {I_MOV, 2, {REG32,REG_TREG,0}, "\2\x0F\x24\101", IF_386|IF_PRIV}, - {I_MOV, 2, {REG_CREG,REG32,0}, "\2\x0F\x22\110", IF_386|IF_PRIV}, - {I_MOV, 2, {REG_DREG,REG32,0}, "\2\x0F\x23\110", IF_386|IF_PRIV}, - {I_MOV, 2, {REG_TREG,REG32,0}, "\2\x0F\x26\110", IF_386|IF_PRIV}, - {I_MOV, 2, {MEMORY,REG8,0}, "\300\1\x88\101", IF_8086|IF_SM}, - {I_MOV, 2, {REG8,REG8,0}, "\1\x88\101", IF_8086}, - {I_MOV, 2, {MEMORY,REG16,0}, "\320\300\1\x89\101", IF_8086|IF_SM}, - {I_MOV, 2, {REG16,REG16,0}, "\320\1\x89\101", IF_8086}, - {I_MOV, 2, {MEMORY,REG32,0}, "\321\300\1\x89\101", IF_386|IF_SM}, - {I_MOV, 2, {REG32,REG32,0}, "\321\1\x89\101", IF_386}, - {I_MOV, 2, {REG8,MEMORY,0}, "\301\1\x8A\110", IF_8086|IF_SM}, - {I_MOV, 2, {REG8,REG8,0}, "\1\x8A\110", IF_8086}, - {I_MOV, 2, {REG16,MEMORY,0}, "\320\301\1\x8B\110", IF_8086|IF_SM}, - {I_MOV, 2, {REG16,REG16,0}, "\320\1\x8B\110", IF_8086}, - {I_MOV, 2, {REG32,MEMORY,0}, "\321\301\1\x8B\110", IF_386|IF_SM}, - {I_MOV, 2, {REG32,REG32,0}, "\321\1\x8B\110", IF_386}, - {I_MOV, 2, {REG8,IMMEDIATE,0}, "\10\xB0\21", IF_8086|IF_SM}, - {I_MOV, 2, {REG16,IMMEDIATE,0}, "\320\10\xB8\31", IF_8086|IF_SM}, - {I_MOV, 2, {REG32,IMMEDIATE,0}, "\321\10\xB8\41", IF_386|IF_SM}, - {I_MOV, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC6\200\21", IF_8086|IF_SM}, - {I_MOV, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC7\200\31", IF_8086|IF_SM}, - {I_MOV, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC7\200\41", IF_386|IF_SM}, - {I_MOV, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\xC6\200\21", IF_8086|IF_SM}, - {I_MOV, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\1\xC7\200\31", IF_8086|IF_SM}, - {I_MOV, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\1\xC7\200\41", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVAPD[] = { - {I_MOVAPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x28\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVAPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x29\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVAPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x29\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVAPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x28\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVAPS[] = { - {I_MOVAPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x28\110", IF_KATMAI|IF_SSE}, - {I_MOVAPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x29\101", IF_KATMAI|IF_SSE}, - {I_MOVAPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x28\110", IF_KATMAI|IF_SSE}, - {I_MOVAPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x29\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVD[] = { - {I_MOVD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6E\110", IF_PENT|IF_MMX|IF_SD}, - {I_MOVD, 2, {MMXREG,REG32,0}, "\2\x0F\x6E\110", IF_PENT|IF_MMX}, - {I_MOVD, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\x7E\101", IF_PENT|IF_MMX|IF_SD}, - {I_MOVD, 2, {REG32,MMXREG,0}, "\2\x0F\x7E\101", IF_PENT|IF_MMX}, - {I_MOVD, 2, {XMMREG,REG32,0}, "\3\x66\x0F\x6E\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVD, 2, {REG32,XMMREG,0}, "\3\x66\x0F\x7E\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x7E\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6E\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVDDUP[] = { - {I_MOVDDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, - {I_MOVDDUP, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVDQ2Q[] = { - {I_MOVDQ2Q, 2, {MMXREG,XMMREG,0}, "\3\xF2\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVDQA[] = { - {I_MOVDQA, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVDQA, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x7F\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVDQA, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVDQA, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7F\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVDQU[] = { - {I_MOVDQU, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVDQU, 2, {MEMORY,XMMREG,0}, "\333\300\2\x0F\x7F\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVDQU, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVDQU, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x7F\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVHLPS[] = { - {I_MOVHLPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x12\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVHPD[] = { - {I_MOVHPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x17\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVHPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x16\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVHPS[] = { - {I_MOVHPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x16\110", IF_KATMAI|IF_SSE}, - {I_MOVHPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x17\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVLHPS[] = { - {I_MOVLHPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x16\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVLPD[] = { - {I_MOVLPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x13\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVLPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x12\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVLPS[] = { - {I_MOVLPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x12\110", IF_KATMAI|IF_SSE}, - {I_MOVLPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x13\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVMSKPD[] = { - {I_MOVMSKPD, 2, {REG32,XMMREG,0}, "\3\x66\x0F\x50\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVMSKPS[] = { - {I_MOVMSKPS, 2, {REG32,XMMREG,0}, "\2\x0F\x50\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTDQ[] = { - {I_MOVNTDQ, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\xE7\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTI[] = { - {I_MOVNTI, 2, {MEMORY,REG32,0}, "\300\2\x0F\xC3\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTPD[] = { - {I_MOVNTPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x2B\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTPS[] = { - {I_MOVNTPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x2B\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVNTQ[] = { - {I_MOVNTQ, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\xE7\101", IF_KATMAI|IF_MMX|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVQ[] = { - {I_MOVQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6F\110", IF_PENT|IF_MMX|IF_SM}, - {I_MOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6F\110", IF_PENT|IF_MMX}, - {I_MOVQ, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\x7F\101", IF_PENT|IF_MMX|IF_SM}, - {I_MOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x7F\101", IF_PENT|IF_MMX}, - {I_MOVQ, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x7E\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVQ, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\xD6\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVQ, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x7E\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVQ2DQ[] = { - {I_MOVQ2DQ, 2, {XMMREG,MMXREG,0}, "\333\2\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSB[] = { - {I_MOVSB, 0, {0,0,0}, "\1\xA4", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSD[] = { - {I_MOVSD, 0, {0,0,0}, "\321\1\xA5", IF_386}, - {I_MOVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x11\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVSD, 2, {MEMORY,XMMREG,0}, "\300\3\xF2\x0F\x11\101", IF_WILLAMETTE|IF_SSE2}, - {I_MOVSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSHDUP[] = { - {I_MOVSHDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF3\x0F\x16\110", IF_PRESCOTT|IF_SSE3}, - {I_MOVSHDUP, 2, {XMMREG,XMMREG,0}, "\3\xF3\x0F\x16\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSLDUP[] = { - {I_MOVSLDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF3\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, - {I_MOVSLDUP, 2, {XMMREG,XMMREG,0}, "\3\xF3\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSS[] = { - {I_MOVSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x10\110", IF_KATMAI|IF_SSE}, - {I_MOVSS, 2, {MEMORY,XMMREG,0}, "\300\333\2\x0F\x11\101", IF_KATMAI|IF_SSE}, - {I_MOVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x10\110", IF_KATMAI|IF_SSE}, - {I_MOVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x11\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSW[] = { - {I_MOVSW, 0, {0,0,0}, "\320\1\xA5", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVSX[] = { - {I_MOVSX, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBE\110", IF_386|IF_SB}, - {I_MOVSX, 2, {REG16,REG8,0}, "\320\2\x0F\xBE\110", IF_386}, - {I_MOVSX, 2, {REG32,REGMEM|BITS8,0}, "\321\301\2\x0F\xBE\110", IF_386}, - {I_MOVSX, 2, {REG32,REGMEM|BITS16,0}, "\321\301\2\x0F\xBF\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVUPD[] = { - {I_MOVUPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVUPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x11\110", IF_WILLAMETTE|IF_SSE2}, - {I_MOVUPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x11\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_MOVUPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x10\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVUPS[] = { - {I_MOVUPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x10\110", IF_KATMAI|IF_SSE}, - {I_MOVUPS, 2, {MEMORY,XMMREG,0}, "\300\331\2\x0F\x11\101", IF_KATMAI|IF_SSE}, - {I_MOVUPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x10\110", IF_KATMAI|IF_SSE}, - {I_MOVUPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x11\101", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MOVZX[] = { - {I_MOVZX, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB6\110", IF_386|IF_SB}, - {I_MOVZX, 2, {REG16,REG8,0}, "\320\2\x0F\xB6\110", IF_386}, - {I_MOVZX, 2, {REG32,REGMEM|BITS8,0}, "\321\301\2\x0F\xB6\110", IF_386}, - {I_MOVZX, 2, {REG32,REGMEM|BITS16,0}, "\321\301\2\x0F\xB7\110", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MUL[] = { - {I_MUL, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\204", IF_8086}, - {I_MUL, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\204", IF_8086}, - {I_MUL, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\204", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MULPD[] = { - {I_MULPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, - {I_MULPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x59\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MULPS[] = { - {I_MULPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x59\110", IF_KATMAI|IF_SSE}, - {I_MULPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x59\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MULSD[] = { - {I_MULSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, - {I_MULSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MULSS[] = { - {I_MULSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x59\110", IF_KATMAI|IF_SSE}, - {I_MULSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x59\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_MWAIT[] = { - {I_MWAIT, 0, {0,0,0}, "\3\x0F\x01\xC9", IF_PRESCOTT}, - {I_MWAIT, 2, {REG_EAX,REG_ECX,0}, "\3\x0F\x01\xC9", IF_PRESCOTT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_NEG[] = { - {I_NEG, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\203", IF_8086}, - {I_NEG, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\203", IF_8086}, - {I_NEG, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\203", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_NOP[] = { - {I_NOP, 0, {0,0,0}, "\1\x90", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_NOT[] = { - {I_NOT, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\202", IF_8086}, - {I_NOT, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\202", IF_8086}, - {I_NOT, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\202", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OR[] = { - {I_OR, 2, {MEMORY,REG8,0}, "\300\1\x08\101", IF_8086|IF_SM}, - {I_OR, 2, {REG8,REG8,0}, "\1\x08\101", IF_8086}, - {I_OR, 2, {MEMORY,REG16,0}, "\320\300\1\x09\101", IF_8086|IF_SM}, - {I_OR, 2, {REG16,REG16,0}, "\320\1\x09\101", IF_8086}, - {I_OR, 2, {MEMORY,REG32,0}, "\321\300\1\x09\101", IF_386|IF_SM}, - {I_OR, 2, {REG32,REG32,0}, "\321\1\x09\101", IF_386}, - {I_OR, 2, {REG8,MEMORY,0}, "\301\1\x0A\110", IF_8086|IF_SM}, - {I_OR, 2, {REG8,REG8,0}, "\1\x0A\110", IF_8086}, - {I_OR, 2, {REG16,MEMORY,0}, "\320\301\1\x0B\110", IF_8086|IF_SM}, - {I_OR, 2, {REG16,REG16,0}, "\320\1\x0B\110", IF_8086}, - {I_OR, 2, {REG32,MEMORY,0}, "\321\301\1\x0B\110", IF_386|IF_SM}, - {I_OR, 2, {REG32,REG32,0}, "\321\1\x0B\110", IF_386}, - {I_OR, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\201\15", IF_8086}, - {I_OR, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\201\15", IF_386}, - {I_OR, 2, {REG_AL,IMMEDIATE,0}, "\1\x0C\21", IF_8086|IF_SM}, - {I_OR, 2, {REG_AX,SBYTE,0}, "\320\1\x83\201\15", IF_8086|IF_SM}, - {I_OR, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x0D\31", IF_8086|IF_SM}, - {I_OR, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\201\15", IF_386|IF_SM}, - {I_OR, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x0D\41", IF_386|IF_SM}, - {I_OR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\201\21", IF_8086|IF_SM}, - {I_OR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\201\131", IF_8086|IF_SM}, - {I_OR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\201\141", IF_386|IF_SM}, - {I_OR, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\201\21", IF_8086|IF_SM}, - {I_OR, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\201\131", IF_8086|IF_SM}, - {I_OR, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\201\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ORPD[] = { - {I_ORPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x56\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_ORPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x56\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ORPS[] = { - {I_ORPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x56\110", IF_KATMAI|IF_SSE}, - {I_ORPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x56\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OUT[] = { - {I_OUT, 2, {IMMEDIATE,REG_AL,0}, "\1\xE6\24", IF_8086|IF_SB}, - {I_OUT, 2, {IMMEDIATE,REG_AX,0}, "\320\1\xE7\24", IF_8086|IF_SB}, - {I_OUT, 2, {IMMEDIATE,REG_EAX,0}, "\321\1\xE7\24", IF_386|IF_SB}, - {I_OUT, 2, {REG_DX,REG_AL,0}, "\1\xEE", IF_8086}, - {I_OUT, 2, {REG_DX,REG_AX,0}, "\320\1\xEF", IF_8086}, - {I_OUT, 2, {REG_DX,REG_EAX,0}, "\321\1\xEF", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OUTSB[] = { - {I_OUTSB, 0, {0,0,0}, "\1\x6E", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OUTSD[] = { - {I_OUTSD, 0, {0,0,0}, "\321\1\x6F", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_OUTSW[] = { - {I_OUTSW, 0, {0,0,0}, "\320\1\x6F", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PACKSSDW[] = { - {I_PACKSSDW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6B\110", IF_PENT|IF_MMX|IF_SM}, - {I_PACKSSDW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6B\110", IF_PENT|IF_MMX}, - {I_PACKSSDW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6B\110", IF_WILLAMETTE|IF_SSE2}, - {I_PACKSSDW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PACKSSWB[] = { - {I_PACKSSWB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x63\110", IF_PENT|IF_MMX|IF_SM}, - {I_PACKSSWB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x63\110", IF_PENT|IF_MMX}, - {I_PACKSSWB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x63\110", IF_WILLAMETTE|IF_SSE2}, - {I_PACKSSWB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x63\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PACKUSWB[] = { - {I_PACKUSWB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x67\110", IF_PENT|IF_MMX|IF_SM}, - {I_PACKUSWB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x67\110", IF_PENT|IF_MMX}, - {I_PACKUSWB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x67\110", IF_WILLAMETTE|IF_SSE2}, - {I_PACKUSWB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x67\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDB[] = { - {I_PADDB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFC\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFC\110", IF_PENT|IF_MMX}, - {I_PADDB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFC\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDD[] = { - {I_PADDD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFE\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFE\110", IF_PENT|IF_MMX}, - {I_PADDD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFE\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDQ[] = { - {I_PADDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDSB[] = { - {I_PADDSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEC\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEC\110", IF_PENT|IF_MMX}, - {I_PADDSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEC\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDSIW[] = { - {I_PADDSIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x51\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PADDSIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x51\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDSW[] = { - {I_PADDSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xED\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xED\110", IF_PENT|IF_MMX}, - {I_PADDSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xED\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xED\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDUSB[] = { - {I_PADDUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDC\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDC\110", IF_PENT|IF_MMX}, - {I_PADDUSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDUSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDC\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDUSW[] = { - {I_PADDUSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDD\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDUSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDD\110", IF_PENT|IF_MMX}, - {I_PADDUSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDD\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PADDUSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDD\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PADDW[] = { - {I_PADDW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFD\110", IF_PENT|IF_MMX|IF_SM}, - {I_PADDW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFD\110", IF_PENT|IF_MMX}, - {I_PADDW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFD\110", IF_WILLAMETTE|IF_SSE2}, - {I_PADDW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFD\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAND[] = { - {I_PAND, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDB\110", IF_PENT|IF_MMX|IF_SM}, - {I_PAND, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDB\110", IF_PENT|IF_MMX}, - {I_PAND, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDB\110", IF_WILLAMETTE|IF_SSE2}, - {I_PAND, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PANDN[] = { - {I_PANDN, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDF\110", IF_PENT|IF_MMX|IF_SM}, - {I_PANDN, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDF\110", IF_PENT|IF_MMX}, - {I_PANDN, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDF\110", IF_WILLAMETTE|IF_SSE2}, - {I_PANDN, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDF\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAUSE[] = { - {I_PAUSE, 0, {0,0,0}, "\333\1\x90", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAVEB[] = { - {I_PAVEB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x50\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PAVEB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x50\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAVGB[] = { - {I_PAVGB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE0\110", IF_KATMAI|IF_MMX}, - {I_PAVGB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE0\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PAVGB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE0\110", IF_WILLAMETTE|IF_SSE2}, - {I_PAVGB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE0\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAVGUSB[] = { - {I_PAVGUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xBF", IF_PENT|IF_3DNOW|IF_SM}, - {I_PAVGUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xBF", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PAVGW[] = { - {I_PAVGW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE3\110", IF_KATMAI|IF_MMX}, - {I_PAVGW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE3\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PAVGW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE3\110", IF_WILLAMETTE|IF_SSE2}, - {I_PAVGW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPEQB[] = { - {I_PCMPEQB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x74\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPEQB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x74\110", IF_PENT|IF_MMX}, - {I_PCMPEQB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x74\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPEQB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x74\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPEQD[] = { - {I_PCMPEQD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x76\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPEQD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x76\110", IF_PENT|IF_MMX}, - {I_PCMPEQD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x76\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPEQD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x76\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPEQW[] = { - {I_PCMPEQW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x75\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPEQW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x75\110", IF_PENT|IF_MMX}, - {I_PCMPEQW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x75\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPEQW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x75\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPGTB[] = { - {I_PCMPGTB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x64\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPGTB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x64\110", IF_PENT|IF_MMX}, - {I_PCMPGTB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x64\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPGTB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x64\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPGTD[] = { - {I_PCMPGTD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x66\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPGTD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x66\110", IF_PENT|IF_MMX}, - {I_PCMPGTD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x66\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPGTD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x66\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PCMPGTW[] = { - {I_PCMPGTW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x65\110", IF_PENT|IF_MMX|IF_SM}, - {I_PCMPGTW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x65\110", IF_PENT|IF_MMX}, - {I_PCMPGTW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x65\110", IF_WILLAMETTE|IF_SSE2}, - {I_PCMPGTW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x65\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PDISTIB[] = { - {I_PDISTIB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x54\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PEXTRW[] = { - {I_PEXTRW, 3, {REG32,MMXREG,IMMEDIATE}, "\2\x0F\xC5\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PEXTRW, 3, {REG32,XMMREG,IMMEDIATE}, "\3\x66\x0F\xC5\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PF2ID[] = { - {I_PF2ID, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x1D", IF_PENT|IF_3DNOW|IF_SM}, - {I_PF2ID, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x1D", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PF2IW[] = { - {I_PF2IW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x1C", IF_PENT|IF_3DNOW|IF_SM}, - {I_PF2IW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x1C", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFACC[] = { - {I_PFACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xAE", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xAE", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFADD[] = { - {I_PFADD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x9E", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFADD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x9E", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFCMPEQ[] = { - {I_PFCMPEQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB0", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFCMPEQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB0", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFCMPGE[] = { - {I_PFCMPGE, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x90", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFCMPGE, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x90", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFCMPGT[] = { - {I_PFCMPGT, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA0", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFCMPGT, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA0", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFMAX[] = { - {I_PFMAX, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA4", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFMAX, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA4", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFMIN[] = { - {I_PFMIN, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x94", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFMIN, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x94", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFMUL[] = { - {I_PFMUL, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB4", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFMUL, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB4", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFNACC[] = { - {I_PFNACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x8A", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFNACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x8A", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFPNACC[] = { - {I_PFPNACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x8E", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFPNACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x8E", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRCP[] = { - {I_PFRCP, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x96", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRCP, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x96", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRCPIT1[] = { - {I_PFRCPIT1, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA6", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRCPIT1, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA6", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRCPIT2[] = { - {I_PFRCPIT2, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB6", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRCPIT2, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB6", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRSQIT1[] = { - {I_PFRSQIT1, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA7", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRSQIT1, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA7", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFRSQRT[] = { - {I_PFRSQRT, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x97", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFRSQRT, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x97", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFSUB[] = { - {I_PFSUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x9A", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFSUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x9A", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PFSUBR[] = { - {I_PFSUBR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xAA", IF_PENT|IF_3DNOW|IF_SM}, - {I_PFSUBR, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xAA", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PI2FD[] = { - {I_PI2FD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x0D", IF_PENT|IF_3DNOW|IF_SM}, - {I_PI2FD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x0D", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PI2FW[] = { - {I_PI2FW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x0C", IF_PENT|IF_3DNOW|IF_SM}, - {I_PI2FW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x0C", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PINSRW[] = { - {I_PINSRW, 3, {MMXREG,REG16,IMMEDIATE}, "\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PINSRW, 3, {MMXREG,REG32,IMMEDIATE}, "\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PINSRW, 3, {MMXREG,MEMORY,IMMEDIATE}, "\301\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PINSRW, 3, {MMXREG,MEMORY|BITS16,IMMEDIATE}, "\301\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PINSRW, 3, {XMMREG,REG16,IMMEDIATE}, "\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PINSRW, 3, {XMMREG,REG32,IMMEDIATE}, "\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PINSRW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PINSRW, 3, {XMMREG,MEMORY|BITS16,IMMEDIATE}, "\301\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMACHRIW[] = { - {I_PMACHRIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5E\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMADDWD[] = { - {I_PMADDWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF5\110", IF_PENT|IF_MMX|IF_SM}, - {I_PMADDWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF5\110", IF_PENT|IF_MMX}, - {I_PMADDWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PMADDWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF5\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMAGW[] = { - {I_PMAGW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x52\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PMAGW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x52\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMAXSW[] = { - {I_PMAXSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEE\110", IF_KATMAI|IF_MMX}, - {I_PMAXSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEE\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMAXSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEE\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMAXSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMAXUB[] = { - {I_PMAXUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDE\110", IF_KATMAI|IF_MMX}, - {I_PMAXUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDE\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMAXUB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDE\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMAXUB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMINSW[] = { - {I_PMINSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEA\110", IF_KATMAI|IF_MMX}, - {I_PMINSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEA\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMINSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEA\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMINSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMINUB[] = { - {I_PMINUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDA\110", IF_KATMAI|IF_MMX}, - {I_PMINUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDA\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMINUB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDA\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMINUB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMOVMSKB[] = { - {I_PMOVMSKB, 2, {REG32,MMXREG,0}, "\2\x0F\xD7\110", IF_KATMAI|IF_MMX}, - {I_PMOVMSKB, 2, {REG32,XMMREG,0}, "\3\x66\x0F\xD7\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHRIW[] = { - {I_PMULHRIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5D\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PMULHRIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x5D\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHRWA[] = { - {I_PMULHRWA, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\1\xB7", IF_PENT|IF_3DNOW|IF_SM}, - {I_PMULHRWA, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\1\xB7", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHRWC[] = { - {I_PMULHRWC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x59\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PMULHRWC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x59\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHUW[] = { - {I_PMULHUW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE4\110", IF_KATMAI|IF_MMX}, - {I_PMULHUW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE4\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PMULHUW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMULHUW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULHW[] = { - {I_PMULHW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE5\110", IF_PENT|IF_MMX|IF_SM}, - {I_PMULHW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE5\110", IF_PENT|IF_MMX}, - {I_PMULHW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PMULHW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE5\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULLW[] = { - {I_PMULLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD5\110", IF_PENT|IF_MMX|IF_SM}, - {I_PMULLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD5\110", IF_PENT|IF_MMX}, - {I_PMULLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PMULLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD5\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMULUDQ[] = { - {I_PMULUDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMULUDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PMULUDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2}, - {I_PMULUDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMVGEZB[] = { - {I_PMVGEZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5C\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMVLZB[] = { - {I_PMVLZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5B\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMVNZB[] = { - {I_PMVNZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5A\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PMVZB[] = { - {I_PMVZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x58\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POP[] = { - {I_POP, 1, {REG16,0,0}, "\320\10\x58", IF_8086}, - {I_POP, 1, {REG32,0,0}, "\321\10\x58", IF_386}, - {I_POP, 1, {REGMEM|BITS16,0,0}, "\320\300\1\x8F\200", IF_8086}, - {I_POP, 1, {REGMEM|BITS32,0,0}, "\321\300\1\x8F\200", IF_386}, - {I_POP, 1, {REG_CS,0,0}, "\1\x0F", IF_8086|IF_UNDOC}, - {I_POP, 1, {REG_DESS,0,0}, "\4", IF_8086}, - {I_POP, 1, {REG_FSGS,0,0}, "\1\x0F\5", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPA[] = { - {I_POPA, 0, {0,0,0}, "\322\1\x61", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPAD[] = { - {I_POPAD, 0, {0,0,0}, "\321\1\x61", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPAW[] = { - {I_POPAW, 0, {0,0,0}, "\320\1\x61", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPF[] = { - {I_POPF, 0, {0,0,0}, "\322\1\x9D", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPFD[] = { - {I_POPFD, 0, {0,0,0}, "\321\1\x9D", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POPFW[] = { - {I_POPFW, 0, {0,0,0}, "\320\1\x9D", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_POR[] = { - {I_POR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEB\110", IF_PENT|IF_MMX|IF_SM}, - {I_POR, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEB\110", IF_PENT|IF_MMX}, - {I_POR, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_POR, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEB\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCH[] = { - {I_PREFETCH, 1, {MEMORY,0,0}, "\2\x0F\x0D\200", IF_PENT|IF_3DNOW|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHNTA[] = { - {I_PREFETCHNTA, 1, {MEMORY,0,0}, "\300\2\x0F\x18\200", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHT0[] = { - {I_PREFETCHT0, 1, {MEMORY,0,0}, "\300\2\x0F\x18\201", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHT1[] = { - {I_PREFETCHT1, 1, {MEMORY,0,0}, "\300\2\x0F\x18\202", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHT2[] = { - {I_PREFETCHT2, 1, {MEMORY,0,0}, "\300\2\x0F\x18\203", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PREFETCHW[] = { - {I_PREFETCHW, 1, {MEMORY,0,0}, "\2\x0F\x0D\201", IF_PENT|IF_3DNOW|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSADBW[] = { - {I_PSADBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF6\110", IF_KATMAI|IF_MMX}, - {I_PSADBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF6\110", IF_KATMAI|IF_MMX|IF_SM}, - {I_PSADBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF6\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSADBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSHUFD[] = { - {I_PSHUFD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\x66\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PSHUFD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSHUFHW[] = { - {I_PSHUFHW, 3, {XMMREG,XMMREG,IMMEDIATE}, "\333\2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PSHUFHW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\333\2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSHUFLW[] = { - {I_PSHUFLW, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\xF2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_PSHUFLW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\xF2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSHUFW[] = { - {I_PSHUFW, 3, {MMXREG,MMXREG,IMMEDIATE}, "\2\x0F\x70\110\22", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, - {I_PSHUFW, 3, {MMXREG,MEMORY,IMMEDIATE}, "\301\2\x0F\x70\110\22", IF_KATMAI|IF_MMX|IF_SM2|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSLLD[] = { - {I_PSLLD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF2\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSLLD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF2\110", IF_PENT|IF_MMX}, - {I_PSLLD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\206\25", IF_PENT|IF_MMX}, - {I_PSLLD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSLLD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF2\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSLLD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSLLDQ[] = { - {I_PSLLDQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\207\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSLLQ[] = { - {I_PSLLQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF3\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSLLQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF3\110", IF_PENT|IF_MMX}, - {I_PSLLQ, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x73\206\25", IF_PENT|IF_MMX}, - {I_PSLLQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSLLQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF3\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSLLQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSLLW[] = { - {I_PSLLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF1\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSLLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF1\110", IF_PENT|IF_MMX}, - {I_PSLLW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\206\25", IF_PENT|IF_MMX}, - {I_PSLLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSLLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF1\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSLLW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRAD[] = { - {I_PSRAD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE2\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRAD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE2\110", IF_PENT|IF_MMX}, - {I_PSRAD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\204\25", IF_PENT|IF_MMX}, - {I_PSRAD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRAD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE2\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRAD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\204\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRAW[] = { - {I_PSRAW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE1\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRAW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE1\110", IF_PENT|IF_MMX}, - {I_PSRAW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\204\25", IF_PENT|IF_MMX}, - {I_PSRAW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRAW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE1\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRAW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\204\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRLD[] = { - {I_PSRLD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD2\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRLD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD2\110", IF_PENT|IF_MMX}, - {I_PSRLD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\202\25", IF_PENT|IF_MMX}, - {I_PSRLD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRLD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD2\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRLD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRLDQ[] = { - {I_PSRLDQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\203\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRLQ[] = { - {I_PSRLQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD3\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRLQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD3\110", IF_PENT|IF_MMX}, - {I_PSRLQ, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x73\202\25", IF_PENT|IF_MMX}, - {I_PSRLQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRLQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD3\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRLQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSRLW[] = { - {I_PSRLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD1\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSRLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD1\110", IF_PENT|IF_MMX}, - {I_PSRLW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\202\25", IF_PENT|IF_MMX}, - {I_PSRLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSRLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD1\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSRLW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBB[] = { - {I_PSUBB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF8\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF8\110", IF_PENT|IF_MMX}, - {I_PSUBB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF8\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBD[] = { - {I_PSUBD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFA\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFA\110", IF_PENT|IF_MMX}, - {I_PSUBD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFA\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBQ[] = { - {I_PSUBQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSUBQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2}, - {I_PSUBQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBSB[] = { - {I_PSUBSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE8\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE8\110", IF_PENT|IF_MMX}, - {I_PSUBSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE8\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBSIW[] = { - {I_PSUBSIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x55\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, - {I_PSUBSIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x55\110", IF_PENT|IF_MMX|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBSW[] = { - {I_PSUBSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE9\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE9\110", IF_PENT|IF_MMX}, - {I_PSUBSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE9\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBUSB[] = { - {I_PSUBUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD8\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD8\110", IF_PENT|IF_MMX}, - {I_PSUBUSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBUSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD8\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBUSW[] = { - {I_PSUBUSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD9\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBUSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD9\110", IF_PENT|IF_MMX}, - {I_PSUBUSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBUSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD9\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSUBW[] = { - {I_PSUBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF9\110", IF_PENT|IF_MMX|IF_SM}, - {I_PSUBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF9\110", IF_PENT|IF_MMX}, - {I_PSUBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PSUBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF9\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PSWAPD[] = { - {I_PSWAPD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xBB", IF_PENT|IF_3DNOW|IF_SM}, - {I_PSWAPD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xBB", IF_PENT|IF_3DNOW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKHBW[] = { - {I_PUNPCKHBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x68\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKHBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x68\110", IF_PENT|IF_MMX}, - {I_PUNPCKHBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x68\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKHBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x68\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKHDQ[] = { - {I_PUNPCKHDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6A\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKHDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6A\110", IF_PENT|IF_MMX}, - {I_PUNPCKHDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6A\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKHDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6A\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKHQDQ[] = { - {I_PUNPCKHQDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6D\110", IF_WILLAMETTE|IF_SSE2}, - {I_PUNPCKHQDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6D\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKHWD[] = { - {I_PUNPCKHWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x69\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKHWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x69\110", IF_PENT|IF_MMX}, - {I_PUNPCKHWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x69\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKHWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x69\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKLBW[] = { - {I_PUNPCKLBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x60\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKLBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x60\110", IF_PENT|IF_MMX}, - {I_PUNPCKLBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x60\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKLBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x60\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKLDQ[] = { - {I_PUNPCKLDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x62\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKLDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x62\110", IF_PENT|IF_MMX}, - {I_PUNPCKLDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x62\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKLDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x62\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKLQDQ[] = { - {I_PUNPCKLQDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6C\110", IF_WILLAMETTE|IF_SSE2}, - {I_PUNPCKLQDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6C\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUNPCKLWD[] = { - {I_PUNPCKLWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x61\110", IF_PENT|IF_MMX|IF_SM}, - {I_PUNPCKLWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x61\110", IF_PENT|IF_MMX}, - {I_PUNPCKLWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x61\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PUNPCKLWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x61\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSH[] = { - {I_PUSH, 1, {REG16,0,0}, "\320\10\x50", IF_8086}, - {I_PUSH, 1, {REG32,0,0}, "\321\10\x50", IF_386}, - {I_PUSH, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\206", IF_8086}, - {I_PUSH, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\206", IF_386}, - {I_PUSH, 1, {REG_CS,0,0}, "\6", IF_8086}, - {I_PUSH, 1, {REG_DESS,0,0}, "\6", IF_8086}, - {I_PUSH, 1, {REG_FSGS,0,0}, "\1\x0F\7", IF_386}, - {I_PUSH, 1, {IMMEDIATE|BITS8,0,0}, "\1\x6A\14", IF_186}, - {I_PUSH, 1, {SBYTE,0,0}, "\1\x6A\14", IF_186}, - {I_PUSH, 1, {IMMEDIATE|BITS16,0,0}, "\320\133\1\x68\130", IF_186}, - {I_PUSH, 1, {IMMEDIATE|BITS32,0,0}, "\321\143\1\x68\140", IF_386}, - {I_PUSH, 1, {IMMEDIATE,0,0}, "\1\x68\34", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHA[] = { - {I_PUSHA, 0, {0,0,0}, "\322\1\x60", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHAD[] = { - {I_PUSHAD, 0, {0,0,0}, "\321\1\x60", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHAW[] = { - {I_PUSHAW, 0, {0,0,0}, "\320\1\x60", IF_186}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHF[] = { - {I_PUSHF, 0, {0,0,0}, "\322\1\x9C", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHFD[] = { - {I_PUSHFD, 0, {0,0,0}, "\321\1\x9C", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PUSHFW[] = { - {I_PUSHFW, 0, {0,0,0}, "\320\1\x9C", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_PXOR[] = { - {I_PXOR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEF\110", IF_PENT|IF_MMX|IF_SM}, - {I_PXOR, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEF\110", IF_PENT|IF_MMX}, - {I_PXOR, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEF\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - {I_PXOR, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEF\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RCL[] = { - {I_RCL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\202", IF_8086}, - {I_RCL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\202", IF_8086}, - {I_RCL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\202\25", IF_186|IF_SB}, - {I_RCL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\202", IF_8086}, - {I_RCL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\202", IF_8086}, - {I_RCL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\202\25", IF_186|IF_SB}, - {I_RCL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\202", IF_386}, - {I_RCL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\202", IF_386}, - {I_RCL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\202\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RCPPS[] = { - {I_RCPPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x53\110", IF_KATMAI|IF_SSE}, - {I_RCPPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x53\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RCPSS[] = { - {I_RCPSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x53\110", IF_KATMAI|IF_SSE}, - {I_RCPSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x53\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RCR[] = { - {I_RCR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\203", IF_8086}, - {I_RCR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\203", IF_8086}, - {I_RCR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\203\25", IF_186|IF_SB}, - {I_RCR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\203", IF_8086}, - {I_RCR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\203", IF_8086}, - {I_RCR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\203\25", IF_186|IF_SB}, - {I_RCR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\203", IF_386}, - {I_RCR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\203", IF_386}, - {I_RCR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\203\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RDMSR[] = { - {I_RDMSR, 0, {0,0,0}, "\2\x0F\x32", IF_PENT|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RDPMC[] = { - {I_RDPMC, 0, {0,0,0}, "\2\x0F\x33", IF_P6}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RDSHR[] = { - {I_RDSHR, 1, {REGMEM|BITS32,0,0}, "\321\300\2\x0F\x36\200", IF_P6|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RDTSC[] = { - {I_RDTSC, 0, {0,0,0}, "\2\x0F\x31", IF_PENT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RESB[] = { - {I_RESB, 1, {IMMEDIATE,0,0}, "\340", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RESD[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_RESQ[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_REST[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_RESW[] = { - ITEMPLATE_END -}; - -static struct itemplate instrux_RET[] = { - {I_RET, 0, {0,0,0}, "\1\xC3", IF_8086}, - {I_RET, 1, {IMMEDIATE,0,0}, "\1\xC2\30", IF_8086|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RETF[] = { - {I_RETF, 0, {0,0,0}, "\1\xCB", IF_8086}, - {I_RETF, 1, {IMMEDIATE,0,0}, "\1\xCA\30", IF_8086|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RETN[] = { - {I_RETN, 0, {0,0,0}, "\1\xC3", IF_8086}, - {I_RETN, 1, {IMMEDIATE,0,0}, "\1\xC2\30", IF_8086|IF_SW}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ROL[] = { - {I_ROL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\200", IF_8086}, - {I_ROL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\200", IF_8086}, - {I_ROL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\200\25", IF_186|IF_SB}, - {I_ROL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\200", IF_8086}, - {I_ROL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\200", IF_8086}, - {I_ROL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\200\25", IF_186|IF_SB}, - {I_ROL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\200", IF_386}, - {I_ROL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\200", IF_386}, - {I_ROL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\200\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_ROR[] = { - {I_ROR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\201", IF_8086}, - {I_ROR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\201", IF_8086}, - {I_ROR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\201\25", IF_186|IF_SB}, - {I_ROR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\201", IF_8086}, - {I_ROR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\201", IF_8086}, - {I_ROR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\201\25", IF_186|IF_SB}, - {I_ROR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\201", IF_386}, - {I_ROR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\201", IF_386}, - {I_ROR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\201\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSDC[] = { - {I_RSDC, 2, {REG_SREG,MEMORY|BITS80,0}, "\301\2\x0F\x79\110", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSLDT[] = { - {I_RSLDT, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7B\200", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSM[] = { - {I_RSM, 0, {0,0,0}, "\2\x0F\xAA", IF_PENT|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSQRTPS[] = { - {I_RSQRTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x52\110", IF_KATMAI|IF_SSE}, - {I_RSQRTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x52\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSQRTSS[] = { - {I_RSQRTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x52\110", IF_KATMAI|IF_SSE}, - {I_RSQRTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x52\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_RSTS[] = { - {I_RSTS, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7D\200", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SAHF[] = { - {I_SAHF, 0, {0,0,0}, "\1\x9E", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SAL[] = { - {I_SAL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\204", IF_8086}, - {I_SAL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\204", IF_8086}, - {I_SAL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\204\25", IF_186|IF_SB}, - {I_SAL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\204", IF_8086}, - {I_SAL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\204", IF_8086}, - {I_SAL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\204\25", IF_186|IF_SB}, - {I_SAL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\204", IF_386}, - {I_SAL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\204", IF_386}, - {I_SAL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\204\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SALC[] = { - {I_SALC, 0, {0,0,0}, "\1\xD6", IF_8086|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SAR[] = { - {I_SAR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\207", IF_8086}, - {I_SAR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\207", IF_8086}, - {I_SAR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\207\25", IF_186|IF_SB}, - {I_SAR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\207", IF_8086}, - {I_SAR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\207", IF_8086}, - {I_SAR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\207\25", IF_186|IF_SB}, - {I_SAR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\207", IF_386}, - {I_SAR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\207", IF_386}, - {I_SAR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\207\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SBB[] = { - {I_SBB, 2, {MEMORY,REG8,0}, "\300\1\x18\101", IF_8086|IF_SM}, - {I_SBB, 2, {REG8,REG8,0}, "\1\x18\101", IF_8086}, - {I_SBB, 2, {MEMORY,REG16,0}, "\320\300\1\x19\101", IF_8086|IF_SM}, - {I_SBB, 2, {REG16,REG16,0}, "\320\1\x19\101", IF_8086}, - {I_SBB, 2, {MEMORY,REG32,0}, "\321\300\1\x19\101", IF_386|IF_SM}, - {I_SBB, 2, {REG32,REG32,0}, "\321\1\x19\101", IF_386}, - {I_SBB, 2, {REG8,MEMORY,0}, "\301\1\x1A\110", IF_8086|IF_SM}, - {I_SBB, 2, {REG8,REG8,0}, "\1\x1A\110", IF_8086}, - {I_SBB, 2, {REG16,MEMORY,0}, "\320\301\1\x1B\110", IF_8086|IF_SM}, - {I_SBB, 2, {REG16,REG16,0}, "\320\1\x1B\110", IF_8086}, - {I_SBB, 2, {REG32,MEMORY,0}, "\321\301\1\x1B\110", IF_386|IF_SM}, - {I_SBB, 2, {REG32,REG32,0}, "\321\1\x1B\110", IF_386}, - {I_SBB, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\203\15", IF_8086}, - {I_SBB, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\203\15", IF_386}, - {I_SBB, 2, {REG_AL,IMMEDIATE,0}, "\1\x1C\21", IF_8086|IF_SM}, - {I_SBB, 2, {REG_AX,SBYTE,0}, "\320\1\x83\203\15", IF_8086|IF_SM}, - {I_SBB, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x1D\31", IF_8086|IF_SM}, - {I_SBB, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\203\15", IF_386|IF_SM}, - {I_SBB, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x1D\41", IF_386|IF_SM}, - {I_SBB, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\203\21", IF_8086|IF_SM}, - {I_SBB, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\203\131", IF_8086|IF_SM}, - {I_SBB, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\203\141", IF_386|IF_SM}, - {I_SBB, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\203\21", IF_8086|IF_SM}, - {I_SBB, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\203\131", IF_8086|IF_SM}, - {I_SBB, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\203\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SCASB[] = { - {I_SCASB, 0, {0,0,0}, "\332\1\xAE", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SCASD[] = { - {I_SCASD, 0, {0,0,0}, "\332\321\1\xAF", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SCASW[] = { - {I_SCASW, 0, {0,0,0}, "\332\320\1\xAF", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SFENCE[] = { - {I_SFENCE, 0, {0,0,0}, "\3\x0F\xAE\xF8", IF_KATMAI}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SGDT[] = { - {I_SGDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\200", IF_286}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHL[] = { - {I_SHL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\204", IF_8086}, - {I_SHL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\204", IF_8086}, - {I_SHL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\204\25", IF_186|IF_SB}, - {I_SHL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\204", IF_8086}, - {I_SHL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\204", IF_8086}, - {I_SHL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\204\25", IF_186|IF_SB}, - {I_SHL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\204", IF_386}, - {I_SHL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\204", IF_386}, - {I_SHL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\204\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHLD[] = { - {I_SHLD, 3, {MEMORY,REG16,IMMEDIATE}, "\300\320\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHLD, 3, {REG16,REG16,IMMEDIATE}, "\320\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHLD, 3, {MEMORY,REG32,IMMEDIATE}, "\300\321\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHLD, 3, {REG32,REG32,IMMEDIATE}, "\321\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHLD, 3, {MEMORY,REG16,REG_CL}, "\300\320\2\x0F\xA5\101", IF_386|IF_SM}, - {I_SHLD, 3, {REG16,REG16,REG_CL}, "\320\2\x0F\xA5\101", IF_386}, - {I_SHLD, 3, {MEMORY,REG32,REG_CL}, "\300\321\2\x0F\xA5\101", IF_386|IF_SM}, - {I_SHLD, 3, {REG32,REG32,REG_CL}, "\321\2\x0F\xA5\101", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHR[] = { - {I_SHR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\205", IF_8086}, - {I_SHR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\205", IF_8086}, - {I_SHR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\205\25", IF_186|IF_SB}, - {I_SHR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\205", IF_8086}, - {I_SHR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\205", IF_8086}, - {I_SHR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\205\25", IF_186|IF_SB}, - {I_SHR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\205", IF_386}, - {I_SHR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\205", IF_386}, - {I_SHR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\205\25", IF_386|IF_SB}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHRD[] = { - {I_SHRD, 3, {MEMORY,REG16,IMMEDIATE}, "\300\320\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHRD, 3, {REG16,REG16,IMMEDIATE}, "\320\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHRD, 3, {MEMORY,REG32,IMMEDIATE}, "\300\321\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHRD, 3, {REG32,REG32,IMMEDIATE}, "\321\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, - {I_SHRD, 3, {MEMORY,REG16,REG_CL}, "\300\320\2\x0F\xAD\101", IF_386|IF_SM}, - {I_SHRD, 3, {REG16,REG16,REG_CL}, "\320\2\x0F\xAD\101", IF_386}, - {I_SHRD, 3, {MEMORY,REG32,REG_CL}, "\300\321\2\x0F\xAD\101", IF_386|IF_SM}, - {I_SHRD, 3, {REG32,REG32,REG_CL}, "\321\2\x0F\xAD\101", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHUFPD[] = { - {I_SHUFPD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\x66\x0F\xC6\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, - {I_SHUFPD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\xC6\110\26", IF_WILLAMETTE|IF_SSE2|IF_SM|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SHUFPS[] = { - {I_SHUFPS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\2\x0F\xC6\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - {I_SHUFPS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\2\x0F\xC6\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SIDT[] = { - {I_SIDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\201", IF_286}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SLDT[] = { - {I_SLDT, 1, {MEMORY,0,0}, "\300\1\x0F\17\200", IF_286}, - {I_SLDT, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\200", IF_286}, - {I_SLDT, 1, {REG16,0,0}, "\320\1\x0F\17\200", IF_286}, - {I_SLDT, 1, {REG32,0,0}, "\321\1\x0F\17\200", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SMI[] = { - {I_SMI, 0, {0,0,0}, "\1\xF1", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SMINT[] = { - {I_SMINT, 0, {0,0,0}, "\2\x0F\x38", IF_P6|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SMINTOLD[] = { - {I_SMINTOLD, 0, {0,0,0}, "\2\x0F\x7E", IF_486|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SMSW[] = { - {I_SMSW, 1, {MEMORY,0,0}, "\300\2\x0F\x01\204", IF_286}, - {I_SMSW, 1, {MEMORY|BITS16,0,0}, "\300\2\x0F\x01\204", IF_286}, - {I_SMSW, 1, {REG16,0,0}, "\320\2\x0F\x01\204", IF_286}, - {I_SMSW, 1, {REG32,0,0}, "\321\2\x0F\x01\204", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SQRTPD[] = { - {I_SQRTPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, - {I_SQRTPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x51\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SQRTPS[] = { - {I_SQRTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x51\110", IF_KATMAI|IF_SSE}, - {I_SQRTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x51\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SQRTSD[] = { - {I_SQRTSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, - {I_SQRTSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SQRTSS[] = { - {I_SQRTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x51\110", IF_KATMAI|IF_SSE}, - {I_SQRTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x51\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STC[] = { - {I_STC, 0, {0,0,0}, "\1\xF9", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STD[] = { - {I_STD, 0, {0,0,0}, "\1\xFD", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STI[] = { - {I_STI, 0, {0,0,0}, "\1\xFB", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STMXCSR[] = { - {I_STMXCSR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\203", IF_KATMAI|IF_SSE|IF_SD}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STOSB[] = { - {I_STOSB, 0, {0,0,0}, "\1\xAA", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STOSD[] = { - {I_STOSD, 0, {0,0,0}, "\321\1\xAB", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STOSW[] = { - {I_STOSW, 0, {0,0,0}, "\320\1\xAB", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_STR[] = { - {I_STR, 1, {MEMORY,0,0}, "\300\1\x0F\17\201", IF_286|IF_PROT}, - {I_STR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\201", IF_286|IF_PROT}, - {I_STR, 1, {REG16,0,0}, "\320\1\x0F\17\201", IF_286|IF_PROT}, - {I_STR, 1, {REG32,0,0}, "\321\1\x0F\17\201", IF_386|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUB[] = { - {I_SUB, 2, {MEMORY,REG8,0}, "\300\1\x28\101", IF_8086|IF_SM}, - {I_SUB, 2, {REG8,REG8,0}, "\1\x28\101", IF_8086}, - {I_SUB, 2, {MEMORY,REG16,0}, "\320\300\1\x29\101", IF_8086|IF_SM}, - {I_SUB, 2, {REG16,REG16,0}, "\320\1\x29\101", IF_8086}, - {I_SUB, 2, {MEMORY,REG32,0}, "\321\300\1\x29\101", IF_386|IF_SM}, - {I_SUB, 2, {REG32,REG32,0}, "\321\1\x29\101", IF_386}, - {I_SUB, 2, {REG8,MEMORY,0}, "\301\1\x2A\110", IF_8086|IF_SM}, - {I_SUB, 2, {REG8,REG8,0}, "\1\x2A\110", IF_8086}, - {I_SUB, 2, {REG16,MEMORY,0}, "\320\301\1\x2B\110", IF_8086|IF_SM}, - {I_SUB, 2, {REG16,REG16,0}, "\320\1\x2B\110", IF_8086}, - {I_SUB, 2, {REG32,MEMORY,0}, "\321\301\1\x2B\110", IF_386|IF_SM}, - {I_SUB, 2, {REG32,REG32,0}, "\321\1\x2B\110", IF_386}, - {I_SUB, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\205\15", IF_8086}, - {I_SUB, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\205\15", IF_386}, - {I_SUB, 2, {REG_AL,IMMEDIATE,0}, "\1\x2C\21", IF_8086|IF_SM}, - {I_SUB, 2, {REG_AX,SBYTE,0}, "\320\1\x83\205\15", IF_8086|IF_SM}, - {I_SUB, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x2D\31", IF_8086|IF_SM}, - {I_SUB, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\205\15", IF_386|IF_SM}, - {I_SUB, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x2D\41", IF_386|IF_SM}, - {I_SUB, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\205\21", IF_8086|IF_SM}, - {I_SUB, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\205\131", IF_8086|IF_SM}, - {I_SUB, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\205\141", IF_386|IF_SM}, - {I_SUB, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\205\21", IF_8086|IF_SM}, - {I_SUB, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\205\131", IF_8086|IF_SM}, - {I_SUB, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\205\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUBPD[] = { - {I_SUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, - {I_SUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUBPS[] = { - {I_SUBPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, - {I_SUBPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUBSD[] = { - {I_SUBSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, - {I_SUBSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SUBSS[] = { - {I_SUBSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, - {I_SUBSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SVDC[] = { - {I_SVDC, 2, {MEMORY|BITS80,REG_SREG,0}, "\300\2\x0F\x78\101", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SVLDT[] = { - {I_SVLDT, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7A\200", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SVTS[] = { - {I_SVTS, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7C\200", IF_486|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SYSCALL[] = { - {I_SYSCALL, 0, {0,0,0}, "\2\x0F\x05", IF_P6|IF_AMD}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SYSENTER[] = { - {I_SYSENTER, 0, {0,0,0}, "\2\x0F\x34", IF_P6}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SYSEXIT[] = { - {I_SYSEXIT, 0, {0,0,0}, "\2\x0F\x35", IF_P6|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SYSRET[] = { - {I_SYSRET, 0, {0,0,0}, "\2\x0F\x07", IF_P6|IF_PRIV|IF_AMD}, - ITEMPLATE_END -}; - -static struct itemplate instrux_TEST[] = { - {I_TEST, 2, {MEMORY,REG8,0}, "\300\1\x84\101", IF_8086|IF_SM}, - {I_TEST, 2, {REG8,REG8,0}, "\1\x84\101", IF_8086}, - {I_TEST, 2, {MEMORY,REG16,0}, "\320\300\1\x85\101", IF_8086|IF_SM}, - {I_TEST, 2, {REG16,REG16,0}, "\320\1\x85\101", IF_8086}, - {I_TEST, 2, {MEMORY,REG32,0}, "\321\300\1\x85\101", IF_386|IF_SM}, - {I_TEST, 2, {REG32,REG32,0}, "\321\1\x85\101", IF_386}, - {I_TEST, 2, {REG8,MEMORY,0}, "\301\1\x84\110", IF_8086|IF_SM}, - {I_TEST, 2, {REG16,MEMORY,0}, "\320\301\1\x85\110", IF_8086|IF_SM}, - {I_TEST, 2, {REG32,MEMORY,0}, "\321\301\1\x85\110", IF_386|IF_SM}, - {I_TEST, 2, {REG_AL,IMMEDIATE,0}, "\1\xA8\21", IF_8086|IF_SM}, - {I_TEST, 2, {REG_AX,IMMEDIATE,0}, "\320\1\xA9\31", IF_8086|IF_SM}, - {I_TEST, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\xA9\41", IF_386|IF_SM}, - {I_TEST, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xF6\200\21", IF_8086|IF_SM}, - {I_TEST, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xF7\200\31", IF_8086|IF_SM}, - {I_TEST, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xF7\200\41", IF_386|IF_SM}, - {I_TEST, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\xF6\200\21", IF_8086|IF_SM}, - {I_TEST, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\1\xF7\200\31", IF_8086|IF_SM}, - {I_TEST, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\1\xF7\200\41", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UCOMISD[] = { - {I_UCOMISD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x2E\110", IF_WILLAMETTE|IF_SSE2}, - {I_UCOMISD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x2E\110", IF_WILLAMETTE|IF_SSE2}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UCOMISS[] = { - {I_UCOMISS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x2E\110", IF_KATMAI|IF_SSE}, - {I_UCOMISS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x2E\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UD0[] = { - {I_UD0, 0, {0,0,0}, "\2\x0F\xFF", IF_286|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UD1[] = { - {I_UD1, 0, {0,0,0}, "\2\x0F\xB9", IF_286|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UD2[] = { - {I_UD2, 0, {0,0,0}, "\2\x0F\x0B", IF_286}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UMOV[] = { - {I_UMOV, 2, {MEMORY,REG8,0}, "\300\2\x0F\x10\101", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG8,REG8,0}, "\2\x0F\x10\101", IF_386|IF_UNDOC}, - {I_UMOV, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\x11\101", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG16,REG16,0}, "\320\2\x0F\x11\101", IF_386|IF_UNDOC}, - {I_UMOV, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\x11\101", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG32,REG32,0}, "\321\2\x0F\x11\101", IF_386|IF_UNDOC}, - {I_UMOV, 2, {REG8,MEMORY,0}, "\301\2\x0F\x12\110", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG8,REG8,0}, "\2\x0F\x12\110", IF_386|IF_UNDOC}, - {I_UMOV, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x13\110", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG16,REG16,0}, "\320\2\x0F\x13\110", IF_386|IF_UNDOC}, - {I_UMOV, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x13\110", IF_386|IF_UNDOC|IF_SM}, - {I_UMOV, 2, {REG32,REG32,0}, "\321\2\x0F\x13\110", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UNPCKHPD[] = { - {I_UNPCKHPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x15\110", IF_WILLAMETTE|IF_SSE2}, - {I_UNPCKHPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x15\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UNPCKHPS[] = { - {I_UNPCKHPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x15\110", IF_KATMAI|IF_SSE}, - {I_UNPCKHPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x15\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UNPCKLPD[] = { - {I_UNPCKLPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x14\110", IF_WILLAMETTE|IF_SSE2}, - {I_UNPCKLPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x14\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_UNPCKLPS[] = { - {I_UNPCKLPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x14\110", IF_KATMAI|IF_SSE}, - {I_UNPCKLPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x14\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_VERR[] = { - {I_VERR, 1, {MEMORY,0,0}, "\300\1\x0F\17\204", IF_286|IF_PROT}, - {I_VERR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\204", IF_286|IF_PROT}, - {I_VERR, 1, {REG16,0,0}, "\1\x0F\17\204", IF_286|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_VERW[] = { - {I_VERW, 1, {MEMORY,0,0}, "\300\1\x0F\17\205", IF_286|IF_PROT}, - {I_VERW, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\205", IF_286|IF_PROT}, - {I_VERW, 1, {REG16,0,0}, "\1\x0F\17\205", IF_286|IF_PROT}, - ITEMPLATE_END -}; - -static struct itemplate instrux_WAIT[] = { - {I_WAIT, 0, {0,0,0}, "\1\x9B", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_WBINVD[] = { - {I_WBINVD, 0, {0,0,0}, "\2\x0F\x09", IF_486|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_WRMSR[] = { - {I_WRMSR, 0, {0,0,0}, "\2\x0F\x30", IF_PENT|IF_PRIV}, - ITEMPLATE_END -}; - -static struct itemplate instrux_WRSHR[] = { - {I_WRSHR, 1, {REGMEM|BITS32,0,0}, "\321\300\2\x0F\x37\200", IF_P6|IF_CYRIX|IF_SMM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XADD[] = { - {I_XADD, 2, {MEMORY,REG8,0}, "\300\2\x0F\xC0\101", IF_486|IF_SM}, - {I_XADD, 2, {REG8,REG8,0}, "\2\x0F\xC0\101", IF_486}, - {I_XADD, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xC1\101", IF_486|IF_SM}, - {I_XADD, 2, {REG16,REG16,0}, "\320\2\x0F\xC1\101", IF_486}, - {I_XADD, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xC1\101", IF_486|IF_SM}, - {I_XADD, 2, {REG32,REG32,0}, "\321\2\x0F\xC1\101", IF_486}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XBTS[] = { - {I_XBTS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xA6\110", IF_386|IF_SW|IF_UNDOC}, - {I_XBTS, 2, {REG16,REG16,0}, "\320\2\x0F\xA6\110", IF_386|IF_UNDOC}, - {I_XBTS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xA6\110", IF_386|IF_SD|IF_UNDOC}, - {I_XBTS, 2, {REG32,REG32,0}, "\321\2\x0F\xA6\110", IF_386|IF_UNDOC}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XCHG[] = { - {I_XCHG, 2, {REG_AX,REG16,0}, "\320\11\x90", IF_8086}, - {I_XCHG, 2, {REG_EAX,REG32,0}, "\321\11\x90", IF_386}, - {I_XCHG, 2, {REG16,REG_AX,0}, "\320\10\x90", IF_8086}, - {I_XCHG, 2, {REG32,REG_EAX,0}, "\321\10\x90", IF_386}, - {I_XCHG, 2, {REG8,MEMORY,0}, "\301\1\x86\110", IF_8086|IF_SM}, - {I_XCHG, 2, {REG8,REG8,0}, "\1\x86\110", IF_8086}, - {I_XCHG, 2, {REG16,MEMORY,0}, "\320\301\1\x87\110", IF_8086|IF_SM}, - {I_XCHG, 2, {REG16,REG16,0}, "\320\1\x87\110", IF_8086}, - {I_XCHG, 2, {REG32,MEMORY,0}, "\321\301\1\x87\110", IF_386|IF_SM}, - {I_XCHG, 2, {REG32,REG32,0}, "\321\1\x87\110", IF_386}, - {I_XCHG, 2, {MEMORY,REG8,0}, "\300\1\x86\101", IF_8086|IF_SM}, - {I_XCHG, 2, {REG8,REG8,0}, "\1\x86\101", IF_8086}, - {I_XCHG, 2, {MEMORY,REG16,0}, "\320\300\1\x87\101", IF_8086|IF_SM}, - {I_XCHG, 2, {REG16,REG16,0}, "\320\1\x87\101", IF_8086}, - {I_XCHG, 2, {MEMORY,REG32,0}, "\321\300\1\x87\101", IF_386|IF_SM}, - {I_XCHG, 2, {REG32,REG32,0}, "\321\1\x87\101", IF_386}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XLAT[] = { - {I_XLAT, 0, {0,0,0}, "\1\xD7", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XLATB[] = { - {I_XLATB, 0, {0,0,0}, "\1\xD7", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XOR[] = { - {I_XOR, 2, {MEMORY,REG8,0}, "\300\1\x30\101", IF_8086|IF_SM}, - {I_XOR, 2, {REG8,REG8,0}, "\1\x30\101", IF_8086}, - {I_XOR, 2, {MEMORY,REG16,0}, "\320\300\1\x31\101", IF_8086|IF_SM}, - {I_XOR, 2, {REG16,REG16,0}, "\320\1\x31\101", IF_8086}, - {I_XOR, 2, {MEMORY,REG32,0}, "\321\300\1\x31\101", IF_386|IF_SM}, - {I_XOR, 2, {REG32,REG32,0}, "\321\1\x31\101", IF_386}, - {I_XOR, 2, {REG8,MEMORY,0}, "\301\1\x32\110", IF_8086|IF_SM}, - {I_XOR, 2, {REG8,REG8,0}, "\1\x32\110", IF_8086}, - {I_XOR, 2, {REG16,MEMORY,0}, "\320\301\1\x33\110", IF_8086|IF_SM}, - {I_XOR, 2, {REG16,REG16,0}, "\320\1\x33\110", IF_8086}, - {I_XOR, 2, {REG32,MEMORY,0}, "\321\301\1\x33\110", IF_386|IF_SM}, - {I_XOR, 2, {REG32,REG32,0}, "\321\1\x33\110", IF_386}, - {I_XOR, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\206\15", IF_8086}, - {I_XOR, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\206\15", IF_386}, - {I_XOR, 2, {REG_AL,IMMEDIATE,0}, "\1\x34\21", IF_8086|IF_SM}, - {I_XOR, 2, {REG_AX,SBYTE,0}, "\320\1\x83\206\15", IF_8086|IF_SM}, - {I_XOR, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x35\31", IF_8086|IF_SM}, - {I_XOR, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\206\15", IF_386|IF_SM}, - {I_XOR, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x35\41", IF_386|IF_SM}, - {I_XOR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\206\21", IF_8086|IF_SM}, - {I_XOR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\206\131", IF_8086|IF_SM}, - {I_XOR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\206\141", IF_386|IF_SM}, - {I_XOR, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\206\21", IF_8086|IF_SM}, - {I_XOR, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\206\131", IF_8086|IF_SM}, - {I_XOR, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\206\141", IF_386|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XORPD[] = { - {I_XORPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x57\110", IF_WILLAMETTE|IF_SSE2}, - {I_XORPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x57\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XORPS[] = { - {I_XORPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x57\110", IF_KATMAI|IF_SSE}, - {I_XORPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x57\110", IF_KATMAI|IF_SSE}, - ITEMPLATE_END -}; - -static struct itemplate instrux_XSTORE[] = { - {I_XSTORE, 0, {0,0,0}, "\3\x0F\xA7\xC0", IF_P6|IF_CYRIX}, - ITEMPLATE_END -}; - -static struct itemplate instrux_CMOVcc[] = { - {I_CMOVcc, 2, {REG16,MEMORY,0}, "\320\301\1\x0F\330\x40\110", IF_P6|IF_SM}, - {I_CMOVcc, 2, {REG16,REG16,0}, "\320\1\x0F\330\x40\110", IF_P6}, - {I_CMOVcc, 2, {REG32,MEMORY,0}, "\321\301\1\x0F\330\x40\110", IF_P6|IF_SM}, - {I_CMOVcc, 2, {REG32,REG32,0}, "\321\1\x0F\330\x40\110", IF_P6}, - ITEMPLATE_END -}; - -static struct itemplate instrux_Jcc[] = { - {I_Jcc, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\x0F\330\x80\64", IF_386}, - {I_Jcc, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\x0F\330\x80\64", IF_386}, - {I_Jcc, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\x0F\330\x80\64", IF_386}, - {I_Jcc, 1, {IMMEDIATE|SHORT,0,0}, "\330\x70\50", IF_8086}, - {I_Jcc, 1, {IMMEDIATE,0,0}, "\370\330\x70\50", IF_8086}, - {I_Jcc, 1, {IMMEDIATE,0,0}, "\1\x0F\330\x80\64", IF_386}, - {I_Jcc, 1, {IMMEDIATE,0,0}, "\330\x71\373\1\xE9\64", IF_8086}, - {I_Jcc, 1, {IMMEDIATE,0,0}, "\330\x70\50", IF_8086}, - ITEMPLATE_END -}; - -static struct itemplate instrux_SETcc[] = { - {I_SETcc, 1, {MEMORY,0,0}, "\300\1\x0F\330\x90\200", IF_386|IF_SB}, - {I_SETcc, 1, {REG8,0,0}, "\300\1\x0F\330\x90\200", IF_386}, - ITEMPLATE_END -}; - -struct itemplate *nasm_instructions[] = { - instrux_AAA, - instrux_AAD, - instrux_AAM, - instrux_AAS, - instrux_ADC, - instrux_ADD, - instrux_ADDPD, - instrux_ADDPS, - instrux_ADDSD, - instrux_ADDSS, - instrux_ADDSUBPD, - instrux_ADDSUBPS, - instrux_AND, - instrux_ANDNPD, - instrux_ANDNPS, - instrux_ANDPD, - instrux_ANDPS, - instrux_ARPL, - instrux_BOUND, - instrux_BSF, - instrux_BSR, - instrux_BSWAP, - instrux_BT, - instrux_BTC, - instrux_BTR, - instrux_BTS, - instrux_CALL, - instrux_CBW, - instrux_CDQ, - instrux_CLC, - instrux_CLD, - instrux_CLFLUSH, - instrux_CLI, - instrux_CLTS, - instrux_CMC, - instrux_CMP, - instrux_CMPEQPD, - instrux_CMPEQPS, - instrux_CMPEQSD, - instrux_CMPEQSS, - instrux_CMPLEPD, - instrux_CMPLEPS, - instrux_CMPLESD, - instrux_CMPLESS, - instrux_CMPLTPD, - instrux_CMPLTPS, - instrux_CMPLTSD, - instrux_CMPLTSS, - instrux_CMPNEQPD, - instrux_CMPNEQPS, - instrux_CMPNEQSD, - instrux_CMPNEQSS, - instrux_CMPNLEPD, - instrux_CMPNLEPS, - instrux_CMPNLESD, - instrux_CMPNLESS, - instrux_CMPNLTPD, - instrux_CMPNLTPS, - instrux_CMPNLTSD, - instrux_CMPNLTSS, - instrux_CMPORDPD, - instrux_CMPORDPS, - instrux_CMPORDSD, - instrux_CMPORDSS, - instrux_CMPPD, - instrux_CMPPS, - instrux_CMPSB, - instrux_CMPSD, - instrux_CMPSS, - instrux_CMPSW, - instrux_CMPUNORDPD, - instrux_CMPUNORDPS, - instrux_CMPUNORDSD, - instrux_CMPUNORDSS, - instrux_CMPXCHG, - instrux_CMPXCHG486, - instrux_CMPXCHG8B, - instrux_COMISD, - instrux_COMISS, - instrux_CPUID, - instrux_CVTDQ2PD, - instrux_CVTDQ2PS, - instrux_CVTPD2DQ, - instrux_CVTPD2PI, - instrux_CVTPD2PS, - instrux_CVTPI2PD, - instrux_CVTPI2PS, - instrux_CVTPS2DQ, - instrux_CVTPS2PD, - instrux_CVTPS2PI, - instrux_CVTSD2SI, - instrux_CVTSD2SS, - instrux_CVTSI2SD, - instrux_CVTSI2SS, - instrux_CVTSS2SD, - instrux_CVTSS2SI, - instrux_CVTTPD2DQ, - instrux_CVTTPD2PI, - instrux_CVTTPS2DQ, - instrux_CVTTPS2PI, - instrux_CVTTSD2SI, - instrux_CVTTSS2SI, - instrux_CWD, - instrux_CWDE, - instrux_DAA, - instrux_DAS, - instrux_DB, - instrux_DD, - instrux_DEC, - instrux_DIV, - instrux_DIVPD, - instrux_DIVPS, - instrux_DIVSD, - instrux_DIVSS, - instrux_DQ, - instrux_DT, - instrux_DW, - instrux_EMMS, - instrux_ENTER, - instrux_EQU, - instrux_F2XM1, - instrux_FABS, - instrux_FADD, - instrux_FADDP, - instrux_FBLD, - instrux_FBSTP, - instrux_FCHS, - instrux_FCLEX, - instrux_FCMOVB, - instrux_FCMOVBE, - instrux_FCMOVE, - instrux_FCMOVNB, - instrux_FCMOVNBE, - instrux_FCMOVNE, - instrux_FCMOVNU, - instrux_FCMOVU, - instrux_FCOM, - instrux_FCOMI, - instrux_FCOMIP, - instrux_FCOMP, - instrux_FCOMPP, - instrux_FCOS, - instrux_FDECSTP, - instrux_FDISI, - instrux_FDIV, - instrux_FDIVP, - instrux_FDIVR, - instrux_FDIVRP, - instrux_FEMMS, - instrux_FENI, - instrux_FFREE, - instrux_FFREEP, - instrux_FIADD, - instrux_FICOM, - instrux_FICOMP, - instrux_FIDIV, - instrux_FIDIVR, - instrux_FILD, - instrux_FIMUL, - instrux_FINCSTP, - instrux_FINIT, - instrux_FIST, - instrux_FISTP, - instrux_FISTTP, - instrux_FISUB, - instrux_FISUBR, - instrux_FLD, - instrux_FLD1, - instrux_FLDCW, - instrux_FLDENV, - instrux_FLDL2E, - instrux_FLDL2T, - instrux_FLDLG2, - instrux_FLDLN2, - instrux_FLDPI, - instrux_FLDZ, - instrux_FMUL, - instrux_FMULP, - instrux_FNCLEX, - instrux_FNDISI, - instrux_FNENI, - instrux_FNINIT, - instrux_FNOP, - instrux_FNSAVE, - instrux_FNSTCW, - instrux_FNSTENV, - instrux_FNSTSW, - instrux_FPATAN, - instrux_FPREM, - instrux_FPREM1, - instrux_FPTAN, - instrux_FRNDINT, - instrux_FRSTOR, - instrux_FSAVE, - instrux_FSCALE, - instrux_FSETPM, - instrux_FSIN, - instrux_FSINCOS, - instrux_FSQRT, - instrux_FST, - instrux_FSTCW, - instrux_FSTENV, - instrux_FSTP, - instrux_FSTSW, - instrux_FSUB, - instrux_FSUBP, - instrux_FSUBR, - instrux_FSUBRP, - instrux_FTST, - instrux_FUCOM, - instrux_FUCOMI, - instrux_FUCOMIP, - instrux_FUCOMP, - instrux_FUCOMPP, - instrux_FWAIT, - instrux_FXAM, - instrux_FXCH, - instrux_FXRSTOR, - instrux_FXSAVE, - instrux_FXTRACT, - instrux_FYL2X, - instrux_FYL2XP1, - instrux_HADDPD, - instrux_HADDPS, - instrux_HLT, - instrux_HSUBPD, - instrux_HSUBPS, - instrux_IBTS, - instrux_ICEBP, - instrux_IDIV, - instrux_IMUL, - instrux_IN, - instrux_INC, - instrux_INCBIN, - instrux_INSB, - instrux_INSD, - instrux_INSW, - instrux_INT, - instrux_INT01, - instrux_INT03, - instrux_INT1, - instrux_INT3, - instrux_INTO, - instrux_INVD, - instrux_INVLPG, - instrux_IRET, - instrux_IRETD, - instrux_IRETW, - instrux_JCXZ, - instrux_JECXZ, - instrux_JMP, - instrux_JMPE, - instrux_LAHF, - instrux_LAR, - instrux_LDDQU, - instrux_LDMXCSR, - instrux_LDS, - instrux_LEA, - instrux_LEAVE, - instrux_LES, - instrux_LFENCE, - instrux_LFS, - instrux_LGDT, - instrux_LGS, - instrux_LIDT, - instrux_LLDT, - instrux_LMSW, - instrux_LOADALL, - instrux_LOADALL286, - instrux_LODSB, - instrux_LODSD, - instrux_LODSW, - instrux_LOOP, - instrux_LOOPE, - instrux_LOOPNE, - instrux_LOOPNZ, - instrux_LOOPZ, - instrux_LSL, - instrux_LSS, - instrux_LTR, - instrux_MASKMOVDQU, - instrux_MASKMOVQ, - instrux_MAXPD, - instrux_MAXPS, - instrux_MAXSD, - instrux_MAXSS, - instrux_MFENCE, - instrux_MINPD, - instrux_MINPS, - instrux_MINSD, - instrux_MINSS, - instrux_MONITOR, - instrux_MOV, - instrux_MOVAPD, - instrux_MOVAPS, - instrux_MOVD, - instrux_MOVDDUP, - instrux_MOVDQ2Q, - instrux_MOVDQA, - instrux_MOVDQU, - instrux_MOVHLPS, - instrux_MOVHPD, - instrux_MOVHPS, - instrux_MOVLHPS, - instrux_MOVLPD, - instrux_MOVLPS, - instrux_MOVMSKPD, - instrux_MOVMSKPS, - instrux_MOVNTDQ, - instrux_MOVNTI, - instrux_MOVNTPD, - instrux_MOVNTPS, - instrux_MOVNTQ, - instrux_MOVQ, - instrux_MOVQ2DQ, - instrux_MOVSB, - instrux_MOVSD, - instrux_MOVSHDUP, - instrux_MOVSLDUP, - instrux_MOVSS, - instrux_MOVSW, - instrux_MOVSX, - instrux_MOVUPD, - instrux_MOVUPS, - instrux_MOVZX, - instrux_MUL, - instrux_MULPD, - instrux_MULPS, - instrux_MULSD, - instrux_MULSS, - instrux_MWAIT, - instrux_NEG, - instrux_NOP, - instrux_NOT, - instrux_OR, - instrux_ORPD, - instrux_ORPS, - instrux_OUT, - instrux_OUTSB, - instrux_OUTSD, - instrux_OUTSW, - instrux_PACKSSDW, - instrux_PACKSSWB, - instrux_PACKUSWB, - instrux_PADDB, - instrux_PADDD, - instrux_PADDQ, - instrux_PADDSB, - instrux_PADDSIW, - instrux_PADDSW, - instrux_PADDUSB, - instrux_PADDUSW, - instrux_PADDW, - instrux_PAND, - instrux_PANDN, - instrux_PAUSE, - instrux_PAVEB, - instrux_PAVGB, - instrux_PAVGUSB, - instrux_PAVGW, - instrux_PCMPEQB, - instrux_PCMPEQD, - instrux_PCMPEQW, - instrux_PCMPGTB, - instrux_PCMPGTD, - instrux_PCMPGTW, - instrux_PDISTIB, - instrux_PEXTRW, - instrux_PF2ID, - instrux_PF2IW, - instrux_PFACC, - instrux_PFADD, - instrux_PFCMPEQ, - instrux_PFCMPGE, - instrux_PFCMPGT, - instrux_PFMAX, - instrux_PFMIN, - instrux_PFMUL, - instrux_PFNACC, - instrux_PFPNACC, - instrux_PFRCP, - instrux_PFRCPIT1, - instrux_PFRCPIT2, - instrux_PFRSQIT1, - instrux_PFRSQRT, - instrux_PFSUB, - instrux_PFSUBR, - instrux_PI2FD, - instrux_PI2FW, - instrux_PINSRW, - instrux_PMACHRIW, - instrux_PMADDWD, - instrux_PMAGW, - instrux_PMAXSW, - instrux_PMAXUB, - instrux_PMINSW, - instrux_PMINUB, - instrux_PMOVMSKB, - instrux_PMULHRIW, - instrux_PMULHRWA, - instrux_PMULHRWC, - instrux_PMULHUW, - instrux_PMULHW, - instrux_PMULLW, - instrux_PMULUDQ, - instrux_PMVGEZB, - instrux_PMVLZB, - instrux_PMVNZB, - instrux_PMVZB, - instrux_POP, - instrux_POPA, - instrux_POPAD, - instrux_POPAW, - instrux_POPF, - instrux_POPFD, - instrux_POPFW, - instrux_POR, - instrux_PREFETCH, - instrux_PREFETCHNTA, - instrux_PREFETCHT0, - instrux_PREFETCHT1, - instrux_PREFETCHT2, - instrux_PREFETCHW, - instrux_PSADBW, - instrux_PSHUFD, - instrux_PSHUFHW, - instrux_PSHUFLW, - instrux_PSHUFW, - instrux_PSLLD, - instrux_PSLLDQ, - instrux_PSLLQ, - instrux_PSLLW, - instrux_PSRAD, - instrux_PSRAW, - instrux_PSRLD, - instrux_PSRLDQ, - instrux_PSRLQ, - instrux_PSRLW, - instrux_PSUBB, - instrux_PSUBD, - instrux_PSUBQ, - instrux_PSUBSB, - instrux_PSUBSIW, - instrux_PSUBSW, - instrux_PSUBUSB, - instrux_PSUBUSW, - instrux_PSUBW, - instrux_PSWAPD, - instrux_PUNPCKHBW, - instrux_PUNPCKHDQ, - instrux_PUNPCKHQDQ, - instrux_PUNPCKHWD, - instrux_PUNPCKLBW, - instrux_PUNPCKLDQ, - instrux_PUNPCKLQDQ, - instrux_PUNPCKLWD, - instrux_PUSH, - instrux_PUSHA, - instrux_PUSHAD, - instrux_PUSHAW, - instrux_PUSHF, - instrux_PUSHFD, - instrux_PUSHFW, - instrux_PXOR, - instrux_RCL, - instrux_RCPPS, - instrux_RCPSS, - instrux_RCR, - instrux_RDMSR, - instrux_RDPMC, - instrux_RDSHR, - instrux_RDTSC, - instrux_RESB, - instrux_RESD, - instrux_RESQ, - instrux_REST, - instrux_RESW, - instrux_RET, - instrux_RETF, - instrux_RETN, - instrux_ROL, - instrux_ROR, - instrux_RSDC, - instrux_RSLDT, - instrux_RSM, - instrux_RSQRTPS, - instrux_RSQRTSS, - instrux_RSTS, - instrux_SAHF, - instrux_SAL, - instrux_SALC, - instrux_SAR, - instrux_SBB, - instrux_SCASB, - instrux_SCASD, - instrux_SCASW, - instrux_SFENCE, - instrux_SGDT, - instrux_SHL, - instrux_SHLD, - instrux_SHR, - instrux_SHRD, - instrux_SHUFPD, - instrux_SHUFPS, - instrux_SIDT, - instrux_SLDT, - instrux_SMI, - instrux_SMINT, - instrux_SMINTOLD, - instrux_SMSW, - instrux_SQRTPD, - instrux_SQRTPS, - instrux_SQRTSD, - instrux_SQRTSS, - instrux_STC, - instrux_STD, - instrux_STI, - instrux_STMXCSR, - instrux_STOSB, - instrux_STOSD, - instrux_STOSW, - instrux_STR, - instrux_SUB, - instrux_SUBPD, - instrux_SUBPS, - instrux_SUBSD, - instrux_SUBSS, - instrux_SVDC, - instrux_SVLDT, - instrux_SVTS, - instrux_SYSCALL, - instrux_SYSENTER, - instrux_SYSEXIT, - instrux_SYSRET, - instrux_TEST, - instrux_UCOMISD, - instrux_UCOMISS, - instrux_UD0, - instrux_UD1, - instrux_UD2, - instrux_UMOV, - instrux_UNPCKHPD, - instrux_UNPCKHPS, - instrux_UNPCKLPD, - instrux_UNPCKLPS, - instrux_VERR, - instrux_VERW, - instrux_WAIT, - instrux_WBINVD, - instrux_WRMSR, - instrux_WRSHR, - instrux_XADD, - instrux_XBTS, - instrux_XCHG, - instrux_XLAT, - instrux_XLATB, - instrux_XOR, - instrux_XORPD, - instrux_XORPS, - instrux_XSTORE, - instrux_CMOVcc, - instrux_Jcc, - instrux_SETcc, -}; diff --git a/AltairZ80/mfdc.c b/AltairZ80/mfdc.c index 5ac79053..e697660d 100644 --- a/AltairZ80/mfdc.c +++ b/AltairZ80/mfdc.c @@ -161,10 +161,6 @@ static MTAB mfdc_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(mfdc_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB mfdc_dt[] = { { "ERROR", ERROR_MSG }, @@ -402,7 +398,7 @@ static uint8 MFDC_Read(const uint32 Addr) cData |= (1 << 7); /* Sector Flag */ mfdc_info->xfr_flag = 1; /* Drive has data */ mfdc_info->datacount = 0; - TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x\n", PCX, cData); break; case 1: cData = (mfdc_info->sel_drive & 0x3); /* [1:0] selected drive */ @@ -414,15 +410,15 @@ static uint8 MFDC_Read(const uint32 Addr) cData |= (0 << 6); /* [6] PINTE from S-100 Bus */ cData |= (mfdc_info->xfr_flag << 7); /* [7] Transfer Flag */ - TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x\n", PCX, cData); break; case 2: case 3: if(mfdc_info->datacount == 0) { unsigned int i, checksum; unsigned long sec_offset; - uint32 flags; - uint32 readlen; + unsigned int flags; + unsigned int readlen; /* Clear out unused portion of sector. */ memset(&sdata.u.unused[0], 0x00, 10); @@ -431,10 +427,7 @@ static uint8 MFDC_Read(const uint32 Addr) sdata.u.header[0] = pDrive->track; sdata.u.header[1] = pDrive->sector; - TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]" NLP, - PCX, - pDrive->track, - pDrive->sector)); + sim_debug(RD_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]\n", PCX, pDrive->track, pDrive->sector); #ifdef USE_VGI sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \ @@ -509,8 +502,7 @@ static uint8 MFDC_Read(const uint32 Addr) mfdc_info->datacount++; if(mfdc_info->datacount == 270) { - TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " Read sector [%d] complete" NLP, - PCX, pDrive->sector)); + sim_debug(RD_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Read sector [%d] complete\n", PCX, pDrive->sector); mfdc_info->read_in_progress = FALSE; } @@ -524,8 +516,8 @@ static uint8 MFDC_Read(const uint32 Addr) static uint8 MFDC_Write(const uint32 Addr, uint8 cData) { unsigned int sec_offset; - uint32 flags = 0; - uint32 writelen; + unsigned int flags = 0; + unsigned int writelen; MFDC_DRIVE_INFO *pDrive; pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; @@ -564,10 +556,7 @@ static uint8 MFDC_Write(const uint32 Addr, uint8 cData) mfdc_info->datacount ++; if(mfdc_info->datacount == 270) { - TRACE_PRINT(WR_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]" NLP, - PCX, - pDrive->track, - pDrive->sector)); + sim_debug(WR_DATA_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]\n", PCX, pDrive->track, pDrive->sector); if (!(pDrive->uptr->flags & UNIT_ATT)) { if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE) @@ -641,7 +630,7 @@ static void MFDC_Command(uint8 cData) switch(cCommand) { case MFDC_CMD_NOP: - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " No Op." NLP, PCX)); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " No Op.\n", PCX); break; case MFDC_CMD_SELECT: mfdc_info->sel_drive = cModifier & 0x03; @@ -654,13 +643,11 @@ static void MFDC_Command(uint8 cData) pDrive->ready = 0; } - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s" NLP, - PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower")); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s\n", PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower"); break; case MFDC_CMD_INTR: mfdc_info->int_enable = cModifier & 1; /* 0=int disable, 1=enable */ - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Interrupts %s." NLP, - PCX, mfdc_info->int_enable ? "Enabled" : "Disabled")); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Interrupts %s.\n", PCX, mfdc_info->int_enable ? "Enabled" : "Disabled"); break; case MFDC_CMD_STEP: if(cModifier & 1) { /* Step IN */ @@ -672,23 +659,22 @@ static void MFDC_Command(uint8 cData) } } - TRACE_PRINT(SEEK_MSG, ("MFDC: " ADDRESS_FORMAT " Step %s, Track=%d." NLP, - PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track)); + sim_debug(SEEK_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Step %s, Track=%d.\n", PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track); break; case MFDC_CMD_SET_WRITE: - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Set WRITE." NLP, PCX)); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Set WRITE.\n", PCX); mfdc_info->wr_latch = 1; /* Allow writes for the current sector */ mfdc_info->datacount = 0; /* reset the byte counter */ break; case MFDC_CMD_RESET: - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Reset Controller." NLP, PCX)); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Reset Controller.\n", PCX); mfdc_info->selected = 0; /* de-select the drive */ mfdc_info->wr_latch = 0; /* Disable the write latch */ mfdc_info->datacount = 0; /* reset the byte counter */ break; default: - TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Unsupported command." NLP, PCX)); + sim_debug(CMD_MSG, &mfdc_dev, "MFDC: " ADDRESS_FORMAT " Unsupported command.\n", PCX); break; } } diff --git a/AltairZ80/n8vem.c b/AltairZ80/n8vem.c index c1dbdbe2..99bfb446 100644 --- a/AltairZ80/n8vem.c +++ b/AltairZ80/n8vem.c @@ -136,10 +136,6 @@ static MTAB n8vem_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(n8vem_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB n8vem_dt[] = { { "ERROR", ERROR_MSG }, @@ -165,7 +161,7 @@ static t_stat n8vem_reset(DEVICE *dptr) { PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reset.\n")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reset.\n"); if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &n8vemdev, TRUE); @@ -196,7 +192,7 @@ static t_stat n8vem_reset(DEVICE *dptr) static t_stat n8vem_boot(int32 unitno, DEVICE *dptr) { - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Boot.\n")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Boot.\n"); /* Clear the RAM and ROM mapping registers */ n8vem_info->mpcl_ram = 0; @@ -226,7 +222,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) /* Determine length of this disk */ uptr->capac = sim_fsize(uptr->fileref); - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Attach %s.\n", i == 0 ? "ROM" : "RAM")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Attach %s.\n", i == 0 ? "ROM" : "RAM"); if(i == 0) { /* Attaching ROM */ n8vem_info->rom_attached = TRUE; @@ -240,9 +236,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) uptr->capac = N8VEM_ROM_SIZE; rtn = fread((void *)(n8vem_info->rom), uptr->capac, 1, uptr->fileref); - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into ROM." - " Result = %ssuccessful.\n", - uptr->capac, rtn == 1 ? "" : "not ")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reading %d bytes into ROM." " Result = %ssuccessful.\n", uptr->capac, rtn == 1 ? "" : "not "); } } else { /* attaching RAM */ /* Erase RAM */ @@ -254,9 +248,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) uptr->capac = N8VEM_RAM_SIZE; rtn = fread((void *)(n8vem_info->ram), uptr->capac, 1, uptr->fileref); - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into RAM." - " Result = %ssuccessful.\n", - uptr->capac, rtn == 1 ? "" : "not ")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Reading %d bytes into RAM." " Result = %ssuccessful.\n", uptr->capac, rtn == 1 ? "" : "not "); } } return r; @@ -274,7 +266,7 @@ static t_stat n8vem_detach(UNIT *uptr) return (SCPE_IERR); } - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Detach %s.\n", i == 0 ? "ROM" : "RAM")); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Detach %s.\n", i == 0 ? "ROM" : "RAM"); /* rewind to the beginning of the file. */ sim_fseek(uptr->fileref, 0, SEEK_SET); @@ -282,13 +274,13 @@ static t_stat n8vem_detach(UNIT *uptr) if(i == 0) { /* ROM */ /* Save the ROM back to disk if SAVEROM is set. */ if(save_rom == 1) { - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Writing %d bytes into ROM image.\n", N8VEM_ROM_SIZE)); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Writing %d bytes into ROM image.\n", N8VEM_ROM_SIZE); fwrite((void *)(n8vem_info->rom), N8VEM_ROM_SIZE, 1, uptr->fileref); } } else { /* RAM */ /* Save the RAM back to disk if SAVERAM is set. */ if(save_ram == 1) { - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Writing %d bytes into RAM image.\n", N8VEM_RAM_SIZE)); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: Writing %d bytes into RAM image.\n", N8VEM_RAM_SIZE); fwrite((void *)(n8vem_info->ram), N8VEM_RAM_SIZE, 1, uptr->fileref); } } @@ -334,7 +326,7 @@ static t_stat n8vem_detach(UNIT *uptr) if(save_rom == 1) { n8vem_info->rom[((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)] = data; } else { - TRACE_PRINT(ROM_MSG, ("N8VEM: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM." NLP, PCX, ((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK))); + sim_debug(ROM_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM.\n", PCX, ((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)); } } return 0; @@ -391,19 +383,19 @@ static uint8 N8VEM_Read(const uint32 Addr) switch(Addr & 0x1F) { case N8VEM_PIO1A: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1A" NLP, PCX)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1A\n", PCX); cData = n8vem_pio1a; break; case N8VEM_PIO1B: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1B" NLP, PCX)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1B\n", PCX); cData = n8vem_pio1b; break; case N8VEM_PIO1C: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1C" NLP, PCX)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1C\n", PCX); cData = n8vem_pio1c; break; case N8VEM_PIO1CONT: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1CTRL" NLP, PCX)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: PIO1CTRL\n", PCX); cData = n8vem_pio1ctrl; break; case N8VEM_UART_LCR: @@ -415,7 +407,7 @@ static uint8 N8VEM_Read(const uint32 Addr) case N8VEM_UART_INTR: case N8VEM_UART_MCR: case N8VEM_UART_MSR: - TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " RD[%02x]: UART not Implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD[%02x]: UART not Implemented.\n", PCX, Addr); break; case N8VEM_UART_SCR: /* 16550 Scratchpad, implemented so software can detect UART is present */ cData = n8vem_info->uart_scr; @@ -424,16 +416,16 @@ static uint8 N8VEM_Read(const uint32 Addr) case N8VEM_MPCL_RAM1: case N8VEM_MPCL_RAM2: case N8VEM_MPCL_RAM3: - TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: MPCL_RAM not Implemented." NLP, PCX)); + sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: MPCL_RAM not Implemented.\n", PCX); break; case N8VEM_MPCL_ROM: case N8VEM_MPCL_ROM1: case N8VEM_MPCL_ROM2: case N8VEM_MPCL_ROM3: - TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: MPCL_ROM not Implemented." NLP, PCX)); + sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD: MPCL_ROM not Implemented.\n", PCX); break; default: - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: " ADDRESS_FORMAT " RD[%02x]: not Implemented." NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " RD[%02x]: not Implemented.\n", PCX, Addr); break; } @@ -446,23 +438,23 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData) switch(Addr & 0x1F) { case N8VEM_PIO1A: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1A=0x%02x" NLP, PCX, cData)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1A=0x%02x\n", PCX, cData); n8vem_pio1a = cData; break; case N8VEM_PIO1B: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1B=0x%02x" NLP, PCX, cData)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1B=0x%02x\n", PCX, cData); n8vem_pio1b = cData; break; case N8VEM_PIO1C: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1C=0x%02x" NLP, PCX, cData)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1C=0x%02x\n", PCX, cData); n8vem_pio1c = cData; break; case N8VEM_PIO1CONT: - TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1_CTRL=0x%02x" NLP, PCX, cData)); + sim_debug(PIO_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: PIO1_CTRL=0x%02x\n", PCX, cData); n8vem_pio1ctrl = cData; break; case N8VEM_UART_LCR: - TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: UART LCR=%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: UART LCR=%02x.\n", PCX, cData); n8vem_info->uart_lcr = cData; break; case N8VEM_UART_DATA: @@ -471,7 +463,7 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData) case N8VEM_UART_MCR: case N8VEM_UART_LSR: case N8VEM_UART_MSR: - TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " WR[%02x]: UART not Implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR[%02x]: UART not Implemented.\n", PCX, Addr); break; case N8VEM_UART_SCR: /* 16550 Scratchpad, implemented so software can detect UART is present */ n8vem_info->uart_scr = cData; @@ -480,18 +472,18 @@ static uint8 N8VEM_Write(const uint32 Addr, uint8 cData) case N8VEM_MPCL_RAM1: case N8VEM_MPCL_RAM2: case N8VEM_MPCL_RAM3: - TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: MPCL_RAM=0x%02x" NLP, PCX, cData)); + sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: MPCL_RAM=0x%02x\n", PCX, cData); n8vem_info->mpcl_ram = cData; break; case N8VEM_MPCL_ROM: case N8VEM_MPCL_ROM1: case N8VEM_MPCL_ROM2: case N8VEM_MPCL_ROM3: - TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: MPCL_ROM=0x%02x" NLP, PCX, cData)); + sim_debug(MPCL_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR: MPCL_ROM=0x%02x\n", PCX, cData); n8vem_info->mpcl_rom = cData; break; default: - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented." NLP, PCX, Addr, cData)); + sim_debug(VERBOSE_MSG, &n8vem_dev, "N8VEM: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented.\n", PCX, Addr, cData); break; } diff --git a/AltairZ80/s100_64fdc.c b/AltairZ80/s100_64fdc.c index 86b7d0e7..03c4f395 100644 --- a/AltairZ80/s100_64fdc.c +++ b/AltairZ80/s100_64fdc.c @@ -86,7 +86,7 @@ typedef struct { uint8 ipend; /* Interrupt Pending Register */ } CROMFDC_INFO; -extern WD179X_INFO_PUB *wd179x_info; +extern WD179X_INFO_PUB *wd179x_infop; static CROMFDC_INFO cromfdc_info_data = { { 0xC000, CROMFDC_ROM_SIZE, 0x3, 2 } }; static CROMFDC_INFO *cromfdc_info = &cromfdc_info_data; @@ -248,10 +248,6 @@ static MTAB cromfdc_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(cromfdc_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB cromfdc_dt[] = { { "ERROR", ERROR_MSG }, @@ -1463,13 +1459,13 @@ static t_stat cromfdc_svc (UNIT *uptr) motor_timeout ++; if(motor_timeout == MOTOR_TO_LIMIT) { cromfdc_info->motor_on = 0; - TRACE_PRINT(DRIVE_MSG, ("CROMFDC: Motor OFF" NLP)) + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: Motor OFF\n"); } } cromfdc_info->rtc ++; - TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: " ADDRESS_FORMAT " Timer IRQ" NLP, PCX)); + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " Timer IRQ\n", PCX); cromfdc_info->ipend |= CROMFDC_IRQ_TIMER3; /* sim_activate (cromfdc_unit, cromfdc_unit->wait); */ /* requeue! */ @@ -1498,14 +1494,13 @@ static t_stat cromfdc_reset(DEVICE *dptr) } else { /* Connect CROMFDC ROM at base address */ if (cromfdc_hasProperty(UNIT_CROMFDC_ROM)) { - TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: ROM Enabled." NLP)); + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: ROM Enabled.\n"); if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &cromfdcrom, FALSE) != 0) { printf("%s: error mapping MEM resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base); return SCPE_ARG; } - } else { - TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: ROM Disabled." NLP)) - } + } else + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: ROM Disabled.\n"); /* Connect CROMFDC Interrupt, and Aux Disk Registers */ if(sim_map_resource(0x03, 0x02, RESOURCE_TYPE_IO, &cromfdc_ext, FALSE) != 0) { printf("%s: error mapping I/O resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base); @@ -1535,7 +1530,7 @@ static t_stat cromfdc_reset(DEVICE *dptr) printf("%s: error mapping I/O resource at 0x%04x" NLP, __FUNCTION__, pnp->io_base); return SCPE_ARG; } else { - TRACE_PRINT(VERBOSE_MSG, ("Mapped CCS2810 UART Status at 0x26" NLP)); + sim_debug(VERBOSE_MSG, &cromfdc_dev, "Mapped CCS2810 UART Status at 0x26\n"); } } @@ -1585,29 +1580,28 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) if(io) { /* I/O Write */ switch(data & 0x0F) { case 0: - wd179x_info->sel_drive = 0xFF; + wd179x_infop->sel_drive = 0xFF; break; case CROMFDC_CTRL_DS1: - wd179x_info->sel_drive = 0; + wd179x_infop->sel_drive = 0; break; case CROMFDC_CTRL_DS2: - wd179x_info->sel_drive = 1; + wd179x_infop->sel_drive = 1; break; case CROMFDC_CTRL_DS3: - wd179x_info->sel_drive = 2; + wd179x_infop->sel_drive = 2; break; case CROMFDC_CTRL_DS4: - wd179x_info->sel_drive = 3; + wd179x_infop->sel_drive = 3; break; default: - TRACE_PRINT(STATUS_MSG, - ("CROMFDC: " ADDRESS_FORMAT " WR CTRL = 0x%02x: Invalid drive selected." NLP, PCX, data & 0xFF)); + sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL = 0x%02x: Invalid drive selected.\n", PCX, data & 0xFF); break; } if(data & CROMFDC_CTRL_MAXI) { - wd179x_info->drivetype = 8; + wd179x_infop->drivetype = 8; } else { - wd179x_info->drivetype = 5; + wd179x_infop->drivetype = 5; } if(data & CROMFDC_CTRL_MTRON) { @@ -1617,13 +1611,12 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) if(data & CROMFDC_CTRL_DDENS) { if(crofdc_type == 4) { /* 4FDC */ - TRACE_PRINT(DRIVE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set double density on 4FDC" NLP, PCX)); + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set double density on 4FDC\n", PCX); } else { - wd179x_info->ddens = 1; + wd179x_infop->ddens = 1; } } else { - wd179x_info->ddens = 0; + wd179x_infop->ddens = 0; } if(data & CROMFDC_CTRL_AUTOWAIT) { cromfdc_info->autowait = 1; @@ -1631,13 +1624,11 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) cromfdc_info->autowait = 0; } - TRACE_PRINT(DRIVE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, motor=%d, dens=%d, aw=%d" NLP, PCX, - wd179x_info->sel_drive, wd179x_info->drivetype, cromfdc_info->motor_on, wd179x_info->ddens, cromfdc_info->autowait)); + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, motor=%d, dens=%d, aw=%d\n", PCX, wd179x_infop->sel_drive, wd179x_infop->drivetype, cromfdc_info->motor_on, wd179x_infop->ddens, cromfdc_info->autowait); } else { /* I/O Read */ result = (crofdc_boot) ? 0 : CROMFDC_FLAG_BOOT; - result |= (wd179x_info->intrq) ? CROMFDC_FLAG_EOJ : 0; - result |= (wd179x_info->drq) ? CROMFDC_FLAG_DRQ : 0; + result |= (wd179x_infop->intrq) ? CROMFDC_FLAG_EOJ : 0; + result |= (wd179x_infop->drq) ? CROMFDC_FLAG_DRQ : 0; if(crofdc_type != 50) { /* Cromemco Controller */ result |= (motor_timeout < MOTOR_TO_LIMIT) ? CROMFDC_FLAG_SEL_REQ : 0; if(crofdc_type > 4) { /* 16, 64FDC */ @@ -1648,7 +1639,7 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) result |= 0x1E; /* Make unused bits '1' on 4FDC */ } } else { /* CCS 2422 Controller */ - switch(wd179x_info->sel_drive) { + switch(wd179x_infop->sel_drive) { case 1: result |= 0x02; break; @@ -1665,8 +1656,8 @@ static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) /* printf("CCS2422FDC: " ADDRESS_FORMAT " Read STATUS1=0x%02x" NLP, PCX, result); */ } - TRACE_PRINT(STATUS_MSG, - ("CROMFDC: " ADDRESS_FORMAT " Read DISK FLAGS, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " Read DISK FLAGS, Port 0x%02x Result 0x%02x\n", PCX, port, result); } return result; @@ -1684,13 +1675,12 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data) if(crofdc_type != 50) { /* Cromemco Controller */ if((data & CROMFDC_AUX_CMD_SIDE) == 0) { if(crofdc_type == 4) { /* 4FDC */ - TRACE_PRINT(DRIVE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set side 1 on 4FDC" NLP, PCX)); + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set side 1 on 4FDC\n", PCX); } else { - wd179x_info->fdc_head = 1; + wd179x_infop->fdc_head = 1; } } else { - wd179x_info->fdc_head = 0; + wd179x_infop->fdc_head = 0; } #if 0 /* hharte - nothing implemented for these */ if((data & CROMFDC_AUX_EJECT) == 0) { @@ -1710,21 +1700,20 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data) } } else { /* CCS 2422 Controller */ if((data & CCSFDC_CMD_SIDE) == 0) { - wd179x_info->fdc_head = 1; + wd179x_infop->fdc_head = 1; } else { - wd179x_info->fdc_head = 0; + wd179x_infop->fdc_head = 0; } } } else if (port == 0x3) { /* Interrupt Address */ - TRACE_PRINT(IRQ_MSG, - ("CROMFDC: " ADDRESS_FORMAT " IRQ Mask=0x%02x" NLP, PCX, data)); + sim_debug(IRQ_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " IRQ Mask=0x%02x\n", PCX, data); cromfdc_info->imask = data; } else { } - TRACE_PRINT(DRIVE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " AUX OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + sim_debug(DRIVE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " AUX OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data); result = 0; } else { /* I/O Read */ if(port == 0x4) { @@ -1732,20 +1721,18 @@ static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data) result |= 0x00; /* Bit 6 is Seek in Progress for Persci drives. */ result |= (cromfdc_info->rtc & 1) ? 0x80 : 0; if(crofdc_type == 50) { - TRACE_PRINT(STATUS_MSG, - ("CCS2422FDC: " ADDRESS_FORMAT " Read STATUS2=0x%02x" NLP, PCX, result)); + sim_debug(STATUS_MSG, &cromfdc_dev, "CCS2422FDC: " ADDRESS_FORMAT " Read STATUS2=0x%02x\n", PCX, result); } } else if (port == 0x3) { /* Interrupt Address */ result = ipend_to_rst_opcode(cromfdc_info->ipend); if(result != 0) { - TRACE_PRINT(IRQ_MSG, - ("CROMFDC: " ADDRESS_FORMAT " RST Opcode=%x, Vector=%04x" NLP, PCX, result, RST_OPCODE_TO_VECTOR(result))); + sim_debug(IRQ_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT " RST Opcode=%x, Vector=%04x\n", PCX, result, RST_OPCODE_TO_VECTOR(result)); } } else { result = 0xFF; } - TRACE_PRINT(STATUS_MSG, - ("CROMFDC: " ADDRESS_FORMAT " AUX IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + sim_debug(STATUS_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " AUX IN, Port 0x%02x Result 0x%02x\n", PCX, port, result); } return result; } @@ -1755,14 +1742,14 @@ static int32 cromfdc_timer(const int32 port, const int32 io, const int32 data) { static int32 result = 0; if(io) { - TRACE_PRINT(VERBOSE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " TIMER%d OUT, Port 0x%02x Data 0x%02x" NLP, PCX, (port-4), port, data)) + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " TIMER%d OUT, Port 0x%02x Data 0x%02x\n", PCX, (port-4), port, data); result = 0; sim_activate(cromfdc_unit, (CROMFDC_SIM_64US * data)); } else { result++; - TRACE_PRINT(VERBOSE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " TIMER%d IN, Port 0x%02x Result 0x%02x" NLP, PCX, (port-4), port, result)) + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " TIMER%d IN, Port 0x%02x Result 0x%02x\n", PCX, (port-4), port, result); } return result; } @@ -1772,15 +1759,15 @@ static int32 cromfdc_banksel(const int32 port, const int32 io, const int32 data) { int32 result; if(io) { - TRACE_PRINT(VERBOSE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " BANKSEL OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " BANKSEL OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data); /* Unmap Boot ROM */ cromfdc_info->rom_disabled = TRUE; result = 0; } else { result = 0xFF; - TRACE_PRINT(VERBOSE_MSG, - ("CROMFDC: " ADDRESS_FORMAT " BANKSEL IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + sim_debug(VERBOSE_MSG, &cromfdc_dev, "CROMFDC: " ADDRESS_FORMAT + " BANKSEL IN, Port 0x%02x Result 0x%02x\n", PCX, port, result); } return result; } diff --git a/AltairZ80/s100_adcs6.c b/AltairZ80/s100_adcs6.c index 7c6b14bd..353b92e6 100644 --- a/AltairZ80/s100_adcs6.c +++ b/AltairZ80/s100_adcs6.c @@ -88,7 +88,7 @@ typedef struct { uint8 s100_addr_u; /* A23:16 of S-100 bus */ } ADCS6_INFO; -extern WD179X_INFO_PUB *wd179x_info; +extern WD179X_INFO_PUB *wd179x_infop; static ADCS6_INFO adcs6_info_data = { { 0xF000, ADCS6_ROM_SIZE, 0x3, 2 } }; static ADCS6_INFO *adcs6_info = &adcs6_info_data; @@ -207,10 +207,6 @@ static MTAB adcs6_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(adcs6_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB adcs6_dt[] = { { "ERROR", ERROR_MSG }, @@ -398,7 +394,7 @@ static t_stat adcs6_svc (UNIT *uptr) motor_timeout ++; if(motor_timeout == MOTOR_TO_LIMIT) { adcs6_info->head_sel = 0; - TRACE_PRINT(DRIVE_MSG, ("ADCS6: Motor OFF" NLP)) + sim_debug(DRIVE_MSG, &adcs6_dev, "ADCS6: Motor OFF\n"); } } @@ -430,14 +426,14 @@ static t_stat adcs6_reset(DEVICE *dptr) } else { /* Connect ADCS6 ROM at base address */ if (adcs6_hasProperty(UNIT_ADCS6_ROM)) { - TRACE_PRINT(VERBOSE_MSG, ("ADCS6: ROM Enabled." NLP)) + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: ROM Enabled.\n"); if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &adcs6rom, FALSE) != 0) { printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, pnp->io_base); return SCPE_ARG; } adcs6_info->rom_disabled = FALSE; } else { - TRACE_PRINT(VERBOSE_MSG, ("ADCS6: ROM Disabled." NLP)) + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: ROM Disabled.\n"); adcs6_info->rom_disabled = TRUE; } @@ -508,8 +504,8 @@ static int32 adcs6rom(const int32 Addr, const int32 write, const int32 data) /* DBG_PRINT(("ADCS6: ROM %s, Addr %04x" NLP, write ? "WR" : "RD", Addr)); */ if(write) { if(adcs6_info->rom_disabled == FALSE) { - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " Cannot write to ROM." NLP, PCX)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " Cannot write to ROM.\n", PCX); } else { adcs6ram[Addr & ADCS6_ADDR_MASK] = data; } @@ -528,26 +524,26 @@ static int32 adcs6_control(const int32 port, const int32 io, const int32 data) { int32 result = 0; if(io) { /* I/O Write */ - wd179x_info->sel_drive = data & 0x03; + wd179x_infop->sel_drive = data & 0x03; if(data & ADCS6_CTRL_MINI) { - wd179x_info->drivetype = 5; + wd179x_infop->drivetype = 5; } else { - wd179x_info->drivetype = 8; + wd179x_infop->drivetype = 8; } if(data & ADCS6_CTRL_HDS) { adcs6_info->head_sel = 1; - wd179x_info->fdc_head = 1; + wd179x_infop->fdc_head = 1; } else { adcs6_info->head_sel = 0; - wd179x_info->fdc_head = 0; + wd179x_infop->fdc_head = 0; } if(data & ADCS6_CTRL_DDENS) { - wd179x_info->ddens = 1; + wd179x_infop->ddens = 1; } else { - wd179x_info->ddens = 0; + wd179x_infop->ddens = 0; } if(data & ADCS6_CTRL_AUTOWAIT) { adcs6_info->autowait = 1; @@ -555,16 +551,15 @@ static int32 adcs6_control(const int32 port, const int32 io, const int32 data) adcs6_info->autowait = 0; } - TRACE_PRINT(DRIVE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, head_sel=%d, dens=%d, aw=%d" NLP, PCX, - wd179x_info->sel_drive, wd179x_info->drivetype, adcs6_info->head_sel, wd179x_info->ddens, adcs6_info->autowait)); + sim_debug(DRIVE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR CTRL: sel_drive=%d, drivetype=%d, head_sel=%d, dens=%d, aw=%d\n", + PCX, wd179x_infop->sel_drive, + wd179x_infop->drivetype, adcs6_info->head_sel, + wd179x_infop->ddens, adcs6_info->autowait); } else { /* I/O Read */ - result = wd179x_info->drq ? 0xFF : 0; - if (wd179x_info->intrq) + result = wd179x_infop->drq ? 0xFF : 0; + if (wd179x_infop->intrq) result &= 0x7F; - -/* TRACE_PRINT(VERBOSE_MSG, */ -/* ("ADCS6: " ADDRESS_FORMAT " Read DISK FLAGS, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) */ } return result; @@ -575,12 +570,12 @@ static int32 adcs6_dma(const int32 port, const int32 io, const int32 data) { int32 result = 0xff; if(io) { /* I/O Write */ - TRACE_PRINT(DMA_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR DMA: 0x%02x" NLP, PCX, data & 0xFF)); + sim_debug(DMA_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR DMA: 0x%02x\n", PCX, data & 0xFF); } else { /* I/O Read */ result = 0xFF; - TRACE_PRINT(DMA_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD DMA: 0x%02x" NLP, PCX, result)); + sim_debug(DMA_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD DMA: 0x%02x\n", PCX, result); } return result; } @@ -592,62 +587,62 @@ static int32 adcs6_timer(const int32 port, const int32 io, const int32 data) if(io) { /* Write */ switch(port) { case 0x04: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR PIOA DATA=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR PIOA DATA=0x%02x\n", PCX, data); break; case 0x05: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR PIOB DATA=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR PIOB DATA=0x%02x\n", PCX, data); break; case 0x06: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR PIOA CTRL=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR PIOA CTRL=0x%02x\n", PCX, data); break; case 0x07: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR PIOB CTRL=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR PIOB CTRL=0x%02x\n", PCX, data); break; case 0x08: case 0x09: case 0x0A: case 0x0B: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR CTC%d: 0x%02x" NLP, PCX, port - 8, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR CTC%d: 0x%02x\n", PCX, port - 8, data); break; default: - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data); break; } } else { /* Read */ result = 0xFF; switch(port) { case 0x04: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD PIOA DATA=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD PIOA DATA=0x%02x\n", PCX, result); break; case 0x05: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD PIOB DATA=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD PIOB DATA=0x%02x\n", PCX, result); break; case 0x06: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD PIOA CTRL=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD PIOA CTRL=0x%02x\n", PCX, result); break; case 0x07: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD PIOB CTRL=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD PIOB CTRL=0x%02x\n", PCX, result); break; case 0x08: case 0x09: case 0x0A: case 0x0B: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD CTC%d: 0x%02x" NLP, PCX, port - 8, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD CTC%d: 0x%02x\n", PCX, port - 8, data); break; default: - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data); break; } } @@ -662,28 +657,28 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data) switch(port) { case 0x15: adcs6_info->s100_addr_u = data & 0xFF; - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR S100 A[23:16]=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR S100 A[23:16]=0x%02x\n", PCX, data); break; case 0x16: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR MCTRL0: 0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR MCTRL0: 0x%02x\n", PCX, data); adcs6_info->rom_disabled = (data & 0x20) ? TRUE : FALSE; /* Unmap Boot ROM */ break; case 0x17: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR MCTRL1: 0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR MCTRL1: 0x%02x\n", PCX, data); break; case 0x18: case 0x19: case 0x1A: case 0x1B: - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR BAUD RATE=0x%02x" NLP, PCX, data)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR BAUD RATE=0x%02x\n", PCX, data); break; default: - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " WR Unhandled Port: 0x%02x=0x%02x" NLP, PCX, port, data)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " WR Unhandled Port: 0x%02x=0x%02x\n", PCX, port, data); break; } result = 0; @@ -697,8 +692,8 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data) * Bit 5:0 = "Baud Rate" */ result = dipswitch; - TRACE_PRINT(VERBOSE_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD BAUD RATE=0x%02x" NLP, PCX, result)); + sim_debug(VERBOSE_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD BAUD RATE=0x%02x\n", PCX, result); break; case 0x16: case 0x17: @@ -707,8 +702,8 @@ static int32 adcs6_banksel(const int32 port, const int32 io, const int32 data) case 0x1A: case 0x1B: default: - TRACE_PRINT(ERROR_MSG, - ("ADCS6: " ADDRESS_FORMAT " RD attempt from write-only 0x%02x=0x%02x" NLP, PCX, port, result)); + sim_debug(ERROR_MSG, &adcs6_dev, "ADCS6: " ADDRESS_FORMAT + " RD attempt from write-only 0x%02x=0x%02x\n", PCX, port, result); break; } } diff --git a/AltairZ80/s100_disk1a.c b/AltairZ80/s100_disk1a.c index 814d910c..5a71aa94 100644 --- a/AltairZ80/s100_disk1a.c +++ b/AltairZ80/s100_disk1a.c @@ -145,10 +145,6 @@ static MTAB disk1a_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(disk1a_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB disk1a_dt[] = { { "ERROR", ERROR_MSG }, @@ -805,14 +801,13 @@ static int32 disk1adev(const int32 port, const int32 io, const int32 data) { int32 result; if(io) { - TRACE_PRINT(VERBOSE_MSG, - ("DISK1A: " ADDRESS_FORMAT " OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " OUT, Port 0x%02x Data 0x%02x\n", PCX, port, data); DISK1A_Write(port, data); result = 0; } else { result = DISK1A_Read(port); - TRACE_PRINT(VERBOSE_MSG, - ("DISK1A: " ADDRESS_FORMAT " IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " IN, Port 0x%02x Result 0x%02x\n", PCX, port, result); } return result; } @@ -835,12 +830,10 @@ static uint8 DISK1A_Read(const uint32 Addr) break; case DISK1A_DRIVE_STATUS: cData = i8272_irq ? 0x81 : 0x01; /* Ready */ - TRACE_PRINT(STATUS_MSG, - ("DISK1A: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " RD STATUS = 0x%02x\n", PCX, cData); break; case DISK1A_MOTOR: - TRACE_PRINT(VERBOSE_MSG, - ("DISK1A: " ADDRESS_FORMAT " Error, can't read from MOTOR register." NLP, PCX)) + sim_debug(VERBOSE_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " Error, can't read from MOTOR register.\n", PCX); cData = 0xFF; /* Return High-Z data */ break; } @@ -862,24 +855,24 @@ static uint8 DISK1A_Write(const uint32 Addr, uint8 cData) disk1a_info->dma_addr <<= 8; disk1a_info->dma_addr &= 0x00FFFF00; disk1a_info->dma_addr |= cData; - TRACE_PRINT(RD_DATA_MSG, ("DISK1A: " ADDRESS_FORMAT " DMA Address=%06x" NLP, - PCX, disk1a_info->dma_addr)) + sim_debug(RD_DATA_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " DMA Address=%06x\n", PCX, disk1a_info->dma_addr); I8272_Set_DMA(disk1a_info->dma_addr); break; case DISK1A_MOTOR: - TRACE_PRINT(CMD_MSG, - ("DISK1A: " ADDRESS_FORMAT " write Motor Reg=0x%02x" NLP, PCX, cData)) + sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " write Motor Reg=0x%02x\n", PCX, cData); if((cData & BOOT_PROM_DISABLE) == 0) { - TRACE_PRINT(CMD_MSG, - ("DISK1A: " ADDRESS_FORMAT " Boot ROM disabled" NLP, PCX)) + sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " Boot ROM disabled\n", PCX); /* Unmap Boot ROM */ disk1a_info->rom_disabled = TRUE; } - TRACE_PRINT(CMD_MSG, ("DISK1A: " ADDRESS_FORMAT " Motors = %x" NLP, - PCX, (cData & FLOPPY_MOTORS) >> 4)) + sim_debug(CMD_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT + " Motors = %x\n", PCX, (cData & FLOPPY_MOTORS) >> 4); break; } @@ -890,7 +883,7 @@ static uint8 DISK1A_Write(const uint32 Addr, uint8 cData) void raise_disk1a_interrupt(void) { - TRACE_PRINT(IRQ_MSG, ("DISK1A: " ADDRESS_FORMAT " Interrupt" NLP, PCX)); + sim_debug(IRQ_MSG, &disk1a_dev, "DISK1A: " ADDRESS_FORMAT " Interrupt\n", PCX); raise_ss1_interrupt(SS1_VI4_INT); diff --git a/AltairZ80/s100_disk2.c b/AltairZ80/s100_disk2.c index 1af9a918..597294df 100644 --- a/AltairZ80/s100_disk2.c +++ b/AltairZ80/s100_disk2.c @@ -174,10 +174,6 @@ static MTAB disk2_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(disk2_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB disk2_dt[] = { { "ERROR", ERROR_MSG }, @@ -313,7 +309,7 @@ t_stat disk2_detach(UNIT *uptr) static int32 disk2dev(const int32 port, const int32 io, const int32 data) { -/* TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); */ +/* sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT " IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port); */ if(io) { DISK2_Write(port, data); return 0; @@ -343,7 +339,8 @@ static uint8 DISK2_Read(const uint32 Addr) cData |= (disk2_info->seek_complete == 0) ? 0x04 : 0x00; cData |= (disk2_info->write_fault) << 1; cData |= ((pDrive->track != 0) || (disk2_info->seek_complete == 0)) ? 0x01 : 0x00; - TRACE_PRINT(STATUS_MSG, ("DISK2: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " RD STATUS = 0x%02x\n", PCX, cData); disk2_info->seek_complete = 1; break; @@ -357,8 +354,9 @@ static uint8 DISK2_Read(const uint32 Addr) pDrive->track --; } } - TRACE_PRINT(SEEK_MSG, ("DISK2: " ADDRESS_FORMAT " Step %s, Track=%d" NLP, - PCX, disk2_info->ctl_op & 0x04 ? "IN" : "OUT", pDrive->track)); + sim_debug(SEEK_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Step %s, Track=%d\n", PCX, + disk2_info->ctl_op & 0x04 ? "IN" : "OUT", pDrive->track); disk2_info->seek_complete = 0; cData = 0xFF; /* Return High-Z data */ break; @@ -399,13 +397,11 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) disk2_info->timeout = 0; } disk2_info->ctl_us = (cData & 0x03); - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " ATTN*=%d, RUN=%d, OP=%d, FAULT_CLR=%d, US=%d" NLP, - PCX, - disk2_info->ctl_attn, - disk2_info->ctl_run, - disk2_info->ctl_op, - disk2_info->ctl_fault_clr, - disk2_info->ctl_us)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " ATTN*=%d, RUN=%d, OP=%d, FAULT_CLR=%d, US=%d\n", + PCX, disk2_info->ctl_attn, disk2_info->ctl_run, + disk2_info->ctl_op, disk2_info->ctl_fault_clr, + disk2_info->ctl_us); /* FIXME: seek_complete = 1 is needed by CP/M, but why? Also, maybe related, * there appears to be a bug in the seeking logic. For some reason, the @@ -428,21 +424,20 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) switch(disk2_info->ctl_op) { case DISK2_CMD_NULL: - TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " NULL Command" NLP, PCX)); + sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " NULL Command\n", PCX); break; case DISK2_CMD_READ_DATA: - TRACE_PRINT(RD_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: (C:%d/H:%d/S:%d)" NLP, - PCX, - disk2_info->cyl, - disk2_info->head, - disk2_info->sector)); + sim_debug(RD_DATA_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_DATA: (C:%d/H:%d/S:%d)\n", PCX, disk2_info->cyl, disk2_info->head, disk2_info->sector); if(disk2_info->head_sel != disk2_info->head) { - printf("DISK2: " ADDRESS_FORMAT " READ_DATA: head_sel != head" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " READ_DATA: head_sel != head" NLP, PCX); } /* See FIXME above... that might be why this does not work properly... */ if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */ - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: cyl=%d, track=%d" NLP, - PCX, disk2_info->cyl, pDrive->track)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_DATA: cyl=%d, track=%d\n", PCX, disk2_info->cyl, pDrive->track); pDrive->track = disk2_info->cyl; /* update track */ } sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); @@ -450,15 +445,18 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) /* Read sector */ rtn = sim_fread(sdata.raw, 1, (pDrive->sectsize + 3), (pDrive->uptr)->fileref); if (rtn != (size_t)(pDrive->sectsize + 3)) { - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_DATA: sim_fread error.\n", PCX); } if(sdata.u.header[2] == disk2_info->sector) { if(sdata.u.header[0] != disk2_info->cyl) { /*pDrive->track) { */ - printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: track" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " READ_DATA Incorrect header: track" NLP, PCX); disk2_info->timeout = 1; } if(sdata.u.header[1] != disk2_info->head) { - printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: head" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " READ_DATA Incorrect header: head" NLP, PCX); disk2_info->timeout = 1; } @@ -466,24 +464,22 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) break; } if(i == pDrive->nsectors) { - printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " Sector not found" NLP, PCX); disk2_info->timeout = 1; } } break; case DISK2_CMD_WRITE_DATA: - TRACE_PRINT(WR_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: (C:%d/H:%d/S:%d)" NLP, - PCX, - disk2_info->cyl, - disk2_info->head, - disk2_info->sector)); + sim_debug(WR_DATA_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_DATA: (C:%d/H:%d/S:%d)\n", PCX, disk2_info->cyl, disk2_info->head, disk2_info->sector); if(disk2_info->head_sel != disk2_info->head) { printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA: head_sel != head" NLP, PCX); } if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */ - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA = 0x%02x, cyl=%d, track=%d" NLP, - PCX, cData, disk2_info->cyl, pDrive->track)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_DATA = 0x%02x, cyl=%d, track=%d\n", PCX, cData, disk2_info->cyl, pDrive->track); pDrive->track = disk2_info->cyl; /* update track */ } @@ -493,15 +489,18 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) file_offset = ftell((pDrive->uptr)->fileref); rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref); if (rtn != 3) { - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_DATA: sim_fread error.\n", PCX); } if(sdata.u.header[2] == disk2_info->sector) { if(sdata.u.header[0] != disk2_info->cyl) { - printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: track" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " WRITE_DATA Incorrect header: track" NLP, PCX); disk2_info->timeout = 1; } if(sdata.u.header[1] != disk2_info->head) { - printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: head" NLP, PCX); + printf("DISK2: " ADDRESS_FORMAT + " WRITE_DATA Incorrect header: head" NLP, PCX); disk2_info->timeout = 1; } @@ -512,7 +511,8 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) } rtn = sim_fread(sdata.raw, 1, pDrive->sectsize, (pDrive->uptr)->fileref); if (rtn != (size_t)(pDrive->sectsize)) { - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_DATA: sim_fread error.\n", PCX); } if(i == pDrive->nsectors) { printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX); @@ -522,12 +522,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) break; case DISK2_CMD_WRITE_HEADER: track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3); - TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_HEADER Command: track=%d (%d), Head=%d, Sector=%d" NLP, - PCX, - pDrive->track, - disk2_info->cyl, - disk2_info->head_sel, - disk2_info->hdr_sector)); + sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " WRITE_HEADER Command: track=%d (%d), Head=%d, Sector=%d\n", + PCX, pDrive->track, disk2_info->cyl, + disk2_info->head_sel, disk2_info->hdr_sector); i = disk2_info->hdr_sector; selchan_dma(sdata.raw, 3); @@ -542,11 +540,13 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) break; case DISK2_CMD_READ_HEADER: track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3); - TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER Command" NLP, PCX)); + sim_debug(CMD_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_HEADER Command\n", PCX); sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref); if (rtn != 3) { - TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " READ_HEADER: sim_fread error.\n", PCX); } selchan_dma(sdata.raw, 3); @@ -578,33 +578,36 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) disk2_info->sel_drive = 3; break; default: - printf("DISK2: " ADDRESS_FORMAT " Error, invalid drive select=0x%x" NLP, PCX, cData >> 4); + printf("DISK2: " ADDRESS_FORMAT + " Error, invalid drive select=0x%x" NLP, PCX, cData >> 4); break; } disk2_info->head_sel = cData & 0x0F; - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [DRIVE]=%d, Head=%d" NLP, - PCX, disk2_info->sel_drive, disk2_info->head)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write DATA [DRIVE]=%d, Head=%d\n", + PCX, disk2_info->sel_drive, disk2_info->head); break; case DISK2_OP_CYL: disk2_info->cyl = cData; - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [CYL] = %02x" NLP, - PCX, cData)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write DATA [CYL] = %02x\n", PCX, cData); break; case DISK2_OP_HEAD: disk2_info->head = cData; - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [HEAD] = %02x" NLP, - PCX, cData)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write DATA [HEAD] = %02x\n", PCX, cData); break; case DISK2_OP_SECTOR: disk2_info->sector = cData; - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register [SECTOR] = %02x" NLP, - PCX, cData)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write Register [SECTOR] = %02x\n", PCX, cData); break; default: - TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register unknown op [%d] = %02x" NLP, - PCX, disk2_info->ctl_op, cData)); + sim_debug(VERBOSE_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Write Register unknown op [%d] = %02x\n", + PCX, disk2_info->ctl_op, cData); break; } } @@ -616,7 +619,8 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) static void raise_disk2_interrupt(void) { - TRACE_PRINT(IRQ_MSG, ("DISK2: " ADDRESS_FORMAT " Interrupt" NLP, PCX)); + sim_debug(IRQ_MSG, &disk2_dev, "DISK2: " ADDRESS_FORMAT + " Interrupt\n", PCX); raise_ss1_interrupt(SS1_VI1_INT); diff --git a/AltairZ80/s100_disk3.c b/AltairZ80/s100_disk3.c index 9d578a83..6cb00874 100644 --- a/AltairZ80/s100_disk3.c +++ b/AltairZ80/s100_disk3.c @@ -237,10 +237,6 @@ static MTAB disk3_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(disk3_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB disk3_dt[] = { { "ERROR", ERROR_MSG }, @@ -384,7 +380,8 @@ t_stat disk3_detach(UNIT *uptr) static int32 disk3dev(const int32 port, const int32 io, const int32 data) { - TRACE_PRINT(VERBOSE_MSG, ("DISK3: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); + sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3: " ADDRESS_FORMAT + " IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port); if(io) { DISK3_Write(port, data); return 0; @@ -417,13 +414,13 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) next_link |= disk3_info->iopb[DISK3_IOPB_LINK+1] << 8; next_link |= disk3_info->iopb[DISK3_IOPB_LINK+2] << 16; - TRACE_PRINT(VERBOSE_MSG, ("DISK3[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, %s DMA@0x%05x\n", - disk3_info->sel_drive, - disk3_info->link_addr, - next_link, - disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_CMD_MASK, - (disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_REQUEST_IRQ) ? "IRQ" : "POLL", - disk3_info->dma_addr)); + sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, %s DMA@0x%05x\n", + disk3_info->sel_drive, + disk3_info->link_addr, + next_link, + disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_CMD_MASK, + (disk3_info->iopb[DISK3_IOPB_CMD] & DISK3_REQUEST_IRQ) ? "IRQ" : "POLL", + disk3_info->dma_addr); pDrive = &disk3_info->drive[disk3_info->sel_drive]; @@ -432,30 +429,33 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) /* Perform command */ switch(cmd & DISK3_CMD_MASK) { case DISK3_CODE_NOOP: - TRACE_PRINT(VERBOSE_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " NOOP" NLP, disk3_info->sel_drive, PCX)); + sim_debug(VERBOSE_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " NOOP\n", disk3_info->sel_drive, PCX); break; case DISK3_CODE_VERSION: break; case DISK3_CODE_GLOBAL: - TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " GLOBAL" NLP, disk3_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " GLOBAL\n", disk3_info->sel_drive, PCX); disk3_info->mode = disk3_info->iopb[DISK3_IOPB_ARG1]; disk3_info->retries = disk3_info->iopb[DISK3_IOPB_ARG2]; disk3_info->ndrives = disk3_info->iopb[DISK3_IOPB_ARG3]; - TRACE_PRINT(SPECIFY_MSG, (" Mode: 0x%02x" NLP, disk3_info->mode)); - TRACE_PRINT(SPECIFY_MSG, (" # Retries: 0x%02x" NLP, disk3_info->retries)); - TRACE_PRINT(SPECIFY_MSG, (" # Drives: 0x%02x" NLP, disk3_info->ndrives)); + sim_debug(SPECIFY_MSG, &disk3_dev, " Mode: 0x%02x\n", disk3_info->mode); + sim_debug(SPECIFY_MSG, &disk3_dev, " # Retries: 0x%02x\n", disk3_info->retries); + sim_debug(SPECIFY_MSG, &disk3_dev, " # Drives: 0x%02x\n", disk3_info->ndrives); if(disk3_info->mode == DISK3_MODE_ABS) { - TRACE_PRINT(ERROR_MSG, ("DISK3: Absolute addressing not supported." NLP)); + sim_debug(ERROR_MSG, &disk3_dev, "DISK3: Absolute addressing not supported.\n"); } break; case DISK3_CODE_SPECIFY: { uint8 specify_data[22]; - TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SPECIFY" NLP, disk3_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " SPECIFY\n", disk3_info->sel_drive, PCX); for(i = 0; i < 22; i++) { specify_data[i] = GetByteDMA(disk3_info->dma_addr + i); @@ -467,32 +467,36 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) pDrive->ntracks = specify_data[10] | (specify_data[11] << 8); pDrive->res_tracks = specify_data[18] | (specify_data[19] << 8); - TRACE_PRINT(SPECIFY_MSG, (" Sectsize: %d" NLP, pDrive->sectsize)); - TRACE_PRINT(SPECIFY_MSG, (" Sectors: %d" NLP, pDrive->nsectors)); - TRACE_PRINT(SPECIFY_MSG, (" Heads: %d" NLP, pDrive->nheads)); - TRACE_PRINT(SPECIFY_MSG, (" Tracks: %d" NLP, pDrive->ntracks)); - TRACE_PRINT(SPECIFY_MSG, (" Reserved: %d" NLP, pDrive->res_tracks)); + sim_debug(SPECIFY_MSG, &disk3_dev, " Sectsize: %d\n", pDrive->sectsize); + sim_debug(SPECIFY_MSG, &disk3_dev, " Sectors: %d\n", pDrive->nsectors); + sim_debug(SPECIFY_MSG, &disk3_dev, " Heads: %d\n", pDrive->nheads); + sim_debug(SPECIFY_MSG, &disk3_dev, " Tracks: %d\n", pDrive->ntracks); + sim_debug(SPECIFY_MSG, &disk3_dev, " Reserved: %d\n", pDrive->res_tracks); break; } case DISK3_CODE_HOME: pDrive->track = 0; - TRACE_PRINT(SEEK_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " HOME" NLP, disk3_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " HOME\n", disk3_info->sel_drive, PCX); break; case DISK3_CODE_SEEK: pDrive->track = disk3_info->iopb[DISK3_IOPB_ARG1]; pDrive->track |= (disk3_info->iopb[DISK3_IOPB_ARG2] << 8); if(pDrive->track > pDrive->ntracks) { - TRACE_PRINT(ERROR_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found" NLP, disk3_info->sel_drive, PCX, pDrive->track)); + sim_debug(ERROR_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " SEEK ERROR %d not found\n", disk3_info->sel_drive, PCX, pDrive->track); pDrive->track = pDrive->ntracks - 1; result = DISK3_STATUS_TIMEOUT; } else { - TRACE_PRINT(SEEK_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " SEEK %d" NLP, disk3_info->sel_drive, PCX, pDrive->track)); + sim_debug(SEEK_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " SEEK %d\n", disk3_info->sel_drive, PCX, pDrive->track); } break; case DISK3_CODE_READ_HDR: { - TRACE_PRINT(CMD_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " READ HEADER: %d" NLP, pDrive->track, PCX, pDrive->track >> 8)); + sim_debug(CMD_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " READ HEADER: %d\n", pDrive->track, PCX, pDrive->track >> 8); PutByteDMA(disk3_info->dma_addr + 0, pDrive->track & 0xFF); PutByteDMA(disk3_info->dma_addr + 1, (pDrive->track >> 8) & 0xFF); PutByteDMA(disk3_info->dma_addr + 2, 0); @@ -510,7 +514,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) size_t rtn; if(disk3_info->mode == DISK3_MODE_ABS) { - TRACE_PRINT(ERROR_MSG, ("DISK3: Absolute addressing not supported." NLP)); + sim_debug(ERROR_MSG, &disk3_dev, "DISK3: Absolute addressing not supported.\n"); break; } @@ -532,16 +536,15 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) if(disk3_info->iopb[DISK3_IOPB_ARG1] == 1) { /* Read */ rtn = sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); - TRACE_PRINT(RD_DATA_MSG, - ("DISK3[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d %s" NLP, - disk3_info->sel_drive, - PCX, - disk3_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects, - rtn == (size_t)xfr_len ? "OK" : "NOK" - )); + sim_debug(RD_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " READ @0x%05x T:%04d/S:%04d/#:%d %s\n", + disk3_info->sel_drive, + PCX, + disk3_info->dma_addr, + pDrive->cur_track, + pDrive->cur_sect, + pDrive->xfr_nsects, + rtn == (size_t)xfr_len ? "OK" : "NOK" ); /* Perform DMA Transfer */ @@ -549,14 +552,8 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) PutByteDMA(disk3_info->dma_addr + xfr_count, dataBuffer[xfr_count]); } } else { /* Write */ - TRACE_PRINT(WR_DATA_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d" NLP, - disk3_info->sel_drive, - PCX, - disk3_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects - )); + sim_debug(WR_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " WRITE @0x%05x T:%04d/S:%04d/#:%d\n", disk3_info->sel_drive, PCX, disk3_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects ); /* Perform DMA Transfer */ for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) { @@ -596,14 +593,14 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) data_len = pDrive->nsectors * pDrive->sectsize; - TRACE_PRINT(WR_DATA_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d" NLP, - disk3_info->sel_drive, - PCX, - pDrive->track, - disk3_info->iopb[DISK3_IOPB_ARG3], - disk3_info->iopb[DISK3_IOPB_ARG2], - data_len - )); + sim_debug(WR_DATA_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d\n", + disk3_info->sel_drive, + PCX, + pDrive->track, + disk3_info->iopb[DISK3_IOPB_ARG3], + disk3_info->iopb[DISK3_IOPB_ARG2], + data_len); file_offset = (pDrive->track * (pDrive->nheads) * data_len); /* Calculate offset based on current track */ file_offset += (disk3_info->iopb[DISK3_IOPB_ARG3] * data_len); @@ -627,7 +624,11 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) case DISK3_CODE_EXAMINE: case DISK3_CODE_MODIFY: default: - TRACE_PRINT(ERROR_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported" NLP, disk3_info->sel_drive, PCX, cmd & DISK3_CMD_MASK)); + sim_debug(ERROR_MSG, &disk3_dev, "DISK3[%d]: " ADDRESS_FORMAT + " CMD=%x Unsupported\n", + disk3_info->sel_drive, + PCX, + cmd & DISK3_CMD_MASK); break; } } else { /* Drive not ready */ @@ -654,7 +655,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) static void raise_disk3_interrupt(void) { - TRACE_PRINT(IRQ_MSG, ("DISK3: " ADDRESS_FORMAT " Interrupt" NLP, PCX)); + sim_debug(IRQ_MSG, &disk3_dev, "DISK3: " ADDRESS_FORMAT " Interrupt\n", PCX); raise_ss1_interrupt(SS1_VI1_INT); diff --git a/AltairZ80/s100_fif.c b/AltairZ80/s100_fif.c index 913de8e0..ca5481c4 100644 --- a/AltairZ80/s100_fif.c +++ b/AltairZ80/s100_fif.c @@ -2,7 +2,7 @@ IMSAI FIF Disk Controller by Ernie Price - Based on altairz80_dsk.c, Copyright (c) 2002-2010, Peter Schorn + Based on altairz80_dsk.c, Copyright (c) 2002-2011, Peter Schorn Plug-n-Play added by Howard M. Harte diff --git a/AltairZ80/s100_hdc1001.c b/AltairZ80/s100_hdc1001.c index a5afa7fb..d23db1da 100644 --- a/AltairZ80/s100_hdc1001.c +++ b/AltairZ80/s100_hdc1001.c @@ -144,10 +144,6 @@ static MTAB hdc1001_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(hdc1001_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB hdc1001_dt[] = { { "ERROR", ERROR_MSG }, @@ -289,7 +285,7 @@ t_stat hdc1001_detach(UNIT *uptr) static int32 hdc1001dev(const int32 port, const int32 io, const int32 data) { -/* TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); */ +/* sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT " IO %s, Port %02x\n", PCX, io ? "WR" : "RD", port); */ if(io) { HDC1001_Write(port, data); return 0; @@ -369,19 +365,18 @@ static uint8 HDC1001_Write(const uint32 Addr, uint8 cData) case TF_CYLLO: case TF_CYLHI: hdc1001_info->taskfile[Addr & 0x07] = cData; - TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " WR TF[%d]=0x%02x" NLP, PCX, Addr & 7, cData)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT + " WR TF[%d]=0x%02x\n", PCX, Addr & 7, cData); break; case TF_CMD: pDrive->track = hdc1001_info->taskfile[TF_CYLLO] | (hdc1001_info->taskfile[TF_CYLHI] << 8); pDrive->xfr_nsects = hdc1001_info->taskfile[TF_SECNT]; - TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: Command=%d, T:%d/H:%d/S:%d N=%d" NLP, - hdc1001_info->sel_drive, - hdc1001_info->taskfile[TF_CMD], - pDrive->track, - hdc1001_info->taskfile[TF_SDH] & 0x07, - hdc1001_info->taskfile[TF_SECNO], - pDrive->xfr_nsects)); + sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: Command=%d, T:%d/H:%d/S:%d N=%d\n", + hdc1001_info->sel_drive, + hdc1001_info->taskfile[TF_CMD], + pDrive->track, hdc1001_info->taskfile[TF_SDH] & 0x07, + hdc1001_info->taskfile[TF_SECNO], pDrive->xfr_nsects); break; default: break; @@ -394,7 +389,8 @@ static uint8 HDC1001_Read(const uint32 Addr) uint8 cData; cData = hdc1001_info->taskfile[Addr & 0x07]; - TRACE_PRINT(VERBOSE_MSG, ("HDC1001: " ADDRESS_FORMAT " RD TF[%d]=0x%02x" NLP, PCX, Addr & 7, cData)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001: " ADDRESS_FORMAT + " RD TF[%d]=0x%02x\n", PCX, Addr & 7, cData); return (cData); } @@ -415,12 +411,7 @@ static uint8 HDC1001_Read(const uint32 Addr) next_link |= hdc1001_info->iopb[0x0E] << 8; next_link |= hdc1001_info->iopb[0x0F] << 16; - TRACE_PRINT(VERBOSE_MSG, ("HDC1001[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, DMA@0x%05x\n", - hdc1001_info->sel_drive, - hdc1001_info->link_addr, - next_link, - hdc1001_info->iopb[0], - hdc1001_info->dma_addr)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001[%d]: LINK=0x%05x, NEXT=0x%05x, CMD=%x, DMA@0x%05x\n", hdc1001_info->sel_drive, hdc1001_info->link_addr, next_link, hdc1001_info->iopb[0], hdc1001_info->dma_addr); @@ -429,26 +420,26 @@ static uint8 HDC1001_Read(const uint32 Addr) /* Perform command */ switch(cmd) { case HDC1001_CODE_NOOP: - TRACE_PRINT(VERBOSE_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " NOOP" NLP, hdc1001_info->sel_drive, PCX)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " NOOP\n", hdc1001_info->sel_drive, PCX); break; case HDC1001_CODE_VERSION: break; case HDC1001_CODE_GLOBAL: - TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " GLOBAL" NLP, hdc1001_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " GLOBAL\n", hdc1001_info->sel_drive, PCX); hdc1001_info->mode = hdc1001_info->iopb[3]; hdc1001_info->retries = hdc1001_info->iopb[4]; hdc1001_info->ndrives = hdc1001_info->iopb[5]; - TRACE_PRINT(VERBOSE_MSG, (" Mode: 0x%02x" NLP, hdc1001_info->mode)); - TRACE_PRINT(VERBOSE_MSG, (" # Retries: 0x%02x" NLP, hdc1001_info->retries)); - TRACE_PRINT(VERBOSE_MSG, (" # Drives: 0x%02x" NLP, hdc1001_info->ndrives)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Mode: 0x%02x\n", hdc1001_info->mode); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " # Retries: 0x%02x\n", hdc1001_info->retries); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " # Drives: 0x%02x\n", hdc1001_info->ndrives); break; case HDC1001_CODE_SPECIFY: { uint8 specify_data[22]; - TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SPECIFY" NLP, hdc1001_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SPECIFY\n", hdc1001_info->sel_drive, PCX); for(i = 0; i < 22; i++) { specify_data[i] = GetBYTEWrapper(hdc1001_info->dma_addr + i); @@ -460,32 +451,32 @@ static uint8 HDC1001_Read(const uint32 Addr) pDrive->ntracks = specify_data[10] | (specify_data[11] << 8); pDrive->res_tracks = specify_data[18] | (specify_data[19] << 8); - TRACE_PRINT(VERBOSE_MSG, (" Sectsize: %d" NLP, pDrive->sectsize)); - TRACE_PRINT(VERBOSE_MSG, (" Sectors: %d" NLP, pDrive->nsectors)); - TRACE_PRINT(VERBOSE_MSG, (" Heads: %d" NLP, pDrive->nheads)); - TRACE_PRINT(VERBOSE_MSG, (" Tracks: %d" NLP, pDrive->ntracks)); - TRACE_PRINT(VERBOSE_MSG, (" Reserved: %d" NLP, pDrive->res_tracks)); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Sectsize: %d\n", pDrive->sectsize); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Sectors: %d\n", pDrive->nsectors); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Heads: %d\n", pDrive->nheads); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Tracks: %d\n", pDrive->ntracks); + sim_debug(VERBOSE_MSG, &hdc1001_dev, " Reserved: %d\n", pDrive->res_tracks); break; } case HDC1001_CODE_HOME: pDrive->track = 0; - TRACE_PRINT(SEEK_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " HOME" NLP, hdc1001_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " HOME\n", hdc1001_info->sel_drive, PCX); break; case HDC1001_CODE_SEEK: pDrive->track = hdc1001_info->iopb[3]; pDrive->track |= (hdc1001_info->iopb[4] << 8); if(pDrive->track > pDrive->ntracks) { - TRACE_PRINT(ERROR_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found" NLP, hdc1001_info->sel_drive, PCX, pDrive->track)); + sim_debug(ERROR_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SEEK ERROR %d not found\n", hdc1001_info->sel_drive, PCX, pDrive->track); pDrive->track = pDrive->ntracks - 1; result = HDC1001_STATUS_TIMEOUT; } else { - TRACE_PRINT(SEEK_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " SEEK %d" NLP, hdc1001_info->sel_drive, PCX, pDrive->track)); + sim_debug(SEEK_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " SEEK %d\n", hdc1001_info->sel_drive, PCX, pDrive->track); } break; case HDC1001_CODE_READ_HDR: { - TRACE_PRINT(CMD_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " READ HEADER: %d" NLP, pDrive->track, PCX)); + sim_debug(CMD_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " READ HEADER: %d\n", pDrive->track, PCX); PutBYTEWrapper(hdc1001_info->dma_addr + 0, pDrive->track & 0xFF); PutBYTEWrapper(hdc1001_info->dma_addr + 1, (pDrive->track >> 8) & 0xFF); PutBYTEWrapper(hdc1001_info->dma_addr + 2, 0); @@ -517,14 +508,7 @@ static uint8 HDC1001_Read(const uint32 Addr) sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET); if(hdc1001_info->iopb[3] == 1) { /* Read */ - TRACE_PRINT(RD_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d" NLP, - hdc1001_info->sel_drive, - PCX, - hdc1001_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects - )); + sim_debug(RD_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d\n", hdc1001_info->sel_drive, PCX, hdc1001_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects ); sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); @@ -533,14 +517,7 @@ static uint8 HDC1001_Read(const uint32 Addr) PutBYTEWrapper(hdc1001_info->dma_addr + xfr_count, dataBuffer[xfr_count]); } } else { /* Write */ - TRACE_PRINT(WR_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d" NLP, - hdc1001_info->sel_drive, - PCX, - hdc1001_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects - )); + sim_debug(WR_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " WRITE @0x%05x T:%04d/S:%04d/#:%d\n", hdc1001_info->sel_drive, PCX, hdc1001_info->dma_addr, pDrive->cur_track, pDrive->cur_sect, pDrive->xfr_nsects ); /* Perform DMA Transfer */ for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) { @@ -562,14 +539,7 @@ static uint8 HDC1001_Read(const uint32 Addr) data_len = pDrive->nsectors * pDrive->sectsize; - TRACE_PRINT(WR_DATA_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d" NLP, - hdc1001_info->sel_drive, - PCX, - pDrive->track, - hdc1001_info->iopb[5], - hdc1001_info->iopb[4], - data_len - )); + sim_debug(WR_DATA_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/Fill=0x%02x/Len=%d\n", hdc1001_info->sel_drive, PCX, pDrive->track, hdc1001_info->iopb[5], hdc1001_info->iopb[4], data_len ); file_offset = (pDrive->track * (pDrive->nheads) * data_len); /* Calculate offset based on current track */ file_offset += (hdc1001_info->iopb[5] * data_len); @@ -592,7 +562,7 @@ static uint8 HDC1001_Read(const uint32 Addr) case HDC1001_CODE_EXAMINE: case HDC1001_CODE_MODIFY: default: - TRACE_PRINT(ERROR_MSG, ("HDC1001[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported" NLP, hdc1001_info->sel_drive, PCX, cmd)); + sim_debug(ERROR_MSG, &hdc1001_dev, "HDC1001[%d]: " ADDRESS_FORMAT " CMD=%x Unsupported\n", hdc1001_info->sel_drive, PCX, cmd); break; } } else { /* Drive not ready */ diff --git a/AltairZ80/s100_if3.c b/AltairZ80/s100_if3.c index 3ca1f9e6..8c844512 100644 --- a/AltairZ80/s100_if3.c +++ b/AltairZ80/s100_if3.c @@ -126,10 +126,6 @@ static MTAB if3_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(if3_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB if3_dt[] = { { "ERROR", ERROR_MSG }, @@ -153,15 +149,15 @@ DEVICE if3_dev = { static t_stat set_if3_connect(UNIT *uptr, int32 val, char *cptr, void *desc) { if(uptr->flags & UNIT_DISABLE) { - TRACE_PRINT(ERROR_MSG, ("IF3[%d]: not enabled." NLP, uptr->u3)); + sim_debug(ERROR_MSG, &if3_dev, "IF3[%d]: not enabled.\n", uptr->u3); return SCPE_OK; } if(val & UNIT_IF3_CONNECT) { - TRACE_PRINT((RXIRQ_MSG|TXIRQ_MSG), ("IF3[%d]: IRQ polling started..." NLP, uptr->u3)); + sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling started...\n", uptr->u3); sim_activate(uptr, 100000); } else { - TRACE_PRINT((RXIRQ_MSG|TXIRQ_MSG), ("IF3[%d]: IRQ polling stopped." NLP, uptr->u3)); + sim_debug((RXIRQ_MSG|TXIRQ_MSG), &if3_dev, "IF3[%d]: IRQ polling stopped.\n", uptr->u3); sim_cancel(uptr); } return (SCPE_OK); @@ -189,7 +185,7 @@ static t_stat if3_reset(DEVICE *dptr) for(i=0;i> 3; /* guarantees that if3_board < IF3_MAX_BOARDS */ if3_user = cData & 0x7; - TRACE_PRINT(USER_MSG, ("IF3[%d]: " ADDRESS_FORMAT " WR UART_SEL=0x%02x (Board=%d, Rel_User=%d, User=%d)" NLP, - if3_board, PCX, cData, if3_board, if3_user, cData)); + sim_debug(USER_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " WR UART_SEL=0x%02x (Board=%d, Rel_User=%d, User=%d)\n", if3_board, PCX, cData, if3_board, if3_user, cData); break; } @@ -334,13 +324,13 @@ static t_stat if3_svc (UNIT *uptr) pending_rx_irqs = if3_risr[board] & if3_rimr[board]; if(pending_rx_irqs) { - TRACE_PRINT(RXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " Rx IRQ Pending: 0x%02x" NLP, board, PCX, pending_rx_irqs)); + sim_debug(RXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Rx IRQ Pending: 0x%02x\n", board, PCX, pending_rx_irqs); raise_ss1_interrupt(SS1_VI2_INT); } pending_tx_irqs = if3_tisr[board] & if3_timr[board]; if(pending_tx_irqs) { - TRACE_PRINT(TXIRQ_MSG, ("IF3[%d]: " ADDRESS_FORMAT " Tx IRQ Pending: 0x%02x" NLP, board, PCX, pending_tx_irqs)); + sim_debug(TXIRQ_MSG, &if3_dev, "IF3[%d]: " ADDRESS_FORMAT " Tx IRQ Pending: 0x%02x\n", board, PCX, pending_tx_irqs); raise_ss1_interrupt(SS1_VI3_INT); } diff --git a/AltairZ80/s100_mdriveh.c b/AltairZ80/s100_mdriveh.c index eaa8791a..ca20262b 100644 --- a/AltairZ80/s100_mdriveh.c +++ b/AltairZ80/s100_mdriveh.c @@ -118,10 +118,6 @@ static MTAB mdriveh_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(mdriveh_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB mdriveh_dt[] = { { "ERROR", ERROR_MSG }, @@ -207,8 +203,7 @@ static uint8 MDRIVEH_Read(const uint32 Addr) switch(Addr & 0x1) { case MDRIVEH_ADDR: - TRACE_PRINT(VERBOSE_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Addr = 0x%02x" NLP, - PCX, cData)); + sim_debug(VERBOSE_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " RD Addr = 0x%02x\n", PCX, cData); break; case MDRIVEH_DATA: unit = (mdriveh_info->dma_addr & 0x380000) >> 19; @@ -218,8 +213,7 @@ static uint8 MDRIVEH_Read(const uint32 Addr) cData = mdriveh_info->storage[unit][offset]; } - TRACE_PRINT(RD_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Data [%x:%05x] = 0x%02x" NLP, - PCX, unit, offset, cData)); + sim_debug(RD_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " RD Data [%x:%05x] = 0x%02x\n", PCX, unit, offset, cData); /* Increment M-DRIVE/H Data Address */ mdriveh_info->dma_addr++; @@ -241,8 +235,7 @@ static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData) mdriveh_info->dma_addr <<= 8; mdriveh_info->dma_addr &= 0x003FFF00; mdriveh_info->dma_addr |= cData; - TRACE_PRINT(SEEK_MSG, ("MDRIVEH: " ADDRESS_FORMAT " DMA Address=%06x" NLP, - PCX, mdriveh_info->dma_addr)); + sim_debug(SEEK_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " DMA Address=%06x\n", PCX, mdriveh_info->dma_addr); break; case MDRIVEH_DATA: unit = (mdriveh_info->dma_addr & 0x380000) >> 19; @@ -250,16 +243,13 @@ static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData) if(mdriveh_info->storage[unit] != NULL) { if(mdriveh_info->uptr[unit].flags & UNIT_MDRIVEH_WLK) { - TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit Write Locked" NLP, - PCX, unit, offset)); + sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit Write Locked\n", PCX, unit, offset); } else { - TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = 0x%02x" NLP, - PCX, unit, offset, cData)); + sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = 0x%02x\n", PCX, unit, offset, cData); mdriveh_info->storage[unit][offset] = cData; } } else { - TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit OFFLINE" NLP, - PCX, unit, offset)); + sim_debug(WR_DATA_MSG, &mdriveh_dev, "MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit OFFLINE\n", PCX, unit, offset); } /* Increment M-DRIVE/H Data Address */ diff --git a/AltairZ80/s100_mdsad.c b/AltairZ80/s100_mdsad.c index 639df98c..fe3c5d65 100644 --- a/AltairZ80/s100_mdsad.c +++ b/AltairZ80/s100_mdsad.c @@ -243,10 +243,6 @@ static MTAB mdsad_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(mdsad_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB mdsad_dt[] = { { "ERROR", ERROR_MSG }, @@ -462,13 +458,10 @@ static uint8 MDSAD_Read(const uint32 Addr) case MDSAD_WRITE_DATA: { if(mdsad_info->datacount == 0) { - TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP, - PCX, - mdsad_info->orders.ds, - pDrive->track, - mdsad_info->orders.ss, - pDrive->sector)); + sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n", + PCX, mdsad_info->orders.ds, pDrive->track, + mdsad_info->orders.ss, pDrive->sector); sec_offset = calculate_mdsad_sec_offset(pDrive->track, mdsad_info->orders.ss, @@ -484,13 +477,12 @@ static uint8 MDSAD_Read(const uint32 Addr) sdata.raw[mdsad_info->datacount] = Addr & 0xFF; if(mdsad_info->datacount == (MDSAD_RAW_LEN - 1)) { - TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " Write Complete" NLP, PCX)); + sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Write Complete\n", PCX); if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) { - TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " Drive: %d not attached - write ignored." NLP, - PCX, mdsad_info->orders.ds)); + sim_debug(WR_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Drive: %d not attached - write ignored.\n", PCX, mdsad_info->orders.ds); return 0x00; } if(mdsad_dev.dctrl & WR_DATA_DETAIL_MSG) @@ -541,34 +533,29 @@ static uint8 MDSAD_Read(const uint32 Addr) } if(mdsad_info->orders.ds != (mdsad_info->orders.ds & 0x03)) { - TRACE_PRINT(ERROR_MSG, ("MDSAD: " ADDRESS_FORMAT - " Controller Orders update drive %x" NLP, PCX, mdsad_info->orders.ds)); + sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Controller Orders update drive %x\n", PCX, mdsad_info->orders.ds); mdsad_info->orders.ds &= 0x03; } - TRACE_PRINT(ORDERS_MSG, ("MDSAD: " ADDRESS_FORMAT - " Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d" NLP, - PCX, - mdsad_info->orders.ds, ds, - mdsad_info->orders.dd, - mdsad_info->orders.ss, - mdsad_info->orders.dp, - mdsad_info->orders.st)); + sim_debug(ORDERS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d\n", + PCX, mdsad_info->orders.ds, ds, mdsad_info->orders.dd, + mdsad_info->orders.ss, mdsad_info->orders.dp, mdsad_info->orders.st); /* use latest selected drive */ pDrive = &mdsad_info->drive[mdsad_info->orders.ds]; if(mdsad_info->orders.st == 1) { if(mdsad_info->orders.dp == 0) { - TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT - " Step out: Track=%d%s" NLP, PCX, pDrive->track, - pDrive->track == 0 ? "[Warn: already at 0]" : "")); + sim_debug(SEEK_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Step out: Track=%d%s\n", PCX, pDrive->track, + pDrive->track == 0 ? "[Warn: already at 0]" : ""); if(pDrive->track > 0) /* anything to do? */ pDrive->track--; } else { - TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT - " Step in: Track=%d%s" NLP, PCX, pDrive->track, - pDrive->track == (MDSAD_TRACKS - 1) ? - "[Warn: already at highest track]" : "")); + sim_debug(SEEK_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Step in: Track=%d%s\n", PCX, pDrive->track, + pDrive->track == (MDSAD_TRACKS - 1) ? "[Warn: already at highest track]" : ""); if(pDrive->track < (MDSAD_TRACKS - 1)) /* anything to do? */ pDrive->track++; } @@ -577,11 +564,11 @@ static uint8 MDSAD_Read(const uint32 Addr) mdsad_info->b_status.t0 = (pDrive->track == 0); break; case MDSAD_CTLR_COMMAND: -/* TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT " DM=%x" NLP, PCX, (Addr & 0xF0) >> 4)); */ +/* sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT " DM=%x\n", PCX, (Addr & 0xF0) >> 4); */ switch(Addr & 0x0F) { case MDSAD_CMD_MOTORS_ON: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Motors On" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Motors On\n", PCX); mdsad_info->com_status.mo = 1; /* Turn motors on */ break; @@ -616,37 +603,37 @@ static uint8 MDSAD_Read(const uint32 Addr) } break; case MDSAD_CMD_RESET_SF: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Reset Sector Flag" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Reset Sector Flag\n", PCX); mdsad_info->com_status.sf = 0; mdsad_info->datacount = 0; break; case MDSAD_CMD_INTR_DIS: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Disarm Interrupt" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Disarm Interrupt\n", PCX); mdsad_info->int_enable = 0; break; case MDSAD_CMD_INTR_ARM: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Arm Interrupt" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Arm Interrupt\n", PCX); mdsad_info->int_enable = 1; break; case MDSAD_CMD_SET_BODY: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Set Body (Diagnostic)" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Set Body (Diagnostic)\n", PCX); break; case MDSAD_CMD_BEGIN_WR: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Begin Write" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Begin Write\n", PCX); break; case MDSAD_CMD_RESET: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " CMD=Reset Controller" NLP, PCX)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " CMD=Reset Controller\n", PCX); mdsad_info->com_status.mo = 0; /* Turn motors off */ break; default: - TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT - " Unsupported CMD=0x%x" NLP, PCX, Addr & 0x0F)); + sim_debug(CMD_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Unsupported CMD=0x%x\n", PCX, Addr & 0x0F); break; } @@ -666,52 +653,56 @@ static uint8 MDSAD_Read(const uint32 Addr) cData |= (mdsad_info->a_status.re & 1) << 2; cData |= (mdsad_info->a_status.sp & 1) << 1; cData |= (mdsad_info->a_status.bd & 1); - TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT - " A-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX, - cData & MDSAD_A_SF ? "SF" : " ", - cData & MDSAD_A_IX ? "IX" : " ", - cData & MDSAD_A_DD ? "DD" : " ", - cData & MDSAD_A_MO ? "MO" : " ", - cData & MDSAD_A_WI ? "WI" : " ", - cData & MDSAD_A_RE ? "RE" : " ", - cData & MDSAD_A_SP ? "SP" : " ", - cData & MDSAD_A_BD ? "BD" : " ")); + sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " A-Status = <%s %s %s %s %s %s %s %s>\n", + PCX, + cData & MDSAD_A_SF ? "SF" : " ", + cData & MDSAD_A_IX ? "IX" : " ", + cData & MDSAD_A_DD ? "DD" : " ", + cData & MDSAD_A_MO ? "MO" : " ", + cData & MDSAD_A_WI ? "WI" : " ", + cData & MDSAD_A_RE ? "RE" : " ", + cData & MDSAD_A_SP ? "SP" : " ", + cData & MDSAD_A_BD ? "BD" : " "); break; case MDSAD_B_STATUS: /* B-STATUS */ cData |= (mdsad_info->b_status.wr & 1) << 3; cData |= (mdsad_info->b_status.sp & 1) << 2; cData |= (mdsad_info->b_status.wp & 1) << 1; cData |= (mdsad_info->b_status.t0 & 1); - TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT - " B-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX, - cData & MDSAD_B_SF ? "SF" : " ", - cData & MDSAD_B_IX ? "IX" : " ", - cData & MDSAD_B_DD ? "DD" : " ", - cData & MDSAD_B_MO ? "MO" : " ", - cData & MDSAD_B_WR ? "WR" : " ", - cData & MDSAD_B_SP ? "SP" : " ", - cData & MDSAD_B_WP ? "WP" : " ", - cData & MDSAD_B_T0 ? "T0" : " ")); + sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " B-Status = <%s %s %s %s %s %s %s %s>\n", + PCX, + cData & MDSAD_B_SF ? "SF" : " ", + cData & MDSAD_B_IX ? "IX" : " ", + cData & MDSAD_B_DD ? "DD" : " ", + cData & MDSAD_B_MO ? "MO" : " ", + cData & MDSAD_B_WR ? "WR" : " ", + cData & MDSAD_B_SP ? "SP" : " ", + cData & MDSAD_B_WP ? "WP" : " ", + cData & MDSAD_B_T0 ? "T0" : " "); break; case MDSAD_C_STATUS: /* C-STATUS */ cData |= (mdsad_info->c_status.sc & 0xF); - TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT - " C-Status = <%s %s %s %s %i>" NLP, PCX, - cData & MDSAD_C_SF ? "SF" : " ", - cData & MDSAD_C_IX ? "IX" : " ", - cData & MDSAD_C_DD ? "DD" : " ", - cData & MDSAD_C_MO ? "MO" : " ", cData & MDSAD_C_SC)); + sim_debug(STATUS_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " C-Status = <%s %s %s %s %i>\n", + PCX, + cData & MDSAD_C_SF ? "SF" : " ", + cData & MDSAD_C_IX ? "IX" : " ", + cData & MDSAD_C_DD ? "DD" : " ", + cData & MDSAD_C_MO ? "MO" : " ", + cData & MDSAD_C_SC); break; case MDSAD_READ_DATA: /* READ DATA */ { if(mdsad_info->datacount == 0) { - TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP, - PCX, - mdsad_info->orders.ds, - pDrive->track, - mdsad_info->orders.ss, - pDrive->sector)); + sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d\n", + PCX, + mdsad_info->orders.ds, + pDrive->track, + mdsad_info->orders.ss, + pDrive->sector); checksum = 0; @@ -721,9 +712,9 @@ static uint8 MDSAD_Read(const uint32 Addr) if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) { - TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " Drive: %d not attached - read ignored." NLP, - PCX, mdsad_info->orders.ds)); + sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " Drive: %d not attached - read ignored.\n", + PCX, mdsad_info->orders.ds); return 0xe5; } @@ -738,7 +729,8 @@ static uint8 MDSAD_Read(const uint32 Addr) rtn = sim_fread(&sdata.u.data[0], 1, MDSAD_SECTOR_LEN, (pDrive->uptr)->fileref); if (rtn != MDSAD_SECTOR_LEN) { - TRACE_PRINT(ERROR_MSG, ("MDSAD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " READ: sim_fread error.\n", PCX); } } break; @@ -768,9 +760,9 @@ static uint8 MDSAD_Read(const uint32 Addr) PCX, sec_offset, mdsad_info->datacount, cData)); } else { /* checksum */ cData = checksum; - TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT - " READ-DATA: Checksum is: 0x%02x" NLP, - PCX, cData)); + sim_debug(RD_DATA_MSG, &mdsad_dev, "MDSAD: " ADDRESS_FORMAT + " READ-DATA: Checksum is: 0x%02x\n", + PCX, cData); } mdsad_info->datacount++; diff --git a/AltairZ80/s100_scp300f.c b/AltairZ80/s100_scp300f.c index 1aaa35eb..38d7c1fb 100644 --- a/AltairZ80/s100_scp300f.c +++ b/AltairZ80/s100_scp300f.c @@ -120,10 +120,6 @@ static MTAB scp300f_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(scp300f_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB scp300f_dt[] = { { "ERROR", ERROR_MSG }, @@ -151,7 +147,7 @@ static t_stat scp300f_reset(DEVICE *dptr) { PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: Reset." NLP)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: Reset.\n"); if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &scp300fdev, TRUE); @@ -321,7 +317,7 @@ static uint8 scp300f_rom[SCP300F_ROM_SIZE] = { if(write) { if(scp300f_info->rom_enabled) { - TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM." NLP, PCX, Addr)); + sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM.\n", PCX, Addr); } else { } return 0; @@ -370,38 +366,38 @@ static uint8 SCP300F_Read(const uint32 Addr) switch(Addr & SCP300F_IO_MASK) { case SCP300F_MPIC_0: case SCP300F_MPIC_1: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Master 8259 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Master 8259 DATA RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_SPIC_0: case SCP300F_SPIC_1: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_9513_DATA: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 DATA RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_9513_STATUS: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 STAT RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 STAT RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_UART_DATA: /* UART is handled by the 2SIO, if this gets called, then the 2SIO was not */ case SCP300F_UART_STATUS: /* configured properly. */ - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD[%02x]: UART not configured properly." NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD[%02x]: UART not configured properly.\n", PCX, Addr); break; case SCP300F_PIO_DATA: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO DATA RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_PIO_STATUS: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO STATUS RD[%02x]: not implemented." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO STATUS RD[%02x]: not implemented.\n", PCX, Addr); break; case SCP300F_EPROM_DIS: - TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " EPROM DIS RD: EPROM Disabled." NLP, PCX)); + sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " EPROM DIS RD: EPROM Disabled.\n", PCX); scp300f_info->rom_enabled = 0; break; case SCP300F_SENSE_SW: /* Sense Switch */ cData = scp300f_sr; - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD: Sense Switch=0x%02x" NLP, PCX, cData)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD: Sense Switch=0x%02x\n", PCX, cData); break; default: - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD[%02x]: not Implemented." NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " RD[%02x]: not Implemented.\n", PCX, Addr); break; } @@ -415,37 +411,37 @@ static uint8 SCP300F_Write(const uint32 Addr, uint8 cData) switch(Addr & SCP300F_IO_MASK) { case SCP300F_MPIC_0: case SCP300F_MPIC_1: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Master 8259 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Master 8259 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_SPIC_0: case SCP300F_SPIC_1: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_9513_DATA: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_9513_STATUS: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 STAT WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " 9513 STAT WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_UART_DATA: /* UART is handled by the 2SIO, if this gets called, then the 2SIO was not */ case SCP300F_UART_STATUS: /* configured properly. */ - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: UART not configured properly." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: UART not configured properly.\n", PCX, Addr); break; case SCP300F_PIO_DATA: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " PIO DATA WR[%02x]=%02x: not implemented.\n", PCX, Addr, cData); break; case SCP300F_PIO_STATUS: - TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to PIO STATUS." NLP, PCX, Addr)); + sim_debug(UART_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to PIO STATUS.\n", PCX, Addr); break; case SCP300F_EPROM_DIS: - TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " EPROM DIS WR: EPROM Disabled." NLP, PCX)); + sim_debug(ROM_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " EPROM DIS WR: EPROM Disabled.\n", PCX); scp300f_info->rom_enabled = 0; break; case SCP300F_SENSE_SW: - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to SR." NLP, PCX, Addr)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to SR.\n", PCX, Addr); break; default: - TRACE_PRINT(VERBOSE_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented." NLP, PCX, Addr, cData)); + sim_debug(VERBOSE_MSG, &scp300f_dev, "SCP300F: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented.\n", PCX, Addr, cData); break; } diff --git a/AltairZ80/s100_selchan.c b/AltairZ80/s100_selchan.c index b9a312cd..926a1b6f 100644 --- a/AltairZ80/s100_selchan.c +++ b/AltairZ80/s100_selchan.c @@ -109,10 +109,6 @@ static MTAB selchan_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(selchan_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB selchan_dt[] = { { "ERROR", ERROR_MSG }, @@ -167,18 +163,12 @@ static int32 selchandev(const int32 port, const int32 io, const int32 data) selchan_info->reg_cnt ++; if(selchan_info->reg_cnt == 4) { - TRACE_PRINT(VERBOSE_MSG, ("SELCHAN: " ADDRESS_FORMAT " DMA=0x%06x, Mode=0x%02x (%s, %s, %s)" NLP, - PCX, - selchan_info->dma_addr, - selchan_info->dma_mode, - selchan_info->dma_mode & SELCHAN_MODE_WRITE ? "WR" : "RD", - selchan_info->dma_mode & SELCHAN_MODE_IO ? "I/O" : "MEM", - selchan_info->dma_mode & SELCHAN_MODE_IO ? "FIX" : selchan_info->dma_mode & SELCHAN_MODE_CNT_UP ? "INC" : "DEC")); + sim_debug(VERBOSE_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " DMA=0x%06x, Mode=0x%02x (%s, %s, %s)\n", PCX, selchan_info->dma_addr, selchan_info->dma_mode, selchan_info->dma_mode & SELCHAN_MODE_WRITE ? "WR" : "RD", selchan_info->dma_mode & SELCHAN_MODE_IO ? "I/O" : "MEM", selchan_info->dma_mode & SELCHAN_MODE_IO ? "FIX" : selchan_info->dma_mode & SELCHAN_MODE_CNT_UP ? "INC" : "DEC"); } return 0; } else { - TRACE_PRINT(VERBOSE_MSG, ("SELCHAN: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(VERBOSE_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " Reset\n", PCX); selchan_info->reg_cnt = 0; return(0xFF); } @@ -199,9 +189,7 @@ int32 selchan_dma(uint8 *buf, uint32 len) printf("SELCHAN: " ADDRESS_FORMAT " I/O Not supported" NLP, PCX); return (-1); } else { - TRACE_PRINT(DMA_MSG, ("SELCHAN: " ADDRESS_FORMAT " DMA %s Transfer, len=%d" NLP, - PCX, - (selchan_info->dma_mode & SELCHAN_MODE_WRITE) ? "WR" : "RD", len)); + sim_debug(DMA_MSG, &selchan_dev, "SELCHAN: " ADDRESS_FORMAT " DMA %s Transfer, len=%d\n", PCX, (selchan_info->dma_mode & SELCHAN_MODE_WRITE) ? "WR" : "RD", len); for(i=0;idma_mode & SELCHAN_MODE_WRITE) { PutByteDMA(selchan_info->dma_addr + i, buf[i]); diff --git a/AltairZ80/s100_ss1.c b/AltairZ80/s100_ss1.c index 7a92b0a4..95184c05 100644 --- a/AltairZ80/s100_ss1.c +++ b/AltairZ80/s100_ss1.c @@ -207,10 +207,6 @@ static MTAB ss1_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(ss1_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB ss1_dt[] = { { "ERROR", ERROR_MSG }, @@ -306,10 +302,12 @@ static uint8 SS1_Read(const uint32 Addr) case SS1_M8259_L: if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x03) { cData = ss1_pic[sel_pic].ISR; - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC ISR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: %s PIC ISR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); } else if((ss1_pic[sel_pic].OCW3 & 0x03) == 0x02) { cData = ss1_pic[sel_pic].IRR; - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC IRR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: %s PIC IRR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); } else { cData = 0xFF; } @@ -318,27 +316,32 @@ static uint8 SS1_Read(const uint32 Addr) sel_pic = SLAVE_PIC; case SS1_M8259_H: cData = ss1_pic[sel_pic].IMR; - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " RD: %s PIC IMR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].IMR = cData; break; case SS1_8253_CTL: cData = ss1_tc[0].CTL; - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " RD: TC CTL=0x%02x." NLP, PCX, cData)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: TC CTL=0x%02x.\n", PCX, cData); break; case SS1_8253_TC2: sel_tc++; case SS1_8253_TC1: sel_tc++; case SS1_8253_TC0: - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " RD: TC [%d]=0x%02x." NLP, PCX, sel_tc, cData)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: TC [%d]=0x%02x.\n", PCX, sel_tc, cData); break; case SS1_9511A_DATA: case SS1_9511A_CMD: - TRACE_PRINT(MATH_MSG, ("SS1: " ADDRESS_FORMAT " RD: Math Coprocessor not Implemented." NLP, PCX)); + sim_debug(MATH_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: Math Coprocessor not Implemented.\n", PCX); break; case SS1_RTC_CMD: cData = 0xFF; - TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " RD: RTC Cmd=0x%02x." NLP, PCX, cData)); + sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: RTC Cmd=0x%02x.\n", PCX, cData); break; case SS1_RTC_DATA: time(&now); @@ -389,20 +392,24 @@ static uint8 SS1_Read(const uint32 Addr) cData = 0; break; } - TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " RD: RTC Data[%x]=0x%02x." NLP, PCX, ss1_rtc[0].digit_sel, cData)); + sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: RTC Data[%x]=0x%02x.\n", PCX, ss1_rtc[0].digit_sel, cData); break; case SS1_UART_DATA: cData = sio0d(Addr, 0, 0); - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART Data=0x%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: UART Data=0x%02x.\n", PCX, cData); break; case SS1_UART_STAT: cData = sio0s(Addr, 0, 0); - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART Stat=0x%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: UART Stat=0x%02x.\n", PCX, cData); break; case SS1_UART_MODE: case SS1_UART_CMD: - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART not Implemented." NLP, PCX)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " RD: UART not Implemented.\n", PCX); break; } @@ -427,15 +434,18 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData) sel_pic = SLAVE_PIC; case SS1_M8259_L: if(cData & 0x10) { - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC ICW1=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: %s PIC ICW1=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].ICW[1] = cData; ss1_pic[sel_pic].config_cnt=1; } else { if(cData & 0x08) { /* OCW3 */ - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC OCW3=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: %s PIC OCW3=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].OCW3 = cData; } else { /* OCW2 */ - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC OCW2=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: %s PIC OCW2=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].OCW2 = cData; } } @@ -444,12 +454,12 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData) sel_pic = SLAVE_PIC; case SS1_M8259_H: if(ss1_pic[sel_pic].config_cnt == 0) { - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC IMR=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC IMR=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), cData); ss1_pic[sel_pic].IMR = cData; generate_ss1_interrupt(); } else { ss1_pic[sel_pic].config_cnt++; - TRACE_PRINT(PIC_MSG, ("SS1: " ADDRESS_FORMAT " WR: %s PIC ICW%d=0x%02x." NLP, PCX, (sel_pic ? "Slave " : "Master"), ss1_pic[sel_pic].config_cnt, cData)); + sim_debug(PIC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " WR: %s PIC ICW%d=0x%02x.\n", PCX, (sel_pic ? "Slave " : "Master"), ss1_pic[sel_pic].config_cnt, cData); ss1_pic[sel_pic].ICW[ss1_pic[sel_pic].config_cnt] = cData; ss1_unit[0].u3 = ss1_pic[SLAVE_PIC].ICW[2]+TC0_IRQ_OFFSET; @@ -464,15 +474,22 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData) case SS1_8253_CTL: ss1_tc[0].CTL = cData; sel_timer = (ss1_tc[0].CTL & I8253_CTL_SC_MASK) >> 6; - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " WR: TC CTL=0x%02x." NLP, PCX, ss1_tc[0].CTL)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: TC CTL=0x%02x.\n", + PCX, ss1_tc[0].CTL); if(ss1_tc[0].CTL & I8253_CTL_BCD) { - TRACE_PRINT(ERROR_MSG, ("SS1: " ADDRESS_FORMAT " Timer %d: BCD Mode not supported: TC CTL=0x%02x." NLP, PCX, sel_timer, ss1_tc[0].CTL)); + sim_debug(ERROR_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " Timer %d: BCD Mode not supported: TC CTL=0x%02x.\n", + PCX, sel_timer, ss1_tc[0].CTL); } ss1_tc[0].bcd[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_BCD); ss1_tc[0].mode[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_MODE_MASK) >> 1; ss1_tc[0].rl[sel_timer] = (ss1_tc[0].CTL & I8253_CTL_RL_MASK) >> 4; - TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " Timer %d: Mode: %d, RL=%d, %s." NLP, PCX, - sel_timer, ss1_tc[0].mode[sel_timer], ss1_tc[0].rl[sel_timer], ss1_tc[0].bcd[sel_timer] ? "BCD" : "Binary")); + sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " Timer %d: Mode: %d, RL=%d, %s.\n", + PCX, sel_timer, ss1_tc[0].mode[sel_timer], + ss1_tc[0].rl[sel_timer], + ss1_tc[0].bcd[sel_timer] ? "BCD" : "Binary"); newcount = 0; bc=0; break; @@ -497,38 +514,45 @@ static uint8 SS1_Write(const uint32 Addr, uint8 cData) sim_activate(&ss1_unit[sel_tc], newcount); } - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " WR: TC [%d]=0x%02x." NLP, PCX, sel_tc, cData)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: TC [%d]=0x%02x.\n", PCX, sel_tc, cData); if(sel_tc == 0) { } break; case SS1_9511A_DATA: case SS1_9511A_CMD: - TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: Math Coprocessor not Implemented." NLP, PCX)); + sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: Math Coprocessor not Implemented.\n", PCX); break; case SS1_RTC_CMD: ss1_rtc[0].digit_sel = cData & 0x0F; ss1_rtc[0].flags = (cData >> 4) & 0x0F; - TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " WR: RTC Cmd=0x%02x (%s%s%s SEL=%x)" NLP, - PCX, cData, - ss1_rtc[0].flags & 0x4 ? "HOLD " :"", - ss1_rtc[0].flags & 0x2 ? "WR" :"", - ss1_rtc[0].flags & 0x1 ? "RD" :"", - ss1_rtc[0].digit_sel)) + sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: RTC Cmd=0x%02x (%s%s%s SEL=%x)\n", + PCX, cData, + ss1_rtc[0].flags & 0x4 ? "HOLD " :"", + ss1_rtc[0].flags & 0x2 ? "WR" :"", + ss1_rtc[0].flags & 0x1 ? "RD" :"", + ss1_rtc[0].digit_sel); break; case SS1_RTC_DATA: - TRACE_PRINT(RTC_MSG, ("SS1: " ADDRESS_FORMAT " WR: RTC Data=0x%02x" NLP, PCX, cData)); + sim_debug(RTC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: RTC Data=0x%02x\n", PCX, cData); break; case SS1_UART_DATA: - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART Data=0x%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: UART Data=0x%02x.\n", PCX, cData); sio0d(Addr, 1, cData); break; case SS1_UART_STAT: - TRACE_PRINT(UART_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART Stat=0x%02x." NLP, PCX, cData)); + sim_debug(UART_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: UART Stat=0x%02x.\n", PCX, cData); sio0s(Addr, 1, cData); break; case SS1_UART_MODE: case SS1_UART_CMD: - TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART not Implemented." NLP, PCX)); + sim_debug(TRACE_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT + " WR: UART not Implemented.\n", PCX); break; } @@ -564,22 +588,12 @@ static void generate_ss1_interrupt(void) if(irq_bit) { ss1_pic[pic].IRR |= (irq_bit << irq_index); irq = ss1_pic[pic].ICW[2]+irq_index; - TRACE_PRINT(IRQ_MSG, ("Handling interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d" NLP, - pic ? "SLAVE" : "MASTER", - ss1_pic[pic].IMR, - ss1_pic[pic].ISR, - ss1_pic[pic].IRR, - irq_index)); + sim_debug(IRQ_MSG, &ss1_dev, "Handling interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index); cpu_raise_interrupt(irq); ss1_pic[pic].IRR &= ~(irq_bit << irq_index); ss1_pic[pic].ISR &= ~(irq_bit << irq_index); if(irq_pend & 0x7E) { -/* TRACE_PRINT(IRQ_MSG, ("Requeue interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d" NLP, - pic ? "SLAVE" : "MASTER", - ss1_pic[pic].IMR, - ss1_pic[pic].ISR, - ss1_pic[pic].IRR, - irq_index)); +/* sim_debug(IRQ_MSG, &ss1_dev, "Requeue interrupt on %s PIC: IMR=0x%02x, ISR=0x%02x, IRR=0x%02x, index=%d\n", pic ? "SLAVE" : "MASTER", ss1_pic[pic].IMR, ss1_pic[pic].ISR, ss1_pic[pic].IRR, irq_index); */ sim_activate(&ss1_unit[3], 1000); /* requeue, because more interrupts are pending. */ } @@ -607,7 +621,7 @@ static t_stat ss1_svc (UNIT *uptr) generate_ss1_interrupt(); sim_activate(uptr, 1000); /* requeue, because we still need to handle the timer interrupt. */ } else if((cData & 1) && ((ss1_pic[SLAVE_PIC].IMR & 0x40) == 0)) { - TRACE_PRINT(IRQ_MSG, ("SS1: " ADDRESS_FORMAT " Calling UART Tx ISR." NLP, PCX)); + sim_debug(IRQ_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling UART Tx ISR.\n", PCX); ss1_pic[SLAVE_PIC].ISR |= 0x40; generate_ss1_interrupt(); sim_activate(uptr, 1000); /* requeue, because we still need to handle the timer interrupt. */ @@ -626,15 +640,15 @@ static t_stat ss1_svc (UNIT *uptr) break; } if(ss1_tc[0].mode[uptr->u4] == 0x0) { - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " Calling Timer%d ISR." NLP, PCX, uptr->u4)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4); ss1_pic[SLAVE_PIC].ISR |= irq_bit; generate_ss1_interrupt(); } if(ss1_tc[0].mode[uptr->u4] == 0x3) { - TRACE_PRINT(TC_MSG, ("SS1: " ADDRESS_FORMAT " Calling Timer%d ISR." NLP, PCX, uptr->u4)); + sim_debug(TC_MSG, &ss1_dev, "SS1: " ADDRESS_FORMAT " Calling Timer%d ISR.\n", PCX, uptr->u4); ss1_pic[SLAVE_PIC].ISR |= irq_bit; generate_ss1_interrupt(); - TRACE_PRINT(TC_MSG, ("Timer %d, mode %d, reloading\n", uptr->u4, ss1_tc[0].mode[uptr->u4])); + sim_debug(TC_MSG, &ss1_dev, "Timer %d, mode %d, reloading\n", uptr->u4, ss1_tc[0].mode[uptr->u4]); sim_activate(uptr, 33280); } } diff --git a/AltairZ80/sim_imd.c b/AltairZ80/sim_imd.c index 3d746d93..b9884b25 100644 --- a/AltairZ80/sim_imd.c +++ b/AltairZ80/sim_imd.c @@ -361,6 +361,7 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment) DISK_INFO *myDisk = NULL; char *comment; char *curptr; + char *result; uint8 answer; int32 len, remaining; @@ -387,8 +388,8 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment) remaining = MAX_COMMENT_LEN; do { printf("IMD> "); - fgets(curptr, remaining - 3, stdin); - if (strcmp(curptr, ".\n") == 0) { + result = fgets(curptr, remaining - 3, stdin); + if ((result == NULL) || (strcmp(curptr, ".\n") == 0)) { remaining = 0; } else { len = strlen(curptr) - 1; @@ -409,7 +410,10 @@ t_stat diskCreate(FILE *fileref, char *ctlr_comment) #ifdef _WIN32 /* This might work under UNIX and/or VMS since this POSIX, but I haven't tried it. */ _chsize(_fileno(fileref), ftell (fileref)); #else - ftruncate(fileno(fileref), ftell (fileref)); + if (ftruncate(fileno(fileref), ftell (fileref)) == -1) { + printf("SIM_IMD: Error overwriting disk image.\n"); + return(SCPE_OPENERR); + } #endif fprintf(fileref, "IMD SIMH %s %s\n", __DATE__, __TIME__); @@ -722,7 +726,11 @@ t_stat trackWrite(DISK_INFO *myDisk, #ifdef _WIN32 /* This might work under UNIX and/or VMS since this POSIX, but I haven't tried it. */ _chsize(_fileno(fileref), ftell (fileref)); #else - ftruncate(fileno(fileref), ftell (fileref)); + if (ftruncate(fileno(fileref), ftell (fileref)) == -1) { + printf("Disk truncation failed." NLP); + *flags |= IMD_DISK_IO_ERROR_GENERAL; + return(SCPE_IOERR); + } #endif /* Flush and re-parse the IMD file. */ fflush(fileref); diff --git a/AltairZ80/vfdhd.c b/AltairZ80/vfdhd.c index 11db5b54..bc03ed44 100644 --- a/AltairZ80/vfdhd.c +++ b/AltairZ80/vfdhd.c @@ -181,10 +181,6 @@ static MTAB vfdhd_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(vfdhd_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB vfdhd_dt[] = { { "ERROR", ERROR_MSG }, @@ -392,7 +388,7 @@ static uint8 VFDHD_Read(const uint32 Addr) cData |= (pDrive->seek_complete & 1) << 4; /* [4] Seek Complete (HD) */ cData |= (pDrive->sync_lost & 1) << 5; /* [5] Loss of Sync (HD) */ cData |= 0xC0; /* [7:6] Reserved (pulled up) */ - TRACE_PRINT(STATUS_MSG, ("VFDHD: " ADDRESS_FORMAT " RD S0 = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD S0 = 0x%02x\n", PCX, cData); break; case FDHD_CTRL_STATUS1: vfdhd_info->floppy_sel = (vfdhd_info->sel_drive == 0) ? 0 : 1; @@ -407,12 +403,12 @@ static uint8 VFDHD_Read(const uint32 Addr) vfdhd_info->controller_busy = 0; - TRACE_PRINT(STATUS_MSG, ("VFDHD: " ADDRESS_FORMAT " RD S1 = 0x%02x" NLP, PCX, cData)); + sim_debug(STATUS_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD S1 = 0x%02x\n", PCX, cData); break; case FDHD_DATA: /* DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data" NLP, PCX)); */ if(vfdhd_info->datacount+40 >= VFDHD_RAW_LEN) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount); vfdhd_info->datacount = 0; } cData = sdata.raw[vfdhd_info->datacount+40]; @@ -422,7 +418,7 @@ static uint8 VFDHD_Read(const uint32 Addr) /* DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, vfdhd_info->datacount, cData)); */ break; case FDHD_RESET_START: /* Reset */ - TRACE_PRINT(CMD_MSG, ("VFDHD: " ADDRESS_FORMAT " Reset" NLP, PCX)); + sim_debug(CMD_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Reset\n", PCX); vfdhd_info->datacount = 0; cData = 0xFF; /* Return High-Z data */ break; @@ -445,14 +441,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) vfdhd_info->direction = (cData >> 6) & 1; vfdhd_info->rwc = (cData >> 7) & 1; - TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR C0=%02x: sel_drive=%d, head=%d, step=%d, dir=%d, rwc=%d" NLP, - PCX, - cData, - vfdhd_info->sel_drive, - vfdhd_info->head, - vfdhd_info->step, - vfdhd_info->direction, - vfdhd_info->rwc)); + sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR C0=%02x: sel_drive=%d, head=%d, step=%d, dir=%d, rwc=%d\n", PCX, cData, vfdhd_info->sel_drive, vfdhd_info->head, vfdhd_info->step, vfdhd_info->direction, vfdhd_info->rwc); if(vfdhd_info->step == 1) { if(vfdhd_info->direction == 1) { /* Step IN */ @@ -462,8 +451,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) pDrive->track--; } } - TRACE_PRINT(SEEK_MSG, ("VFDHD: " ADDRESS_FORMAT " Drive %d on track %d" NLP, - PCX, vfdhd_info->sel_drive, pDrive->track)); + sim_debug(SEEK_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Drive %d on track %d\n", PCX, vfdhd_info->sel_drive, pDrive->track); } break; @@ -473,8 +461,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) vfdhd_info->ecc_enable = (cData >> 6) & 1; vfdhd_info->precomp = (cData >> 7) & 1; if(cData == 0xFF) { - TRACE_PRINT(SEEK_MSG, ("VFDHD: " ADDRESS_FORMAT " Home Disk %d" NLP, - PCX, vfdhd_info->sel_drive)); + sim_debug(SEEK_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Home Disk %d\n", PCX, vfdhd_info->sel_drive); pDrive->track = 0; } DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR C1=%02x: sector=%d, read=%d, ecc_en=%d, precomp=%d" NLP, @@ -490,20 +477,20 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) #ifdef USE_VGI if(vfdhd_info->sel_drive > 0) { /* Floppy */ if(vfdhd_info->datacount >= VFDHD_RAW_LEN) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount); vfdhd_info->datacount = 0; } sdata.raw[vfdhd_info->datacount] = cData; } else { /* Hard */ if(vfdhd_info->datacount+10 >= VFDHD_RAW_LEN) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount); vfdhd_info->datacount = 0; } sdata.raw[vfdhd_info->datacount+10] = cData; } #else if((vfdhd_info->datacount-13 >= VFDHD_RAW_LEN) || (vfdhd_info->datacount < 13)) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " Illegal data count %d." NLP, PCX, vfdhd_info->datacount)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Illegal data count %d.\n", PCX, vfdhd_info->datacount); vfdhd_info->datacount = 13; } sdata.u.data[vfdhd_info->datacount-13] = cData; @@ -513,7 +500,7 @@ static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) break; case FDHD_RESET_START: - TRACE_PRINT(CMD_MSG, ("VFDHD: " ADDRESS_FORMAT " Start Command" NLP, PCX)); + sim_debug(CMD_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " Start Command\n", PCX); VFDHD_Command(); break; } @@ -547,14 +534,9 @@ static void VFDHD_Command(void) if(vfdhd_info->read == 1) { /* Perform a Read operation */ unsigned int i, checksum; - uint32 readlen; + unsigned int readlen; - TRACE_PRINT(RD_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP, - PCX, - vfdhd_info->sel_drive, - pDrive->track, - vfdhd_info->head, - vfdhd_info->sector)); + sim_debug(RD_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector); /* Clear out unused portion of sector. */ memset(&sdata.u.unused[0], 0x00, 10); @@ -597,7 +579,7 @@ static void VFDHD_Command(void) sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); rtn = sim_fread(&sdata.u.sync, 1, 274, /*VFDHD_SECTOR_LEN,*/ (pDrive->uptr)->fileref); if (rtn != 274) { - TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX)); + sim_debug(ERROR_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " READ: sim_fread error.\n", PCX); } memset(&sdata.u.preamble, 0, 40); @@ -619,14 +601,9 @@ static void VFDHD_Command(void) } } else { /* Perform a Write operation */ - uint32 writelen; + unsigned int writelen; - TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP, - PCX, - vfdhd_info->sel_drive, - pDrive->track, - vfdhd_info->head, - vfdhd_info->sector)); + sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector); #ifdef USE_VGI #else diff --git a/AltairZ80/wd179x.c b/AltairZ80/wd179x.c index 743e779a..034d7e80 100644 --- a/AltairZ80/wd179x.c +++ b/AltairZ80/wd179x.c @@ -199,6 +199,7 @@ uint8 floorlog2(unsigned int n); WD179X_INFO wd179x_info_data = { { 0x0, 0, 0x30, 4 } }; WD179X_INFO *wd179x_info = &wd179x_info_data; +WD179X_INFO_PUB *wd179x_infop = (WD179X_INFO_PUB *)&wd179x_info_data; static UNIT wd179x_unit[] = { { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 }, @@ -218,10 +219,6 @@ static MTAB wd179x_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if(wd179x_dev.dctrl & level) { \ - printf args; \ - } - /* Debug Flags */ static DEBTAB wd179x_dt[] = { { "ERROR", ERROR_MSG }, @@ -280,19 +277,21 @@ void wd179x_external_restore(void) WD179X_DRIVE_INFO *pDrive; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { - TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " Illegal drive selected, cannot restore." NLP, PCX)) + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " Illegal drive selected, cannot restore.\n", PCX); return; } pDrive = &wd179x_info->drive[wd179x_info->sel_drive]; if(pDrive->uptr == NULL) { - TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " No drive selected, cannot restore." NLP, PCX)) + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " No drive selected, cannot restore.\n", PCX); return; } - TRACE_PRINT(SEEK_MSG, - ("WD179X[%d]: " ADDRESS_FORMAT " External Restore drive to track 0" NLP, wd179x_info->sel_drive, PCX)) + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " External Restore drive to track 0\n", wd179x_info->sel_drive, PCX); pDrive->track = 0; @@ -445,8 +444,8 @@ uint8 WD179X_Read(const uint32 Addr) { uint8 cData; WD179X_DRIVE_INFO *pDrive; - uint32 flags = 0; - uint32 readlen; + unsigned int flags = 0; + unsigned int readlen; int status; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { @@ -476,19 +475,19 @@ uint8 WD179X_Read(const uint32 Addr) } cData = (pDrive->ready == 0) ? WD179X_STAT_NOT_READY : 0; cData |= wd179x_info->fdc_status; /* Status Register */ - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " RD STATUS = 0x%02x\n", PCX, cData); wd179x_info->intrq = 0; break; case WD179X_TRACK: cData = pDrive->track; - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " RD TRACK = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " RD TRACK = 0x%02x\n", PCX, cData); break; case WD179X_SECTOR: cData = wd179x_info->fdc_sector; - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " RD SECT = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " RD SECT = 0x%02x\n", PCX, cData); break; case WD179X_DATA: cData = 0xFF; /* Return High-Z data */ @@ -496,8 +495,10 @@ uint8 WD179X_Read(const uint32 Addr) if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) { cData = sdata.raw[wd179x_info->fdc_dataindex]; if(wd179x_info->fdc_read_addr == TRUE) { - TRACE_PRINT(STATUS_MSG, - ("WD179X[%d]: " ADDRESS_FORMAT " READ_ADDR[%d] = 0x%02x" NLP, wd179x_info->sel_drive, PCX, wd179x_info->fdc_dataindex, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " READ_ADDR[%d] = 0x%02x\n", + wd179x_info->sel_drive, PCX, + wd179x_info->fdc_dataindex, cData); } wd179x_info->fdc_dataindex++; @@ -514,21 +515,13 @@ uint8 WD179X_Read(const uint32 Addr) wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; return cData; } wd179x_info->fdc_sector ++; - TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d" NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_sector, - wd179x_info->ddens ? "DD" : "SD", - 128 << wd179x_info->fdc_sec_len)); + sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len); status = sectRead(pDrive->imd, pDrive->track, @@ -578,8 +571,8 @@ static uint8 Do1793Command(uint8 cCommand) { uint8 result = 0; WD179X_DRIVE_INFO *pDrive; - uint32 flags = 0; - uint32 readlen; + unsigned int flags = 0; + unsigned int readlen; int status; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { @@ -594,8 +587,9 @@ static uint8 Do1793Command(uint8 cCommand) if(wd179x_info->fdc_status & WD179X_STAT_BUSY) { if(((cCommand & 0xF0) != WD179X_FORCE_INTR)) { /* && ((cCommand & 0xF0) != WD179X_RESTORE)) { */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: Command 0x%02x ignored because controller is BUSY\n" NLP, - wd179x_info->sel_drive, PCX, cCommand)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " ERROR: Command 0x%02x ignored because controller is BUSY\n\n", + wd179x_info->sel_drive, PCX, cCommand); } return 0xFF; } @@ -617,7 +611,7 @@ static uint8 Do1793Command(uint8 cCommand) wd179x_info->fdc_status |= WD179X_STAT_BUSY; /* Set BUSY */ wd179x_info->fdc_status &= ~(WD179X_STAT_CRC_ERROR | WD179X_STAT_SEEK_ERROR | WD179X_STAT_DRQ); wd179x_info->intrq = 0; - wd179x_info->hld = cCommand && 0x08; + wd179x_info->hld = cCommand & 0x08; wd179x_info->verify = cCommand & 0x04; break; /* Type II Commands */ @@ -648,19 +642,26 @@ static uint8 Do1793Command(uint8 cCommand) switch(cCommand & 0xF0) { /* Type I Commands */ case WD179X_RESTORE: - TRACE_PRINT(CMD_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=RESTORE %s" NLP, wd179x_info->sel_drive, PCX, wd179x_info->verify ? "[VERIFY]" : "")); + sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=RESTORE %s\n", wd179x_info->sel_drive, PCX, + wd179x_info->verify ? "[VERIFY]" : ""); pDrive->track = 0; wd179x_info->intrq = 1; break; case WD179X_SEEK: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=SEEK, track=%d, new=%d" NLP, wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_data)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=SEEK, track=%d, new=%d\n", wd179x_info->sel_drive, + PCX, pDrive->track, wd179x_info->fdc_data); pDrive->track = wd179x_info->fdc_data; break; case WD179X_STEP: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP" NLP, wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP\n", wd179x_info->sel_drive, PCX); break; case WD179X_STEP_U: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_U dir=%d" NLP, wd179x_info->sel_drive, PCX, wd179x_info->step_dir)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_U dir=%d\n", wd179x_info->sel_drive, + PCX, wd179x_info->step_dir); if(wd179x_info->step_dir == 1) { if (pDrive->track < 255) pDrive->track++; @@ -668,26 +669,30 @@ static uint8 Do1793Command(uint8 cCommand) if (pDrive->track > 0) pDrive->track--; } else { - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: undefined direction for STEP" NLP, wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " ERROR: undefined direction for STEP\n", + wd179x_info->sel_drive, PCX); } break; case WD179X_STEP_IN: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_IN" NLP, wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_IN\n", wd179x_info->sel_drive, PCX); break; case WD179X_STEP_IN_U: if (pDrive->track < 255) pDrive->track++; wd179x_info->step_dir = 1; - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_IN_U, Track=%d" NLP, - wd179x_info->sel_drive, PCX, pDrive->track)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_IN_U, Track=%d\n", wd179x_info->sel_drive, + PCX, pDrive->track); break; case WD179X_STEP_OUT: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_OUT" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_OUT\n", wd179x_info->sel_drive, PCX); break; case WD179X_STEP_OUT_U: - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_OUT_U" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=STEP_OUT_U\n", wd179x_info->sel_drive, PCX); if (pDrive->track > 0) pDrive->track--; wd179x_info->step_dir = -1; @@ -699,8 +704,8 @@ static uint8 Do1793Command(uint8 cCommand) wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */ wd179x_info->fdc_status &= ~WD179X_STAT_BUSY; wd179x_info->intrq = 1; @@ -710,14 +715,12 @@ static uint8 Do1793Command(uint8 cCommand) } wd179x_info->fdc_multiple = (cCommand & 0x10) ? TRUE : FALSE; - TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d" NLP, - wd179x_info->sel_drive, - PCX, pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_sector, - wd179x_info->fdc_multiple ? "Multiple" : "Single", - wd179x_info->ddens ? "DD" : "SD", - 128 << wd179x_info->fdc_sec_len)); + sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d\n", + wd179x_info->sel_drive, PCX, pDrive->track, + wd179x_info->fdc_head, wd179x_info->fdc_sector, + wd179x_info->fdc_multiple ? "Multiple" : "Single", + wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len); if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) { wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */ @@ -756,26 +759,21 @@ static uint8 Do1793Command(uint8 cCommand) } break; case WD179X_WRITE_RECS: - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Error: WRITE_RECS not implemented." NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Error: WRITE_RECS not implemented.\n", wd179x_info->sel_drive, PCX); break; case WD179X_WRITE_REC: /* Compute Sector Size */ wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; } - TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_REC, T:%d/S:%d/N:%d, %s." NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_sector, - (cCommand & 0x10) ? "Multiple" : "Single")); + sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=WRITE_REC, T:%d/S:%d/N:%d, %s.\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, (cCommand & 0x10) ? "Multiple" : "Single"); wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */ wd179x_info->drq = 1; wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len; @@ -789,12 +787,9 @@ static uint8 Do1793Command(uint8 cCommand) break; /* Type III Commands */ case WD179X_READ_ADDR: - TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_ADDR, T:%d/S:%d, %s" NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->ddens ? "DD" : "SD")); + sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=READ_ADDR, T:%d/S:%d, %s\n", wd179x_info->sel_drive, + PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->ddens ? "DD" : "SD"); /* For some reason 86-DOS tries to use this track, force it to 0. Need to investigate this more. */ if (pDrive->track == 0xFF) @@ -804,8 +799,8 @@ static uint8 Do1793Command(uint8 cCommand) wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; } @@ -833,17 +828,17 @@ static uint8 Do1793Command(uint8 cCommand) } break; case WD179X_READ_TRACK: - TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_TRACK" NLP, wd179x_info->sel_drive, PCX)); - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Error: READ_TRACK not implemented." NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=READ_TRACK\n", wd179x_info->sel_drive, PCX); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Error: READ_TRACK not implemented.\n", wd179x_info->sel_drive, PCX); break; case WD179X_WRITE_TRACK: - TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_TRACK" NLP, wd179x_info->sel_drive, PCX)); - TRACE_PRINT(FMT_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_TRACK, T:%d/S:%d." NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head)); + sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=WRITE_TRACK\n", wd179x_info->sel_drive, PCX); + sim_debug(FMT_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=WRITE_TRACK, T:%d/S:%d.\n", wd179x_info->sel_drive, + PCX, pDrive->track, wd179x_info->fdc_head); wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */ wd179x_info->drq = 1; wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len; @@ -858,7 +853,8 @@ static uint8 Do1793Command(uint8 cCommand) break; /* Type IV Commands */ case WD179X_FORCE_INTR: - TRACE_PRINT(CMD_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=FORCE_INTR" NLP, wd179x_info->sel_drive, PCX)); + sim_debug(CMD_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " CMD=FORCE_INTR\n", wd179x_info->sel_drive, PCX); if((cCommand & 0x0F) == 0) { /* I0-I3 == 0, no intr, but clear BUSY and terminate command */ wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */ wd179x_info->drq = 0; @@ -887,8 +883,8 @@ static uint8 Do1793Command(uint8 cCommand) } break; default: - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " ERROR: Unknown command 0x%02x.\n" NLP, - wd179x_info->sel_drive, PCX, cCommand)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " ERROR: Unknown command 0x%02x.\n\n", wd179x_info->sel_drive, PCX, cCommand); break; } @@ -904,15 +900,16 @@ static uint8 Do1793Command(uint8 cCommand) case WD179X_STEP_OUT: case WD179X_STEP_OUT_U: if(wd179x_info->verify) { /* Verify the selected track/head is ok. */ - TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Verify ", wd179x_info->sel_drive, PCX)); + sim_debug(SEEK_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Verify ", wd179x_info->sel_drive, PCX); if(sectSeek(pDrive->imd, pDrive->track, wd179x_info->fdc_head) != SCPE_OK) { - TRACE_PRINT(SEEK_MSG, ("FAILED" NLP)); + sim_debug(SEEK_MSG, &wd179x_dev, "FAILED\n"); wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; } else if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) { wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */ - TRACE_PRINT(SEEK_MSG, ("NOT FOUND" NLP)); + sim_debug(SEEK_MSG, &wd179x_dev, "NOT FOUND\n"); } else { - TRACE_PRINT(SEEK_MSG, ("Ok" NLP)); + sim_debug(SEEK_MSG, &wd179x_dev, "Ok\n"); } } @@ -955,8 +952,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) { WD179X_DRIVE_INFO *pDrive; /* uint8 disk_read = 0; */ - uint32 flags = 0; - uint32 writelen; + unsigned int flags = 0; + unsigned int writelen; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { return 0xFF; @@ -970,8 +967,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) switch(Addr & 0x3) { case WD179X_STATUS: - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " WR CMD = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " WR CMD = 0x%02x\n", PCX, cData); wd179x_info->fdc_read = FALSE; wd179x_info->fdc_write = FALSE; wd179x_info->fdc_write_track = FALSE; @@ -981,18 +978,18 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) Do1793Command(cData); break; case WD179X_TRACK: - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " WR TRACK = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " WR TRACK = 0x%02x\n", PCX, cData); pDrive->track = cData; break; case WD179X_SECTOR: /* Sector Register */ - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " WR SECT = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " WR SECT = 0x%02x\n", PCX, cData); wd179x_info->fdc_sector = cData; break; case WD179X_DATA: - TRACE_PRINT(STATUS_MSG, - ("WD179X: " ADDRESS_FORMAT " WR DATA = 0x%02x" NLP, PCX, cData)) + sim_debug(STATUS_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " WR DATA = 0x%02x\n", PCX, cData); if(wd179x_info->fdc_write == TRUE) { if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) { sdata.raw[wd179x_info->fdc_dataindex] = cData; @@ -1003,13 +1000,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) wd179x_info->drq = 0; wd179x_info->intrq = 1; - TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Writing sector, T:%d/S:%d/N:%d, Len=%d" NLP, - wd179x_info->sel_drive, - PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_sector, - 128 << wd179x_info->fdc_sec_len)); + sim_debug(WR_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Writing sector, T:%d/S:%d/N:%d, Len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, 128 << wd179x_info->fdc_sec_len); sectWrite(pDrive->imd, pDrive->track, @@ -1026,15 +1018,12 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) } if(wd179x_info->fdc_write_track == TRUE) { -/* TRACE_PRINT(FMT_MSG, */ -/* ("WD179X: " ADDRESS_FORMAT " FMT DATA[%d] = 0x%02x" NLP, PCX, wd179x_info->fdc_fmt_state, cData)); */ - if(wd179x_info->fdc_fmt_state == FMT_GAP1) { if(cData != 0xFC) { wd179x_info->fdc_gap[0]++; } else { - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " FMT GAP1 Length = %d" NLP, PCX, wd179x_info->fdc_gap[0])); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FMT GAP1 Length = %d\n", PCX, wd179x_info->fdc_gap[0]); wd179x_info->fdc_gap[1] = 0; wd179x_info->fdc_fmt_state = FMT_GAP2; } @@ -1042,8 +1031,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) if(cData != 0xFE) { wd179x_info->fdc_gap[1]++; } else { - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " FMT GAP2 Length = %d" NLP, PCX, wd179x_info->fdc_gap[1])); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FMT GAP2 Length = %d\n", PCX, wd179x_info->fdc_gap[1]); wd179x_info->fdc_gap[2] = 0; wd179x_info->fdc_fmt_state = FMT_HEADER; wd179x_info->fdc_header_index = 0; @@ -1053,8 +1042,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) wd179x_info->fdc_gap[2] = 0; wd179x_info->fdc_fmt_state = FMT_GAP3; } else { - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " HEADER[%d]=%02x" NLP, PCX, wd179x_info->fdc_header_index, cData)); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " HEADER[%d]=%02x\n", PCX, wd179x_info->fdc_header_index, cData); switch(wd179x_info->fdc_header_index) { case 0: pDrive->track = cData; @@ -1080,8 +1069,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) if(cData != 0xFB) { wd179x_info->fdc_gap[2]++; } else { - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " FMT GAP3 Length = %d" NLP, PCX, wd179x_info->fdc_gap[2])); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FMT GAP3 Length = %d\n", PCX, wd179x_info->fdc_gap[2]); wd179x_info->fdc_fmt_state = FMT_DATA; wd179x_info->fdc_dataindex = 0; } @@ -1092,28 +1081,26 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) } else { wd179x_info->fdc_sec_len = floorlog2(wd179x_info->fdc_dataindex) - 7; if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ - TRACE_PRINT(ERROR_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!" NLP, - wd179x_info->sel_drive, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT + " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; } if(wd179x_info->fdc_fmt_sector_count >= WD179X_MAX_SECTOR) { - TRACE_PRINT(ERROR_MSG, ("WD179X: " ADDRESS_FORMAT " Illegal sector count" NLP, PCX)); + sim_debug(ERROR_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " Illegal sector count\n", PCX); wd179x_info->fdc_fmt_sector_count = 0; } wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count] = wd179x_info->fdc_sector; wd179x_info->fdc_fmt_sector_count++; - TRACE_PRINT(VERBOSE_MSG, - ("WD179X: " ADDRESS_FORMAT " FMT Data Length = %d" NLP, PCX, wd179x_info->fdc_dataindex)); + sim_debug(VERBOSE_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FMT Data Length = %d\n", PCX, wd179x_info->fdc_dataindex); - TRACE_PRINT(FMT_MSG, - ("WD179X: " ADDRESS_FORMAT " FORMAT T:%d/H:%d/N:%d=%d/L=%d[%d] Fill=0x%02x" NLP, PCX, - pDrive->track, - wd179x_info->fdc_head, - wd179x_info->fdc_fmt_sector_count, - wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count], - wd179x_info->fdc_dataindex, - wd179x_info->fdc_sec_len, - sdata.raw[0])); + sim_debug(FMT_MSG, &wd179x_dev, "WD179X: " ADDRESS_FORMAT + " FORMAT T:%d/H:%d/N:%d=%d/L=%d[%d] Fill=0x%02x\n", PCX, + pDrive->track, wd179x_info->fdc_head, + wd179x_info->fdc_fmt_sector_count, + wd179x_info->fdc_sectormap[wd179x_info->fdc_fmt_sector_count], + wd179x_info->fdc_dataindex, wd179x_info->fdc_sec_len, sdata.raw[0]); wd179x_info->fdc_gap[1] = 0; wd179x_info->fdc_fmt_state = FMT_GAP2; diff --git a/HP2100/hp2100_baci.c b/HP2100/hp2100_baci.c index 779edf96..ac695f6a 100644 --- a/HP2100/hp2100_baci.c +++ b/HP2100/hp2100_baci.c @@ -1,6 +1,6 @@ /* hp2100_baci.c: HP 12966A buffered asynchronous communications interface simulator - Copyright (c) 2007-2008, J. David Bryan + Copyright (c) 2007-2011, J. David Bryan 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 @@ BACI 12966A BACI card + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines 11-Sep-08 JDB Fixed STC,C losing interrupt request on BREAK 07-Sep-08 JDB Fixed IN_LOOPBACK conflict with netinet/in.h @@ -320,11 +322,13 @@ /* BACI state variables */ -FLIP_FLOP baci_control = CLEAR; /* control flip-flop */ -FLIP_FLOP baci_flag = CLEAR; /* flag flip-flop */ -FLIP_FLOP baci_flagbuf = CLEAR; /* flag buffer flip-flop */ -FLIP_FLOP baci_srq = CLEAR; /* SRQ flip-flop */ -FLIP_FLOP baci_lockout = CLEAR; /* interrupt lockout flip-flop */ +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP srq; /* SRQ flip-flop */ + FLIP_FLOP lockout; /* interrupt lockout flip-flop */ + } baci = { CLEAR, CLEAR, CLEAR, CLEAR, CLEAR }; uint16 baci_ibuf = 0; /* status/data in */ uint16 baci_obuf = 0; /* command/data out */ @@ -372,7 +376,8 @@ static void clock_uart (void); /* BACI global routines */ -uint32 baci_io (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER baci_io; + t_stat baci_term_svc (UNIT *uptr); t_stat baci_poll_svc (UNIT *uptr); t_stat baci_reset (DEVICE *dptr); @@ -400,13 +405,14 @@ t_stat baci_detach (UNIT *uptr); ten millisecond period. */ -DIB baci_dib = { BACI, &baci_io }; +DIB baci_dib = { &baci_io, BACI, 0 }; DEVICE baci_dev; -UNIT baci_unit[] = - { { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */ - { UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } }; /* Telnet poll unit */ +UNIT baci_unit[] = { + { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */ + { UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */ + }; REG baci_reg[] = { { ORDATA (IBUF, baci_ibuf, 16), REG_FIT }, @@ -438,12 +444,12 @@ REG baci_reg[] = { { FLDATA (ENQFLAG, baci_enq_seen, 0), REG_HRO }, { DRDATA (ENQCNTR, baci_enq_cntr, 16), REG_HRO }, - { FLDATA (LKO, baci_lockout, 0) }, - { FLDATA (CTL, baci_control, 0) }, - { FLDATA (FLG, baci_flag, 0) }, - { FLDATA (FBF, baci_flagbuf, 0) }, - { FLDATA (SRQ, baci_srq, 0) }, - { ORDATA (DEVNO, baci_dib.devno, 6), REG_HRO }, + { FLDATA (LKO, baci.lockout, 0) }, + { FLDATA (CTL, baci.control, 0) }, + { FLDATA (FLG, baci.flag, 0) }, + { FLDATA (FBF, baci.flagbuf, 0) }, + { FLDATA (SRQ, baci.srq, 0) }, + { ORDATA (DEVNO, baci_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -526,232 +532,233 @@ DEVICE baci_dev = { would be cleared, and the interrupt would be lost. */ -uint32 baci_io (uint32 select_code, IOSIG signal, uint32 data) +uint32 baci_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); uint8 ch; +uint16 data; uint32 mask; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - baci_flag = baci_flagbuf = CLEAR; /* clear flag and flag buffer */ - baci_srq = CLEAR; /* clear SRQ */ + switch (signal) { /* dispatch I/O signal */ - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fputs (">>BACI cmds: [CLF] Flag and SRQ cleared\n", sim_deb); - - update_status (); /* FLG might set when SRQ clears */ - break; - - - case ioSTF: /* set flag flip-flop */ - baci_flag = baci_flagbuf = SET; /* set flag and flag buffer */ - baci_lockout = SET; /* set lockout */ - baci_srq = SET; /* set SRQ */ - - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb); - break; - - - case ioENF: /* enable flag */ - baci_flag = baci_flagbuf = SET; /* set device flag and flag buffer */ - baci_lockout = SET; /* set lockout */ - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (baci); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (baci); - break; - - - case ioIOI: /* I/O data input */ - if (baci_control) { /* control set? */ - baci_ibuf = TO_CHARCNT (baci_fcount); /* get FIFO count */ - - if (IO_MODE == RECV) /* receiving? */ - baci_ibuf = baci_ibuf | fifo_get (); /* add char and validity flag */ - - data = baci_ibuf; /* return received data */ - - if (DEBUG_PRI (baci_dev, DEB_CPU)) - fprintf (sim_deb, ">>BACI cpu: [LIx%s] Received data = %06o\n", hold_or_clear, data); - } - - else { /* control clear? */ - data = baci_status; /* return status */ - - if (DEBUG_PRI (baci_dev, DEB_CPU)) - fprintf (sim_deb, ">>BACI cpu: [LIx%s] Status = %06o\n", hold_or_clear, data); - } - break; - - - case ioIOO: /* I/O data output */ - if (DEBUG_PRI (baci_dev, DEB_CPU)) - fprintf (sim_deb, ">>BACI cpu: [OTx%s] Command = %06o\n", hold_or_clear, data); - - baci_obuf = data; - - if (baci_obuf & OUT_MR) { /* master reset? */ - master_reset (); /* do before processing */ - baci_io (select_code, ioSIR, 0); /* set interrupt request */ + case ioCLF: /* clear flag flip-flop */ + baci.flag = baci.flagbuf = CLEAR; /* clear flag and flag buffer */ + baci.srq = CLEAR; /* clear SRQ */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fprintf (sim_deb, ">>BACI cmds: [OTx%s] Master reset\n", hold_or_clear); - } + fputs (">>BACI cmds: [CLF] Flag and SRQ cleared\n", sim_deb); - switch (GET_ID (baci_obuf)) { /* isolate ID code */ + update_status (); /* FLG might set when SRQ clears */ + break; - case 0: /* transmit data */ - if (IO_MODE == XMIT) { /* transmitting? */ - ch = baci_obuf & OUT_DATA; /* mask to character */ - fifo_put (ch); /* queue character */ - if (baci_term.flags & UNIT_ATT) { /* attached to network? */ - if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */ - (sim_is_active (&baci_term) == 0)) /* service stopped? */ - fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, " - "time = %d\n", hold_or_clear, baci_term.wait); + case ioSTF: /* set flag flip-flop */ + baci.flag = baci.flagbuf = SET; /* set flag and flag buffer */ + baci.lockout = SET; /* set lockout */ + baci.srq = SET; /* set SRQ */ - if (baci_fcount == 1) /* first char to xmit? */ - sim_activate_abs (&baci_term, /* start service with full char time */ - baci_term.wait); - else - sim_activate (&baci_term, /* start service if not running */ - baci_term.wait); - } - } - break; + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb); + break; - case 1: /* enable device status interrupt */ - baci_edsiw = baci_obuf; /* load new enable word */ - update_status (); /* may have enabled an interrupt */ - break; - case 2: /* device status reference */ - if ((baci_term.flags & UNIT_DIAG) && /* diagnostic mode? */ - (baci_dsrw & OUT_DIAG) && /* and last DIAG was high? */ - !(baci_obuf & OUT_DIAG) && /* and new DIAG is low? */ - !(baci_icw & OUT_BAUDRATE)) /* and clock is external? */ - clock_uart (); /* pulse UART clock */ + case ioENF: /* enable flag */ + baci.flag = baci.flagbuf = SET; /* set device flag and flag buffer */ + baci.lockout = SET; /* set lockout */ + break; - baci_dsrw = baci_obuf; /* load new reference word */ - update_status (); /* clocking UART may interrupt */ - break; - case 3: /* character frame control */ - baci_cfcw = baci_obuf; /* load new frame word */ - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (baci); + break; - case 4: /* interface control */ - if ((baci_icw ^ baci_obuf) & OUT_BAUDRATE) { /* baud rate change? */ - baci_term.wait = service_time (baci_obuf); /* set service time to match rate */ - if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */ - if (baci_obuf & OUT_BAUDRATE) { /* internal baud rate requested? */ - sim_activate (&baci_term, /* activate I/O service */ - baci_term.wait); + case ioSFS: /* skip if flag is set */ + setstdSKF (baci); + break; - if (DEBUG_PRI (baci_dev, DEB_CMDS)) + + case ioIOI: /* I/O data input */ + if (baci.control) { /* control set? */ + baci_ibuf = TO_CHARCNT (baci_fcount); /* get FIFO count */ + + if (IO_MODE == RECV) /* receiving? */ + baci_ibuf = baci_ibuf | fifo_get (); /* add char and validity flag */ + + data = baci_ibuf; /* return received data */ + + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [LIx%s] Received data = %06o\n", hold_or_clear, baci_ibuf); + } + + else { /* control clear? */ + data = baci_status; /* return status */ + + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [LIx%s] Status = %06o\n", hold_or_clear, baci_status); + } + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + baci_obuf = IODATA (stat_data); /* get data value */ + + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [OTx%s] Command = %06o\n", hold_or_clear, baci_obuf); + + if (baci_obuf & OUT_MR) { /* master reset? */ + master_reset (); /* do before processing */ + baci_io (&baci_dib, ioSIR, 0); /* set interrupt request */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [OTx%s] Master reset\n", hold_or_clear); + } + + switch (GET_ID (baci_obuf)) { /* isolate ID code */ + + case 0: /* transmit data */ + if (IO_MODE == XMIT) { /* transmitting? */ + ch = baci_obuf & OUT_DATA; /* mask to character */ + fifo_put (ch); /* queue character */ + + if (baci_term.flags & UNIT_ATT) { /* attached to network? */ + if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */ + (sim_is_active (&baci_term) == 0)) /* service stopped? */ fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, " "time = %d\n", hold_or_clear, baci_term.wait); + + if (baci_fcount == 1) /* first char to xmit? */ + sim_activate_abs (&baci_term, /* start service with full char time */ + baci_term.wait); + else + sim_activate (&baci_term, /* start service if not running */ + baci_term.wait); } + } + break; - else { /* external rate */ - sim_cancel (&baci_term); /* stop I/O service */ + case 1: /* enable device status interrupt */ + baci_edsiw = baci_obuf; /* load new enable word */ + update_status (); /* may have enabled an interrupt */ + break; - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service stopped\n", - hold_or_clear); - } - } + case 2: /* device status reference */ + if ((baci_term.flags & UNIT_DIAG) && /* diagnostic mode? */ + (baci_dsrw & OUT_DIAG) && /* and last DIAG was high? */ + !(baci_obuf & OUT_DIAG) && /* and new DIAG is low? */ + !(baci_icw & OUT_BAUDRATE)) /* and clock is external? */ + clock_uart (); /* pulse UART clock */ - baci_icw = baci_obuf; /* load new reference word */ - update_status (); /* loopback may change status */ - break; + baci_dsrw = baci_obuf; /* load new reference word */ + update_status (); /* clocking UART may interrupt */ + break; - case 5: /* interrupt status reset */ - baci_isrw = baci_obuf; /* load new reset word */ + case 3: /* character frame control */ + baci_cfcw = baci_obuf; /* load new frame word */ + break; - mask = (baci_isrw & OUT_IRQCLR) << /* form reset mask */ - IN_V_IRQCLR; /* for common irqs */ + case 4: /* interface control */ + if ((baci_icw ^ baci_obuf) & OUT_BAUDRATE) { /* baud rate change? */ + baci_term.wait = service_time (baci_obuf); /* set service time to match rate */ - if (baci_isrw & OUT_CSC) /* add special char mask bit */ - mask = mask | IN_SPCHAR; /* if requested */ + if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */ + if (baci_obuf & OUT_BAUDRATE) { /* internal baud rate requested? */ + sim_activate (&baci_term, /* activate I/O service */ + baci_term.wait); - baci_status = baci_status & ~mask; /* clear specified status bits */ - break; + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, " + "time = %d\n", hold_or_clear, baci_term.wait); + } - case 6: /* special character */ - baci_spchar [baci_obuf & OUT_SPCHAR] = /* set special character entry */ - ((baci_obuf & OUT_SPFLAG) != 0); - break; - } - break; + else { /* external rate */ + sim_cancel (&baci_term); /* stop I/O service */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service stopped\n", + hold_or_clear); + } + } + + baci_icw = baci_obuf; /* load new reference word */ + update_status (); /* loopback may change status */ + break; + + case 5: /* interrupt status reset */ + baci_isrw = baci_obuf; /* load new reset word */ + + mask = (baci_isrw & OUT_IRQCLR) << /* form reset mask */ + IN_V_IRQCLR; /* for common irqs */ + + if (baci_isrw & OUT_CSC) /* add special char mask bit */ + mask = mask | IN_SPCHAR; /* if requested */ + + baci_status = baci_status & ~mask; /* clear specified status bits */ + break; + + case 6: /* special character */ + baci_spchar [baci_obuf & OUT_SPCHAR] = /* set special character entry */ + ((baci_obuf & OUT_SPFLAG) != 0); + break; + } + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ + case ioCRS: /* control reset */ + master_reset (); /* issue master reset */ - case ioCRS: /* control reset */ - master_reset (); /* issue master reset */ - - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb); - break; + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb); + break; - case ioCLC: /* clear control flip-flop */ - baci_control = CLEAR; /* clear control */ + case ioCLC: /* clear control flip-flop */ + baci.control = CLEAR; /* clear control */ - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fprintf (sim_deb, ">>BACI cmds: [CLC%s] Control cleared\n", hold_or_clear); - break; + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [CLC%s] Control cleared\n", hold_or_clear); + break; - case ioSTC: /* set control flip-flop */ - baci_control = SET; /* set control */ - baci_lockout = CLEAR; /* clear lockout */ + case ioSTC: /* set control flip-flop */ + baci.control = SET; /* set control */ + baci.lockout = CLEAR; /* clear lockout */ - if (DEBUG_PRI (baci_dev, DEB_CMDS)) - fprintf (sim_deb, ">>BACI cmds: [STC%s] Control set and lockout cleared\n", hold_or_clear); + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [STC%s] Control set and lockout cleared\n", hold_or_clear); - if (signal == ioSTC) /* STC without ,C ? */ - update_status (); /* clearing lockout might interrupt */ - break; + if (!(signal_set & ioCLF)) /* STC without ,C ? */ + update_status (); /* clearing lockout might interrupt */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, baci); /* set standard PRL signal */ - setstdIRQ (select_code, baci); /* set standard IRQ signal */ - setSRQ (select_code, baci_srq); /* set SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (baci); /* set standard PRL signal */ + setstdIRQ (baci); /* set standard IRQ signal */ + setSRQ (dibptr->select_code, baci.srq); /* set SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - baci_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + baci.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - baci_io (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - baci_io (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -931,7 +938,7 @@ while (recv_loop && /* OK to process? */ baci_uart_rhr = CLEAR_HR; /* clear RHR */ update_status (); /* update FIFO status (may set flag) */ - recv_loop = fast_timing && !IRQ (baci_dib.devno); /* loop if fast mode and no IRQ */ + recv_loop = fast_timing && !IRQ (baci_dib.select_code); /* loop if fast mode and no IRQ */ } else { /* xmit or ENQ/ACK, leave char in RHR */ @@ -1002,7 +1009,7 @@ return SCPE_OK; t_stat baci_reset (DEVICE *dptr) { -baci_io (baci_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&baci_dib); /* PRESET device (does not use PON) */ baci_ibuf = 0; /* clear input buffer */ baci_obuf = 0; /* clear output buffer */ @@ -1083,10 +1090,10 @@ baci_uart_rr = CLEAR_R; /* clear receiver regist baci_uart_clk = 0; /* clear UART clock */ baci_bcount = 0; /* clear break counter */ -baci_control = CLEAR; /* clear control */ -baci_flag = baci_flagbuf = SET; /* set flag and flag buffer */ -baci_srq = SET; /* set SRQ */ -baci_lockout = SET; /* set lockout flip-flop */ +baci.control = CLEAR; /* clear control */ +baci.flag = baci.flagbuf = SET; /* set flag and flag buffer */ +baci.srq = SET; /* set SRQ */ +baci.lockout = SET; /* set lockout flip-flop */ baci_edsiw = 0; /* clear interrupt enables */ baci_dsrw = 0; /* clear status reference */ @@ -1150,18 +1157,18 @@ if ((baci_status & IN_STDIRQ) || /* standard interrupt? * (baci_edsiw & OUT_ENCM) && /* and char mode */ (baci_fget != baci_fput)) { /* and FIFO not empty? */ - if (baci_lockout) { /* interrupt lockout? */ + if (baci.lockout) { /* interrupt lockout? */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: Lockout prevents flag set", sim_deb); } - else if (baci_srq) { /* SRQ set? */ + else if (baci.srq) { /* SRQ set? */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: SRQ prevents flag set", sim_deb); } else { - baci_io (baci_dib.devno, ioENF, 0); /* set flag */ + baci_io (&baci_dib, ioENF, 0); /* set flag */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: Flag and lockout set", sim_deb); @@ -1175,14 +1182,14 @@ if ((baci_icw & OUT_DCPC) && /* DCPC enabled? */ ((IO_MODE == XMIT) && (baci_fcount < 128) || /* and xmit and room in FIFO */ (IO_MODE == RECV) && (baci_fcount > 0))) { /* or recv and data in FIFO? */ - if (baci_lockout) { /* interrupt lockout? */ + if (baci.lockout) { /* interrupt lockout? */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: Lockout prevents SRQ set", sim_deb); } else { - baci_srq = SET; /* set SRQ */ - baci_io (baci_dib.devno, ioSIR, 0); /* set interrupt request */ + baci.srq = SET; /* set SRQ */ + baci_io (&baci_dib, ioSIR, 0); /* set interrupt request */ if (DEBUG_PRI (baci_dev, DEB_CMDS)) fputs (">>BACI cmds: SRQ set", sim_deb); diff --git a/HP2100/hp2100_bugfixes.txt b/HP2100/hp2100_bugfixes.txt index 71448791..68ef6e55 100644 --- a/HP2100/hp2100_bugfixes.txt +++ b/HP2100/hp2100_bugfixes.txt @@ -1,6 +1,6 @@ HP 2100 SIMULATOR BUG FIX WRITEUPS ================================== - Last update: 2008-09-30 + Last update: 2011-06-21 1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756 @@ -138,8 +138,8 @@ the "ex -u" and "ex -s" commands reveals the same data in both sets of locations. The "ex" command isn't using the DMS maps properly. - CAUSE: String constants are used instead of character constants, preventing - the DMS map switches from being recognized. + CAUSE: String constants are used instead of character constants, + preventing the DMS map switches from being recognized. RESOLUTION: Modify "hp2100_cpu.c" to use character constants rather than string constants in "dms_cons" so that DMS map switches work correctly. @@ -151,14 +151,14 @@ program. The EXEC target is below the MP fence, and the expected action is an MP violation interrupt that is recognized and processed by the system as a legal call to the system executive. However, the MP violation isn't - occurring, so the SJP instruction at the actual EXEC entry point (present to - catch EXEC calls made with the interrupt system off) is attempted, and that - causes the DM violation, due to execution of a protected instruction from - the user map. + occurring, so the SJP instruction at the actual EXEC entry point (present + to catch EXEC calls made with the interrupt system off) is attempted, and + that causes the DM violation, due to execution of a protected instruction + from the user map. CAUSE: Memory writes aren't being checked for an MP violation if DMS is - enabled, i.e., if DMS is enabled, and the page is writable, then whether the - target is below the MP fence is not checked. + enabled, i.e., if DMS is enabled, and the page is writable, then whether + the target is below the MP fence is not checked. RESOLUTION: Modify "hp2100_cpu.c" to do MP check on all writes after DMS translation and violation checks are done (so, to pass, the page must be @@ -430,7 +430,7 @@ RESOLUTION: Alter "ptr_svc" (hp2100_stddev.c) to fail if STOP_IOE is set, or to supply feed frames upon encountering the end of the attached file. "SET PTR TRLLIM" sets the maximum number of feed frames to supply. Note - that RTE needs at least 30 feed frames before signalling EOT. + that RTE needs at least 30 feed frames before signaling EOT. STATUS: Fixed in version 3.2-1. @@ -706,8 +706,8 @@ the simulator doesn't supply it explicitly in this case. The HP "7900A Disc Drive Operating and Service Manual" (07900-90002) says, - in section 4-67, "Attention is set high everytime a seek has been completed - and Access Ready comes high." + in section 4-67, "Attention is set high every time a seek has been + completed and Access Ready comes high." TSB code loads the "drive attention" word from the command channel to create a "request status" command. The code assumes that either bit 0 or bit 1 @@ -848,9 +848,9 @@ from issuing a WRITE command until the first data is requested). Most of these are reported as diagnostic failures. - CAUSE: I/O time modelling is not done properly. In some cases, the times + CAUSE: I/O time modeling is not done properly. In some cases, the times indicated are incorrect. In others, certain characteristics (e.g., that - operations from BOT take longer, due to the initial gap) aren't modelled at + operations from BOT take longer, due to the initial gap) aren't modeled at all. RESOLUTION: Revise "mscio" and "msc_svc" (hp2100_ms.c) to model actual I/O @@ -1200,12 +1200,13 @@ ready (i.e., when the unit is attached). CAUSE: Section 4-67 of the "7900A Disc Drive Operating and Service Manual" - (HP 07900-90002) says, "Attention is set high everytime a seek has completed - and Access Ready comes high." This includes the initial head-loading seek - when the drive becomes ready. The "Troubleshooting Diagrams (Sheet 2 of 4)" - on page 5-17 show that after the heads load, Drive Ready, First Status, - Access Ready (a.k.a. not Busy), and Attention are asserted. The - corresponding code in "dpc_attach" sets First Status but not Attention. + (HP 07900-90002) says, "Attention is set high every time a seek has + completed and Access Ready comes high." This includes the initial + head-loading seek when the drive becomes ready. The "Troubleshooting + Diagrams (Sheet 2 of 4)" on page 5-17 show that after the heads load, Drive + Ready, First Status, Access Ready (a.k.a. not Busy), and Attention are + asserted. The corresponding code in "dpc_attach" sets First Status but not + Attention. In addition, the last diagnostic command prior to the loop is a STATUS CHECK. This leaves the 13210A interface polling for attention bits, and @@ -1332,7 +1333,7 @@ - 51. PROBLEM: The diagnostic configurator mis-identifies the host CPU. + 51. PROBLEM: The diagnostic configurator misidentifies the host CPU. VERSION: 3.2-3 @@ -1509,7 +1510,7 @@ missing the option to indicate that commas are glyph separators. RESOLUTION: Modify the appropriate calls to "get_glyph" (scp.c, - sim_console.c) to specify ',' as the the "optional end of glyph character" + sim_console.c) to specify ',' as the "optional end of glyph character" parameter. STATUS: Fixed in version 3.3-0. @@ -2154,7 +2155,7 @@ conclusion of writes when using the 12606 interface. This is an artifact of the interface design. - CAUSE: The status return from the 12606 interface is not modelled properly. + CAUSE: The status return from the 12606 interface is not modeled properly. RESOLUTION: Modify "drv_svc" (hp2100_dr.c) to return DRS_PER at the conclusion of writes when configured as a 2770/2771 disk. @@ -2542,7 +2543,7 @@ Section I, Paragraph 4-17, "Store Field", of the "HP 1000 M/E/F-Series Computers Engineering and Reference Documentation" (HP 92851-90001) says: - "The A and B addressable flip-slops (ABFF) [38A] can be clocked at the + "The A and B addressable flip-flops (ABFF) [38A] can be clocked at the end of every microcycle. Addresses 0 and 1 are detected on the M-bus and the flip-flops are set accordingly. When DCPC uses the M-bus the ABFFST signal is suppressed." @@ -3867,7 +3868,7 @@ the terminal multiplexer. RESOLUTION: Modify the "ioEDT" handler in "iplio" (hp2100_ipl.c) to sleep - for one millisecond before signalling a DMA completion interrupt for an + for one millisecond before signaling a DMA completion interrupt for an output transfer. This allows the SP time to pulse the IPL before the IOP processes the DMA completion interrupt. Modify "dma_cycle" (hp2100_cpu.c) to pass the DMA channel number and I/O direction flag in the "dat" @@ -4711,7 +4712,7 @@ 191. PROBLEM: The action of certain I/O cards (e.g., the 12936A Privileged - Interrupt Fence) cannot be modelled by SIMH. + Interrupt Fence) cannot be modeled by SIMH. VERSION: 3.8-0 @@ -4722,7 +4723,7 @@ CAUSE: The hardware has I/O signals for interrupt request (IRQ) and interrupt priority to lower-priority devices (PRL). These signals are not - modelled directly in SIMH. Rather, they are implied by control, flag, and + modeled directly in SIMH. Rather, they are implied by control, flag, and flag buffer set (for IRQ) and control and flag set (for PRL). If an I/O card does not follow these conventions, then the proper action cannot be simulated. @@ -5065,7 +5066,7 @@ VERSION: 3.8-0 OBSERVATION: The A and B register values are stored in two places: as - "uint16 ABREG[2]" duing execution, and as "uint32 saved_AR" and "uint32 + "uint16 ABREG[2]" during execution, and as "uint32 saved_AR" and "uint32 saved_BR" between executions. The latter was to accommodate the requirement that register variables must be 32 bits in size. That requirement was removed in version 3.5-2 for registers declared with the @@ -5208,10 +5209,10 @@ VERSION: 3.8-0 - OBSERVATION: Page 2-6 of the 12559A 9-Track Magnetic Tape Unit Interface - Kit Operating and Service Manual says that the CLR command channel flag - flip-flop when the command completes. The MT simulator does not, so the - command channel does not interrupt. + OBSERVATION: Page 2-5 of the 12559A 9-Track Magnetic Tape Unit Interface + Kit Operating and Service Manual says that the command channel flag + flip-flop sets when the CLR command completes. The MT simulator does not + do this, so the command channel does not interrupt. CAUSE: Coding error. @@ -5319,7 +5320,7 @@ This second interrupt would normally be allowed, as the STC sc,C instruction clears the "interrupt lockout" flag that was set when the first - interupt was generated. However, the STC signal handler checks for + interrupt was generated. However, the STC signal handler checks for interrupt status between the STC and the succeeding CLF, rather than after the CLF. The result is that the STC clears lockout, then the FIFO status sets the flag and lockout, and then the CLF clears the flag, leaving @@ -5351,3 +5352,554 @@ to the "interrupt trap cell" execution path. STATUS: Fixed in version 3.8-1. + + + +213. PROBLEM: A DO command without a filename prints the wrong error message. + + VERSION: 3.8-1 + + OBSERVATION: The DO command requires a file argument and zero or more + parameter arguments. Entering DO without the file argument should print + "Too few arguments," as other commands that require arguments do (e.g., + ATTACH, BOOT, etc.). Instead, it prints "File open error." + + CAUSE: A test in "do_cmd" attempts to detect when no arguments are passed + and return SCPE_2FARG in response, but the test always fails. As a result, + "fopen" is called with a NULL filename parameter. The call fails, + resulting in the "File open error" message. + + The test follows the initialization of the "do_arg" array and depends on + initialization stopping when a null argument is encountered. The bug fix + of 25-Jul-2008 ("DO cmd missing params now default to null string") + modified "do_arg" initialization to cover the entire array. Therefore, the + test to determine if "do_arg" was not initialized (which implies that the + file argument was not passed) never trips. + + RESOLUTION: Modify "do_arg" (scp.c) to test "do_arg[0]" for NULL and to + return SCPE_2FARG if so. + + STATUS: Fixed in version 3.8-2. + + + +214. PROBLEM: DMA/DCPC cannot steal consecutive I/O cycles. + + VERSION: 3.8-1 + + OBSERVATION: All DMA and DCPC cards are capable of stealing consecutive + I/O cycles, presuming that SRQ is asserted at the proper time before each + cycle. The current SIMH implementation of DMA/DCPC is capable of stealing + only every other cycle, even if SRQ is asserted continuously. The 12821A + Disc Interface diagnostic checks for consecutive cycle-steal capability and + fails when run. + + CAUSE: Each pass through the instruction simulation loop does a device + timeout check, then a potential DMA cycle, and then an instruction cycle. + The device timeout calls the card unit service routine, which sets SRQ and + schedules the next service. The SRQ is then processed with the DMA cycle, + which dispatches ioIOI/IOO and ioCLF to the device. At the end of the DMA + cycle, the next instruction is executed. + + A device capable of transferring data continuously would leave SRQ asserted + after the I/O cycle. But because SRQ is not checked after the DMA cycle, + the next instruction execution is performed unconditionally. Therefore, + even with continuous SRQ assertion, the simulator will interleave DMA + cycles and instructions. + + RESOLUTION: Modify the instruction execution loop (hp2100_cpu.c) to + recalculate SRQ requests after each DMA cycle, and if a request is still + pending, skip instruction execution. This allows consecutive DMA cycles + without intervening instruction executions if SRQ is asserted continuously. + + STATUS: Fixed in version 3.8-2. + + + +215. PROBLEM: DMA/DCPC does not give priority to channel 1 during contention. + + VERSION: 3.8-1 + + OBSERVATION: Dual-channel DMA/DCPC cards give priority to channel 1 if + both channels are requesting a DMA cycle. If channel 1 SRQ is asserted + continuously, then no channel 2 cycles will occur until channel 1 + completes. + + Under simulation, channel cycle requests alternate unconditionally. If + channel 2 requests a DMA cycle, it will always be granted, regardless of + any pending channel 1 requests. + + CAUSE: Each pass through the instruction simulation loop checks for a + channel 1 request and then a channel 2 request, dispatching DMA cycles as + indicated. The check for a channel 2 request should not occur if a channel + 1 request is still pending at the end of its DMA cycle. + + RESOLUTION: Modify the instruction execution loop (hp2100_cpu.c) to + inhibit DMA channel 2 if a channel 1 request is still pending after a + channel 1 cycle. + + STATUS: Fixed in version 3.8-2. + + + +216. ENHANCEMENT: Rename DMA channels 0 and 1 to 1 and 2 to match the + documentation. + + VERSION: 3.8-1 + + OBSERVATION: The HP 2100 simulator presents DMA0 and DMA1 as the DMA + devices. However, all HP literature refers to these as channel 1 and + channel 2. + + RESOLUTION: Modify the device names (hp2100_cpu.c, hp2100_defs.h, and + hp2100_sys.c) from 0 and 1 to 1 and 2 to align with HP usage. + + STATUS: Fixed in version 3.8-2. + + + +217. PROBLEM: The comments for "cpu_set_idle" (hp2100_cpu.c) are obsolete. + + VERSION: 3.8-1 + + OBSERVATION: The comments for the above routine note the requirement for + clock stabilization. This was added in 3.8-1, but the comments were not + changed. + + CAUSE: Oversight. + + RESOLUTION: Removed obsolete comments. + + STATUS: Fixed in version 3.8-2. + + + +218. PROBLEM: The 12578A DMA device is modeled incorrectly. + + VERSION: 3.8-1 + + OBSERVATION: The 12578A DMA device simulation incorporates a latency + counter that delays the first DMA cycle for one instruction after the STC + is issued to enable the channel. This is incorrect; if SRQ is already + asserted, the first cycle occurs immediately after the channel is enabled. + + CAUSE: Incorrect understanding. + + RESOLUTION: Modify hp2100_cpu.c to remove the latency counter. + + STATUS: Fixed in version 3.8-2. + + + +219. PROBLEM: DMA IOO and CLF/EDT signals are not concurrent. + + VERSION: 3.8-1 + + OBSERVATION: A DMA transfer to the 12821A Disc Interface should not set + the end-of-data-transfer flip-flop on the DI card until the last word has + been sent. Instead, each word transferred sets the flip-flop. + + CAUSE: In the packed output mode, the end-of-data-transfer flip-flop is + set either if the the OTx instruction does not clear the flag (i.e., if OTA + used instead of OTA,C), or if the DMA EDT signal is asserted. DMA + transfers are programmed to clear the flag with each write to prevent the + flip-flop from setting until the EDT signal asserts when the last word is + output. + + In hardware, CLF or EDT is asserted concurrently with IOO. In simulation, + "dma_cycle" calls the device's I/O signal handler with ioIOO, then with + ioCLF, and then, for the last cycle only, with ioEDT. At the time that the + handler receives ioIOO, it has no way of knowing whether ioCLF will follow. + Therefore, the DI sets its end-of-data-transfer flip-flop on the first word + transferred instead of on the last word transferred. + + The fundamental problem is that DMA hardware may assert multiple concurrent + signals, upon which I/O card designs may test and act, but simulation + serializes the signals and therefore prevents concurrency detection. + + RESOLUTION: Modify "dma_cycle" (hp2100_cpu.c) to send one set of + concurrent I/O signals to the target handler for each DMA I/O cycle, and + modify all I/O device handlers to allow processing of multiple concurrent + signals. + + STATUS: Fixed in version 3.8-2. + + + +220. ENHANCEMENT: Enhance the I/O signal dispatcher to provide for multiple + devices controlled by the same device signal handler. + + VERSION: 3.8-1 + + OBSERVATION: Currently, the DCPC, IPL, and DI simulations control multiple + devices. The first two control a pair of devices each and determine the + desired device by checking the select code. The DI will control three, + complicating the test that would have to be done at each signal handler + entry. + + RESOLUTION: Modify "devdisp" (hp2100_cpu.c) to pass the Device Information + Block (DIB) pointer instead of the select code to device signal handlers, + and modify all signal handlers accordingly. Modify all device DIBs to add + card numbers to allow for multiple-device handlers. + + STATUS: Fixed in version 3.8-2. + + + +221. PROBLEM: The LPS diagnostic mode is modeled incorrectly. + + VERSION: 3.8-1 + + OBSERVATION: The 12578A DMA simulation was modified to remove the latency + from enabling a channel to issuing the first DMA cycle. After this change + was made, the card failed DMA diagnostic test 17. + + CAUSE: The LPS device offers a diagnostic mode that simulates a 12566B + Microcircuit Interface card equipped with a loopback connector. This + configuration is used for a number of diagnostics that require an I/O card + in addition to the card under test. Typically, this is to test I/O or + interrupt capability. Jumpers on the card configure it for the diagnostic + response expected. The SET LPS DIAG mode configures the card properly for + all diagnostics except the 12578A DMA diagnostic. + + SET LPS DIAG simulates jumper W1 in position C and W2 in position B. In + these positions, an STC will set the card flag one instruction later. When + used for a DMA transfer, instructions and DMA cycles will interleave 1:1, + i.e., DMA will steal every other cycle. + + The 12578A diagnostic requires jumper W1 in position B and W2 in position + C. In these positions, an STC will set the card flag two instructions + later, so DMA will steal every third cycle, allowing two instructions + between DMA cycles. The 12578A diagnostic depends on this and will report + errors otherwise. + + RESOLUTION: Modify "lpsio" (hp2100_lps.c) to schedule device service in + DIAG mode in three instructions if the CPU is a 2114, 2115, or 2116 and in + two instructions otherwise. + + STATUS: Fixed in version 3.8-2. + + + +222. PROBLEM: The 12821A Disc Interface diagnostic aborts with "Unit not + attached." + + VERSION: 3.8-1 + + OBSERVATION: The 12821A Disc Interface diagnostic locates the card to test + by issuing a CLC sc,C / OTA sc / LIA sc sequence to each card in the card + cage; this writes a zero value and then looks for a specific response that + is characteristic of the DI. When the zero value is written to the MT + device (HP 3030 tape drive), it responds with "Unit not attached." + + CAUSE: The MT device is unusual in that commands are executed when they + are written to the card, rather than in response to STC. Therefore, when + the zero value is written, the MT device attempts to interpret that value + as a command. + + The IOO processor checks for a valid command before proceeding. Zero is + not a valid command, but the check is not coded properly. The search + through the command table loops for the number of bytes in the table, not + for the number of entries. One of the values beyond the end of the table + equals zero, so the command is considered valid, and unit service is + scheduled. The unit service routine determines that the unit is not + attached and returns an error code, causing a simulator stop. + + RESOLUTION: Modify "mtcio" (hp2100_mt.c) to use the count of command table + entries as the loop count. + + STATUS: Fixed in version 3.8-2. + + + +223. ENHANCEMENT: Consolidate reporting of consecutive CRS signals. + + VERSION: 3.8-1 + + OBSERVATION: HP 2000 Time Shared BASIC begins its start sequence by + issuing 128K CLC 0 instructions. This sequence is required by the 12920A + Terminal Multiplexer. If debugging is enabled, the IPL device writes 128K + lines to the log file. It would be more helpful if the ioCRS processor + detected consecutive calls and summarized them in a single line. + + RESOLUTION: Modify "iplio" (hp2100_ipl.c) to add a CRS invocation counter + and to report a single debug line for consecutive CRS calls. + + STATUS: Fixed in version 3.8-2. + + + +224. PROBLEM: Simulation stops are ignored during DMA cycles. + + VERSION: 3.8-1 + + OBSERVATION: An I/O routine may return an error code other than SCPE_OK to + stop the simulator. For example, IPL may return SCPE_IOERR if STC is + issued to a card with a disconnected socket. If the device is invoked via + programmed I/O, an error value return will cause a simulation stop. If the + device is invoked by DMA, it will not. + + CAUSE: The "iogrp" function returns the status code to the instruction + loop, but the "dma_cycle" function ignores status returns from the I/O + handlers. + + RESOLUTION: Modify "dma_cycle" (hp2100_cpu.c) to return the status from + the device signal handler, and modify "sim_instr" to stop instruction + execution if the returned status is not SCPE_OK. + + STATUS: Fixed in version 3.8-2. + + + +225. PROBLEM: Simulation stops do not always preserve the CPU state for + restarting. + + VERSION: 3.8-1 + + OBSERVATION: If the CPU simulator is stopped by certain errors, e.g., an + unimplemented instruction execution, simulation control returns with the + CPU state set as it was just prior to the error. This allows the error to + be corrected and simulation to be resumed. It also allows identification + of the problem instruction. + + Other errors, e.g., SCPE_IOERR returned by the IPL device signal handler, + stop the CPU after processing the offending instruction. In this case, the + PC points to the instruction after the offending instruction, so + identification, correction, and resumption are more difficult. DMA cycles + are also affected, as DMA registers are updated even if the I/O cycle + fails. + + CAUSE: The CPU instruction and DMA cycle routines do not back out properly + when a simulation stop is indicated by a device signal handler. + + RESOLUTION: Modify "sim_instr" (hp2100_cpu.c) to back out the current + instruction if it indicates a simulation stop (except for the HLT + instruction), modify "dma_cycle" to update the address and word count only + if the I/O cycle completes successfully, and modify "iplio" (hp2100_ipl.c) + to allow for restarting of a failed I/O cycle. + + STATUS: Fixed in version 3.8-2. + + + +226. PROBLEM: The comments for the floating-point divide routine are + incomplete. + + VERSION: 3.8-1 + + OBSERVATION: In the comments for the "divide" function in "hp2100_fp1.c", + the explanation of the simulation implementation trails off with, "The + resulting 32-bit quotient is ..." It appears that the comments were never + finished before release. + + CAUSE: Oversight. + + RESOLUTION: Expanded and completed the comments in the "divide" function + (hp2100_fp1.c). + + STATUS: Fixed in version 3.8-2. + + + +227. PROBLEM: The 79xx disc returns incorrect status for a disabled drive. + + VERSION: 3.8-1 + + OBSERVATION: The same "unit present; heads unloaded" status is reported + for both an enabled but unattached unit and a disabled unit. The latter + should report "unit not present" status. + + CAUSE: SIMH initially defines the DS device as having eight 7905 drives + connected to the controller. Each drive reports "heads unloaded" status + (status-2 bits 1-0 = 11) until it has a disc image attached. If a unit is + disabled, it continues to report "heads unloaded" status. It should be + reporting "unit not present" (status-2 bits 1-0 = 10) status. + + RESOLUTION: Modify "ds_updds2" (hp2100_ds.c) to report an "enabled and + unloaded" condition as Not Ready and Busy, and a "disabled" condition as + Not Ready only. + + STATUS: Fixed in version 3.8-2. + + + +228. PROBLEM: The 79xx disc returns incorrect status for an auto-seek beyond + the drive limits. + + VERSION: 3.8-1 + + OBSERVATION: When an auto-seek causes the disc address to move beyond the + drive limits, the wrong status is returned. For example, the following + OPDSN program: + + SM,3 -- set file mask to auto-seek, cylinder mode, incremental + SK,410,2,47 -- seek to last sector of the drive + RD,256 -- read two sectors + EN + + ...results in Cylinder Compare Error status; status-2 shows a seek check. + The result is identical if SM,1 (surface auto-seek, rather than cylinder + auto-seek) is used. + + If the RD,256 is replaced by RF,276, the result is Normal Completion and a + seek check. The resulting disc address is 411,0,1. + + If decremental seeks are used: + + SM,13 -- set file mask to auto-seek, cylinder mode, decremental + SK,0,2,47 -- seek to last sector of the first cylinder + RD,256 -- read two sectors + EN + + ...the status return is the same as above. + + In each of these cases, the result should be Status-2 (Seek Check) on the + second sector transfer. + + CAUSE: If an auto-seek exceeds the drive bounds, a seek check is correctly + detected, but it is not reported back to the host. + + RESOLUTION: Modify "ds_start_rw" (hp2100_ds.c) to check for Seek Check on + an auto-seek and to report Status-2 if set. Also, a reseek resulting from + a cylinder miscompare now either succeeds if the cylinder is valid or + reports Status-2 and Seek Check if the cylinder is invalid. Finally, an + invalid head or sector value reports Status-2 and Seek Check instead of + Head-Sector Compare Error (Head-Sector and Cylinder Compare Errors can only + occur during sparing operations which are not supported in simulation). + + STATUS: Fixed in version 3.8-2. + + + +229. PROBLEM: The Read Without Verify command does not verify the address when a + track boundary is crossed. + + VERSION: 3.8-1 + + OBSERVATION: The Read Without Verify command is identical to the Read + command except that it skips address verification before beginning the + read. If the read continues past a track boundary and auto-seek is + enabled, the new track location should be verified. This does not occur. + The following OPDSN program illustrates the problem: + + SM,3 -- set file mask to auto-seek, cylinder mode, incremental + SK,0,0,47 -- seek to last sector on cylinder 0 head 0 + DB,128,000047 -- fill the sector buffer with the CHS address + WD,128 -- write sector 0/0/47 + DB,128,000100 -- fill the sector buffer with the CHS address + WD,128 -- write sector 0/1/0 + SK,1,0,47 -- seek to the last sector on cylinder 1 head 0 + DB,128,100047 -- fill the sector buffer with the CHS address + WD,128 -- write sector 1/0/47 + DB,128,100100 -- fill the sector buffer with the CHS address + WD,128 -- write sector 1/1/0 + SK,0,0,47 -- seek to last sector on cylinder 0 head 0 + AR,1,0,47 -- change controller address to cylinder 1 + RW,256 -- read two sectors + DR,120,135 -- display end of first sector and start of second sector + EN + + If address verification is performed at the end of track 0, the second + sector will be read from 1,1,0 instead of 0,1,0 because of the cylinder + miscompare after the auto-seek: + + 0120: 000047 000047 000047 000047 000047 000047 000047 000047 + 0128: 100100 100100 100100 100100 100100 100100 100100 100100 + + However, the above program prints: + + 0120: 000047 000047 000047 000047 000047 000047 000047 000047 + 0128: 000100 000100 000100 000100 000100 000100 000100 000100 + + ...indicating that address verification was not done for either sector. + Note that if the Read Without Verify above is changed to Read (RD,256), the + result is: + + 0120: 100047 100047 100047 100047 100047 100047 100047 100047 + 0128: 100100 100100 100100 100100 100100 100100 100100 100100 + + ...indicating that address verification was done correctly for the first + sector. + + CAUSE: The Read Without Verify handler disables address verification for + the entire transfer. It should be disabled only until a track switch + occurs. + + RESOLUTION: Modify the Read Without Verify command handler in "ds_svc_u" + (hp2100_ds.c) to begin verifying if a track boundary is crossed. + + STATUS: Fixed in version 3.8-2. + + + +230. PROBLEM: The Request Sector Address command does not check the unit + number. + + VERSION: 3.8-1 + + OBSERVATION: The Request Sector Address command accepts invalid, unloaded, + or missing units without reporting status errors. Also, the specified unit + number is not reported in the status-1 field of a subsequent Request Status + command. Assuming that unit "ds1" is not attached (heads unloaded) and + unit "ds2" is disabled, the following OPDSN programs illustrate the + problem: + + SD,1 + RA + ST + SC,0001001100000001,1XXXXXX000X00011 + DR,0 + EN + + SD,2 + RA + ST + SC,0001001100000010,1XXXXXX000X00010 + DR,0 + EN + + SD,10 + RA + ST + SC + DR,0 + EN + + All of these should return Status-2 but instead return Normal Completion. + + SD,15 + RA + ST + SC,0001011100001111,1XXXXXX000X00010 + DR,0 + EN + + This should return Unit Unavailable but instead returns Normal Completion. + + CAUSE: The Request Sector Address command handler is not checking the unit + range or status. + + RESOLUTION: Modify "ds_docmd" (hp2100_ds.c) to set the unit number into + the status-1 field and to check for invalid units and report Unit + Unavailable if so. Modify "ds_svc_u" to check that the heads are loaded on + the target unit and report Status-2 if not. + + STATUS: Fixed in version 3.8-2. + + + +231. PROBLEM: The Wakeup command does not check the unit number. + + VERSION: 3.8-1 + + OBSERVATION: The Wakeup command accepts invalid units without reporting + status errors. Also, the specified unit number is not reported in the + status-1 field of a subsequent Request Status command. + + CAUSE: The Wakeup command handler is not checking the unit range. + + RESOLUTION: Modify "ds_docmd" (hp2100_ds.c) to set the unit number into + the status-1 field and to check for invalid units and report Unit + Unavailable if so. + + STATUS: Fixed in version 3.8-2. diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 8a20b98e..0f7331b5 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -1,6 +1,6 @@ /* hp2100_cpu.c: HP 21xx/1000 CPU simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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,9 +26,21 @@ CPU 2114C/2115A/2116C/2100A/1000-M/E/F central processing unit 12731A memory expansion module MP 12581A/12892B memory protect - DMA0,DMA1 12607B/12578A/12895A direct memory access controller - DCPC0,DCPC1 12897B dual channel port controller + DMA1,DMA2 12607B/12578A/12895A direct memory access controller + DCPC1,DCPC2 12897B dual channel port controller + 07-Apr-11 JDB Fixed I/O return status bug for DMA cycles + Failed I/O cycles now stop on failing instruction + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB Revised DMA for new multi-card paradigm + Consolidated DMA reset routines + DMA channels renamed from 0,1 to 1,2 to match documentation + 27-Oct-10 JDB Changed I/O instructions, handlers, and DMA for revised signal model + Changed I/O dispatch table to use DIB pointers + 19-Oct-10 JDB Removed DMA latency counter + 13-Oct-10 JDB Fixed DMA requests to enable stealing every cycle + Fixed DMA priority for channel 1 over channel 2 + Corrected comments for "cpu_set_idle" 30-Sep-08 JDB Breakpoints on interrupt trap cells now work 05-Sep-08 JDB VIS and IOP are now mutually exclusive on 1000-F 11-Aug-08 JDB Removed A/B shadow register variables @@ -442,22 +454,31 @@ /* DMA channels */ +typedef enum { ch1, ch2 } CHANNEL; /* channel number */ + +#define DMA_CHAN_COUNT 2 /* number of DMA channels */ + #define DMA_OE 020000000000 /* byte packing odd/even flag */ #define DMA1_STC 0100000 /* DMA - issue STC */ #define DMA1_PB 0040000 /* DMA - pack bytes */ #define DMA1_CLC 0020000 /* DMA - issue CLC */ #define DMA2_OI 0100000 /* DMA - output/input */ -struct DMA { /* DMA channel */ - uint32 cw1; /* device select */ - uint32 cw2; /* direction, address */ - uint32 cw3; /* word count */ - uint32 latency; /* 1st cycle delay */ - uint32 packer; /* byte-packer holding reg */ - }; +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP xferen; /* transfer enable flip-flop */ + FLIP_FLOP select; /* register select flip-flop */ -#define DMAR0 1 -#define DMAR1 2 + uint32 cw1; /* device select */ + uint32 cw2; /* direction, address */ + uint32 cw3; /* word count */ + uint32 packer; /* byte-packer holding reg */ + } DMA_STATE; + +#define DMA_1_REQ (1 << ch1) /* channel 1 request */ +#define DMA_2_REQ (1 << ch2) /* channel 2 request */ /* Command line switches */ @@ -525,12 +546,7 @@ jmp_buf save_env; /* MP abort handler */ /* DMA global data */ -struct DMA dmac[2] = { { 0 }, { 0 } }; /* DMA channels */ -FLIP_FLOP dma_xferen [2] = { CLEAR, CLEAR }; /* transfer enable flip-flops */ -FLIP_FLOP dma_control [2] = { CLEAR, CLEAR }; /* control flip-flops */ -FLIP_FLOP dma_flag [2] = { CLEAR, CLEAR }; /* flag flip-flops */ -FLIP_FLOP dma_flagbuf [2] = { CLEAR, CLEAR }; /* flag buffer flip-flops */ -FLIP_FLOP dma_select [2] = { CLEAR, CLEAR }; /* register select flip-flops */ +DMA_STATE dma [DMA_CHAN_COUNT]; /* per-channel state */ /* Dynamic mapping system global data */ @@ -558,10 +574,10 @@ static t_stat Ea (uint32 IR, uint32 *addr, uint32 irq); static uint16 ReadTAB (uint32 va); static uint32 dms (uint32 va, uint32 map, uint32 prot); static uint32 shift (uint32 inval, uint32 flag, uint32 oper); -static void dma_cycle (uint32 chan, uint32 map); +static t_stat dma_cycle (CHANNEL chan, uint32 map); static uint32 calc_dma (void); static t_bool dev_conflict (void); -static uint32 devdisp (uint32 select_code, IOSIG signal, uint32 data); +static uint32 devdisp (uint32 select_code, IOCYCLE signal_set, uint16 data); /* CPU global routines */ @@ -570,8 +586,7 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_boot (int32 unitno, DEVICE *dptr); t_stat mp_reset (DEVICE *dptr); -t_stat dma0_reset (DEVICE *dptr); -t_stat dma1_reset (DEVICE *dptr); +t_stat dma_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc); t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc); t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); @@ -582,13 +597,13 @@ t_stat cpu_set_idle (UNIT *uptr, int32 option, char *cptr, void *desc); t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc); void hp_post_cmd (t_bool from_scp); -uint32 cpuio (uint32 select_code, IOSIG signal, uint32 data); -uint32 ovflio (uint32 select_code, IOSIG signal, uint32 data); -uint32 pwrfio (uint32 select_code, IOSIG signal, uint32 data); -uint32 protio (uint32 select_code, IOSIG signal, uint32 data); -uint32 dmasio (uint32 select_code, IOSIG signal, uint32 data); -uint32 dmapio (uint32 select_code, IOSIG signal, uint32 data); -uint32 nullio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER cpuio; +IOHANDLER ovflio; +IOHANDLER pwrfio; +IOHANDLER protio; +IOHANDLER dmapio; +IOHANDLER dmasio; +IOHANDLER nullio; /* External routines */ @@ -652,8 +667,13 @@ static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx }; +/* Null device information block */ + +DIB null_dib = { &nullio, 0 }; + /* CPU data structures + cpu_dib CPU device information block cpu_dev CPU device descriptor cpu_unit CPU unit descriptor cpu_reg CPU register list @@ -661,6 +681,8 @@ static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx cpu_deb CPU debug flags */ +DIB cpu_dib = { &cpuio, CPU }; + UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 0) }; REG cpu_reg[] = { @@ -815,13 +837,21 @@ DEVICE cpu_dev = { &cpu_boot, /* boot routine */ NULL, /* attach routine */ NULL, /* detach routine */ - NULL, /* device information block */ + &cpu_dib, /* device information block */ DEV_DEBUG, /* device flags */ 0, /* debug control flags */ cpu_deb, /* debug flag name table */ NULL, /* memory size change routine */ NULL }; /* logical device name */ +/* Overflow device information block */ + +DIB ovfl_dib = { &ovflio, OVF }; + +/* Powerfail device information block */ + +DIB pwrf_dib = { &pwrfio, PWR }; + /* Memory protect data structures mp_dib MP device information block @@ -831,7 +861,7 @@ DEVICE cpu_dev = { mp_mod MP modifiers list */ -DIB mp_dib = { PRO, &protio }; +DIB mp_dib = { &protio, PRO }; UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) }; /* default is JSB in, INT in, SEL1 out */ @@ -887,65 +917,22 @@ DEVICE mp_dev = { dmax_reg DMAx register list */ -DIB dma0_dib = { DMA0, &dmapio }; - -UNIT dma0_unit = { UDATA (NULL, 0, 0) }; - -REG dma0_reg[] = { - { FLDATA (XFR, dma_xferen [0], 0) }, - { FLDATA (CTL, dma_control [0], 0) }, - { FLDATA (FLG, dma_flag [0], 0) }, - { FLDATA (FBF, dma_flagbuf [0], 0) }, - { FLDATA (CTL2, dma_select [0], 0) }, - { ORDATA (CW1, dmac[0].cw1, 16) }, - { ORDATA (CW2, dmac[0].cw2, 16) }, - { ORDATA (CW3, dmac[0].cw3, 16) }, - { DRDATA (LATENCY, dmac[0].latency, 8) }, - { FLDATA (BYTE, dmac[0].packer, 31) }, - { ORDATA (PACKER, dmac[0].packer, 8) }, - { NULL } - }; - -DEVICE dma0_dev = { - "DMA0", /* device name */ - &dma0_unit, /* unit array */ - dma0_reg, /* register array */ - NULL, /* modifier array */ - 1, /* number of units */ - 8, /* address radix */ - 1, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 16, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &dma0_reset, /* reset routine */ - NULL, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &dma0_dib, /* device information block */ - DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - NULL, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - -DIB dma1_dib = { DMA1, &dmapio }; +DIB dmap1_dib = { &dmapio, DMA1, ch1 }; +DIB dmas1_dib = { &dmasio, DMALT1, ch1 }; UNIT dma1_unit = { UDATA (NULL, 0, 0) }; REG dma1_reg[] = { - { FLDATA (XFR, dma_xferen [1], 0) }, - { FLDATA (CTL, dma_control [1], 0) }, - { FLDATA (FLG, dma_flag [1], 0) }, - { FLDATA (FBF, dma_flagbuf [1], 0) }, - { FLDATA (CTL3, dma_select [1], 0) }, - { ORDATA (CW1, dmac[1].cw1, 16) }, - { ORDATA (CW2, dmac[1].cw2, 16) }, - { ORDATA (CW3, dmac[1].cw3, 16) }, - { DRDATA (LATENCY, dmac[1].latency, 8) }, - { FLDATA (BYTE, dmac[1].packer, 31) }, - { ORDATA (PACKER, dmac[1].packer, 8) }, + { FLDATA (XFR, dma [ch1].xferen, 0) }, + { FLDATA (CTL, dma [ch1].control, 0) }, + { FLDATA (FLG, dma [ch1].flag, 0) }, + { FLDATA (FBF, dma [ch1].flagbuf, 0) }, + { FLDATA (CTL2, dma [ch1].select, 0) }, + { ORDATA (CW1, dma [ch1].cw1, 16) }, + { ORDATA (CW2, dma [ch1].cw2, 16) }, + { ORDATA (CW3, dma [ch1].cw3, 16) }, + { FLDATA (BYTE, dma [ch1].packer, 31) }, + { ORDATA (PACKER, dma [ch1].packer, 8) }, { NULL } }; @@ -962,50 +949,97 @@ DEVICE dma1_dev = { 16, /* data width */ NULL, /* examine routine */ NULL, /* deposit routine */ - &dma1_reset, /* reset routine */ + &dma_reset, /* reset routine */ NULL, /* boot routine */ NULL, /* attach routine */ NULL, /* detach routine */ - &dma1_dib, /* device information block */ + &dmap1_dib, /* device information block */ DEV_DISABLE, /* device flags */ 0, /* debug control flags */ NULL, /* debug flag name table */ NULL, /* memory size change routine */ NULL }; /* logical device name */ +DIB dmap2_dib = { &dmapio, DMA2, ch2 }; +DIB dmas2_dib = { &dmasio, DMALT2, ch2 }; + +UNIT dma2_unit = { UDATA (NULL, 0, 0) }; + +REG dma2_reg[] = { + { FLDATA (XFR, dma [ch2].xferen, 0) }, + { FLDATA (CTL, dma [ch2].control, 0) }, + { FLDATA (FLG, dma [ch2].flag, 0) }, + { FLDATA (FBF, dma [ch2].flagbuf, 0) }, + { FLDATA (CTL2, dma [ch2].select, 0) }, + { ORDATA (CW1, dma [ch2].cw1, 16) }, + { ORDATA (CW2, dma [ch2].cw2, 16) }, + { ORDATA (CW3, dma [ch2].cw3, 16) }, + { FLDATA (BYTE, dma [ch2].packer, 31) }, + { ORDATA (PACKER, dma [ch2].packer, 8) }, + { NULL } + }; + +DEVICE dma2_dev = { + "DMA2", /* device name */ + &dma2_unit, /* unit array */ + dma2_reg, /* register array */ + NULL, /* modifier array */ + 1, /* number of units */ + 8, /* address radix */ + 1, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &dma_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &dmap2_dib, /* device information block */ + DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + NULL, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + +static DEVICE *dma_dptrs [] = { &dma1_dev, &dma2_dev }; + /* Interrupt deferral table (1000 version) */ /* Deferral for I/O subops: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ static t_bool defer_tab [] = { FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE }; -/* Device dispatch table */ +/* Device I/O dispatch table */ + +DIB *dtab [64] = { &cpu_dib, &ovfl_dib }; /* init with immutable devices */ -IODISP *dtab[64] = { &cpuio, &ovflio }; /* init with immutable devices */ /* Execute CPU instructions. This routine is the instruction decode routine for the HP 2100. 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. + memory, starting at the simulated PC. It runs until 'reason' is set to a + status other than SCPE_OK. */ t_stat sim_instr (void) { uint32 intrq, dmarq; /* set after setjmp */ uint32 iotrap = 0; /* set after setjmp */ -t_stat reason; /* set after setjmp */ +t_stat reason = SCPE_OK; /* set after setjmp */ int32 i; /* temp */ DEVICE *dptr; /* temp */ -DIB *dibp; /* temp */ +DIB *dibptr; /* temp */ int abortval; /* Restore register state */ -if (dev_conflict ()) return SCPE_STOP; /* check consistency */ +if (dev_conflict ()) /* check device assignment consistency */ + return SCPE_STOP; /* conflict; stop execution */ + err_PC = PC = PC & VAMASK; /* load local PC */ -reason = 0; /* Restore I/O state */ @@ -1013,25 +1047,25 @@ dev_prl [0] = dev_prl [1] = ~(uint32) 0; /* set all priority lows dev_irq [0] = dev_irq [1] = 0; /* clear all interrupt requests */ dev_srq [0] = dev_srq [1] = 0; /* clear all service requests */ -for (i = OPTDEV; i <= I_DEVMASK; i++) /* default optional devices dispatch */ - dtab [i] = &nullio; +for (i = OPTDEV; i <= MAXDEV; i++) /* default optional devices */ + dtab [i] = &null_dib; -dtab [PWR] = &pwrfio; /* for now, powerfail is always present */ +dtab [PWR] = &pwrf_dib; /* for now, powerfail is always present */ for (i = 0; dptr = sim_devices [i]; i++) { /* loop thru dev */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ + dibptr = (DIB *) dptr->ctxt; /* get DIB */ - if (dibp && !(dptr->flags & DEV_DIS)) { /* exist, enabled? */ - dtab [dibp->devno] = dibp->iot; /* set I/O signal dispatch */ - dtab [dibp->devno] (dibp->devno, ioSIR, 0); /* set interrupt request state */ + if (dibptr && !(dptr->flags & DEV_DIS)) { /* handler exists and device is enabled? */ + dtab [dibptr->select_code] = dibptr; /* set DIB pointer into dispatch table */ + dibptr->io_handler (dibptr, ioSIR, 0); /* set interrupt request state */ } } -if (dtab [DMA0] == &dmapio) /* first DMA channel enabled? */ - dtab [DMALT0] = &dmasio; /* set up secondary handler */ +if (dtab [DMA1] != &null_dib) /* first DMA channel enabled? */ + dtab [DMALT1] = &dmas1_dib; /* set up secondary device handler */ -if (dtab [DMA1] == &dmapio) /* second DMA channel enabled? */ - dtab [DMALT1] = &dmasio; /* set up secondary handler */ +if (dtab [DMA2] != &null_dib) /* second DMA channel enabled? */ + dtab [DMALT2] = &dmas2_dib; /* set up secondary device handler */ /* Configure interrupt deferral table */ @@ -1085,7 +1119,7 @@ if (abortval) { /* memory protect abort? dms_upd_vr (abortval); /* update violation register (if not MEV) */ if (ion) /* interrupt system on? */ - protio (PRO, ioENF, 0); /* set flag */ + protio (dtab [PRO], ioENF, 0); /* set flag */ } dmarq = calc_dma (); /* initial recalc of DMA masks */ @@ -1094,30 +1128,92 @@ intrq = calc_int (); /* initial recalc of int /* Main instruction fetch/decode loop */ -while (reason == 0) { /* loop until halted */ +while (reason == SCPE_OK) { /* loop until halted */ uint32 IR, MA, absel, v1, t, skip; + err_PC = PC; /* save PC for error recovery */ + if (sim_interval <= 0) { /* event timeout? */ - if (reason = sim_process_event ()) /* process event service */ - break; /* service status not OK */ + reason = sim_process_event (); /* process event service */ + + if (reason != SCPE_OK) /* service failed? */ + break; /* stop execution */ dmarq = calc_dma (); /* recalc DMA reqs */ intrq = calc_int (); /* recalc interrupts */ } +/* DMA cycles are requested by an I/O card asserting its SRQ signal. If a DMA + channel is programmed to respond to that card's select code, a DMA cycle will + be initiated. A DMA cycle consists of a memory cycle and an I/O cycle. + These cycles are synchronized with the control processor on the 21xx CPUs. + On the 1000s, memory cycles are asynchronous, while I/O cycles are + synchronous. Memory cycle time is about 40% of the I/O cycle time. + + With properly designed interface cards, DMA is capable of taking consecutive + I/O cycles. On all machines except the 1000 M-Series, a DMA cycle freezes + the CPU for the duration of the cycle. On the M-Series, a DMA cycle freezes + the CPU if it attempts an I/O cycle (including IAK) or a directly-interfering + memory cycle. An interleaved memory cycle is allowed. Otherwise, the + control processor is allowed to run. Therefore, during consecutive DMA + cycles, the M-Series CPU will run until an IOG instruction is attempted, + whereas the other CPUs will freeze completely. + + All DMA cards except the 12607B provide two independent channels. If both + channels are active simultaneously, channel 1 has priority for I/O cycles + over channel 2. + + Most I/O cards assert SRQ no more than 50% of the time. A few buffered + cards, such as the 12821A and 13175A Disc Interfaces, are capable of + asserting SRQ continuously while filling or emptying the buffer. If SRQ for + channel 1 is asserted continuously when both channels are active, then no + channel 2 cycles will occur until channel 1 completes. + + Implementation notes: + + 1. CPU freeze is simulated by skipping instruction execution during the + current loop cycle. + + 2. If both channels have SRQ asserted, DMA priority is simulated by skipping + the channel 2 cycle if channel 1's SRQ is still asserted at the end of + its cycle. If it is not, then channel 2 steals the next cycle from the + CPU. + + 3. The 1000 M-Series allows some CPU processing concurrently with + continuous DMA cycles, whereas all other CPUs freeze. The processor + freezes if an I/O cycle is attempted, including an interrupt + acknowledgement. Because some microcode extensions (e.g., Access IOP, + RTE-6/VM OS) perform I/O cycles, advance detection of I/O cycles is + difficult. Therefore, we freeze all processing for the M-Series as well. +*/ + if (dmarq) { - if (dmarq & DMAR0) /* DMA channel 1 request? */ - dma_cycle (0, PAMAP); /* do one DMA cycle using port A map */ + if (dmarq & DMA_1_REQ) { /* DMA channel 1 request? */ + reason = dma_cycle (ch1, PAMAP); /* do one DMA cycle using port A map */ - if (dmarq & DMAR1) /* DMA channel 2 request? */ - dma_cycle (1, PBMAP); /* do one DMA cycle using port B map */ + if (reason == SCPE_OK) /* cycle OK? */ + dmarq = calc_dma (); /* recalc DMA requests */ + else + break; /* cycle failed, so stop */ + } - dmarq = calc_dma (); /* recalc DMA requests */ - intrq = calc_int (); /* recalc interrupts */ + if ((dmarq & (DMA_1_REQ | DMA_2_REQ)) == DMA_2_REQ) { /* DMA channel 1 idle and channel 2 request? */ + reason = dma_cycle (ch2, PBMAP); /* do one DMA cycle using port B map */ + + if (reason == SCPE_OK) /* cycle OK? */ + dmarq = calc_dma (); /* recalc DMA requests */ + else + break; /* cycle failed, so stop */ + } + + if (dmarq) /* DMA request still pending? */ + continue; /* service it before instruction execution */ + + intrq = calc_int (); /* recalc interrupts */ } - if (intrq && ion_defer) /* interrupt pending but deferred? */ - ion_defer = calc_defer (); /* confirm deferral */ + if (intrq && ion_defer) /* interrupt pending but deferred? */ + ion_defer = calc_defer (); /* confirm deferral */ /* Check for pending interrupt request. @@ -1182,23 +1278,28 @@ while (reason == 0) { /* loop until halted */ IR = ReadW (intaddr); /* get trap cell instruction */ - devdisp (intaddr, ioIAK, IR); /* acknowledge interrupt */ + devdisp (intaddr, ioIAK, (uint16) IR); /* acknowledge interrupt */ if (intaddr != PRO) /* not MP interrupt? */ - protio (intaddr, ioIAK, IR); /* send IAK for device to MP too */ + protio (dtab [intaddr], ioIAK, IR); /* send IAK for device to MP too */ } else { /* normal instruction */ iotrap = 0; /* not a trap cell instruction */ - err_PC = PC; /* save PC for error */ + if (sim_brk_summ && /* any breakpoints? */ sim_brk_test (PC, SWMASK ('E') | /* unconditional or */ - (dms_enb? (dms_ump? SWMASK ('U'): SWMASK ('S')): - SWMASK ('N')))) { /* or right type for DMS? */ + (dms_enb ? /* correct type for DMS state? */ + (dms_ump ? + SWMASK ('U') : SWMASK ('S')) : + SWMASK ('N')))) { reason = STOP_IBKPT; /* stop simulation */ break; } - if (mp_evrff) mp_viol = PC; /* if ok, upd mp_viol */ + + if (mp_evrff) /* violation register enabled */ + mp_viol = PC; /* update with current PC */ + IR = ReadW (PC); /* fetch instr */ PC = (PC + 1) & VAMASK; ion_defer = FALSE; @@ -1221,7 +1322,8 @@ while (reason == 0) { /* loop until halted */ 1 0 0 0 1 0 1 0 extended instr group 0 (A/B must be set) 1 0 0 0 x 0 1 1 extended instr group 1 (A/B ignored) */ - absel = (IR & I_AB)? 1: 0; /* get A/B select */ + absel = (IR & I_AB) ? 1 : 0; /* get A/B select */ + switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ /* Memory reference instructions */ @@ -1230,7 +1332,11 @@ while (reason == 0) { /* loop until halted */ case 0024:case 0025:case 0026:case 0027: case 0220:case 0221:case 0222:case 0223: case 0224:case 0225:case 0226:case 0227: - if (reason = Ea (IR, &MA, intrq)) break; /* AND */ + reason = Ea (IR, &MA, intrq); /* AND */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + AR = AR & ReadW (MA); break; @@ -1250,7 +1356,10 @@ while (reason == 0) { /* loop until halted */ case 0030:case 0031:case 0032:case 0033: case 0034:case 0035:case 0036:case 0037: - if (reason = Ea (IR, &MA, intrq)) break; /* JSB */ + reason = Ea (IR, &MA, intrq); /* JSB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ mp_dms_jmp (MA, jsb_plb); /* validate jump address */ @@ -1263,7 +1372,11 @@ while (reason == 0) { /* loop until halted */ case 0044:case 0045:case 0046:case 0047: case 0240:case 0241:case 0242:case 0243: case 0244:case 0245:case 0246:case 0247: - if (reason = Ea (IR, &MA, intrq)) break; /* XOR */ + reason = Ea (IR, &MA, intrq); /* XOR */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + AR = AR ^ ReadW (MA); break; @@ -1317,7 +1430,11 @@ while (reason == 0) { /* loop until halted */ case 0050:case 0051:case 0052:case 0053: case 0054:case 0055:case 0056:case 0057: - if (reason = Ea (IR, &MA, intrq)) break; /* JMP */ + reason = Ea (IR, &MA, intrq); /* JMP */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + mp_dms_jmp (MA, 0); /* validate jump addr */ PCQ_ENTRY; PC = MA; /* jump */ @@ -1349,7 +1466,7 @@ while (reason == 0) { /* loop until halted */ ((PC == (err_PC - 1)) && /* RTE-6/VM */ ((ReadW (PC) & I_MRG) == I_ISZ))) && /* RTE jump target */ (mp_fence == CLEAR) && (M [xeqt] == 0) && /* RTE idle indications */ - (M [tbg] == clk_dib.devno) || /* RTE verification */ + (M [tbg] == clk_dib.select_code) || /* RTE verification */ (PC == (err_PC - 3)) && /* DOS through DOS-III */ (ReadW (PC) == I_STF) && /* DOS jump target */ @@ -1364,7 +1481,11 @@ while (reason == 0) { /* loop until halted */ case 0064:case 0065:case 0066:case 0067: case 0260:case 0261:case 0262:case 0263: case 0264:case 0265:case 0266:case 0267: - if (reason = Ea (IR, &MA, intrq)) break; /* IOR */ + reason = Ea (IR, &MA, intrq); /* IOR */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + AR = AR | ReadW (MA); break; @@ -1372,21 +1493,36 @@ while (reason == 0) { /* loop until halted */ case 0074:case 0075:case 0076:case 0077: case 0270:case 0271:case 0272:case 0273: case 0274:case 0275:case 0276:case 0277: - if (reason = Ea (IR, &MA, intrq)) break; /* ISZ */ + reason = Ea (IR, &MA, intrq); /* ISZ */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + t = (ReadW (MA) + 1) & DMASK; WriteW (MA, t); - if (t == 0) PC = (PC + 1) & VAMASK; + + if (t == 0) + PC = (PC + 1) & VAMASK; break; case 0100:case 0101:case 0102:case 0103: case 0104:case 0105:case 0106:case 0107: case 0300:case 0301:case 0302:case 0303: case 0304:case 0305:case 0306:case 0307: - if (reason = Ea (IR, &MA, intrq)) break; /* ADA */ + reason = Ea (IR, &MA, intrq); /* ADA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + v1 = ReadW (MA); t = AR + v1; - if (t > DMASK) E = 1; - if (((~AR ^ v1) & (AR ^ t)) & SIGN) O = 1; + + if (t > DMASK) + E = 1; + + if (((~AR ^ v1) & (AR ^ t)) & SIGN) + O = 1; + AR = t & DMASK; break; @@ -1394,11 +1530,20 @@ while (reason == 0) { /* loop until halted */ case 0114:case 0115:case 0116:case 0117: case 0310:case 0311:case 0312:case 0313: case 0314:case 0315:case 0316:case 0317: - if (reason = Ea (IR, &MA, intrq)) break; /* ADB */ + reason = Ea (IR, &MA, intrq); /* ADB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + v1 = ReadW (MA); t = BR + v1; - if (t > DMASK) E = 1; - if (((~BR ^ v1) & (BR ^ t)) & SIGN) O = 1; + + if (t > DMASK) + E = 1; + + if (((~BR ^ v1) & (BR ^ t)) & SIGN) + O = 1; + BR = t & DMASK; break; @@ -1406,23 +1551,37 @@ while (reason == 0) { /* loop until halted */ case 0124:case 0125:case 0126:case 0127: case 0320:case 0321:case 0322:case 0323: case 0324:case 0325:case 0326:case 0327: - if (reason = Ea (IR, &MA, intrq)) break; /* CPA */ - if (AR != ReadW (MA)) PC = (PC + 1) & VAMASK; + reason = Ea (IR, &MA, intrq); /* CPA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + if (AR != ReadW (MA)) + PC = (PC + 1) & VAMASK; break; case 0130:case 0131:case 0132:case 0133: case 0134:case 0135:case 0136:case 0137: case 0330:case 0331:case 0332:case 0333: case 0334:case 0335:case 0336:case 0337: - if (reason = Ea (IR, &MA, intrq)) break; /* CPB */ - if (BR != ReadW (MA)) PC = (PC + 1) & VAMASK; + reason = Ea (IR, &MA, intrq); /* CPB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + if (BR != ReadW (MA)) + PC = (PC + 1) & VAMASK; break; case 0140:case 0141:case 0142:case 0143: case 0144:case 0145:case 0146:case 0147: case 0340:case 0341:case 0342:case 0343: case 0344:case 0345:case 0346:case 0347: - if (reason = Ea (IR, &MA, intrq)) break; /* LDA */ + reason = Ea (IR, &MA, intrq); /* LDA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + AR = ReadW (MA); break; @@ -1430,7 +1589,11 @@ while (reason == 0) { /* loop until halted */ case 0154:case 0155:case 0156:case 0157: case 0350:case 0351:case 0352:case 0353: case 0354:case 0355:case 0356:case 0357: - if (reason = Ea (IR, &MA, intrq)) break; /* LDB */ + reason = Ea (IR, &MA, intrq); /* LDB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + BR = ReadW (MA); break; @@ -1438,7 +1601,11 @@ while (reason == 0) { /* loop until halted */ case 0164:case 0165:case 0166:case 0167: case 0360:case 0361:case 0362:case 0363: case 0364:case 0365:case 0366:case 0367: - if (reason = Ea (IR, &MA, intrq)) break; /* STA */ + reason = Ea (IR, &MA, intrq); /* STA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + WriteW (MA, AR); break; @@ -1446,7 +1613,11 @@ while (reason == 0) { /* loop until halted */ case 0174:case 0175:case 0176:case 0177: case 0370:case 0371:case 0372:case 0373: case 0374:case 0375:case 0376:case 0377: - if (reason = Ea (IR, &MA, intrq)) break; /* STB */ + reason = Ea (IR, &MA, intrq); /* STB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + WriteW (MA, BR); break; @@ -1455,42 +1626,85 @@ while (reason == 0) { /* loop until halted */ case 0004:case 0005:case 0006:case 0007: case 0014:case 0015:case 0016:case 0017: skip = 0; /* no skip */ - if (IR & 000400) t = 0; /* CLx */ - else t = ABREG[absel]; - if (IR & 001000) t = t ^ DMASK; /* CMx */ + + if (IR & 000400) /* CLx */ + t = 0; + else + t = ABREG[absel]; + + if (IR & 001000) /* CMx */ + t = t ^ DMASK; + if (IR & 000001) { /* RSS? */ - if ((IR & 000040) && (E != 0)) skip = 1; /* SEZ,RSS */ - if (IR & 000100) E = 0; /* CLE */ - if (IR & 000200) E = E ^ 1; /* CME */ + if ((IR & 000040) && (E != 0)) /* SEZ,RSS */ + skip = 1; + + if (IR & 000100) /* CLE */ + E = 0; + + if (IR & 000200) /* CME */ + E = E ^ 1; + if (((IR & 000030) == 000030) && /* SSx,SLx,RSS */ - ((t & 0100001) == 0100001)) skip = 1; + ((t & 0100001) == 0100001)) + skip = 1; + if (((IR & 000030) == 000020) && /* SSx,RSS */ - ((t & SIGN) != 0)) skip = 1; + ((t & SIGN) != 0)) + skip = 1; + if (((IR & 000030) == 000010) && /* SLx,RSS */ - ((t & 1) != 0)) skip = 1; + ((t & 1) != 0)) + skip = 1; + if (IR & 000004) { /* INx */ t = (t + 1) & DMASK; - if (t == 0) E = 1; - if (t == SIGN) O = 1; + + if (t == 0) + E = 1; + + if (t == SIGN) + O = 1; } - if ((IR & 000002) && (t != 0)) skip = 1; /* SZx,RSS */ - if ((IR & 000072) == 0) skip = 1; /* RSS */ + + if ((IR & 000002) && (t != 0)) /* SZx,RSS */ + skip = 1; + + if ((IR & 000072) == 0) /* RSS */ + skip = 1; } /* end if RSS */ + else { - if ((IR & 000040) && (E == 0)) skip = 1; /* SEZ */ - if (IR & 000100) E = 0; /* CLE */ - if (IR & 000200) E = E ^ 1; /* CME */ + if ((IR & 000040) && (E == 0)) /* SEZ */ + skip = 1; + + if (IR & 000100) /* CLE */ + E = 0; + + if (IR & 000200) /* CME */ + E = E ^ 1; + if ((IR & 000020) && /* SSx */ - ((t & SIGN) == 0)) skip = 1; + ((t & SIGN) == 0)) + skip = 1; + if ((IR & 000010) && /* SLx */ - ((t & 1) == 0)) skip = 1; + ((t & 1) == 0)) + skip = 1; + if (IR & 000004) { /* INx */ t = (t + 1) & DMASK; - if (t == 0) E = 1; - if (t == SIGN) O = 1; + + if (t == 0) + E = 1; + + if (t == SIGN) + O = 1; } - if ((IR & 000002) && (t == 0)) skip = 1; /* SZx */ + if ((IR & 000002) && (t == 0)) /* SZx */ + skip = 1; } /* end if ~RSS */ + ABREG[absel] = t; /* store result */ PC = (PC + skip) & VAMASK; /* add in skip */ break; /* end if alter/skip */ @@ -1500,9 +1714,13 @@ while (reason == 0) { /* loop until halted */ case 0000:case 0001:case 0002:case 0003: case 0010:case 0011:case 0012:case 0013: t = shift (ABREG[absel], IR & 01000, IR >> 6); /* do first shift */ - if (IR & 000040) E = 0; /* CLE */ + + if (IR & 000040) /* CLE */ + E = 0; + if ((IR & 000010) && ((t & 1) == 0)) /* SLx */ PC = (PC + 1) & VAMASK; + ABREG[absel] = shift (t, IR & 00020, IR); /* do second shift */ break; /* end if shift */ @@ -1538,33 +1756,44 @@ while (reason == 0) { /* loop until halted */ if (reason == NOTE_IOG) { /* I/O instr exec? */ dmarq = calc_dma (); /* recalc DMA masks */ intrq = calc_int (); /* recalc interrupts */ - reason = 0; /* continue */ + reason = SCPE_OK; /* continue */ } else if (reason == NOTE_INDINT) { /* intr pend during indir? */ PC = err_PC; /* back out of inst */ - reason = 0; /* continue */ + reason = SCPE_OK; /* continue */ } } /* end while */ /* Simulation halted */ -if (iotrap && (reason == STOP_HALT)) MR = intaddr; /* HLT in trap cell? */ -else MR = (PC - 1) & VAMASK; /* no, M = P - 1 */ -TR = ReadTAB (MR); /* last word fetched */ +if (iotrap && (reason == STOP_HALT)) /* HLT in trap cell? */ + MR = intaddr; /* M = interrupt address */ +else /* normal HLT */ + MR = (PC - 1) & VAMASK; /* M = P - 1 */ + +TR = ReadTAB (MR); /* T = last word fetched */ saved_MR = MR; /* save for T cmd update */ -if ((reason == STOP_RSRV) || (reason == STOP_IODV) || /* instr error? */ - (reason == STOP_IND)) PC = err_PC; /* back up PC */ + +if (reason == STOP_HALT) /* programmed halt? */ + cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (after T is read) */ +else /* simulation stop */ + PC = err_PC; /* back out instruction */ + dms_upd_sr (); /* update dms_sr */ dms_upd_vr (MR); /* update dms_vr */ -if (reason == STOP_HALT) /* programmed halt? */ - cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (ignore errors) */ pcq_r->qptr = pcq_p; /* update pc q ptr */ -if (dms_enb) /* default breakpoint type */ - if (dms_ump) sim_brk_dflt = SWMASK ('U'); /* to current map mode */ - else sim_brk_dflt = SWMASK ('S'); -else sim_brk_dflt = SWMASK ('N'); -return reason; + +if (dms_enb) /* DMS enabled? */ + if (dms_ump) /* set default */ + sim_brk_dflt = SWMASK ('U'); /* breakpoint type */ + else /* to current */ + sim_brk_dflt = SWMASK ('S'); /* map mode */ + +else /* DMS disabled */ + sim_brk_dflt = SWMASK ('N'); /* set breakpoint type to non-DMS */ + +return reason; /* return status code */ } @@ -1595,9 +1824,13 @@ for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ if ((i > 2) || int_enable) /* 4th or higher or INT out? */ return NOTE_INDINT; /* break out now */ } + MA = ReadW (MA & VAMASK); /* follow address chain */ } -if (MA & I_IA) return STOP_IND; /* indirect loop? */ + +if (MA & I_IA) /* indirect loop? */ + return STOP_IND; /* stop simulation */ + *addr = MA; return SCPE_OK; } @@ -1610,7 +1843,10 @@ static t_stat Ea (uint32 IR, uint32 *addr, uint32 irq) uint32 MA; MA = IR & (I_IA | I_DISP); /* ind + disp */ -if (IR & I_CP) MA = ((PC - 1) & I_PAGENO) | MA; /* current page? */ + +if (IR & I_CP) /* current page? */ + MA = ((PC - 1) & I_PAGENO) | MA; /* merge in page from PC */ + return resolve (MA, addr, irq); /* resolve indirects */ } @@ -1654,8 +1890,13 @@ if (flag) { /* enabled? */ return (((t << 4) | (t >> 12)) & DMASK); } /* end case */ } /* end if */ -if (op == 05) E = t & 1; /* disabled ext rgt rot */ -if (op == 06) E = (t >> 15) & 1; /* disabled ext lft rot */ + +if (op == 05) /* disabled ext rgt rot */ + E = t & 1; + +if (op == 06) /* disabled ext lft rot */ + E = (t >> 15) & 1; + return t; /* input unchanged */ } @@ -1702,48 +1943,49 @@ return t; /* input unchanged */ t_stat iogrp (uint32 ir, uint32 iotrap) { -/* Translation for I/O subopcodes: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ -static const IOSIG generate_signal [] = { ioNONE, ioSTF, ioSFC, ioSFS, ioIOI, ioIOI, ioIOO, ioSTC }; +/* Translation for I/O subopcodes: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ +static const IOSIGNAL generate_signal [] = { ioNONE, ioSTF, ioSFC, ioSFS, ioIOI, ioIOI, ioIOO, ioSTC }; -const uint32 dev = ir & I_DEVMASK; /* device select code */ -const uint32 sop = I_GETIOOP (ir); /* I/O subopcode */ -const uint32 ab = (ir & I_AB) != 0; /* A/B register select */ -const t_bool clf = (ir & I_HC) != 0; /* H/C flag select */ -uint32 iodata = (SCPE_OK << IOT_V_REASON) | (uint32) ioNONE; /* initialize for SKF test */ +const uint32 dev = ir & I_DEVMASK; /* device select code */ +const uint32 sop = I_GETIOOP (ir); /* I/O subopcode */ +const uint32 ab = (ir & I_AB) != 0; /* A/B register select */ +const t_bool clf = (ir & I_HC) != 0; /* H/C flag select */ +uint16 iodata = (uint16) ioNONE; /* initialize for SKF test */ uint32 ioreturn; t_stat iostat; -IOSIG iosig; +IOCYCLE signal_set; if (!iotrap && mp_control && /* instr not in trap cell and MP on? */ ((sop == soHLT) || /* and is HLT? */ ((dev != OVF) && (mp_unit.flags & UNIT_MP_SEL1)))) { /* or is not SC 01 and SEL1 out? */ if (sop == soLIX) /* MP violation; is LIA/B instruction? */ ABREG [ab] = 0; /* A/B writes anyway */ + MP_ABORT (err_PC); /* MP abort */ } -iosig = generate_signal [sop]; /* generate I/O signal */ +signal_set = generate_signal [sop]; /* generate I/O signal from instruction */ ion_defer = defer_tab [sop]; /* defer depending on instruction */ if (sop == soOTX) /* OTA/B instruction? */ - iodata = (SCPE_OK << IOT_V_REASON) | ABREG [ab]; /* pass A/B register value */ + iodata = ABREG [ab]; /* pass A/B register value */ else if ((sop == soCTL) && (ir & I_CTL)) /* CLC instruction? */ - iosig = ioCLC; /* change STC to CLC signal */ + signal_set = ioCLC; /* change STC to CLC signal */ if ((sop == soFLG) && clf) /* CLF instruction? */ - iosig = ioCLF; /* change STF to CLF signal */ + signal_set = ioCLF; /* change STF to CLF signal */ else if (clf) /* CLF with another instruction? */ - iosig = iosig + ioCLF; /* add CLF signal */ + signal_set = signal_set | ioCLF; /* add CLF signal */ -ioreturn = devdisp (dev, iosig, iodata); /* dispatch I/O signal */ +ioreturn = devdisp (dev, signal_set, IORETURN (SCPE_OK, iodata)); /* dispatch I/O signal */ -iostat = (t_stat) (ioreturn >> IOT_V_REASON); /* extract status */ -iodata = ioreturn & DMASK; /* extract return data value */ +iostat = IOSTATUS (ioreturn); /* extract status */ +iodata = IODATA (ioreturn); /* extract return data value */ if (((sop == soSFC) || (sop == soSFS)) && /* testing flag state? */ - ((IOSIG) iodata == ioSKF)) /* and SKF asserted? */ + ((IOSIGNAL) iodata == ioSKF)) /* and SKF asserted? */ PC = (PC + 1) & VAMASK; /* bump P to skip next instruction */ else if (sop == soLIX) /* LIA/B instruction? */ @@ -1765,11 +2007,13 @@ else /* abnormal status */ } -/* Device dispatcher */ +/* Device I/O signal dispatcher */ -static uint32 devdisp (uint32 select_code, IOSIG signal, uint32 data) +static uint32 devdisp (uint32 select_code, IOCYCLE signal_set, uint16 data) { -return dtab [select_code] (select_code, signal, data); +return dtab [select_code]->io_handler (dtab [select_code], + signal_set, + IORETURN (SCPE_OK, data)); } @@ -1779,10 +2023,10 @@ static uint32 calc_dma (void) { uint32 r = 0; -if (dma_xferen [0] && SRQ (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */ - r = r | DMAR0; -if (dma_xferen [1] && SRQ (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ - r = r | DMAR1; +if (dma [ch1].xferen && SRQ (dma [ch1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ + r = r | DMA_1_REQ; +if (dma [ch2].xferen && SRQ (dma [ch2].cw1 & I_DEVMASK)) /* check DMA2 cycle */ + r = r | DMA_2_REQ; return r; } @@ -1854,8 +2098,8 @@ else bit that is clear. The device corresponding to that bit is the only device that may interrupt (a higher priority device that had IRQ set would also have had PRL set, which is a state violation). We calculate a priority mask by - ANDing the complement of the PRL bits with an increment of the PRL bits. Only - the lowest-order bit will differ. For example: + ANDing the complement of the PRL bits with an increment of the PRL bits. + Only the lowest-order bit will differ. For example: dev_prl : ...1 1 0 1 1 0 1 1 1 1 1 1 (PRL denied for SC 06 and 11) @@ -1896,7 +2140,7 @@ if (ion) /* interrupt system else { /* interrupt system off */ req_grant [0] = req_grant [0] & /* only PF and PE can interrupt */ - (INT_M (PWR) | INT_M (PRO)); + (BIT_M (PWR) | BIT_M (PRO)); req_grant [1] = 0; } @@ -2265,14 +2509,30 @@ uint32 map_sel; if ((dms_enb == 0) || /* DMS off? */ (sw & (SWMASK ('N') | SIM_SW_REST))) /* no mapping rqst or save/rest? */ return va; /* use physical address */ -else if (sw & SWMASK ('S')) map_sel = SMAP; -else if (sw & SWMASK ('U')) map_sel = UMAP; -else if (sw & SWMASK ('P')) map_sel = PAMAP; -else if (sw & SWMASK ('Q')) map_sel = PBMAP; -else map_sel = dms_ump; /* dflt to log addr, cur map */ -if (va >= VASIZE) return MEMSIZE; /* virtual, must be 15b */ -else if (dms_enb) return dms (va, map_sel, NOPROT); /* DMS on? go thru map */ -else return va; /* else return virtual */ + +else if (sw & SWMASK ('S')) + map_sel = SMAP; + +else if (sw & SWMASK ('U')) + map_sel = UMAP; + +else if (sw & SWMASK ('P')) + map_sel = PAMAP; + +else if (sw & SWMASK ('Q')) + map_sel = PBMAP; + +else /* dflt to log addr, cur map */ + map_sel = dms_ump; + +if (va >= VASIZE) /* virtual, must be 15b */ + return MEMSIZE; + +else if (dms_enb) /* DMS on? go thru map */ + return dms (va, map_sel, NOPROT); + +else /* else return virtual */ + return va; } @@ -2407,9 +2667,16 @@ return dms_vr; uint32 dms_upd_sr (void) { dms_sr = dms_sr & ~(MST_ENB | MST_UMP | MST_PRO); -if (dms_enb) dms_sr = dms_sr | MST_ENB; -if (dms_ump) dms_sr = dms_sr | MST_UMP; -if (mp_control) dms_sr = dms_sr | MST_PRO; + +if (dms_enb) + dms_sr = dms_sr | MST_ENB; + +if (dms_ump) + dms_sr = dms_sr | MST_UMP; + +if (mp_control) + dms_sr = dms_sr | MST_PRO; + return dms_sr; } @@ -2421,6 +2688,12 @@ return dms_sr; the interrupt system. When the interrupt system is off, only power fail and parity error interrupts are allowed. + A PON reset initializes certain CPU registers. The 1000 series does a + microcoded memory clear and leaves the T and P registers set as a result. + + Front-panel PRESET performs additional initialization. We also handle MEM + preset here. + Implementation notes: 1. An IOI signal reads the floating I/O bus (0 on all machines). @@ -2450,46 +2723,80 @@ return dms_sr; 4. Select code 0 cannot interrupt, so there is no SIR handler. */ -uint32 cpuio (uint32 select_code, IOSIG signal, uint32 data) +uint32 cpuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ uint32 sc; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - ion = CLEAR; /* turn interrupt system off */ - break; + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - ion = SET; /* turn interrupt system on */ - break; + case ioCLF: /* clear flag flip-flop */ + ion = CLEAR; /* turn interrupt system off */ + break; - case ioSFC: /* skip if flag is clear */ - setSKF (!ion); /* skip if interrupt system is off */ - break; + case ioSTF: /* set flag flip-flop */ + ion = SET; /* turn interrupt system on */ + break; - case ioSFS: /* skip if flag is set */ - setSKF (ion); /* skip if interupt system is on */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (!ion); /* skip if interrupt system is off */ + break; - case ioIOI: /* I/O input */ - data = 0; /* returns 0 */ - break; + case ioSFS: /* skip if flag is set */ + setSKF (ion); /* skip if interupt system is on */ + break; - case ioCLC: /* clear control flip-flop */ - for (sc = 6; sc <= I_DEVMASK; sc++) /* send CRS to devices */ - devdisp (sc, ioCRS, 0); /* from select code 6 and up */ - break; + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, 0); /* returns 0 */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioPON: /* power on normal */ + AR = 0; /* clear A register */ + BR = 0; /* clear B register */ + SR = 0; /* clear S register */ + TR = 0; /* clear T register */ + E = 1; /* set E register */ + + if (UNIT_CPU_FAMILY == UNIT_FAMILY_1000) { /* 1000 series? */ + memset (M, 0, MEMSIZE * 2); /* zero allocated memory */ + MR = 0077777; /* set M register */ + PC = 0100000; /* set P register */ + } + + else { /* 21xx series */ + MR = 0; /* clear M register */ + PC = 0; /* clear P register */ + } + break; + + case ioPOPIO: /* power-on preset to I/O */ + O = 0; /* clear O register */ + ion = CLEAR; /* turn off interrupt system */ + ion_defer = FALSE; /* clear interrupt deferral */ + + dms_enb = 0; /* turn DMS off */ + dms_ump = 0; /* init to system map */ + dms_sr = 0; /* clear status register and BP fence */ + dms_vr = 0; /* clear violation register */ + break; + + case ioCLC: /* clear control flip-flop */ + for (sc = CRSDEV; sc <= MAXDEV; sc++) /* send CRS to devices */ + devdisp (sc, ioCRS, 0); /* from select code 6 and up */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - cpuio (select_code, ioCLF, 0); /* issue CLF */ - -return data; +return stat_data; } @@ -2507,46 +2814,50 @@ return data; 1. Select code 1 cannot interrupt, so there is no SIR handler. */ -uint32 ovflio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ovflio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - O = 0; /* clear overflow */ - break; + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - O = 1; /* set overflow */ - break; + case ioCLF: /* clear flag flip-flop */ + O = 0; /* clear overflow */ + break; - case ioSFC: /* skip if flag is clear */ - setSKF (!O); /* skip if overflow is clear */ - break; + case ioSTF: /* set flag flip-flop */ + O = 1; /* set overflow */ + break; - case ioSFS: /* skip if flag is set */ - setSKF (O); /* skip if overflow is set */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (!O); /* skip if overflow is clear */ + break; - case ioIOI: /* I/O input */ - data = SR; /* read switch register value */ - break; + case ioSFS: /* skip if flag is set */ + setSKF (O); /* skip if overflow is set */ + break; - case ioIOO: /* I/O output */ - if ((UNIT_CPU_MODEL != UNIT_2116) && /* no S register display on */ - (UNIT_CPU_MODEL != UNIT_2115)) /* 2116 and 2115 machines */ - SR = data; /* write S register value */ - break; + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, SR); /* read switch register value */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIOO: /* I/O output */ + if ((UNIT_CPU_MODEL != UNIT_2116) && /* no S register display on */ + (UNIT_CPU_MODEL != UNIT_2115)) /* 2116 and 2115 machines */ + SR = IODATA (stat_data); /* write S register value */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - ovflio (select_code, ioCLF, 0); /* issue CLF */ - -return data; +return stat_data; } @@ -2561,35 +2872,37 @@ return data; interrupt register (CIR) is always read by an IOI directed to select code 4. */ -uint32 pwrfio (uint32 select_code, IOSIG signal, uint32 data) +uint32 pwrfio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioSTC: /* set control flip-flop */ - break; /* reinitializes power fail */ + switch (signal) { /* dispatch I/O signal */ - case ioCLC: /* clear control flip-flop */ - break; /* reinitializes power fail */ + case ioSTC: /* set control flip-flop */ + break; /* reinitializes power fail */ - case ioSFC: /* skip if flag is clear */ - break; /* skips if power fail occurred */ + case ioCLC: /* clear control flip-flop */ + break; /* reinitializes power fail */ - case ioIOI: /* I/O input */ - data = intaddr; /* input CIR value */ - break; + case ioSFC: /* skip if flag is clear */ + break; /* skips if power fail occurred */ - default: /* all other signals */ - break; /* are ignored */ + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, intaddr); /* input CIR value */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - pwrfio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - pwrfio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -2634,7 +2947,7 @@ return data; 1. Because the card uses IAK unqualified, this routine is called whenever any interrupt occurs. If the MP card itself is not interrupting, the select code passed will not be SC 05. In either case, the trap cell - instruction is passed in the "data" parameter. + instruction is passed in the data portion of the "stat_data" parameter. 2. The MEV flip-flop records memory expansion (a.k.a. dynamic mapping) violations. It is set when an DM violation is encountered and can be @@ -2649,83 +2962,88 @@ return data; 4. Parity error logic is not implemented. */ -uint32 protio (uint32 select_code, IOSIG signal, uint32 data) +uint32 protio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - break; /* turns off PE interrupt */ + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - break; /* turns on PE interrupt */ + case ioCLF: /* clear flag flip-flop */ + break; /* turns off PE interrupt */ - case ioENF: /* enable flag */ - mp_flag = mp_flagbuf = SET; /* set flag buffer and flag flip-flops */ - mp_evrff = CLEAR; /* inhibit violation register updates */ - break; + case ioSTF: /* set flag flip-flop */ + break; /* turns on PE interrupt */ - case ioSFC: /* skip if flag is clear */ - setSKF (!mp_mevff); /* skip if MP interrupt */ - break; + case ioENF: /* enable flag */ + mp_flag = mp_flagbuf = SET; /* set flag buffer and flag flip-flops */ + mp_evrff = CLEAR; /* inhibit violation register updates */ + break; - case ioSFS: /* skip if flag is set */ - setSKF (mp_mevff); /* skip if DMS interrupt */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (!mp_mevff); /* skip if MP interrupt */ + break; - case ioIOI: /* I/O input */ - data = mp_viol; /* read MP violation register */ - break; + case ioSFS: /* skip if flag is set */ + setSKF (mp_mevff); /* skip if DMS interrupt */ + break; - case ioIOO: /* I/O output */ - mp_fence = data & VAMASK; /* write to MP fence register */ + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, mp_viol); /* read MP violation register */ + break; - if (cpu_unit.flags & UNIT_2100) /* 2100 IOP uses MP fence */ - iop_sp = mp_fence; /* as a stack pointer */ - break; + case ioIOO: /* I/O output */ + mp_fence = IODATA (stat_data) & VAMASK; /* write to MP fence register */ - case ioPOPIO: /* power-on preset to I/O */ - mp_control = CLEAR; /* clear control flip-flop */ - mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer flip-flops */ - mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ - mp_evrff = SET; /* set enable violation register flip-flop */ - break; + if (cpu_unit.flags & UNIT_2100) /* 2100 IOP uses MP fence */ + iop_sp = mp_fence; /* as a stack pointer */ + break; - case ioSTC: /* set control flip-flop */ - mp_control = SET; /* turn on MP */ - mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ - mp_evrff = SET; /* set enable violation register flip-flop */ - break; + case ioPOPIO: /* power-on preset to I/O */ + mp_control = CLEAR; /* clear control flip-flop */ + mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer flip-flops */ + mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ + mp_evrff = SET; /* set enable violation register flip-flop */ + break; - case ioSIR: /* set interrupt request */ - setPRL (PRO, !mp_flag); /* set PRL signal */ - setIRQ (PRO, mp_flag); /* set IRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + mp_control = SET; /* turn on MP */ + mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ + mp_evrff = SET; /* set enable violation register flip-flop */ + break; - case ioIAK: /* interrupt acknowledge */ - if (select_code == PRO) /* MP interrupt acknowledgement? */ - mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer */ + case ioSIR: /* set interrupt request */ + setPRL (PRO, !mp_flag); /* set PRL signal */ + setIRQ (PRO, mp_flag); /* set IRQ signal */ + break; - if (((data & I_NMRMASK) != I_IO) || /* trap cell instruction not I/O */ - (I_GETIOOP (data) == soHLT)) /* or is halt? */ - mp_control = CLEAR; /* turn protection off */ - else { /* non-HLT I/O instruction leaves MP on */ - mp_mevff = CLEAR; /* but clears MEV flip-flop */ - mp_evrff = SET; /* and reenables violation register flip-flop */ - } - break; + case ioIAK: /* interrupt acknowledge */ + if (dibptr->select_code == PRO) /* MP interrupt acknowledgement? */ + mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer */ - default: /* all other signals */ - break; /* are ignored */ + data = IODATA (stat_data); /* get trap cell instruction */ + + if (((data & I_NMRMASK) != I_IO) || /* trap cell instruction not I/O */ + (I_GETIOOP (data) == soHLT)) /* or is halt? */ + mp_control = CLEAR; /* turn protection off */ + else { /* non-HLT I/O instruction leaves MP on */ + mp_mevff = CLEAR; /* but clears MEV flip-flop */ + mp_evrff = SET; /* and reenables violation register flip-flop */ + } + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - protio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - protio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -2753,45 +3071,55 @@ return data; 2. Select codes 2 and 3 cannot interrupt, so there is no SIR handler. */ -uint32 dmasio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dmasio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const uint32 ch = select_code & 1; /* DMA channel number */ -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const CHANNEL ch = dibptr->card_index; /* DMA channel number */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioIOI: /* I/O data input */ - if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ - data = dmac [ch].cw3 & 0017777; /* only 13-bit count */ - else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2115/2116? */ - data = dmac [ch].cw3 & 0037777; /* only 14-bit count */ - else /* other models */ - data = dmac [ch].cw3; /* rest use full value */ - break; /* read remaining word count */ + switch (signal) { /* dispatch I/O signal */ - case ioIOO: /* I/O data output */ - if (dma_select [ch]) /* word count selected? */ - dmac [ch].cw3 = data; /* save count */ - else /* memory address selected */ + case ioIOI: /* I/O data input */ if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ - dmac [ch].cw2 = data & 0137777; /* only 14-bit address */ + data = dma [ch].cw3 & 0017777; /* only 13-bit count */ + else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2115/2116? */ + data = dma [ch].cw3 & 0037777; /* only 14-bit count */ else /* other models */ - dmac [ch].cw2 = data; /* full address stored */ - break; + data = dma [ch].cw3; /* rest use full value */ - case ioCLC: /* clear control flip-flop */ - dma_select [ch] = CLEAR; /* set for word count access */ - break; + stat_data = IORETURN (SCPE_OK, data); /* merge status and remaining word count */ + break; - case ioSTC: /* set control flip-flop */ - dma_select [ch] = SET; /* set for memory address access */ - break; + case ioIOO: /* I/O data output */ + if (dma [ch].select) /* word count selected? */ + dma [ch].cw3 = IODATA (stat_data); /* save count */ + else /* memory address selected */ + if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ + dma [ch].cw2 = IODATA (stat_data) & 0137777; /* only 14-bit address */ + else /* other models */ + dma [ch].cw2 = IODATA (stat_data); /* full address stored */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioCLC: /* clear control flip-flop */ + dma [ch].select = CLEAR; /* set for word count access */ + break; + + case ioSTC: /* set control flip-flop */ + dma [ch].select = SET; /* set for memory address access */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -return data; +return stat_data; } @@ -2819,99 +3147,95 @@ return data; flip-flops. Under simulation, ioCRS is dispatched to select codes 6 and up, so we reset the flip-flop in our handler. - 3. The 12578A card does not start the transfer until one instruction after - the STC 6/7 has executed. The diagnostic tests for this, so we - implement a startup latency counter to provide the proper delay. - - 4. The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is + 3. The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is ignored by all other DMA cards, which support word transfers only. Under simulation, we use a byte-packing/unpacking register to hold one byte while the other is read or written during the DMA cycle. */ -uint32 dmapio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dmapio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const uint32 ch = select_code & 1; /* DMA channel number */ -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const CHANNEL ch = dibptr->card_index; /* DMA channel number */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dma_flag [ch] = dma_flagbuf [ch] = CLEAR; /* clear flag and flag buffer */ - break; + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dma_flag [ch] = dma_flagbuf [ch] = SET; /* set flag and flag buffer */ - dma_xferen [ch] = CLEAR; /* clear transfer enable to abort transfer */ - break; + case ioCLF: /* clear flag flip-flop */ + dma [ch].flag = dma [ch].flagbuf = CLEAR; /* clear flag and flag buffer */ + break; - case ioSFC: /* skip if flag is clear */ - setSKF (!dma_flag [ch]); /* skip if transfer in progress */ - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dma [ch].flag = dma [ch].flagbuf = SET; /* set flag and flag buffer */ + dma [ch].xferen = CLEAR; /* clear transfer enable to abort transfer */ + break; - case ioSFS: /* skip if flag is set */ - setSKF (dma_flag [ch]); /* skip if transfer is complete */ - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dma [ch]); /* skip if transfer in progress */ + break; - case ioIOI: /* I/O data input */ - if (UNIT_CPU_TYPE == UNIT_TYPE_1000) /* 1000? */ - data = DMASK; /* return all ones */ - else /* other models */ - data = 0; /* return all zeros */ - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dma [ch]); /* skip if transfer is complete */ + break; - case ioIOO: /* I/O data output */ - if (UNIT_CPU_MODEL == UNIT_2114) /* 12607? */ - dmac [ch].cw1 = (data & 0137707) | 010; /* mask SC, convert to 10-17 */ - else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 12578? */ - dmac [ch].cw1 = data; /* store full select code, flags */ - else /* 12895, 12897 */ - dmac [ch].cw1 = data & ~DMA1_PB; /* clip byte-packing flag */ - break; + case ioIOI: /* I/O data input */ + if (UNIT_CPU_TYPE == UNIT_TYPE_1000) /* 1000? */ + stat_data = IORETURN (SCPE_OK, DMASK); /* return all ones */ + else /* other models */ + stat_data = IORETURN (SCPE_OK, 0); /* return all zeros */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dma_flag [ch] = dma_flagbuf [ch] = SET; /* set flag and flag buffer */ - /* fall into CRS handler */ + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ - case ioCRS: /* control reset */ - dma_xferen [ch] = CLEAR; /* clear transfer enable */ - dma_select [ch] = CLEAR; /* set secondary for word count access */ + if (UNIT_CPU_MODEL == UNIT_2114) /* 12607? */ + dma [ch].cw1 = (data & 0137707) | 010; /* mask SC, convert to 10-17 */ + else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 12578? */ + dma [ch].cw1 = data; /* store full select code, flags */ + else /* 12895, 12897 */ + dma [ch].cw1 = data & ~DMA1_PB; /* clip byte-packing flag */ + break; + + case ioPOPIO: /* power-on preset to I/O */ + dma [ch].flag = dma [ch].flagbuf = SET; /* set flag and flag buffer */ + break; + + case ioCRS: /* control reset */ + dma [ch].xferen = CLEAR; /* clear transfer enable */ + dma [ch].select = CLEAR; /* set secondary for word count access */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - dma_control [ch] = CLEAR; /* clear control */ - break; + case ioCLC: /* clear control flip-flop */ + dma [ch].control = CLEAR; /* clear control */ + break; - case ioSTC: /* set control flip-flop */ - if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* slow DMA card? */ - dmac [ch].latency = 1; /* needs startup latency */ - else - dmac [ch].latency = 0; /* DCPC starts immediately */ + case ioSTC: /* set control flip-flop */ + dma [ch].packer = 0; /* clear packing register */ + dma [ch].xferen = dma [ch].control = SET; /* set transfer enable and control */ + break; - dmac [ch].packer = 0; /* clear packing register */ - dma_xferen [ch] = dma_control [ch] = SET; /* set transfer enable and control */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (dma [ch]); + setstdIRQ (dma [ch]); + break; - case ioSIR: /* set interrupt request */ - setPRL (select_code, !(dma_control [ch] & dma_flag [ch])); - setIRQ (select_code, dma_control [ch] & dma_flag [ch] & dma_flagbuf [ch]); - break; + case ioIAK: /* interrupt acknowledge */ + dma [ch].flagbuf = CLEAR; /* clear flag buffer */ + break; - case ioIAK: /* interrupt acknowledge */ - dma_flagbuf [ch] = CLEAR; /* clear flag buffer */ - break; + default: /* all other signals */ + break; /* are ignored */ + } - default: /* all other signals */ - break; /* are ignored */ + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - dmapio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dmapio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -2935,134 +3259,173 @@ return data; device is accessed. */ -uint32 nullio (uint32 select_code, IOSIG signal, uint32 data) +uint32 nullio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data = 0; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioIOI: /* I/O data input */ - if ((select_code < VARDEV) && /* internal device */ - (UNIT_CPU_TYPE == UNIT_TYPE_1000)) /* and 1000? */ - data = DMASK; /* return all ones */ - else /* external or other model */ - data = 0; /* return all zeros */ - break; + switch (signal) { /* dispatch I/O signal */ - default: /* all other signals */ - break; /* are ignored */ + case ioIOI: /* I/O data input */ + if ((dibptr->select_code < VARDEV) && /* internal device */ + (UNIT_CPU_TYPE == UNIT_TYPE_1000)) /* and 1000? */ + data = DMASK; /* return all ones */ + else /* external or other model */ + data = 0; /* return all zeros */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -return (stop_dev << IOT_V_REASON) | data; /* flag missing device */ +return IORETURN (stop_dev, data); /* flag missing device */ } -/* DMA cycle routine +/* DMA cycle routine. + + This routine performs one DMA input or output cycle using the indicated DMA + channel number and DMS map. When the transfer word count reaches zero, the + flag is set on the corresponding DMA channel to indicate completion. The 12578A card supports byte-packing. If bit 14 in control word 1 is set, each transfer will involve one read/write from memory and two output/input operations in order to transfer sequential bytes to/from the device. - The last cycle (word count reaches 0) logic is quite tricky. + DMA I/O cycles differ from programmed I/O cycles in that multiple I/O control + backplane signals may be asserted simultaneously. With programmed I/O, only + CLF may be asserted with other signals, specifically with STC, CLC, SFS, SFC, + IOI, or IOO. With DMA, as many as five signals may be asserted concurrently. - Input cases: - - CLC requested: issue CLC + DMA I/O timing looks like this: - Output cases: - - neither STC nor CLC requested: issue CLF - - STC requested but not CLC: issue STC,C - - CLC requested but not STC: issue CLC,C - - STC and CLC both requested: issue STC,C and CLC,C, in that order + ------------ Input ------------ ----------- Output ------------ + Sig Normal Cycle Last Cycle Normal Cycle Last Cycle + === ============== ============== ============== ============== + IOI T2-T3 T2-T3 + IOO T3-T4 T3-T4 + STC * T3 T3 T3 + CLC * T3-T4 T3-T4 + CLF T3 T3 T3 + EDT T4 T4 - Either case: issue EDT + * if enabled by control word 1 + + Under simulation, this routine dispatches one set of I/O signals per DMA + cycle to the target device's I/O signal handler. The signals correspond to + the table above, except that all signals for a given cycle are concurrent + (e.g., the last input cycle has IOI, EDT, and optionally CLC asserted, even + though IOI and EDT are not coincident in hardware). I/O signal handlers will + process these signals sequentially, in the order listed above, before + returning. Implementation notes: - 1. The EDT signal is sent to the device signal handler with the "data" - parameter set to ioIOI or ioIOO to indicate the completion of an input or - output transfer, respectively. The IPL device is the only one that uses - this (at the moment). + 1. The address increment and word count decrement is done only after the I/O + cycle has completed successfully. This allows a failed transfer to be + retried after correcting the I/O error. */ -static void dma_cycle (uint32 ch, uint32 map) +static t_stat dma_cycle (CHANNEL ch, uint32 map) { -uint32 temp, dev; -int32 MA; -int32 inp = dmac[ch].cw2 & DMA2_OI; /* input flag */ -int32 byt = dmac[ch].cw1 & DMA1_PB; /* pack bytes flag */ +const uint32 dev = dma [ch].cw1 & I_DEVMASK; /* device select code */ +const uint32 stc = dma [ch].cw1 & DMA1_STC; /* STC enable flag */ +const uint32 bytes = dma [ch].cw1 & DMA1_PB; /* pack bytes flag */ +const uint32 clc = dma [ch].cw1 & DMA1_CLC; /* CLC enable flag */ +const uint32 MA = dma [ch].cw2 & VAMASK; /* memory address */ +const uint32 input = dma [ch].cw2 & DMA2_OI; /* input flag */ +const uint32 even = dma [ch].packer & DMA_OE; /* odd/even packed byte flag */ +uint16 data; +t_stat status; +uint32 ioresult; +IOCYCLE signals; -if (dmac[ch].latency) { /* start-up latency? */ - dmac[ch].latency = dmac[ch].latency - 1; /* decrease it */ - return; /* that's all this cycle */ +if (bytes && !even || dma [ch].cw3 != DMASK) { /* normal cycle? */ + if (input) /* input cycle? */ + signals = ioIOI | ioCLF; /* assert IOI and CLF */ + else /* output cycle */ + signals = ioIOO | ioCLF; /* assert IOO and CLF */ + + if (stc) /* STC wanted? */ + signals = signals | ioSTC; /* assert STC */ } -dev = dmac[ch].cw1 & I_DEVMASK; /* get device */ -MA = dmac[ch].cw2 & VAMASK; /* get mem addr */ +else { /* last cycle */ + if (input) /* input cycle? */ + signals = ioIOI | ioEDT; /* assert IOI and EDT */ + else { /* output cycle */ + signals = ioIOO | ioCLF | ioEDT; /* assert IOO and CLF and EDT */ -if (inp) { /* input cycle? */ - temp = devdisp (dev, ioIOI, 0); /* do I/O input */ - - if (byt) { /* byte packing? */ - if (dmac[ch].packer & DMA_OE) { /* second byte? */ - temp = (dmac[ch].packer << 8) | /* merge stored byte */ - (temp & DMASK8); - WriteIO (MA, temp, map); /* store word data */ - } - else /* first byte */ - dmac[ch].packer = (temp & DMASK8); /* save it */ - - dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */ + if (stc) /* STC wanted? */ + signals = signals | ioSTC; /* assert STC */ } - else /* no byte packing */ - WriteIO (MA, temp, map); /* store word data */ + + if (clc) /* CLC wanted? */ + signals = signals | ioCLC; /* assert CLC */ } + +if (input) { /* input cycle? */ + ioresult = devdisp (dev, signals, /* do I/O input */ + IORETURN (SCPE_OK, 0)); + + status = IOSTATUS (ioresult); /* get cycle status */ + + if (status == SCPE_OK) { /* good I/O cycle? */ + data = IODATA (ioresult); /* extract return data value */ + + if (bytes) { /* byte packing? */ + if (even) { /* second byte? */ + data = (dma [ch].packer << 8) | /* merge stored byte */ + (data & DMASK8); + WriteIO (MA, data, map); /* store word data */ + } + else /* first byte */ + dma [ch].packer = (data & DMASK8); /* save it */ + + dma [ch].packer = dma [ch].packer ^ DMA_OE; /* flip odd/even bit */ + } + else /* no byte packing */ + WriteIO (MA, data, map); /* store word data */ + } + } + else { /* output cycle */ - if (byt) { /* byte packing? */ - if (dmac[ch].packer & DMA_OE) /* second byte? */ - temp = dmac[ch].packer & DMASK8; /* retrieve it */ + if (bytes) { /* byte packing? */ + if (even) /* second byte? */ + data = dma [ch].packer & DMASK8; /* retrieve it */ else { /* first byte */ - dmac[ch].packer = ReadIO (MA, map); /* read word data */ - temp = (dmac[ch].packer >> 8) & DMASK8; /* get high byte */ + dma [ch].packer = ReadIO (MA, map); /* read word data */ + data = (dma [ch].packer >> 8) & DMASK8; /* get high byte */ } - dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */ + dma [ch].packer = dma [ch].packer ^ DMA_OE; /* flip odd/even bit */ } else /* no byte packing */ - temp = ReadIO (MA, map); /* read word data */ + data = ReadIO (MA, map); /* read word data */ - devdisp (dev, ioIOO, temp); /* do I/O output */ + ioresult = devdisp (dev, signals, /* do I/O output */ + IORETURN (SCPE_OK, data)); + + status = IOSTATUS (ioresult); /* get cycle status */ } -if ((dmac[ch].packer & DMA_OE) == 0) { /* new byte or no packing? */ - dmac[ch].cw2 = (dmac[ch].cw2 & DMA2_OI) | /* increment address */ - ((dmac[ch].cw2 + 1) & VAMASK); - dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* increment word count */ +if ((even || !bytes) && (status == SCPE_OK)) { /* new byte or no packing and good xfer? */ + dma [ch].cw2 = input | (dma [ch].cw2 + 1) & VAMASK; /* increment address */ + dma [ch].cw3 = (dma [ch].cw3 + 1) & DMASK; /* increment word count */ + + if (dma [ch].cw3 == 0) /* end of transfer? */ + dmapio (dtab [DMA1 + ch], ioENF, 0); /* set DMA channel flag */ } -if (dmac[ch].cw3) { /* more to do? */ - if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */ - devdisp (dev, ioSTC + ioCLF, 0); /* do STC,C dev */ - else devdisp (dev, ioCLF, 0); /* else CLF dev */ - } -else { - if (inp) { /* last cycle, input? */ - if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */ - devdisp (dev, ioCLC, 0); /* yes */ - } /* end input */ - else { /* output */ - if ((dmac[ch].cw1 & (DMA1_STC | DMA1_CLC)) == 0) - devdisp (dev, ioCLF, 0); /* clear flag */ - if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */ - devdisp (dev, ioSTC + ioCLF, 0); /* do STC,C dev */ - if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */ - devdisp (dev, ioCLC + ioCLF, 0); /* yes */ - } /* end output */ - - dmapio (DMA0 + ch, ioENF, 0); /* set DMA channel flag */ - devdisp (dev, ioEDT, (uint32) (inp ? ioIOI : ioIOO)); /* send EDT to device */ - } -return; +return status; /* return I/O status */ } @@ -3070,9 +3433,9 @@ return; The reset routines are called to simulate either an initial power on condition or a front-panel PRESET button press. For initial power on - (corresponds to PON signal assertion in the CPU), the "P" command switch will - be set. For PRESET (corresponds to POPIO and CRS assertion), the switch will - be clear. + (corresponds to PON, POPIO, and CRS signal assertion in the CPU), the "P" + command switch will be set. For PRESET (corresponds to POPIO and CRS + assertion), the switch will be clear. SCP delivers a power-on reset to all devices when the simulator is started. A RUN, BOOT, RESET, or RESET ALL command delivers a PRESET to all devices. A @@ -3084,15 +3447,6 @@ return; If this is the first call after simulator startup, allocate the initial memory array, set the default CPU model, and install the default BBL. - - A PON reset initializes certain CPU registers. The 1000 series does a - microcoded memory clear and leaves the T and P registers set as a result. - - Front-panel PRESET performs additional initialization. We also handle MEM - preset here. - - Because PRESET is dispatched to every device separately, each of which will - handle POPIO and CRS in response, we do not need to dispatch POPIO ourselves. */ t_stat cpu_reset (DEVICE *dptr) @@ -3121,33 +3475,10 @@ if (M == NULL) { /* initial call after st } } -if (sim_switches & SWMASK ('P')) { /* PON reset? */ - AR = 0; /* clear A register */ - BR = 0; /* clear B register */ - SR = 0; /* clear S register */ - TR = 0; /* clear T register */ - E = 1; /* set E register */ - - if (UNIT_CPU_FAMILY == UNIT_FAMILY_1000) { /* 1000 series? */ - memset (M, 0, MEMSIZE * 2); /* zero allocated memory */ - MR = 0077777; /* set M register */ - PC = 0100000; /* set P register */ - } - - else { /* 21xx series */ - MR = 0; /* clear M register */ - PC = 0; /* clear P register */ - } - } - -O = 0; /* PRESET: clear O register */ -ion = CLEAR; /* PRESET: turn off interrupt system */ -ion_defer = FALSE; /* PRESET: clear interrupt deferral */ - -dms_enb = 0; /* POPIO: turn DMS off */ -dms_ump = 0; /* POPIO: init to system map */ -dms_sr = 0; /* POPIO: clear status register and BP fence */ -dms_vr = 0; /* POPIO: clear violation register */ +if (sim_switches & SWMASK ('P')) /* PON reset? */ + IOPOWERON (&cpu_dib); +else /* PRESET */ + IOPRESET (&cpu_dib); sim_brk_dflt = SWMASK ('N'); /* type is nomap as DMS is off */ @@ -3159,7 +3490,7 @@ return SCPE_OK; t_stat mp_reset (DEVICE *dptr) { -protio (PRO, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&mp_dib); /* PRESET device (does not use PON) */ mp_fence = 0; /* clear fence register */ mp_viol = 0; /* clear violation register */ @@ -3168,36 +3499,27 @@ return SCPE_OK; } -/* DMA channel 1 reset */ +/* DMA reset */ -t_stat dma0_reset (DEVICE *tptr) +t_stat dma_reset (DEVICE *dptr) { +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ +const CHANNEL ch = dibptr->card_index; /* DMA channel number */ + if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ - hp_enbdis_pair (&dma0_dev, &dma1_dev); /* make pair cons */ + hp_enbdis_pair (dma_dptrs [ch], /* make specified channel */ + dma_dptrs [ch ^ 1]); /* consistent with other channel */ -if (sim_switches & SWMASK ('P')) /* PON reset? */ - dmac[0].cw1 = dmac[0].cw2 = dmac[0].cw3 = 0; /* clear control word registers */ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ + dma [ch].cw1 = 0; /* clear control word registers */ + dma [ch].cw2 = 0; + dma [ch].cw3 = 0; + } -dmapio (DMA0, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ -dmac[0].latency = dmac[0].packer = 0; /* clear latency and byte packer */ -return SCPE_OK; -} +dma [ch].packer = 0; /* clear byte packer */ - -/* DMA channel 2 reset */ - -t_stat dma1_reset (DEVICE *tptr) -{ -if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ - hp_enbdis_pair (&dma1_dev, &dma0_dev); /* make pair cons */ - -if (sim_switches & SWMASK ('P')) /* PON reset? */ - dmac[1].cw1 = dmac[1].cw2 = dmac[1].cw3 = 0; /* clear control word registers */ - -dmapio (DMA1, ioPOPIO, 0); /* send POPIO signal */ - -dmac[1].latency = dmac[1].packer = 0; /* clear latency and byte packer */ return SCPE_OK; } @@ -3251,8 +3573,11 @@ return SCPE_OK; void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp) { -if (ccp->flags & DEV_DIS) dcp->flags = dcp->flags | DEV_DIS; -else dcp->flags = dcp->flags & ~DEV_DIS; +if (ccp->flags & DEV_DIS) + dcp->flags = dcp->flags | DEV_DIS; +else + dcp->flags = dcp->flags & ~DEV_DIS; + return; } @@ -3277,38 +3602,51 @@ return; static t_bool dev_conflict (void) { DEVICE *dptr; -DIB *dibp; +DIB *dibptr; uint32 i, j, k; t_bool is_conflict = FALSE; -uint32 conflicts[I_DEVMASK + 1] = { 0 }; +uint32 conflicts[MAXDEV + 1] = { 0 }; for (i = 0; dptr = sim_devices[i]; i++) { - dibp = (DIB *) dptr->ctxt; - if (dibp && !(dptr->flags & DEV_DIS)) - if (++conflicts[dibp->devno] > 1) + dibptr = (DIB *) dptr->ctxt; + if (dibptr && !(dptr->flags & DEV_DIS)) + if (++conflicts[dibptr->select_code] > 1) is_conflict = TRUE; } if (is_conflict) { sim_ttcmd(); - for (i = 0; i <= I_DEVMASK; i++) { + for (i = 0; i <= MAXDEV; i++) { if (conflicts[i] > 1) { k = conflicts[i]; + printf ("Select code %o conflict:", i); - if (sim_log) fprintf (sim_log, "Select code %o conflict:", i); + + if (sim_log) + fprintf (sim_log, "Select code %o conflict:", i); + for (j = 0; dptr = sim_devices[j]; j++) { - dibp = (DIB *) dptr->ctxt; - if (dibp && !(dptr->flags & DEV_DIS) && (i == dibp->devno)) { + dibptr = (DIB *) dptr->ctxt; + if (dibptr && !(dptr->flags & DEV_DIS) && (i == dibptr->select_code)) { if (k < conflicts[i]) { printf (" and"); - if (sim_log) fputs (" and", sim_log); + + if (sim_log) + fputs (" and", sim_log); } + printf (" %s", sim_dname (dptr)); - if (sim_log) fprintf (sim_log, " %s", sim_dname (dptr)); + + if (sim_log) + fprintf (sim_log, " %s", sim_dname (dptr)); + k = k - 1; + if (k == 0) { putchar ('\n'); - if (sim_log) fputc ('\n', sim_log); + + if (sim_log) + fputc ('\n', sim_log); break; } } @@ -3345,7 +3683,9 @@ if ((new_size <= 0) || (new_size > PASIZE) || ((new_size & 07777) != 0)) return SCPE_NXM; /* invalid size (prog err) */ if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */ - for (i = new_size; i < MEMSIZE; i++) mc = mc | M[i]; + for (i = new_size; i < MEMSIZE; i++) /* check truncated memory */ + mc = mc | M[i]; /* for content */ + if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_INCOMP; } @@ -3358,7 +3698,9 @@ if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx CPU? */ else /* loader unsupported */ fwanxm = MEMSIZE = new_size; /* set new memory size */ -for (i = fwanxm; i < old_size; i++) M[i] = 0; /* zero non-existent memory */ +for (i = fwanxm; i < old_size; i++) /* zero non-existent memory */ + M[i] = 0; + return SCPE_OK; } @@ -3367,7 +3709,7 @@ return SCPE_OK; For convenience, MP and DMA are typically enabled if available; they may be disabled subsequently if desired. Note that the 2114 supports only one DMA - channel (channel 0). All other models support two channels. + channel (channel 1). All other models support two channels. Validation: - Sets standard equipment and convenience features. @@ -3400,41 +3742,41 @@ else if (cpu_features[new_index].typ & UNIT_DMA) { /* DMA in typ config? */ - dma0_dev.flags = dma0_dev.flags & ~DEV_DIS; /* enable DMA channel 0 */ + dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; /* enable DMA channel 1 */ if (new_model == UNIT_2114) /* 2114 has only one channel */ - dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */ + dma2_dev.flags = dma2_dev.flags | DEV_DIS; /* disable channel 2 */ else /* all others have two channels */ - dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; /* enable it */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DIS; /* enable it */ } else { - dma0_dev.flags = dma0_dev.flags | DEV_DIS; /* disable channel 0 */ dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */ + dma2_dev.flags = dma2_dev.flags | DEV_DIS; /* disable channel 2 */ } if (cpu_features[new_index].opt & UNIT_DMA) { /* DMA an option? */ - dma0_dev.flags = dma0_dev.flags | DEV_DISABLE; /* make it alterable */ + dma1_dev.flags = dma1_dev.flags | DEV_DISABLE; /* make it alterable */ if (new_model == UNIT_2114) /* 2114 has only one channel */ - dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DISABLE; /* make it unalterable */ else /* all others have two channels */ - dma1_dev.flags = dma1_dev.flags | DEV_DISABLE; /* make it alterable */ + dma2_dev.flags = dma2_dev.flags | DEV_DISABLE; /* make it alterable */ } else { - dma0_dev.flags = dma0_dev.flags & ~DEV_DISABLE; /* make it unalterable */ dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DISABLE; /* make it unalterable */ } if ((old_family == UNIT_FAMILY_1000) && /* if current family is 1000 */ (new_family == UNIT_FAMILY_21XX)) { /* and new family is 21xx */ - deassign_device (&dma0_dev); /* delete DCPC names */ - deassign_device (&dma1_dev); + deassign_device (&dma1_dev); /* delete DCPC names */ + deassign_device (&dma2_dev); } else if ((old_family == UNIT_FAMILY_21XX) && /* if current family is 21xx */ (new_family == UNIT_FAMILY_1000)) { /* and new family is 1000 */ - assign_device (&dma0_dev, "DCPC0"); /* change DMA device name */ - assign_device (&dma1_dev, "DCPC1"); /* to DCPC for familiarity */ + assign_device (&dma1_dev, "DCPC1"); /* change DMA device name */ + assign_device (&dma2_dev, "DCPC2"); /* to DCPC for familiarity */ } if ((MEMSIZE == 0) || /* current mem size not set? */ @@ -3593,16 +3935,7 @@ return SCPE_OK; } -/* Idle set/clear. - - Idling must have a calibrated clock before sleeping, or the TBG rate will - be wrong. When we handle a SET CPU IDLE, we want to... - - ...do something to allow the clock to stabilize before actually enabling. - Probably set sim_idle_enab immediately, so idling is reported as on, but - don't actually call sim_idle() until clock stabilizes. Maybe "cpu_idle" = 0 - and then = 1 after 100 clocks? - */ +/* Idle enable/disable */ t_stat cpu_set_idle (UNIT *uptr, int32 option, char *cptr, void *desc) { @@ -3629,7 +3962,9 @@ extern const BOOT_ROM ptr_rom, dq_rom, ms_rom, ds_rom; int32 dev = (SR >> IBL_V_DEV) & I_DEVMASK; int32 sel = (SR >> IBL_V_SEL) & IBL_M_SEL; -if (dev < 010) return SCPE_NOFNC; +if (dev < 010) + return SCPE_NOFNC; + switch (sel) { case 0: /* PTR boot */ @@ -3657,11 +3992,11 @@ return SCPE_OK; - Use memory size to set the initial PC and base of the boot area - Copy boot ROM to memory, updating I/O instructions - - Place 2's complement of boot base in last location + - Place 2s complement of boot base in last location Notes: - SR settings are done by the caller - - Boot ROM's must be assembled with a device code of 10 (10 and 11 for + - Boot ROMs must be assembled with a device code of 10 (10 and 11 for devices requiring two codes) */ @@ -3672,16 +4007,23 @@ uint16 wd; cpu_set_ldr (NULL, TRUE, NULL, NULL); /* enable loader (ignore errors) */ -if (dev < 010) return SCPE_ARG; /* valid device? */ +if (dev < 010) /* valid device? */ + return SCPE_ARG; + PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ + for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ wd = rom[i]; /* get word */ + if (((wd & I_NMRMASK) == I_IO) && /* IO instruction? */ ((wd & I_DEVMASK) >= 010) && /* dev >= 10? */ (I_GETIOOP (wd) != soHLT)) /* not a HALT? */ M[PC + i] = (wd + (dev - 010)) & DMASK; /* change dev code */ - else M[PC + i] = wd; /* leave unchanged */ + + else /* leave unchanged */ + M[PC + i] = wd; } + M[PC + IBL_DPC] = (M[PC + IBL_DPC] + (dev - 010)) & DMASK; /* patch DMA ctrl */ M[PC + IBL_END] = (~PC + 1) & DMASK; /* fill in start of boot */ return SCPE_OK; diff --git a/HP2100/hp2100_cpu.h b/HP2100/hp2100_cpu.h index 4b1f8e94..4e0db47e 100644 --- a/HP2100/hp2100_cpu.h +++ b/HP2100/hp2100_cpu.h @@ -281,24 +281,25 @@ extern uint32 O; /* O register */ /* CPU state */ -extern uint32 err_PC; -extern uint32 dms_enb; -extern uint32 dms_ump; -extern uint32 dms_sr; -extern uint32 dms_vr; -extern FLIP_FLOP mp_control; -extern uint32 mp_fence; -extern uint32 mp_viol; -extern FLIP_FLOP mp_mevff; -extern uint32 iop_sp; -extern t_bool ion_defer; -extern uint32 intaddr; -extern uint16 pcq [PCQ_SIZE]; -extern uint32 pcq_p; -extern uint32 stop_inst; -extern UNIT cpu_unit; -extern DEVICE cpu_dev; -extern jmp_buf save_env; +extern uint32 err_PC; +extern uint32 dms_enb; +extern uint32 dms_ump; +extern uint32 dms_sr; +extern uint32 dms_vr; +extern FLIP_FLOP mp_control; +extern uint32 mp_fence; +extern uint32 mp_viol; +extern FLIP_FLOP mp_mevff; +extern uint32 iop_sp; +extern t_bool ion_defer; +extern uint32 intaddr; +extern uint16 pcq [PCQ_SIZE]; +extern uint32 pcq_p; +extern uint32 stop_inst; +extern UNIT cpu_unit; +extern DEVICE cpu_dev; +extern jmp_buf save_env; + /* CPU functions */ diff --git a/HP2100/hp2100_cpu0.c b/HP2100/hp2100_cpu0.c index df199de2..2e7e6eb2 100644 --- a/HP2100/hp2100_cpu0.c +++ b/HP2100/hp2100_cpu0.c @@ -1,6 +1,6 @@ /* hp2100_cpu0.c: HP 1000 user microcode and unimplemented instruction set stubs - Copyright (c) 2006-2008, J. David Bryan + Copyright (c) 2006-2010, J. David Bryan 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 @@ CPU0 User microcode and unimplemented firmware options + 04-Nov-10 JDB Removed DS note regarding PIF card (is now implemented) 18-Sep-08 JDB .FLUN and self-tests for VIS and SIGNAL are NOP if not present 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) @@ -81,8 +82,7 @@ the cards. Implementation of the DS instructions will also require simulation of the - 12665A Hardwired Serial Data Interface Card and the 12620A RTE Privileged - Interrupt Fence. These are required for DS/1000. + 12665A Hardwired Serial Data Interface Card. Option implementation by CPU was as follows: @@ -180,11 +180,11 @@ t_stat reason = SCPE_OK; if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2116/15/14 CPU? */ return stop_inst; /* user microprograms not supported */ -switch (IR) { /* opcodes for firmware detection */ - case 0105226: /* FFP .FLUN */ - case 0105355: /* RTE-6/VM OS self-test */ - case 0105477: /* VIS self-test */ - case 0105617: /* SIGNAL/1000 self-test */ +switch (IR) { + case 0105226: /* firmware detection: FFP .FLUN */ + case 0105355: /* firmware detection: RTE-6/VM OS self-test */ + case 0105477: /* firmware detection: VIS self-test */ + case 0105617: /* firmware detection: SIGNAL/1000 self-test */ return SCPE_OK; /* execute as NOP */ } diff --git a/HP2100/hp2100_cpu6.c b/HP2100/hp2100_cpu6.c index f0a464de..5606a178 100644 --- a/HP2100/hp2100_cpu6.c +++ b/HP2100/hp2100_cpu6.c @@ -1,6 +1,6 @@ /* hp2100_cpu6.c: HP 1000 RTE-6/VM OS instructions - Copyright (c) 2006-2008, J. David Bryan + Copyright (c) 2006-2010, J. David Bryan 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 @@ CPU6 RTE-6/VM OS instructions + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation 18-Sep-08 JDB Corrected .SIP debug formatting 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) @@ -258,8 +259,8 @@ if (iotrap) { /* do priv setup only if if (priv_fence) { /* privileged system? */ reason = iogrp (STC_0 + priv_fence, iotrap); /* STC SC on priv fence */ - reason = iogrp (CLC_0 + DMA0, iotrap); /* CLC 6 to inh IRQ on DCPC 0 */ - reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 7 to inh IRQ on DCPC 1 */ + reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 6 to inh IRQ on DCPC 1 */ + reason = iogrp (CLC_0 + DMA2, iotrap); /* CLC 7 to inh IRQ on DCPC 2 */ reason = iogrp (STF_0, iotrap); /* turn interrupt system back on */ } } @@ -600,11 +601,11 @@ switch (entry) { /* decode IR<3:0> */ reason = iogrp (CLC_0 + priv_fence, iotrap); /* CLC SC on priv fence */ reason = iogrp (STF_0 + priv_fence, iotrap); /* STF SC on priv fence */ - if (cpu_get_intbl (DMA0) & SIGN) /* DCPC 0 active? */ - reason = iogrp (STC_0 + DMA0, iotrap); /* STC 6 to enable IRQ on DCPC 0 */ - if (cpu_get_intbl (DMA1) & SIGN) /* DCPC 1 active? */ - reason = iogrp (STC_0 + DMA1, iotrap); /* STC 7 to enable IRQ on DCPC 1 */ + reason = iogrp (STC_0 + DMA1, iotrap); /* STC 6 to enable IRQ on DCPC 1 */ + + if (cpu_get_intbl (DMA2) & SIGN) /* DCPC 2 active? */ + reason = iogrp (STC_0 + DMA2, iotrap); /* STC 7 to enable IRQ on DCPC 2 */ } tbg_tick = 0; /* .IRT terminates TBG servicing */ diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index b0e8ff40..f999867b 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-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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. + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation + 27-Oct-10 JDB Revised I/O signal enum values for concurrent signals + Revised I/O macros for new signal handling 07-Sep-08 JDB Added POLL_FIRST to indicate immediate connection attempt 15-Jul-08 JDB Rearranged declarations with hp2100_cpu.h 26-Jun-08 JDB Rewrote device I/O to model backplane signals @@ -128,87 +132,18 @@ typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization #define soOTX 6 /* output from A/B */ #define soCTL 7 /* set/clear control */ - -/* I/O backplane signals. - - The IOSIG declarations mirror the I/O backplane signals. These are sent to - the device I/O signal handlers for action. Normally, only one signal may be - sent at a time. However, the ioCLF signal may be added (arithmetically) to - another signal; the handlers will process the other signal first and then the - CLF signal. - - Implementation notes: - - 1. The first valid signal must have a value > 0, and ioCLF must be - enumerated last, so that adding ioCLF produces a result > ioCLF. - - 2. The signals are structured so that all those that might change the - interrupt state are enumerated after ioSIR. The handlers will detect - this and add an ioSIR signal automatically. - - 3. In hardware, the POPIO signal is asserted concurrently with the CRS - signal. Under simulation, ioPOPIO implies ioCRS, so the handlers are - structured to fall from POPIO handling into CRS handling. It is not - necessary to send both signals for a PRESET. - - 4. In hardware, the SIR signal is generated unconditionally every T5 period - to time the setting of the IRQ flip-flop. Under simulation, ioSIR is - sent to set the PRL, IRQ, and SRQ signals as indicated by the interface - logic. It is necessary to send ioSIR only when that logic indicates a - change in one or more of the three signals. - - 5. In hardware, the ENF signal is unconditionally generated every T2 period - to time the setting of the flag flip-flop and to reset the IRQ flip-flop. - If the flag buffer flip-flip is set, then flag will be set by ENF. If - the flag buffer is clear, ENF will not affect flag. Under simulation, - ioENF is sent to set the flag buffer and flag flip-flops. For those - interfaces where this action is identical to that provided by STF, the - ioENF handler may simply fall into the ioSTF handler. - - 6. The ioSKF signal is never sent to an I/O device. Rather, it is returned - from the device if the SFC or SFS condition is true. - - 7. A device will receive ioNONE when a HLT instruction is executed, and the - H/C bit is clear (i.e., no CLF generated). -*/ - -typedef enum { CLEAR, SET } FLIP_FLOP; /* flip-flop type and values */ - -typedef enum { ioNONE, /* no signal asserted */ - ioSKF, /* skip on flag */ - ioSFC, /* skip if flag is clear */ - ioSFS, /* skip if flag is set */ - ioIOI, /* I/O data input */ - ioIOO, /* I/O data output */ - ioEDT, /* end data transfer */ - ioSIR, /* set interrupt request */ - ioIAK, /* interrupt acknowledge */ - ioCRS, /* control reset */ - ioPOPIO, /* power-on preset to I/O */ - ioCLC, /* clear control flip-flop */ - ioSTC, /* set control flip-flop */ - ioENF, /* enable flag */ - ioSTF, /* set flag flip-flop */ - ioCLF } IOSIG; /* clear flag flip-flop */ - -/* I/O devices - fixed assignments */ +/* I/O devices - fixed select code assignments */ #define CPU 000 /* interrupt control */ #define OVF 001 /* overflow */ -#define DMALT0 002 /* DMA 0 alternate */ -#define DMALT1 003 /* DMA 1 alternate */ +#define DMALT1 002 /* DMA 1 alternate */ +#define DMALT2 003 /* DMA 2 alternate */ #define PWR 004 /* power fail */ #define PRO 005 /* parity/mem protect */ -#define DMA0 006 /* DMA channel 0 */ -#define DMA1 007 /* DMA channel 1 */ -#define OPTDEV DMALT0 /* start of optional devices */ -#define VARDEV (DMA1 + 1) /* start of var assign */ -#define M_NXDEV (INT_M (CPU) | INT_M (OVF) | \ - INT_M (DMALT0) | INT_M (DMALT1)) -#define M_FXDEV (M_NXDEV | INT_M (PWR) | INT_M (PRO) | \ - INT_M (DMA0) | INT_M (DMA1)) +#define DMA1 006 /* DMA channel 1 */ +#define DMA2 007 /* DMA channel 2 */ -/* I/O devices - variable assignment defaults */ +/* I/O devices - variable select code assignment defaults */ #define PTR 010 /* 12597A-002 paper tape reader */ #define TTY 011 /* 12531C teleprinter */ @@ -236,6 +171,11 @@ typedef enum { ioNONE, /* no signal asserted */ #define MUXU 041 /* 12920A upper data */ #define MUXC 042 /* 12920A control */ +#define OPTDEV 002 /* start of optional devices */ +#define CRSDEV 006 /* start of devices that receive CRS */ +#define VARDEV 010 /* start of variable assignments */ +#define MAXDEV 077 /* end of select code range */ + /* IBL assignments */ #define IBL_V_SEL 14 /* ROM select */ @@ -257,41 +197,240 @@ typedef enum { ioNONE, /* no signal asserted */ typedef uint16 BOOT_ROM [IBL_LNT]; /* boot ROM data */ -/* Dynamic device information table */ -typedef uint32 IODISP (uint32 select_code, IOSIG signal, uint32 data); /* I/O signal dispatch function */ +/* I/O backplane signals. -typedef struct { - uint32 devno; /* device select code */ - IODISP *iot; /* pointer to I/O signal dispatcher */ - } DIB; + The IOSIGNAL declarations mirror the hardware I/O backplane signals. A set + of one or more signals forms an IOCYCLE that is sent to a device IOHANDLER + for action. The CPU and DMA dispatch one signal set to the target device + handler per I/O cycle. A CPU cycle consists of either one or two signals; if + present, the second signal will be CLF. A DMA cycle consists of from two to + five signals. In addition, a front-panel PRESET or power-on reset dispatches + two or three signals, respectively. -/* I/O macros */ + In hardware, signals are assigned to one or more specific I/O T-periods, and + some signals are asserted concurrently. For example, a programmed STC sc,C + instruction asserts the STC and CLF signals together in period T4. Under + simulation, signals are ORed to form an I/O cycle; in this example, the + signal handler would receive an IOCYCLE value of "ioSTC | ioCLF". -#define IOBASE(S) ((S) > ioCLF ? (S) - ioCLF : (S)) /* base signal from compound signal */ + Hardware allows parallel action for concurrent signals. Under simulation, a + "concurrent" set of signals is processed sequentially by the signal handler + in order of ascending numerical value. Although assigned T-periods differ + between programmed I/O and DMA I/O cycles, a single processing order is used. + The order of execution generally follows the order of T-period assertion, + except that ioSIR is processed after all other signals that may affect the + interrupt request chain. -#define INT_V(x) ((x) & 037) /* device bit position */ -#define INT_M(x) (1u << INT_V (x)) /* device bit mask */ + Implementation notes: -#define setSKF(B) data = (uint32) ((B) ? ioSKF : ioNONE) + 1. The ioCLF signal must be processed after ioSFS/ioSFC to ensure that a + true skip test generates ioSKF before the flag is cleared, and after + ioIOI/ioIOO/ioSTC/ioCLC to meet the requirement that executing an + instruction having the H/C bit set is equivalent to executing the same + instruction with the H/C bit clear and then a CLF instruction. -#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S)) -#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S)) -#define setSRQ(S,B) dev_srq[(S)/32] = dev_srq[(S)/32] & ~INT_M (S) | (((B) & 1) << INT_V (S)) + 2. The ioSKF signal is never sent to an I/O handler. Rather, it is returned + from the handler if the SFC or SFS condition is true. If the condition + is false, ioNONE is returned instead. As these two values are returned + in the 16-bit data portion of the returned value, their assigned values + must be <= 100000 octal. -#define setstdSKF(N) setSKF ((base_signal == ioSFC) && !N ## _flag || \ - (base_signal == ioSFS) && N ## _flag) + 3. An I/O handler will receive ioCRS as a result of a CLC 0 instruction, + ioPOPIO and ioCRS as a result of a RESET command, and ioPON, ioPOPIO, and + ioCRS as a result of a RESET -P command. -#define setstdPRL(S,N) setPRL ((S), !(N ## _control & N ## _flag)); -#define setstdIRQ(S,N) setIRQ ((S), N ## _control & N ## _flag & N ## _flagbuf); -#define setstdSRQ(S,N) setSRQ ((S), N ## _flag); + 4. An I/O handler will receive ioNONE when a HLT instruction is executed + that has the H/C bit clear (i.e., no CLF generated). -#define PRL(S) ((dev_prl[(S)/32] >> INT_V (S)) & 1) -#define IRQ(S) ((dev_irq[(S)/32] >> INT_V (S)) & 1) -#define SRQ(S) ((dev_srq[(S)/32] >> INT_V (S)) & 1) + 5. In hardware, the SIR signal is generated unconditionally every T5 period + to time the setting of the IRQ flip-flop. Under simulation, ioSIR + indicates that the I/O handler must set the PRL, IRQ, and SRQ signals as + required by the interface logic. ioSIR must be included in the I/O cycle + if any of the flip-flops affecting these signals are changed and the + interface supports interrupts or DMA transfers. + + 6. In hardware, the ENF signal is unconditionally generated every T2 period + to time the setting of the flag flip-flop and to reset the IRQ flip-flop. + If the flag buffer flip-flip is set, then flag will be set by ENF. If + the flag buffer is clear, ENF will not affect flag. Under simulation, + ioENF is sent to set the flag buffer and flag flip-flops. For those + interfaces where this action is identical to that provided by STF, the + ioENF handler may simply fall into the ioSTF handler. + + 7. In hardware, the PON signal is asserted continuously while the CPU is + operating. Under simulation, ioPON is asserted only at simulator + initialization or when processing a RESET -P command. +*/ + +typedef enum { ioNONE = 0000000, /* -- -- -- -- -- no signal asserted */ + ioPON = 0000001, /* T2 T3 T4 T5 T6 power on normal */ + ioENF = 0000002, /* T2 -- -- -- -- enable flag */ + ioIOI = 0000004, /* -- -- T4 T5 -- I/O data input (CPU) + T2 T3 -- -- -- I/O data input (DMA) */ + ioIOO = 0000010, /* -- T3 T4 -- -- I/O data output */ + ioSKF = 0000020, /* -- T3 T4 T5 -- skip on flag */ + ioSFS = 0000040, /* -- T3 T4 T5 -- skip if flag is set */ + ioSFC = 0000100, /* -- T3 T4 T5 -- skip if flag is clear */ + ioSTC = 0000200, /* -- -- T4 -- -- set control flip-flop (CPU) + -- T3 -- -- -- set control flip-flop (DMA) */ + ioCLC = 0000400, /* -- -- T4 -- -- clear control flip-flop (CPU) + -- T3 T4 -- -- clear control flip-flop (DMA) */ + ioSTF = 0001000, /* -- T3 -- -- -- set flag flip-flop */ + ioCLF = 0002000, /* -- -- T4 -- -- clear flag flip-flop (CPU) + -- T3 -- -- -- clear flag flip-flop (DMA) */ + ioEDT = 0004000, /* -- -- T4 -- -- end data transfer */ + ioCRS = 0010000, /* -- -- -- T5 -- control reset */ + ioPOPIO = 0020000, /* -- -- -- T5 -- power-on preset to I/O */ + ioIAK = 0040000, /* -- -- -- -- T6 interrupt acknowledge */ + ioSIR = 0100000 } IOSIGNAL; /* -- -- -- T5 -- set interrupt request */ + + +typedef uint32 IOCYCLE; /* a set of signals forming one I/O cycle */ + +#define IOIRQSET (ioSTC | ioCLC | ioENF | \ + ioSTF | ioCLF | ioIAK | \ + ioCRS | ioPOPIO | ioPON) /* signals that may affect interrupt state */ + + +/* I/O structures */ + +typedef enum { CLEAR, SET } FLIP_FLOP; /* flip-flop type and values */ + +typedef struct dib DIB; /* incomplete definition */ + +typedef uint32 IOHANDLER (DIB *dibptr, /* I/O signal handler prototype */ + IOCYCLE signal_set, + uint32 stat_data); + +struct dib { /* Device information block */ + IOHANDLER *io_handler; /* pointer to device's I/O signal handler */ + uint32 select_code; /* device's select code */ + uint32 card_index; /* device's card index for state variables */ + }; + + +/* I/O signal and status macros. + + The following macros are useful in I/O signal handlers and unit service + routines. The parameter definition symbols employed are: + + I = an IOCYCLE value + E = a t_stat error status value + D = a uint16 data value + C = a uint32 combined status and data value + P = a pointer to a DIB structure + B = a Boolean test value + + Implementation notes: + + 1. The IONEXT macro isolates the next signal in sequence to process from the + I/O cycle I. + + 2. The IOADDSIR macro adds an ioSIR signal to the I/O cycle I if it + contains signals that might change the interrupt state. + + 3. The IORETURN macro forms the combined status and data value to be + returned by a handler from the t_stat error code E and the 16-bit data + value D. + + 4. The IOSTATUS macro isolates the t_stat error code from a combined status + and data value value C. + + 5. The IODATA macro isolates the 16-bit data value from a combined status + and data value value C. + + 6. The IOPOWERON macro calls signal handler P->H with DIB pointer P to + process a power-on reset action. + + 7. The IOPRESET macro calls signal handler P->H with DIB pointer P to + process a front-panel PRESET action. + + 8. The IOERROR macro returns t_stat error code E from a unit service routine + if the Boolean test B is true. +*/ + +#define IONEXT(I) (IOSIGNAL) ((I) & (IOCYCLE) (- (int32) (I))) /* extract next I/O signal to handle */ +#define IOADDSIR(I) ((I) & IOIRQSET ? (I) | ioSIR : (I)) /* add SIR if IRQ state might change */ + +#define IORETURN(E,D) ((uint32) ((E) << 16 | (D) & DMASK)) /* form I/O handler return value */ +#define IOSTATUS(C) ((t_stat) ((C) >> 16) & DMASK) /* extract I/O status from combined value */ +#define IODATA(C) ((uint16) ((C) & DMASK)) /* extract data from combined value */ + +#define IOPOWERON(P) (P)->io_handler ((P), ioPON | ioPOPIO | ioCRS, 0) /* send power-on signals to handler */ +#define IOPRESET(P) (P)->io_handler ((P), ioPOPIO | ioCRS, 0) /* send PRESET signals to handler */ +#define IOERROR(B,E) ((B) ? (E) : SCPE_OK) /* stop on I/O error if enabled */ + + +/* I/O signal logic macros. + + The following macros implement the logic for the SKF, PRL, IRQ, and SRQ + signals. Both standard and general logic macros are provided. The parameter + definition symbols employed are: + + S = a uint32 select code value + B = a Boolean test value + N = a name of a structure containing the standard flip-flops + + Implementation notes: + + 1. The setSKF macro sets the Skip on Flag signal in the return data value if + the Boolean value B is true. + + 2. The setPRL macro sets the Priority Low signal for select code S to the + Boolean value B. + + 3. The setIRQ macro sets the Interrupt Request signal for select code S to + the Boolean value B. + + 4. The setSRQ macro sets the Service Request signal for select code S to the + Boolean value B. + + 5. The PRL macro returns the Priority Low signal for select code S as a + Boolean value. + + 6. The IRQ macro returns the Interrupt Request signal for select code S as a + Boolean value. + + 7. The SRQ macro returns the Service Request signal for select code S as a + Boolean value. + + 8. The setstdSKF macro sets Skip on Flag signal in the return data value if + the flag state in structure N matches the current skip test condition. + + 9. The setstdPRL macro sets the Priority Low signal for the select code + referenced by "dibptr" using the standard logic and the control and flag + states in structure N. + + 10. The setstdIRQ macro sets the Interrupt Request signal for the select code + referenced by "dibptr" using the standard logic and the control, flag, + and flag buffer states in structure N. + + 11. The setstdSRQ macro sets the Service Request signal for the select code + referenced by "dibptr" using the standard logic and the flag state in + structure N. +*/ + +#define BIT_V(S) ((S) & 037) /* convert select code to bit position */ +#define BIT_M(S) (1u << BIT_V (S)) /* convert select code to bit mask */ + +#define setSKF(B) stat_data = IORETURN (SCPE_OK, (uint16) ((B) ? ioSKF : ioNONE)) + +#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) +#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) +#define setSRQ(S,B) dev_srq[(S)/32] = dev_srq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) + +#define PRL(S) ((dev_prl[(S)/32] >> BIT_V (S)) & 1) +#define IRQ(S) ((dev_irq[(S)/32] >> BIT_V (S)) & 1) +#define SRQ(S) ((dev_srq[(S)/32] >> BIT_V (S)) & 1) + +#define setstdSKF(N) setSKF ((signal == ioSFC) && !N.flag || \ + (signal == ioSFS) && N.flag) + +#define setstdPRL(N) setPRL (dibptr->select_code, !(N.control & N.flag)); +#define setstdIRQ(N) setIRQ (dibptr->select_code, N.control & N.flag & N.flagbuf); +#define setstdSRQ(N) setSRQ (dibptr->select_code, N.flag); -#define IOT_V_REASON 16 -#define IORETURN(F,V) ((F) ? (V) : SCPE_OK) /* stop on I/O error */ /* CPU state */ diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index 86e4ed6c..f2eddd5c 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-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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 @@ DP 12557A 2871 disk subsystem 13210A 7900 disk subsystem + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -206,10 +208,12 @@ #define STA_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY) #define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */ -FLIP_FLOP dpc_command = CLEAR; /* cch command flip-flop */ -FLIP_FLOP dpc_control = CLEAR; /* cch control flip-flop */ -FLIP_FLOP dpc_flag = CLEAR; /* cch flag flip-flop */ -FLIP_FLOP dpc_flagbuf = CLEAR; /* cch flag buffer flip-flop */ +struct { + FLIP_FLOP command; /* cch command flip-flop */ + FLIP_FLOP control; /* cch control flip-flop */ + FLIP_FLOP flag; /* cch flag flip-flop */ + FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ + } dpc = { CLEAR, CLEAR, CLEAR, CLEAR }; enum { A12557, A13210 } dp_ctype = A13210; /* ctrl type */ int32 dpc_busy = 0; /* cch unit */ @@ -223,10 +227,12 @@ int32 dpc_dtime = 2; /* dch time */ int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */ int32 dpc_obuf = 0; /* cch buffers */ -FLIP_FLOP dpd_command = CLEAR; /* dch command flip-flop */ -FLIP_FLOP dpd_control = CLEAR; /* dch control flip-flop */ -FLIP_FLOP dpd_flag = CLEAR; /* dch flag flip-flop */ -FLIP_FLOP dpd_flagbuf = CLEAR; /* dch flag buffer flip-flop */ +struct { + FLIP_FLOP command; /* dch command flip-flop */ + FLIP_FLOP control; /* dch control flip-flop */ + FLIP_FLOP flag; /* dch flag flip-flop */ + FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */ + } dpd = { CLEAR, CLEAR, CLEAR, CLEAR }; int32 dpd_xfer = 0; /* xfer in prog */ int32 dpd_wval = 0; /* write data valid */ @@ -239,8 +245,10 @@ uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */ uint16 dpxb[DP_NUMWD]; /* sector buffer */ DEVICE dpd_dev, dpc_dev; -uint32 dpdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 dpcio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER dpdio; +IOHANDLER dpcio; + t_stat dpc_svc (UNIT *uptr); t_stat dpd_svc (UNIT *uptr); t_stat dpc_reset (DEVICE *dptr); @@ -261,8 +269,8 @@ t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); */ DIB dp_dib[] = { - { DPD, &dpdio }, - { DPC, &dpcio } + { &dpdio, DPD }, + { &dpcio, DPC } }; #define dpd_dib dp_dib[0] @@ -275,13 +283,13 @@ REG dpd_reg[] = { { ORDATA (OBUF, dpd_obuf, 16) }, { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) }, { DRDATA (BPTR, dp_ptr, DP_N_NUMWD) }, - { FLDATA (CMD, dpd_command, 0) }, - { FLDATA (CTL, dpd_control, 0) }, - { FLDATA (FLG, dpd_flag, 0) }, - { FLDATA (FBF, dpd_flagbuf, 0) }, + { FLDATA (CMD, dpd.command, 0) }, + { FLDATA (CTL, dpd.control, 0) }, + { FLDATA (FLG, dpd.flag, 0) }, + { FLDATA (FBF, dpd.flagbuf, 0) }, { FLDATA (XFER, dpd_xfer, 0) }, { FLDATA (WVAL, dpd_wval, 0) }, - { ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, dpd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -322,10 +330,10 @@ REG dpc_reg[] = { { ORDATA (OBUF, dpc_obuf, 16) }, { ORDATA (BUSY, dpc_busy, 4), REG_RO }, { ORDATA (CNT, dpc_cnt, 5) }, - { FLDATA (CMD, dpc_command, 0) }, - { FLDATA (CTL, dpc_control, 0) }, - { FLDATA (FLG, dpc_flag, 0) }, - { FLDATA (FBF, dpc_flagbuf, 0) }, + { FLDATA (CMD, dpc.command, 0) }, + { FLDATA (CTL, dpc.control, 0) }, + { FLDATA (FLG, dpc.flag, 0) }, + { FLDATA (FBF, dpc.flagbuf, 0) }, { FLDATA (EOC, dpc_eoc, 0) }, { FLDATA (POLL, dpc_poll, 0) }, { DRDATA (RARC, dpc_rarc, 8), PV_RZRO | REG_FIT }, @@ -342,7 +350,7 @@ REG dpc_reg[] = { DP_NUMDRV, REG_HRO) }, { URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0, DP_NUMDRV, PV_LEFT | REG_HRO) }, - { ORDATA (DEVNO, dpc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, dpc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -389,112 +397,114 @@ DEVICE dpc_dev = { register. */ -uint32 dpdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dpdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dpd_flag = dpd_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dpd.flag = dpd.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dpd_flag = dpd_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dpd.flag = dpd.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (dpd); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dpd); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (dpd); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dpd); + break; - case ioIOI: /* I/O data input */ - data = dpd_ibuf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, dpd_ibuf); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - dpd_obuf = data; + case ioIOO: /* I/O data output */ + dpd_obuf = IODATA (stat_data); /* clear supplied status */ - if (!dpc_busy || dpd_xfer) /* if !overrun */ - dpd_wval = 1; /* valid */ - break; + if (!dpc_busy || dpd_xfer) /* if !overrun */ + dpd_wval = 1; /* valid */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dpd_flag = dpd_flagbuf = SET; /* set flag buffer and flag */ + case ioPOPIO: /* power-on preset to I/O */ + dpd.flag = dpd.flagbuf = SET; /* set flag buffer and flag */ - if (dp_ctype == A12557) /* 12557? */ - dpd_obuf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - dpd_command = CLEAR; /* clear command */ - - if (dp_ctype == A12557) /* 12557? */ - dpd_control = CLEAR; /* clear control */ - - else { /* 13210 */ - dpc_rarc = 0; /* clear controller cylinder address */ - dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0; /* clear last drive addressed cylinder */ - } - break; + if (dp_ctype == A12557) /* 12557? */ + dpd_obuf = 0; /* clear output buffer */ + break; - case ioCLC: /* clear control flip-flop */ - if (dp_ctype == A12557) /* 12557? */ - dpd_control = CLEAR; /* clear control */ + case ioCRS: /* control reset */ + dpd.command = CLEAR; /* clear command */ - dpd_xfer = 0; /* clr xfer in progress */ - break; + if (dp_ctype == A12557) /* 12557? */ + dpd.control = CLEAR; /* clear control */ + + else { /* 13210 */ + dpc_rarc = 0; /* clear controller cylinder address */ + dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0; /* clear last drive addressed cylinder */ + } + break; - case ioSTC: /* set control flip-flop */ - if (dp_ctype == A12557) /* 12557? */ - dpd_control = SET; /* set control */ + case ioCLC: /* clear control flip-flop */ + if (dp_ctype == A12557) /* 12557? */ + dpd.control = CLEAR; /* clear control */ - dpd_command = SET; /* set cmd */ - - if (dpc_busy && !dpd_xfer) /* overrun? */ - dpc_sta[dpc_busy - 1] |= STA_OVR; - break; + dpd_xfer = 0; /* clr xfer in progress */ + break; - case ioSIR: /* set interrupt request */ - if (dp_ctype == A12557) { /* 12557? */ - setstdPRL (select_code, dpd); /* set standard PRL signal */ - setstdIRQ (select_code, dpd); /* set standard IRQ signal */ - } + case ioSTC: /* set control flip-flop */ + if (dp_ctype == A12557) /* 12557? */ + dpd.control = SET; /* set control */ - setstdSRQ (select_code, dpd); /* set standard SRQ signal */ - break; + dpd.command = SET; /* set cmd */ + + if (dpc_busy && !dpd_xfer) /* overrun? */ + dpc_sta[dpc_busy - 1] |= STA_OVR; + break; - case ioIAK: /* interrupt acknowledge */ - if (dp_ctype == A12557) /* 12557? */ - dpd_flagbuf = CLEAR; /* clear flag buffer */ - break; + case ioSIR: /* set interrupt request */ + if (dp_ctype == A12557) { /* 12557? */ + setstdPRL (dpd); /* set standard PRL signal */ + setstdIRQ (dpd); /* set standard IRQ signal */ + } + + setstdSRQ (dpd); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + if (dp_ctype == A12557) /* 12557? */ + dpd.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - dpdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dpdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -515,139 +525,144 @@ return data; to interrupt. */ -uint32 dpcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dpcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; int32 i, fnc, drv; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dpc_flag = dpc_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dpc.flag = dpc.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dpc_flag = dpc_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dpc.flag = dpc.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (dpc); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dpc); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (dpc); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dpc); + break; - case ioIOI: /* I/O data input */ - data = 0; + case ioIOI: /* I/O data input */ + data = 0; - for (i = 0; i < DP_NUMDRV; i++) /* form attention register value */ - if (dpc_sta[i] & STA_ATN) data = data | (1 << i); - break; + for (i = 0; i < DP_NUMDRV; i++) /* form attention register value */ + if (dpc_sta[i] & STA_ATN) data = data | (1 << i); + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - dpc_obuf = data; + case ioIOO: /* I/O data output */ + dpc_obuf = IODATA (stat_data); /* clear supplied status */ - if (dp_ctype == A13210) /* 13210? */ - dpcio (select_code, ioCLC, 0); /* OTx causes CLC */ - break; + if (dp_ctype == A13210) /* 13210? */ + dpcio (dibptr, ioCLC, 0); /* OTx causes CLC */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dpc_flag = dpc_flagbuf = SET; /* set flag buffer and flag */ + case ioPOPIO: /* power-on preset to I/O */ + dpc.flag = dpc.flagbuf = SET; /* set flag buffer and flag */ - if (dp_ctype == A12557) /* 12557? */ - dpd_obuf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - dpc_control = CLEAR; /* clear control */ - - if (dp_ctype == A12557) /* 12557? */ - dpc_command = CLEAR; /* clear command */ - break; - - - case ioCLC: /* clear control flip-flop */ - dpc_control = CLEAR; /* clr ctl */ - - if (dp_ctype == A12557) /* 12557? */ - dpc_command = CLEAR; /* cancel non-seek */ - - if (dpc_busy) - sim_cancel (&dpc_unit[dpc_busy - 1]); - - sim_cancel (&dpd_unit); /* cancel dch */ - dpd_xfer = 0; /* clr dch xfer */ - dpc_busy = 0; /* clr cch busy */ - dpc_poll = 0; /* clr cch poll */ - break; - - - case ioSTC: /* set control flip-flop */ - dpc_control = SET; /* set ctl */ - - if ((dp_ctype == A13210) || !dpc_command) { /* 13210 or command is clear? */ if (dp_ctype == A12557) /* 12557? */ - dpc_command = SET; /* set command */ - - drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ - fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ - - switch (fnc) { /* case on fnc */ - - case FNC_SEEK: /* seek */ - dpc_poll = 1; /* enable polling */ - dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ - break; - - case FNC_STA: /* rd sta */ - if (dp_ctype == A13210) /* 13210? clr dch flag */ - dpdio (dpd_dib.devno, ioCLF, 0); - - case FNC_CHK: /* check */ - case FNC_AR: /* addr rec */ - dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ - break; - - case FNC_RD: case FNC_WD: /* read, write */ - case FNC_REF: case FNC_INIT: /* refine, init */ - dp_goc (fnc, drv, dpc_ctime); /* sched drive */ - break; - } /* end case */ - } /* end if */ - break; + dpd_obuf = 0; /* clear output buffer */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, dpc); /* set standard PRL signal */ - setstdIRQ (select_code, dpc); /* set standard IRQ signal */ - setstdSRQ (select_code, dpc); /* set standard SRQ signal */ - break; + case ioCRS: /* control reset */ + dpc.control = CLEAR; /* clear control */ + + if (dp_ctype == A12557) /* 12557? */ + dpc.command = CLEAR; /* clear command */ + break; - case ioIAK: /* interrupt acknowledge */ - dpc_flagbuf = CLEAR; /* clear flag buffer */ - break; + case ioCLC: /* clear control flip-flop */ + dpc.control = CLEAR; /* clr ctl */ + + if (dp_ctype == A12557) /* 12557? */ + dpc.command = CLEAR; /* cancel non-seek */ + + if (dpc_busy) + sim_cancel (&dpc_unit[dpc_busy - 1]); + + sim_cancel (&dpd_unit); /* cancel dch */ + dpd_xfer = 0; /* clr dch xfer */ + dpc_busy = 0; /* clr cch busy */ + dpc_poll = 0; /* clr cch poll */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioSTC: /* set control flip-flop */ + dpc.control = SET; /* set ctl */ + + if ((dp_ctype == A13210) || !dpc.command) { /* 13210 or command is clear? */ + if (dp_ctype == A12557) /* 12557? */ + dpc.command = SET; /* set command */ + + drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ + + switch (fnc) { /* case on fnc */ + + case FNC_SEEK: /* seek */ + dpc_poll = 1; /* enable polling */ + dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ + break; + + case FNC_STA: /* rd sta */ + if (dp_ctype == A13210) /* 13210? clr dch flag */ + dpdio (&dpd_dib, ioCLF, 0); + + case FNC_CHK: /* check */ + case FNC_AR: /* addr rec */ + dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ + break; + + case FNC_RD: case FNC_WD: /* read, write */ + case FNC_REF: case FNC_INIT: /* refine, init */ + dp_goc (fnc, drv, dpc_ctime); /* sched drive */ + break; + } /* end case */ + } /* end if */ + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (dpc); /* set standard PRL signal */ + setstdIRQ (dpc); /* set standard IRQ signal */ + setstdSRQ (dpc); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + dpc.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - dpcio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dpcio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -712,12 +727,12 @@ switch (uptr->FNC) { /* case function */ case FNC_AR: /* arec, need cyl */ case FNC_SEEK: /* seek, need cyl */ - if (dpd_command) { /* dch active? */ + if (dpd.command) { /* dch active? */ dpc_rarc = DA_GETCYL (dpd_obuf); /* set RAR from cyl word */ dpd_wval = 0; /* clr data valid */ - dpd_command = CLEAR; /* clr dch cmd */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ if (uptr->FNC == FNC_AR) uptr->FNC = FNC_AR1; else uptr->FNC = FNC_SEEK1; /* advance state */ @@ -727,17 +742,17 @@ switch (uptr->FNC) { /* case function */ case FNC_AR1: /* arec, need hd/sec */ case FNC_SEEK1: /* seek, need hd/sec */ - if (dpd_command) { /* dch active? */ + if (dpd.command) { /* dch active? */ dpc_rarh = DA_GETHD (dpd_obuf); /* set RAR from head */ dpc_rars = DA_GETSC (dpd_obuf); /* set RAR from sector */ dpd_wval = 0; /* clr data valid */ - dpd_command = CLEAR; /* clr dch cmd */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ if (uptr->FNC == FNC_AR1) { - dpc_command = CLEAR; /* clr cch cmd */ - dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set drv attn */ break; /* done if Address Record */ @@ -766,7 +781,7 @@ switch (uptr->FNC) { /* case function */ break; case FNC_STA: /* read status */ - if (dpd_command || (dp_ctype == A13210)) { /* dch act or 13210? */ + if (dpd.command || (dp_ctype == A13210)) { /* dch act or 13210? */ if ((dpc_unit[drv].flags & UNIT_UNLOAD) == 0) { /* drive up? */ dpd_ibuf = dpc_sta[drv] & ~STA_ERR; /* clear err */ if (dp_ctype == A13210) dpd_ibuf = /* 13210? */ @@ -777,9 +792,9 @@ switch (uptr->FNC) { /* case function */ if (dpd_ibuf & STA_ANYERR) /* errors? set flg */ dpd_ibuf = dpd_ibuf | STA_ERR; - dpc_command = CLEAR; /* clr cch cmd */ - dpd_command = CLEAR; /* clr dch cmd */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + dpc.command = CLEAR; /* clr cch cmd */ + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ } dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ @@ -789,14 +804,14 @@ switch (uptr->FNC) { /* case function */ dpc_poll = 1; /* enable polling */ for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ if (dpc_sta[i] & STA_ATN) { /* any ATN set? */ - dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ break; } } break; case FNC_CHK: /* check, need cnt */ - if (dpd_command) { /* dch active? */ + if (dpd.command) { /* dch active? */ dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ dpd_wval = 0; /* clr data valid */ dp_goc (FNC_CHK1, drv, dpc_xtime); /* sched drv */ @@ -836,8 +851,8 @@ err = 0; /* assume no err */ drv = uptr - dpc_dev.units; /* get drive no */ if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ - dpc_command = CLEAR; /* clr cch cmd */ - dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ dpc_sta[drv] = 0; /* clr status */ dpc_busy = 0; /* ctlr is free */ @@ -852,8 +867,8 @@ switch (uptr->FNC) { /* case function */ dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; /* fall into cmpl */ case FNC_SEEK3: /* seek complete */ if (dpc_poll) { /* polling enabled? */ - dpc_command = CLEAR; /* clr cch cmd */ - dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ } return SCPE_OK; @@ -863,7 +878,7 @@ switch (uptr->FNC) { /* case function */ case FNC_RD: /* read */ case FNC_CHK1: /* check */ if (dp_ptr == 0) { /* new sector? */ - if (!dpd_command && (uptr->FNC != FNC_CHK1)) break; + if (!dpd.command && (uptr->FNC != FNC_CHK1)) break; if (dpc_rarc != dpc_ucyl[drv]) /* RAR cyl miscompare? */ dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */ if (dpc_rars >= DP_NUMSC) { /* bad sector? */ @@ -893,17 +908,17 @@ switch (uptr->FNC) { /* case function */ } dp_ptr = 0; /* wrap buf ptr */ } - if (dpd_command && dpd_xfer) /* dch on, xfer? */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + if (dpd.command && dpd_xfer) /* dch on, xfer? */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - dpd_command = CLEAR; /* clr dch cmd */ + dpd.command = CLEAR; /* clr dch cmd */ sim_activate (uptr, dpc_xtime); /* sched next word */ return SCPE_OK; case FNC_INIT: /* init */ case FNC_WD: /* write */ if (dp_ptr == 0) { /* start sector? */ - if (!dpd_command && !dpd_wval) break; /* xfer done? */ + if (!dpd.command && !dpd_wval) break; /* xfer done? */ if (uptr->flags & UNIT_WPRT) { /* wr prot? */ dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */ break; /* done */ @@ -933,10 +948,10 @@ switch (uptr->FNC) { /* case function */ if (err = ferror (uptr->fileref)) break; /* error? */ dp_ptr = 0; /* next sector */ } - if (dpd_command && dpd_xfer) /* dch on, xfer? */ - dpdio (dpd_dib.devno, ioENF, 0); /* set dch flg */ + if (dpd.command && dpd_xfer) /* dch on, xfer? */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - dpd_command = CLEAR; /* clr dch cmd */ + dpd.command = CLEAR; /* clr dch cmd */ sim_activate (uptr, dpc_xtime); /* sched next word */ return SCPE_OK; @@ -946,8 +961,8 @@ switch (uptr->FNC) { /* case function */ dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set ATN */ -dpc_command = CLEAR; /* clr cch cmd */ -dpcio (dpc_dib.devno, ioENF, 0); /* set cch flg */ +dpc.command = CLEAR; /* clr cch cmd */ +dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ dpc_busy = 0; /* ctlr is free */ dpd_xfer = dpd_wval = 0; @@ -966,21 +981,18 @@ return SCPE_OK; t_stat dpc_reset (DEVICE *dptr) { int32 drv; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &dpd_dev)? &dpc_dev: &dpd_dev); + (dptr == &dpd_dev) ? &dpc_dev : &dpd_dev); -if (sim_switches & SWMASK ('P')) { /* PON reset? */ - dpd_ibuf = 0; /* clear buffers */ - dpd_obuf = 0; - dpc_obuf = 0; +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ + dpd_ibuf = dpd_obuf = 0; /* clear buffers */ + dpc_obuf = 0; /* clear buffer */ dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear RAR */ } -if (dptr == &dpc_dev) /* command channel reset? */ - dpcio (dpc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - dpdio (dpd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ dpc_busy = 0; /* reset controller state */ dpc_poll = 0; @@ -1040,7 +1052,7 @@ else { /* load heads */ drv = uptr - dpc_dev.units; /* get drive no */ dpc_sta[drv] = dpc_sta[drv] | STA_ATN | STA_1ST; /* update status */ if (dpc_poll) /* polling enabled? */ - dpcio (dpc_dib.devno, ioENF, 0); /* set flag */ + dpcio (&dpc_dib, ioENF, 0); /* set flag */ } return SCPE_OK; } @@ -1144,7 +1156,7 @@ t_stat dpc_boot (int32 unitno, DEVICE *dptr) int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = dpd_dib.devno; /* get data chan dev */ +dev = dpd_dib.select_code; /* get data chan dev */ if (ibl_copy (dp_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & IBL_OPT) | IBL_DP | (dev << IBL_V_DEV); /* set SR */ if (sim_switches & SWMASK ('R')) SR = SR | IBL_DP_REM; /* boot from removable? */ diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index 216dfc03..726aa4ba 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -1,7 +1,7 @@ /* hp2100_dq.c: HP 2100 12565A disk simulator Copyright (c) 1993-2006, Bill McDermith - Copyright (c) 2004-2008 J. David Bryan + Copyright (c) 2004-2011 J. David Bryan 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 @@ DQ 12565A 2883 disk system + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -144,10 +146,12 @@ #define STA_ERR 0000001 /* any error */ #define STA_ANYERR (STA_NRDY | STA_EOC | STA_AER | STA_FLG | STA_DTE) -FLIP_FLOP dqc_command = CLEAR; /* cch command flip-flop */ -FLIP_FLOP dqc_control = CLEAR; /* cch control flip-flop */ -FLIP_FLOP dqc_flag = CLEAR; /* cch flag flip-flop */ -FLIP_FLOP dqc_flagbuf = CLEAR; /* cch flag buffer flip-flop */ +struct { + FLIP_FLOP command; /* cch command flip-flop */ + FLIP_FLOP control; /* cch control flip-flop */ + FLIP_FLOP flag; /* cch flag flip-flop */ + FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ + } dqc = { CLEAR, CLEAR, CLEAR, CLEAR }; int32 dqc_busy = 0; /* cch xfer */ int32 dqc_cnt = 0; /* check count */ @@ -156,10 +160,12 @@ int32 dqc_ctime = 100; /* command time */ int32 dqc_xtime = 3; /* xfer time */ int32 dqc_dtime = 2; /* dch time */ -FLIP_FLOP dqd_command = CLEAR; /* dch command flip-flop */ -FLIP_FLOP dqd_control = CLEAR; /* dch control flip-flop */ -FLIP_FLOP dqd_flag = CLEAR; /* dch flag flip-flop */ -FLIP_FLOP dqd_flagbuf = CLEAR; /* dch flag buffer flip-flop */ +struct { + FLIP_FLOP command; /* dch command flip-flop */ + FLIP_FLOP control; /* dch control flip-flop */ + FLIP_FLOP flag; /* dch flag flip-flop */ + FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */ + } dqd = { CLEAR, CLEAR, CLEAR, CLEAR }; int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */ int32 dqc_obuf = 0; /* cch buffers */ @@ -175,8 +181,10 @@ uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* unit status */ uint16 dqxb[DQ_NUMWD]; /* sector buffer */ DEVICE dqd_dev, dqc_dev; -uint32 dqdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 dqcio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER dqdio; +IOHANDLER dqcio; + t_stat dqc_svc (UNIT *uptr); t_stat dqd_svc (UNIT *uptr); t_stat dqc_reset (DEVICE *dptr); @@ -195,8 +203,8 @@ void dq_goc (int32 fnc, int32 drv, int32 time); */ DIB dq_dib[] = { - { DQD, &dqdio }, - { DQC, &dqcio } + { &dqdio, DQD }, + { &dqcio, DQC } }; #define dqd_dib dq_dib[0] @@ -209,13 +217,13 @@ REG dqd_reg[] = { { ORDATA (OBUF, dqd_obuf, 16) }, { BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) }, { DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) }, - { FLDATA (CMD, dqd_command, 0) }, - { FLDATA (CTL, dqd_control, 0) }, - { FLDATA (FLG, dqd_flag, 0) }, - { FLDATA (FBF, dqd_flagbuf, 0) }, + { FLDATA (CMD, dqd.command, 0) }, + { FLDATA (CTL, dqd.control, 0) }, + { FLDATA (FLG, dqd.flag, 0) }, + { FLDATA (FBF, dqd.flagbuf, 0) }, { FLDATA (XFER, dqd_xfer, 0) }, { FLDATA (WVAL, dqd_wval, 0) }, - { ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, dqd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -252,10 +260,10 @@ REG dqc_reg[] = { { ORDATA (OBUF, dqc_obuf, 16) }, { ORDATA (BUSY, dqc_busy, 2), REG_RO }, { ORDATA (CNT, dqc_cnt, 9) }, - { FLDATA (CMD, dqc_command, 0) }, - { FLDATA (CTL, dqc_control, 0) }, - { FLDATA (FLG, dqc_flag, 0) }, - { FLDATA (FBF, dqc_flagbuf, 0) }, + { FLDATA (CMD, dqc.command, 0) }, + { FLDATA (CTL, dqc.control, 0) }, + { FLDATA (FLG, dqc.flag, 0) }, + { FLDATA (FBF, dqc.flagbuf, 0) }, { DRDATA (RARC, dqc_rarc, 8), PV_RZRO | REG_FIT }, { DRDATA (RARH, dqc_rarh, 5), PV_RZRO | REG_FIT }, { DRDATA (RARS, dqc_rars, 5), PV_RZRO | REG_FIT }, @@ -268,7 +276,7 @@ REG dqc_reg[] = { { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT }, { URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0, DQ_NUMDRV, REG_HRO) }, - { ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, dqc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -293,93 +301,95 @@ DEVICE dqc_dev = { /* Data channel I/O signal handler */ -uint32 dqdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dqdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dqd_flag = dqd_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dqd.flag = dqd.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dqd_flag = dqd_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dqd.flag = dqd.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (dqd); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dqd); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (dqd); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dqd); + break; - case ioIOI: /* I/O data input */ - data = dqd_ibuf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, dqd_ibuf); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - dqd_obuf = data; + case ioIOO: /* I/O data output */ + dqd_obuf = IODATA (stat_data); /* clear supplied status */ - if (!dqc_busy || dqd_xfer) - dqd_wval = 1; /* if !overrun, valid */ - break; + if (!dqc_busy || dqd_xfer) + dqd_wval = 1; /* if !overrun, valid */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dqd_flag = dqd_flagbuf = SET; /* set flag and flag buffer */ - dqd_obuf = 0; /* clear output buffer */ - /* fall into CRS handler */ + case ioPOPIO: /* power-on preset to I/O */ + dqd.flag = dqd.flagbuf = SET; /* set flag and flag buffer */ + dqd_obuf = 0; /* clear output buffer */ + break; - case ioCRS: /* control reset */ - dqd_command = CLEAR; /* clear command */ + + case ioCRS: /* control reset */ + dqd.command = CLEAR; /* clear command */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - dqd_control = CLEAR; /* clear control */ - dqd_xfer = 0; /* clr xfer */ - break; + case ioCLC: /* clear control flip-flop */ + dqd.control = CLEAR; /* clear control */ + dqd_xfer = 0; /* clr xfer */ + break; - case ioSTC: /* set control flip-flop */ - dqd_command = SET; /* set ctl, cmd */ - dqd_control = SET; + case ioSTC: /* set control flip-flop */ + dqd.command = SET; /* set ctl, cmd */ + dqd.control = SET; - if (dqc_busy && !dqd_xfer) /* overrun? */ - dqc_sta[dqc_busy - 1] |= STA_DTE; - break; + if (dqc_busy && !dqd_xfer) /* overrun? */ + dqc_sta[dqc_busy - 1] |= STA_DTE; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, dqd); /* set standard PRL signal */ - setstdIRQ (select_code, dqd); /* set standard IRQ signal */ - setstdSRQ (select_code, dqd); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (dqd); /* set standard PRL signal */ + setstdIRQ (dqd); /* set standard IRQ signal */ + setstdSRQ (dqd); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - dqd_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + dqd.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - dqdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dqdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -392,113 +402,112 @@ return data; signalled. */ -uint32 dqcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dqcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ int32 fnc, drv; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - dqc_flag = dqc_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dqc.flag = dqc.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dqc_flag = dqc_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dqc.flag = dqc.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (dqc); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (dqc); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (dqc); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (dqc); + break; - case ioIOI: /* I/O data input */ - data = 0; /* no data */ - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, 0); /* no data */ + break; - case ioIOO: /* I/O data output */ - dqc_obuf = data; - break; + case ioIOO: /* I/O data output */ + dqc_obuf = IODATA (stat_data); /* clear supplied status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - dqc_flag = dqc_flagbuf = SET; /* set flag and flag buffer */ - dqc_obuf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - dqc_command = CLEAR; /* clear command */ - dqc_control = CLEAR; /* clear control */ - - if (dqc_busy) - sim_cancel (&dqc_unit[dqc_busy - 1]); - - sim_cancel (&dqd_unit); /* cancel dch */ - dqd_xfer = 0; /* clr dch xfer */ - dqc_busy = 0; /* clr busy */ - break; + case ioPOPIO: /* power-on preset to I/O */ + dqc.flag = dqc.flagbuf = SET; /* set flag and flag buffer */ + dqc_obuf = 0; /* clear output buffer */ + break; - case ioSTC: /* set control flip-flop */ - dqc_control = SET; /* set ctl */ + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + dqc.command = CLEAR; /* clear command */ + dqc.control = CLEAR; /* clear control */ - if (!dqc_command) { /* cmd clr? */ - dqc_command = SET; /* set cmd */ - drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ - fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ + if (dqc_busy) + sim_cancel (&dqc_unit[dqc_busy - 1]); - switch (fnc) { /* case on fnc */ - case FNC_SEEK: case FNC_RCL: /* seek, recal */ - case FNC_CHK: /* check */ - dqc_sta[drv] = 0; /* clear status */ - case FNC_STA: case FNC_LA: /* rd sta, load addr */ - dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */ - break; - case FNC_RD: case FNC_WD: /* read, write */ - case FNC_RA: case FNC_WA: /* rd addr, wr addr */ - case FNC_AS: /* address skip */ - dq_goc (fnc, drv, dqc_ctime); /* sched drive */ - break; - } /* end case */ - } /* end if !CMD */ - break; + sim_cancel (&dqd_unit); /* cancel dch */ + dqd_xfer = 0; /* clr dch xfer */ + dqc_busy = 0; /* clr busy */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, dqc); /* set standard PRL signal */ - setstdIRQ (select_code, dqc); /* set standard IRQ signal */ - setstdSRQ (select_code, dqc); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + dqc.control = SET; /* set ctl */ + + if (!dqc.command) { /* cmd clr? */ + dqc.command = SET; /* set cmd */ + drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ + + switch (fnc) { /* case on fnc */ + case FNC_SEEK: case FNC_RCL: /* seek, recal */ + case FNC_CHK: /* check */ + dqc_sta[drv] = 0; /* clear status */ + case FNC_STA: case FNC_LA: /* rd sta, load addr */ + dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */ + break; + case FNC_RD: case FNC_WD: /* read, write */ + case FNC_RA: case FNC_WA: /* rd addr, wr addr */ + case FNC_AS: /* address skip */ + dq_goc (fnc, drv, dqc_ctime); /* sched drive */ + break; + } /* end case */ + } /* end if !CMD */ + break; - case ioIAK: /* interrupt acknowledge */ - dqc_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (dqc); /* set standard PRL signal */ + setstdIRQ (dqc); /* set standard IRQ signal */ + setstdSRQ (dqc); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + dqc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - - -if (signal > ioCLF) /* multiple signals? */ - dqcio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dqcio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -562,11 +571,11 @@ switch (uptr->FNC) { /* case function */ case FNC_LA: /* arec, need cyl */ case FNC_SEEK: /* seek, need cyl */ - if (dqd_command) { /* dch active? */ + if (dqd.command) { /* dch active? */ dqc_rarc = DA_GETCYL (dqd_obuf); /* set RAR from cyl word */ dqd_wval = 0; /* clr data valid */ - dqd_command = CLEAR; /* clr dch cmd */ - dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ if (uptr->FNC == FNC_LA) uptr->FNC = FNC_LA1; else uptr->FNC = FNC_SEEK1; /* advance state */ } @@ -575,15 +584,15 @@ switch (uptr->FNC) { /* case function */ case FNC_LA1: /* arec, need hd/sec */ case FNC_SEEK1: /* seek, need hd/sec */ - if (dqd_command) { /* dch active? */ + if (dqd.command) { /* dch active? */ dqc_rarh = DA_GETHD (dqd_obuf); /* set RAR from head */ dqc_rars = DA_GETSC (dqd_obuf); /* set RAR from sector */ dqd_wval = 0; /* clr data valid */ - dqd_command = CLEAR; /* clr dch cmd */ - dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ if (uptr->FNC == FNC_LA1) { - dqc_command = CLEAR; /* clr cch cmd */ - dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */ + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ break; /* done if Load Address */ } if (sim_is_active (&dqc_unit[drv])) break; /* if busy, seek check */ @@ -610,23 +619,23 @@ switch (uptr->FNC) { /* case function */ break; case FNC_STA: /* read status */ - if (dqd_command) { /* dch active? */ + if (dqd.command) { /* dch active? */ if ((dqc_unit[drv].flags & UNIT_UNLOAD) == 0) /* drive up? */ dqd_ibuf = dqc_sta[drv] & ~STA_DID; else dqd_ibuf = STA_NRDY; if (dqd_ibuf & STA_ANYERR) /* errors? set flg */ dqd_ibuf = dqd_ibuf | STA_ERR; if (drv) dqd_ibuf = dqd_ibuf | STA_DID; - dqc_command = CLEAR; /* clr cch cmd */ - dqd_command = CLEAR; /* clr dch cmd */ - dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */ + dqc.command = CLEAR; /* clr cch cmd */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ dqc_sta[drv] = dqc_sta[drv] & ~STA_ANYERR; /* clr sta flags */ } else sim_activate (uptr, dqc_xtime); /* wait more */ break; case FNC_CHK: /* check, need cnt */ - if (dqd_command) { /* dch active? */ + if (dqd.command) { /* dch active? */ dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ dqd_wval = 0; /* clr data valid */ dq_goc (FNC_CHK1, drv, dqc_ctime); /* sched drv */ @@ -663,15 +672,13 @@ return SCPE_OK; t_stat dqc_svc (UNIT *uptr) { -int32 da, drv, devc, devd, err; +int32 da, drv, err; err = 0; /* assume no err */ drv = uptr - dqc_dev.units; /* get drive no */ -devc = dqc_dib.devno; /* get cch devno */ -devd = dqd_dib.devno; /* get dch devno */ if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ - dqc_command = CLEAR; /* clr cch cmd */ - dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */ + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ dqc_sta[drv] = 0; /* clr status */ dqc_busy = 0; /* ctlr is free */ dqd_xfer = dqd_wval = 0; @@ -686,18 +693,18 @@ switch (uptr->FNC) { /* case function */ } else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */ case FNC_SEEK3: - if (dqc_busy || dqc_flag) { /* ctrl busy? */ + if (dqc_busy || dqc.flag) { /* ctrl busy? */ uptr->FNC = FNC_SEEK3; /* next state */ sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ } else { - dqc_command = CLEAR; /* clr cch cmd */ - dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */ + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ } return SCPE_OK; case FNC_RA: /* read addr */ - if (!dqd_command) break; /* dch clr? done */ + if (!dqd.command) break; /* dch clr? done */ if (dq_ptr == 0) dqd_ibuf = dqc_ucyl[drv]; /* 1st word? */ else if (dq_ptr == 1) { /* second word? */ dqd_ibuf = (dqc_uhed[drv] << DA_V_HD) | /* use drive head */ @@ -706,8 +713,8 @@ switch (uptr->FNC) { /* case function */ } else break; dq_ptr = dq_ptr + 1; - dqd_command = CLEAR; /* clr dch cmd */ - dqdio (dqd_dib.devno, ioENF, 0); /* set dch flg */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; @@ -715,7 +722,7 @@ switch (uptr->FNC) { /* case function */ case FNC_RD: /* read */ case FNC_CHK1: /* check */ if (dq_ptr == 0) { /* new sector? */ - if (!dqd_command && (uptr->FNC != FNC_CHK1)) break; + if (!dqd.command && (uptr->FNC != FNC_CHK1)) break; if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */ (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */ (dqc_rars >= DQ_NUMSC)) { /* bad sector? */ @@ -743,17 +750,17 @@ switch (uptr->FNC) { /* case function */ } dq_ptr = 0; /* wrap buf ptr */ } - if (dqd_command && dqd_xfer) { /* dch on, xfer? */ - dqdio (dqd_dib.devno, ioENF, 0); /* set flag */ + if (dqd.command && dqd_xfer) { /* dch on, xfer? */ + dqdio (&dqd_dib, ioENF, 0); /* set flag */ } - dqd_command = CLEAR; /* clr dch cmd */ + dqd.command = CLEAR; /* clr dch cmd */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; case FNC_WA: /* write address */ case FNC_WD: /* write */ if (dq_ptr == 0) { /* sector start? */ - if (!dqd_command && !dqd_wval) break; /* xfer done? */ + if (!dqd.command && !dqd_wval) break; /* xfer done? */ if (uptr->flags & UNIT_WPRT) { /* write protect? */ dqc_sta[drv] = dqc_sta[drv] | STA_FLG; break; /* done */ @@ -782,10 +789,10 @@ switch (uptr->FNC) { /* case function */ if (err = ferror (uptr->fileref)) break; dq_ptr = 0; } - if (dqd_command && dqd_xfer) { /* dch on, xfer? */ - dqdio (dqd_dib.devno, ioENF, 0); /* set flag */ + if (dqd.command && dqd_xfer) { /* dch on, xfer? */ + dqdio (&dqd_dib, ioENF, 0); /* set flag */ } - dqd_command = CLEAR; /* clr dch cmd */ + dqd.command = CLEAR; /* clr dch cmd */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; @@ -793,8 +800,8 @@ switch (uptr->FNC) { /* case function */ return SCPE_IERR; } /* end case fnc */ -dqc_command = CLEAR; /* clr cch cmd */ -dqcio (dqc_dib.devno, ioENF, 0); /* set cch flg */ +dqc.command = CLEAR; /* clr cch cmd */ +dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ dqc_busy = 0; /* ctlr is free */ dqd_xfer = dqd_wval = 0; if (err != 0) { /* error? */ @@ -810,21 +817,19 @@ return SCPE_OK; t_stat dqc_reset (DEVICE *dptr) { int32 drv; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &dqd_dev)? &dqc_dev: &dqd_dev); -if (sim_switches & SWMASK ('P')) { /* PON reset? */ +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ dqd_ibuf = 0; /* clear buffers */ dqd_obuf = 0; - dqc_obuf = 0; + dqc_obuf = 0; /* clear buffer */ dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */ } -if (dptr == &dqc_dev) /* command channel reset? */ - dqcio (dqc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - dqdio (dqd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ dqc_busy = 0; /* reset controller state */ dqd_xfer = 0; @@ -947,7 +952,7 @@ t_stat dqc_boot (int32 unitno, DEVICE *dptr) int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = dqd_dib.devno; /* get data chan dev */ +dev = dqd_dib.select_code; /* get data chan dev */ if (ibl_copy (dq_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & IBL_OPT) | IBL_DQ | (dev << IBL_V_DEV); /* set SR */ return SCPE_OK; diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c index d8af0a68..1ae61f6a 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-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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 @@ DR 12606B 2770/2771 fixed head disk 12610B 2773/2774/2775 drum + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 09-Jul-08 JDB Revised drc_boot to use ibl_copy 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -178,8 +180,10 @@ int32 drc_cw = 0; /* fnc, addr */ int32 drc_sta = 0; /* status */ int32 drc_run = 0; /* run flip-flop */ -FLIP_FLOP drd_control = CLEAR; -FLIP_FLOP drd_flag = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + } drd = { CLEAR, CLEAR }; int32 drd_ibuf = 0; /* input buffer */ int32 drd_obuf = 0; /* output buffer */ @@ -192,9 +196,9 @@ static int32 sz_tab[16] = { 184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288, 0, 655360, 0, 786432, 0, 917504, 0, 0 }; -DEVICE drd_dev, drc_dev; -uint32 drdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 drcio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER drdio; +IOHANDLER drcio; + t_stat drc_svc (UNIT *uptr); t_stat drc_reset (DEVICE *dptr); t_stat drc_attach (UNIT *uptr, char *cptr); @@ -205,6 +209,8 @@ t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat dr_show_prot (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +DEVICE drd_dev, drc_dev; + /* DRD data structures drd_dev device descriptor @@ -213,8 +219,8 @@ t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); */ DIB dr_dib[] = { - { DRD, &drdio }, - { DRC, &drcio } + { &drdio, DRD }, + { &drcio, DRC } }; #define drd_dib dr_dib[0] @@ -231,10 +237,10 @@ UNIT drd_unit[] = { REG drd_reg[] = { { ORDATA (IBUF, drd_ibuf, 16) }, { ORDATA (OBUF, drd_obuf, 16) }, - { FLDATA (CTL, drd_control, 0) }, - { FLDATA (FLG, drd_flag, 0) }, + { FLDATA (CTL, drd.control, 0) }, + { FLDATA (FLG, drd.flag, 0) }, { ORDATA (BPTR, drd_ptr, 6) }, - { ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, drd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -272,7 +278,7 @@ REG drc_reg[] = { { FLDATA (RUN, drc_run, 0) }, { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, dr_stopioe, 0) }, - { ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, drc_dib.select_code, 6), REG_HRO }, { DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO }, { NULL } }; @@ -326,82 +332,80 @@ DEVICE drc_dev = { and as CRS is sent to all devices, we simply clear the control word here. */ -uint32 drdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 drdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ int32 t; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - drd_flag = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + drd.flag = CLEAR; + break; - case ioENF: /* enable flag */ - drd_flag = SET; - break; + case ioENF: /* enable flag */ + drd.flag = SET; + break; - case ioIOI: /* I/O data input */ - data = drd_ibuf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, drd_ibuf); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - drd_obuf = data; - break; + case ioIOO: /* I/O data output */ + drd_obuf = IODATA (stat_data); /* clear supplied status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606B? */ - drc_cw = 0; /* clear control word */ + case ioCRS: /* control reset */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606B? */ + drc_cw = 0; /* clear control word */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - drd_flag = drd_control = CLEAR; /* clear control and flag */ + case ioCLC: /* clear control flip-flop */ + drd.flag = drd.control = CLEAR; /* clear control and flag */ - if (!drc_run) /* cancel curr op */ - sim_cancel (&drc_unit); + if (!drc_run) /* cancel curr op */ + sim_cancel (&drc_unit); - drc_sta = drc_sta & ~DRS_SAC; /* clear SAC flag */ - break; + drc_sta = drc_sta & ~DRS_SAC; /* clear SAC flag */ + break; - case ioSTC: /* set control flip-flop */ - drd_control = SET; /* set ctl */ + case ioSTC: /* set control flip-flop */ + drd.control = SET; /* set ctl */ - if (drc_cw & CW_WR) /* writing? */ - drd_flag = SET; /* prime DMA */ + if (drc_cw & CW_WR) /* writing? */ + drd.flag = SET; /* prime DMA */ - drc_sta = 0; /* clr status */ - drd_ptr = 0; /* clear sec ptr */ - sim_cancel (&drc_unit); /* cancel curr op */ - t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime()); - if (t <= 0) t = t + DR_NUMSC; - sim_activate (&drc_unit, t * DR_NUMWD * dr_time); - break; + drc_sta = 0; /* clr status */ + drd_ptr = 0; /* clear sec ptr */ + sim_cancel (&drc_unit); /* cancel curr op */ + t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime()); + if (t <= 0) t = t + DR_NUMSC; + sim_activate (&drc_unit, t * DR_NUMWD * dr_time); + break; - case ioSIR: /* set interrupt request */ - setstdSRQ (select_code, drd); /* set SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdSRQ (drd); /* set SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - drdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - drdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -423,81 +427,80 @@ return data; 2. The command channel cannot interrupt, so there is no SIR handler. */ -uint32 drcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 drcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ + +uint16 data; int32 sec; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ - sec = dr_seccntr (sim_gtime ()); /* current sector */ - sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */ - sim_activate (&drd_unit[TMR_ORG], - (DR_FNUMSC - sec) * DR_NUMWD * dr_time); - } - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ + sec = dr_seccntr (sim_gtime ()); /* current sector */ + sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */ + sim_activate (&drd_unit[TMR_ORG], + (DR_FNUMSC - sec) * DR_NUMWD * dr_time); + } + break; - case ioSFC: /* skip if flag is clear */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ - setSKF (!(CALC_SCP (sim_gtime()))); /* skip if nearing end of sector */ - break; + case ioSFC: /* skip if flag is clear */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ + setSKF (!(CALC_SCP (sim_gtime()))); /* skip if nearing end of sector */ + break; - case ioSFS: /* skip if flag is set */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ - setSKF (!sim_is_active (&drd_unit[TMR_ORG])); /* skip if origin seen */ - break; + case ioSFS: /* skip if flag is set */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ + setSKF (!sim_is_active (&drd_unit[TMR_ORG])); /* skip if origin seen */ + break; - case ioIOI: /* I/O data input */ - data = drc_sta; /* static bits */ + case ioIOI: /* I/O data input */ + data = drc_sta; /* static bits */ - if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */ - (CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */ - data = data | DRS_WEN; /* set wrt enb status */ + if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */ + (CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */ + data = data | DRS_WEN; /* set wrt enb status */ - if (drc_unit.flags & UNIT_ATT) { /* attached? */ - data = data | (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY; - if (sim_is_active (&drc_unit)) /* op in progress? */ - data = data | DRS_BSY; - if (CALC_SCP (sim_gtime())) /* SCP ff set? */ - data = data | DRS_SEC; /* set sector flag */ - if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */ - !(drc_cw & CW_WR)) - data = data | DRS_RIF; /* set read inh flag */ - } - break; + if (drc_unit.flags & UNIT_ATT) { /* attached? */ + data = data | (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY; + if (sim_is_active (&drc_unit)) /* op in progress? */ + data = data | DRS_BSY; + if (CALC_SCP (sim_gtime())) /* SCP ff set? */ + data = data | DRS_SEC; /* set sector flag */ + if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */ + !(drc_cw & CW_WR)) + data = data | DRS_RIF; /* set read inh flag */ + } + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ - sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */ - sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD); - } - drc_cw = data; /* get control word */ - break; + case ioIOO: /* I/O data output */ + if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ + sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */ + sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD); + } + drc_cw = IODATA (stat_data); /* get control word */ + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ + default: /* all other signals */ + break; /* are ignored */ + } - case ioCRS: /* control reset */ - break; /* allow data channel to handle this */ - - - default: /* all other signals */ - break; /* are ignored */ + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - drcio (select_code, ioCLF, 0); /* issue CLF */ - -return data; - +return stat_data; } @@ -511,7 +514,7 @@ uint16 *bptr = (uint16 *) uptr->filebuf; if ((uptr->flags & UNIT_ATT) == 0) { drc_sta = DRS_ABO; - return IORETURN (dr_stopioe, SCPE_UNATT); + return IOERROR (dr_stopioe, SCPE_UNATT); } trk = CW_GETTRK (drc_cw); @@ -527,8 +530,8 @@ if (drc_cw & CW_WR) { /* write? */ uptr->hwmark = da + drd_ptr + 1; } drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */ - if (drd_control) { /* dch active? */ - drdio (drd_dib.devno, ioENF, 0); /* set SRQ */ + if (drd.control) { /* dch active? */ + drdio (&drd_dib, ioENF, 0); /* set SRQ */ sim_activate (uptr, dr_time); /* sched next word */ } else { /* done */ @@ -541,11 +544,11 @@ if (drc_cw & CW_WR) { /* write? */ } } /* end write */ else { /* read */ - if (drd_control) { /* dch active? */ + if (drd.control) { /* dch active? */ if ((da >= uptr->capac) || (sec >= DR_NUMSC)) drd_ibuf = 0; else drd_ibuf = bptr[da + drd_ptr]; drd_ptr = dr_incda (trk, sec, drd_ptr); - drdio (drd_dib.devno, ioENF, 0); /* set SRQ */ + drdio (&drd_dib, ioENF, 0); /* set SRQ */ sim_activate (uptr, dr_time); /* sched next word */ } else drc_run = 0; /* clear run ff */ @@ -601,16 +604,17 @@ else return ((curword - DR_OVRHEAD) / DR_NUMWD + t_stat drc_reset (DEVICE *dptr) { +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &drd_dev)? &drc_dev: &drd_dev); -if (sim_switches & SWMASK ('P')) /* PON reset? */ - drc_sta = drc_cw = drd_ptr = 0; /* clear controller state variables */ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ + drd_ptr = 0; /* clear sector pointer */ + drc_sta = drc_cw = 0; /* clear controller state variables */ + } -if (dptr == &drc_dev) /* command channel reset? */ - drcio (drc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - drdio (drd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ sim_cancel (&drc_unit); sim_cancel (&drd_unit[TMR_ORG]); @@ -726,7 +730,7 @@ static const BOOT_ROM dr_rom = { /* padded to start at x7 t_stat drc_boot (int32 unitno, DEVICE *dptr) { -const int32 dev = drd_dib.devno; /* data chan select code */ +const int32 dev = drd_dib.select_code; /* data chan select code */ if (unitno != 0) /* only unit 0 */ return SCPE_NOFNC; diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c index 7017736c..ee22bead 100644 --- a/HP2100/hp2100_ds.c +++ b/HP2100/hp2100_ds.c @@ -1,6 +1,6 @@ /* hp2100_ds.c: HP 2100 13037 disk controller simulator - Copyright (c) 2004-2008, Robert M. Supnik + Copyright (c) 2004-2011, Robert 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,13 @@ DS 13037 disk controller + 21-Jun-11 JDB Corrected status returns for disabled drive, auto-seek + beyond drive limits, Request Sector Address and Wakeup + with invalid or offline unit + Address verification reenabled if auto-seek during + Read Without Verify + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals 31-Dec-07 JDB Corrected and verified ioCRS action 20-Dec-07 JDB Corrected DPTR register definition from FLDATA to DRDATA @@ -346,10 +353,12 @@ static struct drvtyp drv_tab[] = { { 0 } }; -FLIP_FLOP ds_control = CLEAR; -FLIP_FLOP ds_flag = CLEAR; -FLIP_FLOP ds_flagbuf = CLEAR; -FLIP_FLOP ds_srq = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP srq; /* service request flip-flop */ + } ds = { CLEAR, CLEAR, CLEAR, CLEAR }; uint32 ds_fifo[DS_FIFO_SIZE] = { 0 }; /* fifo */ uint32 ds_fifo_ip = 0; /* insertion ptr */ @@ -412,7 +421,9 @@ static const uint32 ds_opflags[32] = { /* flags for ops */ }; DEVICE ds_dev; -uint32 dsio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER dsio; + t_stat ds_svc_c (UNIT *uptr); t_stat ds_svc_u (UNIT *uptr); t_stat ds_svc_t (UNIT *uptr); @@ -455,7 +466,7 @@ void ds_fifo_reset (void); ds_mod DS modifier list */ -DIB ds_dib = { DS, &dsio }; +DIB ds_dib = { &dsio, DS }; UNIT ds_unit[] = { { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | @@ -491,10 +502,10 @@ REG ds_reg[] = { { DRDATA (FIP, ds_fifo_ip, 4) }, { DRDATA (FRP, ds_fifo_rp, 4) }, { DRDATA (FCNT, ds_fifo_cnt, 5) }, - { FLDATA (CTL, ds_control, 0) }, - { FLDATA (FLG, ds_flag, 0) }, - { FLDATA (FBF, ds_flagbuf, 0) }, - { FLDATA (SRQ, ds_srq, 0) }, + { FLDATA (CTL, ds.control, 0) }, + { FLDATA (FLG, ds.flag, 0) }, + { FLDATA (FBF, ds.flagbuf, 0) }, + { FLDATA (SRQ, ds.srq, 0) }, { FLDATA (BUSY, ds_busy, 0) }, { FLDATA (CMDF, ds_cmdf, 0) }, { FLDATA (CMDP, ds_cmdp, 0) }, @@ -515,7 +526,7 @@ REG ds_reg[] = { DS_NUMDR + 1, REG_HRO) }, { URDATA (CAPAC, ds_unit[0].capac, 10, T_ADDR_W, 0, DS_NUMDR, PV_LEFT | REG_HRO) }, - { ORDATA (DEVNO, ds_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, ds_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -576,7 +587,7 @@ DEVICE ds_dev = { of a command. Also unusual is that SFC and SFS test different things, rather than - complementaty states of the same thing. SFC tests the busy flip-flop, and + complementary states of the same thing. SFC tests the busy flip-flop, and SFS tests the flag flip-flop. Implementation notes: @@ -586,108 +597,110 @@ DEVICE ds_dev = { access to fail. */ -uint32 dsio (uint32 select_code, IOSIG signal, uint32 data) +uint32 dsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - ds_flag = ds_flagbuf = CLEAR; /* clear flag */ - ds_srq = CLEAR; /* CLF clears SRQ */ - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ds.flag = ds.flagbuf = CLEAR; /* clear flag */ + ds.srq = CLEAR; /* CLF clears SRQ */ + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ds_flag = ds_flagbuf = SET; /* set flag and flag buffer */ - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ds.flag = ds.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioSFC: /* skip if flag is clear */ - setSKF (ds_busy == 0); /* skip if not busy */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (ds_busy == 0); /* skip if not busy */ + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (ds); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (ds); + break; - case ioIOI: /* I/O data input */ - data = ds_fifo_read (); - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, ds_fifo_read ()); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - if (ds_cmdf) { /* expecting command? */ - ds_cmd = data; /* save command */ - ds_cmdf = 0; - ds_cmdp = 1; /* command present */ - } + case ioIOO: /* I/O data output */ + if (ds_cmdf) { /* expecting command? */ + ds_cmd = IODATA (stat_data); /* save command */ + ds_cmdf = 0; + ds_cmdp = 1; /* command present */ + } - else - ds_fifo_write (data); /* put in fifo */ - break; + else + ds_fifo_write (IODATA (stat_data)); /* put in fifo */ + break; - case ioPOPIO: /* power-on preset to I/O */ - ds_flag = ds_flagbuf = SET; /* set flag and flag buffer */ - ds_cmdp = 0; /* clear command ready */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - ds_control = CLEAR; /* clear control */ - ds_cmdf = 0; /* not expecting command */ - ds_clear (); /* do controller CLEAR */ - break; + case ioPOPIO: /* power-on preset to I/O */ + ds.flag = ds.flagbuf = SET; /* set flag and flag buffer */ + ds_cmdp = 0; /* clear command ready */ + break; - case ioCLC: /* clear control flip-flop */ - ds_control = CLEAR; /* clear control */ - ds_cmdf = 1; /* expecting command */ - ds_cmdp = 0; /* none pending */ - ds_eod = 1; /* set EOD flag */ - ds_fifo_reset (); /* clear fifo */ - break; + case ioCRS: /* control reset */ + ds.control = CLEAR; /* clear control */ + ds_cmdf = 0; /* not expecting command */ + ds_clear (); /* do controller CLEAR */ + break; - case ioSTC: /* set control flip-flop */ - ds_control = SET; /* set control */ - break; + case ioCLC: /* clear control flip-flop */ + ds.control = CLEAR; /* clear control */ + ds_cmdf = 1; /* expecting command */ + ds_cmdp = 0; /* none pending */ + ds_eod = 1; /* set EOD flag */ + ds_fifo_reset (); /* clear fifo */ + break; - case ioEDT: /* end data transfer */ - ds_eod = 1; /* flag end transfer */ - break; + case ioSTC: /* set control flip-flop */ + ds.control = SET; /* set control */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, ds); /* set standard PRL signal */ - setstdIRQ (select_code, ds); /* set standard IRQ signal */ - setSRQ (select_code, ds_srq); /* set SRQ signal */ - break; + case ioEDT: /* end data transfer */ + ds_eod = 1; /* flag end transfer */ + break; - case ioIAK: /* interrupt acknowledge */ - ds_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (ds); /* set standard PRL signal */ + setstdIRQ (ds); /* set standard IRQ signal */ + setSRQ (dibptr->select_code, ds.srq); /* set SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + ds.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - dsio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - dsio (select_code, ioSIR, 0); /* set interrupt request */ - - -if ((signal != ioSIR) && (signal != ioENF)) /* if not IRQ update */ +if (!(signal_set & ioSIR) && !(signal_set & ioENF)) /* if not IRQ update */ ds_poll (); /* run the controller */ -return data; +return stat_data; } @@ -702,7 +715,7 @@ void ds_poll (void) { if ((ds_state != DS_BUSY) && ds_cmdp) /* cmd pending? */ ds_docmd (ds_cmd); /* do it */ -if ((ds_state == DS_IDLE) && ds_control) /* idle? */ +if ((ds_state == DS_IDLE) && ds.control) /* idle? */ ds_doatn (); /* check ATN */ return; } @@ -719,7 +732,7 @@ return; void ds_docmd (uint32 cmd) { -uint32 op, f, dtyp, unum; +uint32 op, f, unum; op = DSC_GETOP (cmd); /* operation */ f = ds_opflags[op]; /* flags */ @@ -749,6 +762,7 @@ switch (op) { (DSC_GETCSC (ds_cmd) << DSHS_V_SC); case DSC_RECAL: /* recalibrate */ case DSC_SEEK: /* seek */ + case DSC_RSA: /* read sector address */ case DSC_READ: /* read */ case DSC_RFULL: /* read full */ case DSC_ROFF: /* read offset */ @@ -786,12 +800,6 @@ switch (op) { ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */ break; - case DSC_RSA: /* read sector address */ - dtyp = GET_DTYPE (ds_unit[unum].flags); /* get unit type */ - dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */ - ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */ - break; - case DSC_RDA: /* read disk address */ ds_reqad (&dsxb[1], &dsxb[0]); /* return disk address */ ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */ @@ -806,10 +814,15 @@ switch (op) { /* Other controller commands */ + case DSC_WAKE: /* wakeup */ + ds_sr1 = unum; /* init status */ + if (unum >= DS_NUMDR) { /* invalid unit? */ + ds_sched_ctrl_op (DSC_BADU, unum, CLR_BUSY);/* sched, not busy */ + return; + } case DSC_SFM: /* set file mask */ case DSC_CLEAR: /* clear */ case DSC_AREC: /* address record */ - case DSC_WAKE: /* wakeup */ case DSC_WTIO: /* write TIO */ ds_sched_ctrl_op (op, 0, SET_BUSY); /* schedule, busy */ break; @@ -833,7 +846,7 @@ for (i = 0; i < DS_NUMDR; i++) { /* intr disabled? */ ds_lastatn = (ds_lastatn + 1) & DS_DRMASK; /* loop through units */ if (ds_unit[ds_lastatn].STA & DS2_ATN) { /* ATN set? */ ds_unit[ds_lastatn].STA &= ~DS2_ATN; /* clear ATN */ - dsio (ds_dib.devno, ioENF, 0); /* request interrupt */ + dsio (&ds_dib, ioENF, 0); /* request interrupt */ ds_sr1 = DS1_ATN | ds_lastatn; /* set up status 1 */ ds_state = DS_WAIT; /* block atn intrs */ return; @@ -889,9 +902,9 @@ switch (op) { case DSC_CLEAR: /* clear */ ds_clear (); /* reset ctrl */ - ds_control = CLEAR; /* clear CTL, SRQ */ - ds_srq = CLEAR; - dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */ + ds.control = CLEAR; /* clear CTL, SRQ */ + ds.srq = CLEAR; + dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ ds_cmd_done (1, DS1_OK); /* op done, set flag */ break; @@ -994,6 +1007,15 @@ switch (op) { /* case on function */ /* Read variants */ + case DSC_RSA: /* read sector address */ + if ((uptr->flags & UNIT_UNLOAD) == 0) { /* drive up? */ + dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */ + ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */ + } + else /* no drive or heads unloaded */ + ds_cmd_done (1, DS1_S2ERR); /* not ready error */ + break; + case DSC_ROFF: /* read with offset */ ds_wait_for_cpu (uptr, DSC_ROFF|DSC_2ND); /* set flag, new state */ break; @@ -1001,7 +1023,7 @@ switch (op) { /* case on function */ if (!DS_FIFO_EMPTY) { /* OTA ds? new state */ ds_fifo_read (); /* drain fifo */ uptr->FNC = DSC_READ; - dsio (ds_dib.devno, ioENF, 0); /* handshake */ + dsio (&ds_dib, ioENF, 0); /* handshake */ } sim_activate (uptr, ds_ctime); /* schedule unit */ break; @@ -1022,14 +1044,15 @@ switch (op) { /* case on function */ ds_end_rw (uptr, DSC_READ); /* see if more to do */ break; - case DSC_RNOVFY: /* read, no verify */ + case DSC_RNOVFY: /* read, no verify before xfer */ if (r = ds_start_rd (uptr, 0, 0)) return r; /* new sector; error? */ break; case DSC_RNOVFY | DSC_2ND: /* word transfer */ ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */ break; case DSC_RNOVFY | DSC_3RD: /* end of sector */ - ds_end_rw (uptr, DSC_RNOVFY); /* see if more to do */ + ds_end_rw (uptr, /* see if more to do */ + DSHS_GETSC (ds_hs) ? DSC_RNOVFY : DSC_READ); /* start verifying if end of track */ break; case DSC_RFULL: /* read full */ @@ -1049,7 +1072,7 @@ switch (op) { /* case on function */ case DSC_VFY: /* verify */ ds_wait_for_cpu (uptr, DSC_VFY|DSC_2ND); /* set flag, new state */ break; - case DSC_VFY | DSC_2ND: /* poll done */ + case DSC_VFY | DSC_2ND: /* poll done */ if (!DS_FIFO_EMPTY) { /* OTA ds? */ ds_vctr = ds_fifo_read (); /* save count */ uptr->FNC = DSC_VFY | DSC_3RD; /* next state */ @@ -1058,11 +1081,11 @@ switch (op) { /* case on function */ else sim_activate (uptr, ds_ctime); /* no, continue poll */ break; case DSC_VFY | DSC_3RD: /* start sector */ - if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) break; - /* new sector; error? */ + if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) /* new sector; error? */ + break; ds_next_sec (uptr); /* increment hd, sc */ break; - case DSC_VFY | DSC_4TH: /* end sector */ + case DSC_VFY | DSC_4TH: /* end sector */ ds_vctr = (ds_vctr - 1) & DMASK; /* decrement count */ if (ds_vctr) ds_end_rw (uptr, DSC_VFY|DSC_3RD); /* more to do? */ else ds_cmd_done (1, DS1_OK); /* no, set done */ @@ -1120,7 +1143,7 @@ return SCPE_OK; void ds_wait_for_cpu (UNIT *uptr, uint32 newst) { -dsio (ds_dib.devno, ioENF, 0); /* set flag */ +dsio (&ds_dib, ioENF, 0); /* set flag */ uptr->FNC = newst; /* new state */ sim_activate (uptr, ds_ctime); /* activate unit */ sim_cancel (&ds_timer); /* activate timeout */ @@ -1154,7 +1177,7 @@ return; void ds_cmd_done (t_bool sf, uint32 sr1) { if (sf) /* set host flag? */ - dsio (ds_dib.devno, ioENF, 0); /* set flag */ + dsio (&ds_dib, ioENF, 0); /* set flag */ ds_busy = 0; /* clear visible busy */ ds_sr1 = ds_sr1 | sr1; /* final status */ @@ -1165,7 +1188,20 @@ return; } -/* Return drive status (status word 2) */ +/* Return drive status (status word 2). + + In hardware, the controller outputs the Address Unit command on the drive tag + bus and the unit number on the drive control bus. The addressed drive + responds by setting its internal "selected" flag. The controller then + outputs Request Status on the tag bug. If a drive is selected but the heads + are unloaded, the drive returns Not Ready and Busy status on the control bus. + If no drive is selected, the control bus floats inactive. This is + interpreted by the controller as Not Ready status (because the drive returns + inactive Ready status). + + Under simulation, an enabled but detached unit corresponds to "selected but + heads unloaded," and a disabled unit corresponds to a non-existent unit. +*/ uint32 ds_updds2 (UNIT *uptr) { @@ -1174,10 +1210,11 @@ uint32 dtyp = GET_DTYPE (uptr->flags); sta = drv_tab[dtyp].id | /* form status */ uptr->STA | /* static bits */ - ((uptr->flags & UNIT_WPR)? DS2_RO: 0) | /* dynamic bits */ - ((uptr->flags & UNIT_FMT)? DS2_FRM: 0) | - ((uptr->flags & UNIT_UNLOAD)? DS2_NR | DS2_BS: 0) | - (sim_is_active (uptr)? DS2_BS: 0); + ((uptr->flags & UNIT_WPR) ? DS2_RO : 0) | /* dynamic bits */ + ((uptr->flags & UNIT_FMT) ? DS2_FRM : 0) | + ((uptr->flags & UNIT_DIS) ? DS2_NR : + (uptr->flags & UNIT_UNLOAD) ? DS2_NR | DS2_BS : 0) | + (sim_is_active (uptr) ? DS2_BS : 0); if (sta & DS2_ALLERR) sta = sta | DS2_ERR; /* set error */ return sta; } @@ -1240,7 +1277,12 @@ return; - If error, set command done, return TRUE, nothing is scheduled - If implicit seek, return TRUE, implicit seek is scheduled, but state is not changed - we will return here when seek is done - - Otherwise, advance state, set position in file, schedule next state */ + - Otherwise, advance state, set position in file, schedule next state + + If a an auto-seek was done, it may have incremented or decremented beyond the + cylinder bounds. If so, then Seek Check status will have been set. If we + see that, terminate the current command with a Status-2 error. +*/ t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy) { @@ -1249,8 +1291,8 @@ uint32 dtyp = GET_DTYPE (uptr->flags); ds_eod = 0; /* init eod */ ds_ptr = 0; /* init buffer ptr */ -if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ - ds_cmd_done (1, DS1_S2ERR); +if (uptr->flags & UNIT_UNLOAD | uptr->STA & DS2_SC) { /* drive down or seek check? */ + ds_cmd_done (1, DS1_S2ERR); /* report Status-2 error */ return TRUE; } if (ds_eoc) { /* at end of cylinder? */ @@ -1258,21 +1300,16 @@ if (ds_eoc) { /* at end of cylinder? * return TRUE; /* or error */ } if (vfy && ((uint32) uptr->CYL != ds_cyl)) { /* on wrong cylinder? */ - if (ds_cyl >= drv_tab[dtyp].cyl) /* seeking to bad? */ - ds_cmd_done (1, DS1_CYLCE); /* lose */ - else ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek right cyl */ + ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek right cyl */ return TRUE; } hd = DSHS_GETHD (ds_hs); sc = DSHS_GETSC (ds_hs); -if ((uint32) uptr->CYL >= drv_tab[dtyp].cyl) { /* valid cylinder? */ - uptr->STA = uptr->STA | DS2_SC; /* set seek check */ - ds_cmd_done (1, DS1_S2ERR); /* error */ - return TRUE; - } -if ((hd >= drv_tab[dtyp].hd) || /* valid head, sector? */ +if (((uint32) uptr->CYL >= drv_tab[dtyp].cyl) || /* valid cylinder? (sanity check) */ + (hd >= drv_tab[dtyp].hd) || /* valid head, sector? */ (sc >= drv_tab[dtyp].sc)) { - ds_cmd_done (1, DS1_HSCE); /* no, error */ + uptr->STA = uptr->STA | DS2_SC; /* set seek check */ + ds_cmd_done (1, DS1_S2ERR); /* report Status-2 error */ return TRUE; } da = GET_DA (uptr->CYL, hd, sc, dtyp); /* position in file */ @@ -1327,8 +1364,8 @@ if ((uptr->flags & UNIT_WPR) || /* write protected? */ } if (ds_start_rw (uptr, ds_rtime, vfy)) return; /* new sec; err or seek? */ for (i = 0; i < DS_NUMWDF; i++) dsxb[i] = 0; /* clear buffer */ -ds_srq = SET; /* request word */ -dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */ +ds.srq = SET; /* request word */ +dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ return; } @@ -1355,7 +1392,10 @@ return; /* Advance to next cylinder - If autoseek enabled, seek to cylinder +/- 1 - - Otherwise, done with end of cylinder error */ + - Otherwise, done with end of cylinder error. + + If we exceed the cylinder range, the seek will set Seek Check status. +*/ void ds_next_cyl (UNIT *uptr) { @@ -1378,14 +1418,14 @@ return; void ds_cont_rd (UNIT *uptr, uint32 bsize) { if (ds_eod) ds_cmd_done (1, DS1_OK); /* DMA end? done */ -else if (ds_srq) { /* overrun? */ +else if (ds.srq) { /* overrun? */ ds_cmd_done (1, DS1_OVRUN); /* set done */ return; } else { ds_fifo_write (dsxb[ds_ptr++]); /* next word */ - ds_srq = SET; /* request service */ - dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */ + ds.srq = SET; /* request service */ + dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ if (ds_ptr >= bsize) uptr->FNC += DSC_NEXT; /* sec done? next state */ sim_activate (uptr, ds_dtime); /* schedule */ } @@ -1398,13 +1438,13 @@ return; - Copy word from fifo to buffer - If end of data, write buffer, terminate command, nothing scheduled - If end of sector, write buffer, next state, schedule - - Otherwises, set service request, schedule */ + - Otherwise, set service request, schedule */ t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize) { uint32 i, dat; -if (ds_srq) { /* overrun? */ +if (ds.srq) { /* overrun? */ ds_cmd_done (1, DS1_OVRUN); /* set done */ return SCPE_OK; } @@ -1422,8 +1462,8 @@ if (ds_eod || (ds_ptr >= bsize)) { /* xfr or sector done? * else uptr->FNC += DSC_NEXT; /* no, next state */ } else { - ds_srq = SET; /* request next word */ - dsio (ds_dib.devno, ioSIR, 0); /* set interrupt request */ + ds.srq = SET; /* request next word */ + dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ } sim_activate (uptr, ds_dtime); /* schedule */ return SCPE_OK; @@ -1529,8 +1569,8 @@ return SCPE_OK; t_stat ds_reset (DEVICE *dptr) { -dsio (ds_dib.devno, ioPOPIO, 0); /* send POPIO signal */ -ds_srq = CLEAR; /* clear SRQ */ +IOPRESET (&ds_dib); /* PRESET device */ +ds.srq = CLEAR; /* clear SRQ */ return SCPE_OK; } @@ -1593,7 +1633,7 @@ void ds_sched_atn (UNIT *uptr) { int32 i; -if (!ds_control || (sim_switches & SIM_SW_REST)) return; +if (!ds.control || (sim_switches & SIM_SW_REST)) return; for (i = 0; i < (DS_NUMDR + 1); i++) { /* check units, ctrl */ if (sim_is_active (ds_dev.units + i)) return; } @@ -1687,7 +1727,7 @@ t_stat ds_boot (int32 unitno, DEVICE *dptr) int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = ds_dib.devno; /* get data chan dev */ +dev = ds_dib.select_code; /* get data chan dev */ if (ibl_copy (ds_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & (IBL_OPT | IBL_DS_HEAD)) | IBL_DS | IBL_MAN | (dev << IBL_V_DEV); return SCPE_OK; diff --git a/HP2100/hp2100_fp1.c b/HP2100/hp2100_fp1.c index 0ca50848..cf078435 100644 --- a/HP2100/hp2100_fp1.c +++ b/HP2100/hp2100_fp1.c @@ -1,6 +1,6 @@ /* hp2100_fp1.c: HP 1000 multiple-precision floating point routines - Copyright (c) 2005-2008, J. David Bryan + Copyright (c) 2005-2011, J. David Bryan 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 @@ in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the author. + 21-Jun-11 JDB Completed the comments for divide; no code changes 08-Jun-08 JDB Quieted bogus gcc warning in fp_exec 10-May-08 JDB Fixed uninitialized return in fp_accum when setting 19-Mar-08 JDB Reworked "complement" to avoid inlining bug in gcc-4.x @@ -153,7 +154,7 @@ initial letters of the instructions (F/X/T) to indicate the precision used. The FPP hardware consisted of two circuit boards that interfaced to the main - CPU via the Microprogammable Processor Port (MPP) that had been introduced + CPU via the Microprogrammable Processor Port (MPP) that had been introduced with the 1000 E-Series. One board contained argument registers and ALUs, split into separate mantissa and exponent parts. The other contained a state machine sequencer. FPP results were copied automatically to the argument @@ -675,9 +676,9 @@ return; two operands. If the magnitude of the difference between the exponents is greater than the number of significant bits, then the smaller number has been scaled to zero (swamped), and so the sum is simply the larger operand. - Otherwise, the sum is computed and checked for overflow, which has occured if - the signs of the operands are the same but differ from that of the result. - Scaling and renormalization is perfomed if overflow occurred. + Otherwise, the sum is computed and checked for overflow, which has occurred + if the signs of the operands are the same but differ from that of the result. + Scaling and renormalization is performed if overflow occurred. */ static void add (FPU *sum, FPU augend, FPU addend) @@ -727,11 +728,11 @@ return; The single-precision firmware (FMP) operates differently from the firmware extended-precision (.XMPY) and the hardware multiplies of any precision. - Firmware implementations form 16-bit x 16-bit = 32-bit partial products and - sum them to form the result. The hardware uses a series of shifts and adds. - This means that firmware FMP and hardware FMP return slightly different - values, as may be seen by attempting to run the firmware FMP diagnostic on - the FPP. + Firmware implementations use the MPY micro-order to form 16-bit x 16-bit = + 32-bit partial products and sum them to form the result. The hardware uses a + series of shifts and adds. This means that firmware FMP and hardware FMP + return slightly different values, as may be seen by attempting to run the + firmware FMP diagnostic on the FPP. The FMP microcode calls a signed multiply routine to calculate three partial products (all but LSB * LSB). Because the LSBs are unsigned, i.e., all bits @@ -779,7 +780,7 @@ return; The basic FPP hardware algorithm scans the multiplier and adds a shifted copy of the multiplicand whenever a one-bit is detected. To avoid successive adds when a string of ones is encountered (because adds are more expensive than - shifts), the hardware instead adds the multiplicand shifted by N+1+P and + shifts), the hardware instead adds the multiplicand shifted by N + 1 + P and subtracts the multiplicand shifted by P to obtain the equivalent value with a maximum of two operations. @@ -884,16 +885,32 @@ return; As with multiply, the single-precision firmware (FDV) operates differently from the firmware extended-precision (.XDIV) and the hardware divisions of - any precision. Firmware implementations utilize a "divide and correct" - algorithm, wherein the quotient is estimated and then corrected by comparing - the dividend to the product of the quotient and the divisor. The hardware - uses a series of shifts and subtracts. This means that firmware FDV and - hardware FDV once again return slightly different values. + any precision. Firmware implementations use the DIV micro-order to form + 32-bit / 16-bit = 16-bit quotients and 16-bit remainders. These are used in + a "divide and correct" algorithm, wherein the quotient is estimated and then + corrected by comparing the dividend to the product of the quotient and the + divisor. The hardware uses a series of shifts and subtracts. This means + that firmware FDV and hardware FDV once again return slightly different + values. Under simulation, the classic divide-and-correct method is employed, using - 64-bit / 32-bit = 32-bit divisions. This involves dividing the 64-bit - dividend "a1a2a3a4" by the first 32-bit digit "b1b2" of the 64-bit divisor - "b1b2b3b4". The resulting 32-bit quotient is ... + 64-bit / 32-bit = 32-bit divisions. This method considers the 64-bit + dividend and divisor each to consist of two 32-bit "digits." The 64-bit + dividend "a1a2a3a4" is divided by the first 32-bit digit "b1b2" of the 64-bit + divisor "b1b2b3b4", yielding a 32-bit trial quotient digit and a 32-bit + remainder digit. A correction is developed by subtracting the product of the + second 32-bit digit "b3b4" of the divisor and the trial quotient digit from + the remainder (we take advantage of the eight bits vacated by the exponent + during unpacking to ensure that this product will not overflow into the sign + bit). If the remainder is negative, the trial quotient is too large, so it + is decremented, and the (full 64-bit) divisor is added to the correction. + This is repeated until the correction is non-negative, indicating that the + first quotient digit is correct. The process is then repeated using the + remainder as the dividend to develop the second 32-bit digit of the quotient. + The two digits are then concatenated for produce the final 64-bit value. + + (See, "Divide-and-Correct Methods for Multiple Precision Division" by Marvin + L. Stein, Communications of the ACM, August 1964 for background.) The microcoded single-precision division avoids overflows by right-shifting some values, which leads to a loss of precision in the LSBs. We duplicate @@ -1365,7 +1382,7 @@ return 0; } - /* Complement an unpacked mantissa. +/* Complement an unpacked mantissa. An unpacked mantissa is passed as a "packed" number with a zero exponent. The exponent increment, i.e., either zero or one, depending on whether a diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 69eebc90..14811d01 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-2008, Robert M Supnik + Copyright (c) 2002-2011, Robert 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,11 @@ IPLI, IPLO 12875A interprocessor link + 07-Apr-11 JDB A failed STC may now be retried + 28-Mar-11 JDB Tidied up signal handling + 27-Mar-11 JDB Consolidated reporting of consecutive CRS signals + 29-Oct-10 JDB Revised for new multi-card paradigm + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach 15-Jul-08 JDB Revised EDT handler to refine completion delay conditions 09-Jul-08 JDB Revised ipl_boot to use ibl_copy @@ -62,6 +67,10 @@ #include "sim_sock.h" #include "sim_tmxr.h" +typedef enum { ipli, iplo } CARD_INDEX; /* card index number */ + +#define CARD_COUNT 2 /* count of cards supported */ + #define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */ #define UNIT_V_ACTV (UNIT_V_UF + 1) /* making connection */ #define UNIT_V_ESTB (UNIT_V_UF + 2) /* connection established */ @@ -83,19 +92,21 @@ extern DIB ptr_dib; /* need PTR select code for boot */ -typedef enum { CIN, COUT } CARD; /* ipli/iplo selector */ - int32 ipl_edtdelay = 1; /* EDT delay (msec) */ int32 ipl_ptime = 31; /* polling interval */ int32 ipl_stopioe = 0; /* stop on error */ -int32 ipl_hold[2] = { 0 }; /* holding character */ -FLIP_FLOP ipl_control [2] = { CLEAR, CLEAR }; -FLIP_FLOP ipl_flag [2] = { CLEAR, CLEAR }; -FLIP_FLOP ipl_flagbuf [2] = { CLEAR, CLEAR }; +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + int32 hold; /* holding character */ + } CARD_STATE; + +CARD_STATE ipl [CARD_COUNT]; /* per-card state */ + +IOHANDLER iplio; -DEVICE ipli_dev, iplo_dev; -uint32 iplio (uint32 select_code, IOSIG signal, uint32 data); t_stat ipl_svc (UNIT *uptr); t_stat ipl_reset (DEVICE *dptr); t_stat ipl_attach (UNIT *uptr, char *cptr); @@ -107,12 +118,37 @@ t_bool ipl_check_conn (UNIT *uptr); /* Debug flags table */ -DEBTAB ipl_deb[] = { +DEBTAB ipl_deb [] = { { "CMDS", DEB_CMDS }, { "CPU", DEB_CPU }, { "XFER", DEB_XFER }, { NULL, 0 } }; +/* Common structures */ + +DEVICE ipli_dev, iplo_dev; + +static DEVICE *dptrs [] = { &ipli_dev, &iplo_dev }; + + +UNIT ipl_unit [] = { + { UDATA (&ipl_svc, UNIT_ATTABLE, 0) }, + { UDATA (&ipl_svc, UNIT_ATTABLE, 0) } + }; + +#define ipli_unit ipl_unit [ipli] +#define iplo_unit ipl_unit [iplo] + + +DIB ipl_dib [] = { + { &iplio, IPLI, 0 }, + { &iplio, IPLO, 1 } + }; + +#define ipli_dib ipl_dib [ipli] +#define iplo_dib ipl_dib [iplo] + + /* IPLI data structures ipli_dev IPLI device descriptor @@ -120,36 +156,20 @@ DEBTAB ipl_deb[] = { ipli_reg IPLI register list */ -DIB ipl_dib[] = { - { IPLI, &iplio }, - { IPLO, &iplio } - }; - -#define ipli_dib ipl_dib[0] -#define iplo_dib ipl_dib[1] - -UNIT ipl_unit[] = { - { UDATA (&ipl_svc, UNIT_ATTABLE, 0) }, - { UDATA (&ipl_svc, UNIT_ATTABLE, 0) } - }; - -#define ipli_unit ipl_unit[0] -#define iplo_unit ipl_unit[1] - -REG ipli_reg[] = { +REG ipli_reg [] = { { ORDATA (IBUF, ipli_unit.IBUF, 16) }, { ORDATA (OBUF, ipli_unit.OBUF, 16) }, - { FLDATA (CTL, ipl_control [CIN], 0) }, - { FLDATA (FLG, ipl_flag [CIN], 0) }, - { FLDATA (FBF, ipl_flagbuf [CIN], 0) }, - { ORDATA (HOLD, ipl_hold[CIN], 8) }, + { FLDATA (CTL, ipl [ipli].control, 0) }, + { FLDATA (FLG, ipl [ipli].flag, 0) }, + { FLDATA (FBF, ipl [ipli].flagbuf, 0) }, + { ORDATA (HOLD, ipl [ipli].hold, 8) }, { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, ipl_stopioe, 0) }, - { ORDATA (DEVNO, ipli_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, ipli_dib.select_code, 6), REG_HRO }, { NULL } }; -MTAB ipl_mod[] = { +MTAB ipl_mod [] = { { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &ipl_setdiag }, { UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag }, { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", @@ -175,15 +195,15 @@ DEVICE ipli_dev = { iplo_reg IPLO register list */ -REG iplo_reg[] = { +REG iplo_reg [] = { { ORDATA (IBUF, iplo_unit.IBUF, 16) }, { ORDATA (OBUF, iplo_unit.OBUF, 16) }, - { FLDATA (CTL, ipl_control [COUT], 0) }, - { FLDATA (FLG, ipl_flag [COUT], 0) }, - { FLDATA (FBF, ipl_flagbuf [COUT], 0) }, - { ORDATA (HOLD, ipl_hold[COUT], 8) }, + { FLDATA (CTL, ipl [iplo].control, 0) }, + { FLDATA (FLG, ipl [iplo].flag, 0) }, + { FLDATA (FBF, ipl [iplo].flagbuf, 0) }, + { ORDATA (HOLD, ipl [iplo].hold, 8) }, { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, - { ORDATA (DEVNO, iplo_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, iplo_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -206,11 +226,7 @@ DEVICE iplo_dev = { Implementation notes: - 1. Because this routine is written to handle two devices, the flip-flops are - stored in arrays, preventing the use of the "setstd" macros for PRL, IRQ, - and SRQ signals. The logic for all three is standard, however. - - 2. 2000 Access has a race condition that manifests itself by an apparently + 1. 2000 Access has a race condition that manifests itself by an apparently normal boot and operational system console but no PLEASE LOG IN response to terminals connected to the multiplexer. The frequency of occurrence is higher on multiprocessor host systems, where the SP and IOP instances @@ -259,157 +275,176 @@ DEVICE iplo_dev = { sleep expiration, the SP still has not executed the STC/CLC. Still, in testing, the incidence dropped dramatically, so the problem is much less intrusive. + + 2. The operating manual for the 12920A Terminal Multiplexer says that "at + least 100 milliseconds of CLC 0s must be programmed" by systems employing + the multiplexer to ensure that the multiplexer resets. In practice, such + systems issue 128K CLC 0 instructions. As we provide debug logging of + IPL resets, a CRS counter is used to ensure that only one debug line is + printed in response to these 128K CRS invocations. + + 3. The STC handler may return "Unit not attached", "I/O error", or "No + connection on interprocessor link" status if the link fails or is + improperly configured. If the error is corrected, the operation may be + retried by resuming simulated execution. */ -uint32 iplio (uint32 select_code, IOSIG signal, uint32 data) +uint32 iplio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const CARD card = (select_code == iplo_dib.devno); /* set card selector */ -UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */ -const char uc = (card == CIN) ? 'I' : 'O'; /* identify unit for debug */ -const DEVICE *dbdev = (card == CIN) ? &ipli_dev : &iplo_dev; /* identify device for debug */ -const char *iotype[] = { "Status", "Command" }; -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const CARD_INDEX card = dibptr->card_index; /* set card selector */ +UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */ +const char *iotype [] = { "Status", "Command" }; int32 sta; -char msg[2]; +char msg [2]; +static uint32 crs_count [CARD_COUNT] = { 0, 0 }; /* per-card cntrs for ioCRS repeat */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +if (crs_count [card] && !(signal_set & ioCRS)) { /* counting CRSes and not present? */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) /* report reset count */ + fprintf (sim_deb, ">>%s cmds: [CRS] Control cleared %d times\n", + dptrs [card]->name, crs_count [card]); - case ioCLF: /* clear flag flip-flop */ - ipl_flag [card] = ipl_flagbuf [card] = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ipl_flag [card] = ipl_flagbuf [card] = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setSKF (!ipl_flag [card]); - break; - - - case ioSFS: /* skip if flag is set */ - setSKF (ipl_flag [card]); - break; - - - case ioIOI: /* I/O data input */ - data = uptr->IBUF; /* get return data */ - - if (DEBUG_PRJ (dbdev, DEB_CPU)) - fprintf (sim_deb, ">>IPL%c LIx: %s = %06o\n", uc, iotype [card ^ 1], data); - break; - - - case ioIOO: /* I/O data output */ - uptr->OBUF = data; - - if (DEBUG_PRJ (dbdev, DEB_CPU)) - fprintf (sim_deb, ">>IPL%c OTx: %s = %06o\n", uc, iotype [card], data); - break; - - - case ioPOPIO: /* power-on preset to I/O */ - ipl_flag [card] = ipl_flagbuf [card] = SET; /* set flag buffer and flag */ - uptr->OBUF = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - ipl_control [card] = CLEAR; /* clear control */ - - if (DEBUG_PRJ (dbdev, DEB_CMDS)) - fprintf (sim_deb, ">>IPL%c CRS: Control cleared\n", uc); - break; - - - case ioCLC: /* clear control flip-flop */ - ipl_control [card] = CLEAR; /* clear ctl */ - - if (DEBUG_PRJ (dbdev, DEB_CMDS)) - fprintf (sim_deb, ">>IPL%c CLC: Control cleared\n", uc); - break; - - - case ioSTC: /* set control flip-flop */ - ipl_control [card] = SET; /* set ctl */ - - if (DEBUG_PRJ (dbdev, DEB_CMDS)) - fprintf (sim_deb, ">>IPL%c STC: Control set\n", uc); - - if (uptr->flags & UNIT_ATT) { /* attached? */ - if ((uptr->flags & UNIT_ESTB) == 0) /* established? */ - if (!ipl_check_conn (uptr)) { /* not established? */ - data = STOP_NOCONN << IOT_V_REASON; /* lose */ - break; - } - - msg[0] = (uptr->OBUF >> 8) & 0377; - msg[1] = uptr->OBUF & 0377; - sta = sim_write_sock (uptr->DSOCKET, msg, 2); - - if (DEBUG_PRJ (dbdev, DEB_XFER)) - fprintf (sim_deb, - ">>IPL%c STC: Socket write = %06o, status = %d\n", - uc, uptr->OBUF, sta); - - if (sta == SOCKET_ERROR) { - printf ("IPL: socket write error\n"); - data = SCPE_IOERR << IOT_V_REASON; - break; - } - - sim_os_sleep (0); - } - - else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */ - ipl_unit [card ^ 1].IBUF = uptr->OBUF; /* output to other */ - iplio (ipl_dib [card ^ 1].devno, ioENF, 0); /* set other flag */ - } - - else - data = SCPE_UNATT << IOT_V_REASON; /* lose */ - break; - - - case ioEDT: /* end data transfer */ - if ((cpu_unit.flags & UNIT_IOP) && /* are we the IOP? */ - ((IOSIG) data == ioIOO) && (card == CIN)) { /* and doing output on input card? */ - - if (DEBUG_PRJ (dbdev, DEB_CMDS)) - fprintf (sim_deb, - ">>IPL%c EDT: Delaying DMA completion interrupt for %d msec\n", - uc, ipl_edtdelay); - - sim_os_ms_sleep (ipl_edtdelay); /* delay completion */ - } - break; - - - case ioSIR: /* set interrupt request */ - setPRL (select_code, !(ipl_control [card] & ipl_flag [card])); - setIRQ (select_code, ipl_control [card] & ipl_flag [card] & ipl_flagbuf [card]); - setSRQ (select_code, ipl_flag [card]); - break; - - - case ioIAK: /* interrupt acknowledge */ - ipl_flagbuf [card] = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ + crs_count [card] = 0; /* clear counter */ } +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ -if (signal > ioCLF) /* multiple signals? */ - iplio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - iplio (select_code, ioSIR, 0); /* set interrupt request */ + switch (signal) { /* dispatch I/O signal */ -return data; + case ioCLF: /* clear flag flip-flop */ + ipl [card].flag = ipl [card].flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ipl [card].flag = ipl [card].flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (ipl [card]); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (ipl [card]); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, uptr->IBUF); /* get return data */ + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [LIx] %s = %06o\n", dptrs [card]->name, iotype [card ^ 1], uptr->IBUF); + break; + + + case ioIOO: /* I/O data output */ + uptr->OBUF = IODATA (stat_data); /* clear supplied status */ + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [OTx] %s = %06o\n", dptrs [card]->name, iotype [card], uptr->OBUF); + break; + + + case ioPOPIO: /* power-on preset to I/O */ + ipl [card].flag = ipl [card].flagbuf = SET; /* set flag buffer and flag */ + uptr->OBUF = 0; /* clear output buffer */ + break; + + + case ioCRS: /* control reset */ + if (crs_count [card] == 0) /* first reset? */ + ipl [card].control = CLEAR; /* clear control */ + + crs_count [card] = crs_count [card] + 1; /* increment count */ + break; + + + case ioCLC: /* clear control flip-flop */ + ipl [card].control = CLEAR; /* clear ctl */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [CLC] Control cleared\n", dptrs [card]->name); + break; + + + case ioSTC: /* set control flip-flop */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [STC] Control set\n", dptrs [card]->name); + + if (uptr->flags & UNIT_ATT) { /* attached? */ + if (!ipl_check_conn (uptr)) /* not established? */ + return IORETURN (STOP_NOCONN, 0); /* lose */ + + msg [0] = (uptr->OBUF >> 8) & 0377; + msg [1] = uptr->OBUF & 0377; + sta = sim_write_sock (uptr->DSOCKET, msg, 2); + + if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, + ">>%s xfer: [STC] Socket write = %06o, status = %d\n", + dptrs [card]->name, uptr->OBUF, sta); + + if (sta == SOCKET_ERROR) { + printf ("IPL socket write error\n"); + return IORETURN (SCPE_IOERR, 0); + } + + ipl [card].control = SET; /* set ctl */ + + sim_os_sleep (0); + } + + else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */ + ipl [card].control = SET; /* set ctl */ + ipl_unit [card ^ 1].IBUF = uptr->OBUF; /* output to other */ + iplio ((DIB *) dptrs [card ^ 1]->ctxt, ioENF, 0); /* set other flag */ + } + + else + return IORETURN (SCPE_UNATT, 0); /* lose */ + break; + + + case ioEDT: /* end data transfer */ + if ((cpu_unit.flags & UNIT_IOP) && /* are we the IOP? */ + (signal_set & ioIOO) && /* and doing output? */ + (card == ipli)) { /* on the input card? */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, + ">>%s cmds: [EDT] Delaying DMA completion interrupt for %d msec\n", + dptrs [card]->name, ipl_edtdelay); + + sim_os_ms_sleep (ipl_edtdelay); /* delay completion */ + } + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (ipl [card]); + setstdIRQ (ipl [card]); + setstdSRQ (ipl [card]); + break; + + + case ioIAK: /* interrupt acknowledge */ + ipl [card].flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; } @@ -417,46 +452,46 @@ return data; t_stat ipl_svc (UNIT *uptr) { -CARD card; +CARD_INDEX card; int32 nb; -char msg[2], uc; -DEVICE *dbdev; /* device ptr for debug */ +char msg [2]; + +if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return SCPE_OK; -if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */ sim_activate (uptr, ipl_ptime); /* reactivate */ -if ((uptr->flags & UNIT_ESTB) == 0) /* not established? */ - if (!ipl_check_conn (uptr)) /* check for conn */ - return SCPE_OK; /* cot connected */ +if (!ipl_check_conn (uptr)) /* check for conn */ + return SCPE_OK; /* not connected */ nb = sim_read_sock (uptr->DSOCKET, msg, ((uptr->flags & UNIT_HOLD)? 1: 2)); + if (nb < 0) { /* connection closed? */ - printf ("IPL: socket read error\n"); + printf ("IPL socket read error\n"); return SCPE_IOERR; } -if (nb == 0) return SCPE_OK; /* no data? */ + +else if (nb == 0) /* no data? */ + return SCPE_OK; card = (uptr == &iplo_unit); /* set card selector */ if (uptr->flags & UNIT_HOLD) { /* holdover byte? */ - uptr->IBUF = (ipl_hold[card] << 8) | (((int32) msg[0]) & 0377); + uptr->IBUF = (ipl [card].hold << 8) | (((int32) msg [0]) & 0377); uptr->flags = uptr->flags & ~UNIT_HOLD; } else if (nb == 1) { - ipl_hold[card] = ((int32) msg[0]) & 0377; + ipl [card].hold = ((int32) msg [0]) & 0377; uptr->flags = uptr->flags | UNIT_HOLD; } -else uptr->IBUF = ((((int32) msg[0]) & 0377) << 8) | - (((int32) msg[1]) & 0377); +else + uptr->IBUF = ((((int32) msg [0]) & 0377) << 8) | (((int32) msg [1]) & 0377); -iplio (ipl_dib [card].devno, ioENF, 0); /* set flag */ +iplio ((DIB *) dptrs [card]->ctxt, ioENF, 0); /* set flag */ -uc = (card == CIN) ? 'I' : 'O'; /* identify unit for debug */ -dbdev = (card == CIN) ? &ipli_dev : &iplo_dev; /* identify device for debug */ - -if (DEBUG_PRJ (dbdev, DEB_XFER)) - fprintf (sim_deb, ">>IPL%c svc: Socket read = %06o, status = %d\n", - uc, uptr->IBUF, nb); +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, ">>%s xfer: Socket read = %06o, status = %d\n", + dptrs [card]->name, uptr->IBUF, nb); return SCPE_OK; } @@ -466,15 +501,23 @@ t_bool ipl_check_conn (UNIT *uptr) { SOCKET sock; -if (uptr->flags & UNIT_ESTB) return TRUE; /* established? */ +if (uptr->flags & UNIT_ESTB) /* established? */ + return TRUE; + if (uptr->flags & UNIT_ACTV) { /* active connect? */ - if (sim_check_conn (uptr->DSOCKET, 0) <= 0) return FALSE; + if (sim_check_conn (uptr->DSOCKET, 0) <= 0) + return FALSE; } + else { sock = sim_accept_conn (uptr->LSOCKET, NULL); /* poll connect */ - if (sock == INVALID_SOCKET) return FALSE; /* got a live one? */ + + if (sock == INVALID_SOCKET) /* got a live one? */ + return FALSE; + uptr->DSOCKET = sock; /* save data socket */ } + uptr->flags = uptr->flags | UNIT_ESTB; /* conn established */ return TRUE; } @@ -493,17 +536,15 @@ return TRUE; t_stat ipl_reset (DEVICE *dptr) { UNIT *uptr = dptr->units; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ +CARD_INDEX card = dibptr->card_index; /* card number */ -hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &ipli_dev)? &iplo_dev: &ipli_dev); +hp_enbdis_pair (dptr, dptrs [card ^ 1]); /* make pair cons */ -if (sim_switches & SWMASK ('P')) /* PON reset? */ +if (sim_switches & SWMASK ('P')) /* initialization reset? */ uptr->IBUF = uptr->OBUF = 0; /* clr buffers */ -if (dptr == &ipli_dev) /* input channel reset? */ - iplio (ipli_dib.devno, ioPOPIO, 0); /* send POPIO signal */ -else /* output channel reset */ - iplio (iplo_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ if (uptr->flags & UNIT_ATT) /* socket attached? */ sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ @@ -529,31 +570,39 @@ char *tptr; t_stat r; r = get_ipaddr (cptr, &ipa, &ipp); -if ((r != SCPE_OK) || (ipp == 0)) return SCPE_ARG; +if ((r != SCPE_OK) || (ipp == 0)) + return SCPE_ARG; oldf = uptr->flags; -if (oldf & UNIT_ATT) ipl_detach (uptr); +if (oldf & UNIT_ATT) + ipl_detach (uptr); if ((sim_switches & SWMASK ('C')) || ((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) { - if (ipa == 0) ipa = 0x7F000001; + if (ipa == 0) + ipa = 0x7F000001; newsock = sim_connect_sock (ipa, ipp); - if (newsock == INVALID_SOCKET) return SCPE_IOERR; + if (newsock == INVALID_SOCKET) + return SCPE_IOERR; printf ("Connecting to IP address %d.%d.%d.%d, port %d\n", (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, (ipa >> 8) & 0xff, ipa & 0xff, ipp); - if (sim_log) fprintf (sim_log, - "Connecting to IP address %d.%d.%d.%d, port %d\n", - (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, - (ipa >> 8) & 0xff, ipa & 0xff, ipp); + if (sim_log) + fprintf (sim_log, + "Connecting to IP address %d.%d.%d.%d, port %d\n", + (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, + (ipa >> 8) & 0xff, ipa & 0xff, ipp); uptr->flags = uptr->flags | UNIT_ACTV; uptr->LSOCKET = 0; uptr->DSOCKET = newsock; } else { - if (ipa != 0) return SCPE_ARG; + if (ipa != 0) + return SCPE_ARG; newsock = sim_master_sock (ipp); - if (newsock == INVALID_SOCKET) return SCPE_IOERR; + if (newsock == INVALID_SOCKET) + return SCPE_IOERR; printf ("Listening on port %d\n", ipp); - if (sim_log) fprintf (sim_log, "Listening on port %d\n", ipp); + if (sim_log) + fprintf (sim_log, "Listening on port %d\n", ipp); uptr->flags = uptr->flags & ~UNIT_ACTV; uptr->LSOCKET = newsock; uptr->DSOCKET = 0; @@ -570,12 +619,14 @@ uptr->filename = tptr; /* save */ sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ if (sim_switches & SWMASK ('W')) { /* wait? */ for (i = 0; i < 30; i++) { /* check for 30 sec */ - if (t = ipl_check_conn (uptr)) break; /* established? */ + if (t = ipl_check_conn (uptr)) /* established? */ + break; if ((i % 10) == 0) /* status every 10 sec */ printf ("Waiting for connnection\n"); sim_os_sleep (1); /* sleep 1 sec */ } - if (t) printf ("Connection established\n"); + if (t) + printf ("Connection established\n"); } return SCPE_OK; } @@ -584,13 +635,18 @@ return SCPE_OK; t_stat ipl_detach (UNIT *uptr) { -if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */ -if (uptr->flags & UNIT_ACTV) sim_close_sock (uptr->DSOCKET, 1); +if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return SCPE_OK; + +if (uptr->flags & UNIT_ACTV) + sim_close_sock (uptr->DSOCKET, 1); + else { if (uptr->flags & UNIT_ESTB) /* if established, */ sim_close_sock (uptr->DSOCKET, 0); /* close data socket */ sim_close_sock (uptr->LSOCKET, 1); /* closen listen socket */ } + free (uptr->filename); /* free string */ uptr->filename = NULL; uptr->LSOCKET = 0; @@ -604,9 +660,12 @@ return SCPE_OK; t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (cptr) return SCPE_ARG; -if (((uptr->flags & UNIT_ATT) == 0) || (uptr->flags & UNIT_ACTV) || - ((uptr->flags & UNIT_ESTB) == 0)) return SCPE_NOFNC; +if (cptr) + return SCPE_ARG; +if (((uptr->flags & UNIT_ATT) == 0) || + (uptr->flags & UNIT_ACTV) || + ((uptr->flags & UNIT_ESTB) == 0)) + return SCPE_NOFNC; sim_close_sock (uptr->DSOCKET, 0); uptr->DSOCKET = 0; uptr->flags = uptr->flags & ~UNIT_ESTB; @@ -705,14 +764,14 @@ static const BOOT_ROM ipl_rom = { t_stat ipl_boot (int32 unitno, DEVICE *dptr) { -const int32 devi = ipli_dib.devno; -const int32 devp = ptr_dib.devno; +const int32 devi = ipli_dib.select_code; +const int32 devp = ptr_dib.select_code; ibl_copy (ipl_rom, devi); /* copy bootstrap to memory */ SR = (devi << IBL_V_DEV) | devp; /* set SR */ WritePW (PC + MAX_BASE, (~PC + 1) & DMASK); /* fix ups */ -WritePW (PC + IPL_PNTR, ipl_rom[IPL_PNTR] | PC); -WritePW (PC + PTR_PNTR, ipl_rom[PTR_PNTR] | PC); +WritePW (PC + IPL_PNTR, ipl_rom [IPL_PNTR] | PC); +WritePW (PC + PTR_PNTR, ipl_rom [PTR_PNTR] | PC); WritePW (PC + IPL_DEVA, devi); WritePW (PC + PTR_DEVA, devp); return SCPE_OK; diff --git a/HP2100/hp2100_lps.c b/HP2100/hp2100_lps.c index 5d165358..165c2190 100644 --- a/HP2100/hp2100_lps.c +++ b/HP2100/hp2100_lps.c @@ -1,6 +1,6 @@ /* hp2100_lps.c: HP 2100 12653A/2767 line printer simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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 @@ LPS 12653A 2767 line printer 12566B microcircuit interface with loopback diagnostic connector + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + Revised detection of CLC at last DMA cycle + 19-Oct-10 JDB Corrected 12566B (DIAG mode) jumper settings 26-Jun-08 JDB Rewrote device I/O to model backplane signals 10-May-07 RMS Added UNIT_TEXT flag 11-Jan-07 JDB CLC cancels I/O event if DIAG (jumper W9 in "A" pos) @@ -58,16 +62,24 @@ This module simulates two different devices. In "diagnostic mode," it - simulates a 12566B microcircuit interface card with a loopback connector and - the jumpers set as required for execution of the General Purpose Register - diagnostic. In non-diagnostic mode, it simulates a 12653A line printer - interface card and a 2767 line printer. + simulates a 12566B microcircuit interface card with a loopback connector. In + non-diagnostic mode, it simulates a 12653A line printer interface card and a + 2767 line printer. + + In diagnostic mode, the 12566B interface has a loopback connector that ties + the output data lines to the input data lines and the device command output + to the device flag input. In addition, card configuration jumpers are set as + needed for the diagnostic programs. + + Jumper settings depend on the CPU model. For the 2114/15/16 CPUs, jumper W1 + is installed in position B and jumper W2 in position C. In these positions, + the card flag sets two instructions after the STC, allowing DMA to steal + every third cycle. For the 2100 and 1000 CPUs, jumper W1 is installed in + position C and jumper W2 in position B. In these positions, the card flag + sets one instruction after the STC, allowing DMA to steal every other cycle. + For all CPUs, jumpers W3 and W4 are installed in position B, W5-W8 are + installed, and W9 is installed in position A. - The 12566B interface with the loopback connector ties the device command - output to the device flag input. Setting control therefore causes device - flag to set almost immediately. Device command is active only during that - interim. Under simulation, the loopback occurs within the STC handler, and - CMD is never set. The 2767 impact printer has a rotating drum with 80 columns of 64 raised characters. ASCII codes 32 through 95 (SPACE through "_") form the print @@ -144,9 +156,11 @@ #define UNIT_POWEROFF (1 << UNIT_V_POWEROFF) #define UNIT_OFFLINE (1 << UNIT_V_OFFLINE) -FLIP_FLOP lps_control = CLEAR; -FLIP_FLOP lps_flag = CLEAR; -FLIP_FLOP lps_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } lps = { CLEAR, CLEAR, CLEAR }; int32 lps_ccnt = 0; /* character count */ int32 lps_lcnt = 0; /* line count */ @@ -190,7 +204,9 @@ const TIMESET lps_times[2] = { }; DEVICE lps_dev; -uint32 lpsio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER lpsio; + t_stat lps_svc (UNIT *uptr); t_stat lps_reset (DEVICE *dptr); t_stat lps_restart (UNIT *uptr, int32 value, char *cptr, void *desc); @@ -207,7 +223,7 @@ t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); lps_reg LPS register list */ -DIB lps_dib = { LPS, &lpsio }; +DIB lps_dib = { &lpsio, LPS }; UNIT lps_unit = { UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0) @@ -217,9 +233,9 @@ REG lps_reg[] = { { ORDATA (BUF, lps_unit.buf, 16) }, { ORDATA (STA, lps_sta, 16) }, { ORDATA (POWER, lps_power, 2), REG_RO }, - { FLDATA (CTL, lps_control, 0) }, - { FLDATA (FLG, lps_flag, 0) }, - { FLDATA (FBF, lps_flagbuf, 0) }, + { FLDATA (CTL, lps.control, 0) }, + { FLDATA (FLG, lps.flag, 0) }, + { FLDATA (FBF, lps.flagbuf, 0) }, { DRDATA (CCNT, lps_ccnt, 7), PV_LEFT }, { DRDATA (LCNT, lps_lcnt, 7), PV_LEFT }, { DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT }, @@ -229,7 +245,7 @@ REG lps_reg[] = { { DRDATA (RTIME, lps_rtime, 24), PV_LEFT }, { FLDATA (TIMING, lps_timing, 0), REG_HRO }, { FLDATA (STOP_IOE, lps_stopioe, 0) }, - { ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, lps_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -260,164 +276,174 @@ DEVICE lps_dev = { }; -/* I/O signal handler */ +/* I/O signal handler. -uint32 lpsio (uint32 select_code, IOSIG signal, uint32 data) + Implementation note: + + 1. The 211x DMA diagnostic expects that a programmed STC and CLC sequence + will set the card flag in two instructions, whereas a last-DMA-cycle + assertion of STC and CLC simultaneously will not. +*/ + +uint32 lpsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const t_bool clf = (signal > ioCLF); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ int32 sched; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - lps_flag = lps_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + lps.flag = lps.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - lps_flag = lps_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + lps.flag = lps.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (lps); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (lps); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (lps); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (lps); + break; - case ioIOI: /* I/O data input */ - if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */ - if (lps_power == LPS_ON) { /* power on? */ - if (((lps_unit.flags & UNIT_ATT) == 0) || /* paper out? */ - (lps_unit.flags & UNIT_OFFLINE) || /* offline? */ - sim_is_active (&lps_unit)) lps_sta = LPS_BUSY; + case ioIOI: /* I/O data input */ + if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */ + if (lps_power == LPS_ON) { /* power on? */ + if (((lps_unit.flags & UNIT_ATT) == 0) || /* paper out? */ + (lps_unit.flags & UNIT_OFFLINE) || /* offline? */ + sim_is_active (&lps_unit)) lps_sta = LPS_BUSY; - else - lps_sta = 0; - } - - else - lps_sta = LPS_PWROFF; - } - - data = lps_sta; /* diag, rtn status */ - - if (DEBUG_PRS (lps_dev)) - fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", data); - break; - - - case ioIOO: /* I/O data output */ - if (DEBUG_PRS (lps_dev)) - fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", data); - - lps_unit.buf = data; - break; - - - case ioPOPIO: /* power-on preset to I/O */ - lps_flag = lps_flagbuf = SET; /* set flag and flag buffer */ - lps_unit.buf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - lps_control = CLEAR; /* clear control */ - sim_cancel (&lps_unit); /* deactivate unit */ - break; - - - case ioCLC: /* clear control flip-flop */ - lps_control = CLEAR; - - if ((lps_unit.flags & UNIT_DIAG) && clf) /* diagnostic mode and clearing flag? */ - sim_cancel (&lps_unit); /* prevent FLG/SRQ */ - break; - - - case ioSTC: /* set control flip-flop */ - lps_control = SET; /* set control */ - - if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */ - lps_sta = lps_unit.buf; /* loop back data */ - sim_activate (&lps_unit, 2); /* schedule flag */ - } - - else { /* real lpt, sched */ - if (DEBUG_PRS (lps_dev)) fprintf (sim_deb, - ">>LPS STC: Character %06o scheduled for line %d, column %d, ", - lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1); - - if ((lps_unit.buf != '\f') && - (lps_unit.buf != '\n') && - (lps_unit.buf != '\r')) { /* normal char */ - lps_ccnt = lps_ccnt + 1; /* incr char counter */ - if (lps_ccnt % LPS_ZONECNT == 0) /* end of zone? */ - sched = lps_ptime; /* print zone */ - else - sched = lps_ctime; /* xfer char */ - } - - else { /* print cmd */ - if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */ - sched = lps_ctime; /* yes, so just char time */ - else - sched = lps_ptime; /* no, so print needed */ - - lps_ccnt = 0; /* reset char counter */ - - if (lps_unit.buf == '\n') { /* line advance */ - lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT; - - if (lps_lcnt > 0) - sched = sched + lps_stime; else - sched = sched + /* allow for perf skip */ - lps_stime * (LPS_FORMLNT - LPS_PAGELNT); + lps_sta = 0; } - else if (lps_unit.buf == '\f') { /* form advance */ - sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt); - lps_lcnt = 0; - } + else + lps_sta = LPS_PWROFF; } - sim_activate (&lps_unit, sched); + stat_data = IORETURN (SCPE_OK, lps_sta); /* diag, rtn status */ if (DEBUG_PRS (lps_dev)) - fprintf (sim_deb, "time = %d\n", sched); - } - break; + fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", lps_sta); + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, lps); /* set standard PRL signal */ - setstdIRQ (select_code, lps); /* set standard IRQ signal */ - setstdSRQ (select_code, lps); /* set standard SRQ signal */ - break; + case ioIOO: /* I/O data output */ + lps_unit.buf = IODATA (stat_data); + + if (DEBUG_PRS (lps_dev)) + fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", lps_unit.buf); + break; - case ioIAK: /* interrupt acknowledge */ - lps_flagbuf = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + lps.flag = lps.flagbuf = SET; /* set flag and flag buffer */ + lps_unit.buf = 0; /* clear output buffer */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioCRS: /* control reset */ + lps.control = CLEAR; /* clear control */ + sim_cancel (&lps_unit); /* deactivate unit */ + break; + + + case ioCLC: /* clear control flip-flop */ + lps.control = CLEAR; + break; + + + case ioSTC: /* set control flip-flop */ + lps.control = SET; /* set control */ + + if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */ + lps_sta = lps_unit.buf; /* loop back data */ + + if (!(signal_set & ioCLC)) /* CLC not asserted simultaneously? */ + if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2114/15/16 CPU? */ + sim_activate (&lps_unit, 3); /* schedule flag after two instructions */ + else /* 2100 or 1000 */ + sim_activate (&lps_unit, 2); /* schedule flag after next instruction */ + } + + else { /* real lpt, sched */ + if (DEBUG_PRS (lps_dev)) fprintf (sim_deb, + ">>LPS STC: Character %06o scheduled for line %d, column %d, ", + lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1); + + if ((lps_unit.buf != '\f') && + (lps_unit.buf != '\n') && + (lps_unit.buf != '\r')) { /* normal char */ + lps_ccnt = lps_ccnt + 1; /* incr char counter */ + if (lps_ccnt % LPS_ZONECNT == 0) /* end of zone? */ + sched = lps_ptime; /* print zone */ + else + sched = lps_ctime; /* xfer char */ + } + + else { /* print cmd */ + if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */ + sched = lps_ctime; /* yes, so just char time */ + else + sched = lps_ptime; /* no, so print needed */ + + lps_ccnt = 0; /* reset char counter */ + + if (lps_unit.buf == '\n') { /* line advance */ + lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT; + + if (lps_lcnt > 0) + sched = sched + lps_stime; + else + sched = sched + /* allow for perf skip */ + lps_stime * (LPS_FORMLNT - LPS_PAGELNT); + } + + else if (lps_unit.buf == '\f') { /* form advance */ + sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt); + lps_lcnt = 0; + } + } + + sim_activate (&lps_unit, sched); + + if (DEBUG_PRS (lps_dev)) + fprintf (sim_deb, "time = %d\n", sched); + } + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (lps); /* set standard PRL signal */ + setstdIRQ (lps); /* set standard IRQ signal */ + setstdSRQ (lps); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + lps.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - lpsio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - lpsio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -435,17 +461,17 @@ if (lps_power == LPS_TURNING_ON) { /* printer warmed up? */ return SCPE_OK; /* done */ } if (uptr->flags & UNIT_DIAG) { /* diagnostic? */ - lpsio (lps_dib.devno, ioENF, 0); /* set flag */ + lpsio (&lps_dib, ioENF, 0); /* set flag */ return SCPE_OK; /* done */ } if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lps_stopioe, SCPE_UNATT); + return IOERROR (lps_stopioe, SCPE_UNATT); else if (uptr->flags & UNIT_OFFLINE) /* offline? */ - return IORETURN (lps_stopioe, STOP_OFFLINE); + return IOERROR (lps_stopioe, STOP_OFFLINE); else if (uptr->flags & UNIT_POWEROFF) /* powered off? */ - return IORETURN (lps_stopioe, STOP_PWROFF); + return IOERROR (lps_stopioe, STOP_PWROFF); -lpsio (lps_dib.devno, ioENF, 0); /* set flag */ +lpsio (&lps_dib, ioENF, 0); /* set flag */ if (((c < ' ') || (c > '_')) && /* non-printing char? */ (c != '\f') && (c != '\n') && (c != '\r')) { @@ -482,12 +508,12 @@ return SCPE_OK; t_stat lps_reset (DEVICE *dptr) { -if (sim_switches & SWMASK ('P')) { /* PON reset? */ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ lps_power = LPS_ON; /* power is on */ lps_set_timing (NULL, lps_timing, NULL, NULL); /* init timing set */ } -lpsio (lps_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&lps_dib); /* PRESET device (does not use PON) */ lps_sta = 0; /* clear status */ sim_cancel (&lps_unit); /* deactivate unit */ @@ -511,7 +537,7 @@ return SCPE_OK; t_stat lps_restart (UNIT *uptr, int32 value, char *cptr, void *desc) { -if (lps_control && !sim_is_active (uptr)) +if (lps.control && !sim_is_active (uptr)) sim_activate (uptr, 0); /* reschedule I/O */ return SCPE_OK; } diff --git a/HP2100/hp2100_lpt.c b/HP2100/hp2100_lpt.c index b2f67439..6122841d 100644 --- a/HP2100/hp2100_lpt.c +++ b/HP2100/hp2100_lpt.c @@ -1,6 +1,6 @@ /* hp2100_lpt.c: HP 2100 12845B line printer simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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 @@ LPT 12845B 2607 line printer + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals Changed CTIME register width to match documentation 22-Jan-07 RMS Added UNIT_TEXT flag @@ -89,9 +91,11 @@ #define UNIT_POWEROFF (1 << UNIT_V_POWEROFF) #define UNIT_OFFLINE (1 << UNIT_V_OFFLINE) -FLIP_FLOP lpt_control = CLEAR; -FLIP_FLOP lpt_flag = CLEAR; -FLIP_FLOP lpt_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } lpt = { CLEAR, CLEAR, CLEAR }; int32 lpt_ctime = 4; /* char time */ int32 lpt_ptime = 10000; /* print time */ @@ -102,7 +106,9 @@ static int32 lpt_cct[8] = { }; DEVICE lpt_dev; -uint32 lptio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER lptio; + t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); t_stat lpt_restart (UNIT *uptr, int32 value, char *cptr, void *desc); @@ -115,7 +121,7 @@ t_stat lpt_attach (UNIT *uptr, char *cptr); lpt_reg LPT register list */ -DIB lpt_dib = { LPT, &lptio }; +DIB lpt_dib = { &lptio, LPT }; UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0) @@ -123,15 +129,15 @@ UNIT lpt_unit = { REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 7) }, - { FLDATA (CTL, lpt_control, 0) }, - { FLDATA (FLG, lpt_flag, 0) }, - { FLDATA (FBF, lpt_flagbuf, 0) }, + { FLDATA (CTL, lpt.control, 0) }, + { FLDATA (FLG, lpt.flag, 0) }, + { FLDATA (FBF, lpt.flagbuf, 0) }, { DRDATA (LCNT, lpt_lcnt, 7) }, { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (CTIME, lpt_ctime, 24), PV_LEFT }, { DRDATA (PTIME, lpt_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, - { ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, lpt_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -156,101 +162,102 @@ DEVICE lpt_dev = { /* I/O signal handler */ -uint32 lptio (uint32 select_code, IOSIG signal, uint32 data) +uint32 lptio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - lpt_flag = lpt_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + lpt.flag = lpt.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - lpt_flag = lpt_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + lpt.flag = lpt.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (lpt); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (lpt); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (lpt); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (lpt); + break; - case ioIOI: /* I/O data input */ - if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */ - data = LPT_PWROFF; + case ioIOI: /* I/O data input */ + data = 0; - else if (!(lpt_unit.flags & UNIT_OFFLINE)) { /* online? */ - if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */ - data = LPT_RDY; - if (!sim_is_active (&lpt_unit)) /* printer busy? */ - data = data | LPT_NBSY; + if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */ + data = LPT_PWROFF; + + else if (!(lpt_unit.flags & UNIT_OFFLINE)) { /* online? */ + if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */ + data = LPT_RDY; + if (!sim_is_active (&lpt_unit)) /* printer busy? */ + data = data | LPT_NBSY; + } + + else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */ + data = LPT_PAPO; } - else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */ - data = LPT_PAPO; - } - - else - data = 0; - break; + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - lpt_unit.buf = data & (LPT_CTL | 0177); - break; + case ioIOO: /* I/O data output */ + lpt_unit.buf = IODATA (stat_data) & (LPT_CTL | 0177); + break; - case ioPOPIO: /* power-on preset to I/O */ - lpt_flag = lpt_flagbuf = SET; /* set flag and flag buffer */ - lpt_unit.buf = 0; /* clear output buffer */ - /* fall into CRS handler */ + case ioPOPIO: /* power-on preset to I/O */ + lpt.flag = lpt.flagbuf = SET; /* set flag and flag buffer */ + lpt_unit.buf = 0; /* clear output buffer */ + break; - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - lpt_control = CLEAR; - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + lpt.control = CLEAR; + break; - case ioSTC: /* set control flip-flop */ - lpt_control = SET; - sim_activate (&lpt_unit, /* schedule op */ - (lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime); - break; + case ioSTC: /* set control flip-flop */ + lpt.control = SET; + sim_activate (&lpt_unit, /* schedule op */ + (lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime); + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, lpt); /* set standard PRL signal */ - setstdIRQ (select_code, lpt); /* set standard IRQ signal */ - setstdSRQ (select_code, lpt); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (lpt); /* set standard PRL signal */ + setstdIRQ (lpt); /* set standard IRQ signal */ + setstdSRQ (lpt); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - lpt_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + lpt.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - lptio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - lptio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -261,13 +268,13 @@ t_stat lpt_svc (UNIT *uptr) int32 i, skip, chan; if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lpt_stopioe, SCPE_UNATT); + return IOERROR (lpt_stopioe, SCPE_UNATT); else if (uptr->flags & UNIT_OFFLINE) /* offline? */ - return IORETURN (lpt_stopioe, STOP_OFFLINE); + return IOERROR (lpt_stopioe, STOP_OFFLINE); else if (uptr->flags & UNIT_POWEROFF) /* powered off? */ - return IORETURN (lpt_stopioe, STOP_PWROFF); + return IOERROR (lpt_stopioe, STOP_PWROFF); -lptio (lpt_dib.devno, ioENF, 0); /* set flag */ +lptio (&lpt_dib, ioENF, 0); /* set flag */ if (uptr->buf & LPT_CTL) { /* control word? */ if (uptr->buf & LPT_CHAN) { @@ -302,7 +309,7 @@ return SCPE_OK; t_stat lpt_reset (DEVICE *dptr) { -lptio (lpt_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&lpt_dib); /* PRESET device (does not use PON) */ sim_cancel (&lpt_unit); /* deactivate unit */ return SCPE_OK; @@ -325,7 +332,7 @@ return SCPE_OK; t_stat lpt_restart (UNIT *uptr, int32 value, char *cptr, void *desc) { -if (lpt_control && !sim_is_active (uptr)) +if (lpt.control && !sim_is_active (uptr)) sim_activate (uptr, 0); /* reschedule I/O */ return SCPE_OK; } diff --git a/HP2100/hp2100_mpx.c b/HP2100/hp2100_mpx.c index 46ecf043..ab51adf0 100644 --- a/HP2100/hp2100_mpx.c +++ b/HP2100/hp2100_mpx.c @@ -1,6 +1,6 @@ /* hp2100_mpx.c: HP 12792C eight-channel asynchronous multiplexer simulator - Copyright (c) 2008, J. David Bryan + Copyright (c) 2008-2011, J. David Bryan 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 @@ MPX 12792C 8-channel multiplexer card + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines 14-Nov-08 JDB Cleaned up VC++ size mismatch warnings for zero assignments 03-Oct-08 JDB Fixed logic for ENQ/XOFF transmit wait @@ -517,10 +519,11 @@ uint32 mpx_portkey = 0; /* current port's key */ t_bool mpx_uien = FALSE; /* unsolicited interrupts enabled */ uint32 mpx_uicode = 0; /* unsolicited interrupt reason and port */ -FLIP_FLOP mpx_control = CLEAR; /* control flip-flop */ -FLIP_FLOP mpx_flag = CLEAR; /* flag flip-flop */ -FLIP_FLOP mpx_flagbuf = CLEAR; /* flag buffer flip-flop */ - +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mpx = { CLEAR, CLEAR, CLEAR }; /* Multiplexer per-line state variables */ @@ -581,7 +584,7 @@ static uint32 buf_avail (IO_OPER rw, uint32 port); /* Multiplexer global routines */ -uint32 mpx_io (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER mpx_io; t_stat mpx_line_svc (UNIT *uptr); t_stat mpx_cntl_svc (UNIT *uptr); @@ -632,7 +635,7 @@ int32 mpx_order [MPX_PORTS] = { -1 }; /* connection order TMLN mpx_ldsc [MPX_PORTS] = { { 0 } }; /* line descriptors */ TMXR mpx_desc = { MPX_PORTS, 0, 0, mpx_ldsc, mpx_order }; /* device descriptor */ -DIB mpx_dib = { MPX, &mpx_io }; +DIB mpx_dib = { &mpx_io, MPX }; DEVICE mpx_dev; @@ -682,10 +685,10 @@ REG mpx_reg [] = { { BRDATA (SEP, mpx_sep, 10, 10, MPX_PORTS * 2) }, { BRDATA (PUT, mpx_put, 10, 10, MPX_PORTS * 2) }, - { FLDATA (CTL, mpx_control, 0) }, - { FLDATA (FLG, mpx_flag, 0) }, - { FLDATA (FBF, mpx_flagbuf, 0) }, - { ORDATA (DEVNO, mpx_dib.devno, 6), REG_HRO }, + { FLDATA (CTL, mpx.control, 0) }, + { FLDATA (FLG, mpx.flag, 0) }, + { FLDATA (FBF, mpx.flagbuf, 0) }, + { ORDATA (DEVNO, mpx_dib.select_code, 6), REG_HRO }, { BRDATA (CONNORD, mpx_order, 10, 32, MPX_PORTS), REG_HRO }, { NULL } @@ -746,7 +749,6 @@ DEVICE mpx_dev = { NULL }; /* logical device name */ - /* I/O signal handler. Commands are sent to the card via an OTA/B. Issuing an STC SC,C causes the @@ -798,161 +800,156 @@ DEVICE mpx_dev = { 2. The "Fast binary read" command inhibits all other commands until the card is reset. - - 3. The card does not respond to POPIO. However, as PRESET asserts POPIO and - CRS together, we fall into the latter from the former. */ -uint32 mpx_io (uint32 select_code, IOSIG signal, uint32 data) +uint32 mpx_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { static const char *output_state [] = { "Command", "Command override", "Parameter", "Data" }; static const char *input_state [] = { "Status", "Invalid status", "Parameter", "Data" }; -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); int32 delay; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - mpx_flag = mpx_flagbuf = CLEAR; /* clear flag and flag buffer */ + switch (signal) { /* dispatch I/O signal */ - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [CLF] Flag cleared\n", sim_deb); - break; - - - case ioSTF: /* set flag flip-flop */ - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [STF] Flag set\n", sim_deb); - /* fall into ENF */ - - case ioENF: /* enable flag */ - mpx_flag = mpx_flagbuf = SET; /* set flag and flag buffer */ - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (mpx); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (mpx); - break; - - - case ioIOI: /* I/O data input */ - data = mpx_ibuf; /* return info */ - - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fprintf (sim_deb, ">>MPX cpu: [LIx%s] %s = %06o\n", - hold_or_clear, input_state [mpx_state], data); - - if (mpx_state == exec) /* if this is input data word */ - sim_activate (&mpx_cntl, DATA_DELAY); /* continue transmission */ - break; - - - case ioIOO: /* I/O data output */ - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fprintf (sim_deb, ">>MPX cpu: [OTx%s] %s = %06o\n", - hold_or_clear, output_state [mpx_state], data); - - mpx_obuf = data; /* save word */ - - if (mpx_state == param) { /* if this is parameter word */ - sim_activate (&mpx_cntl, CMD_DELAY); /* do command now */ + case ioCLF: /* clear flag flip-flop */ + mpx.flag = mpx.flagbuf = CLEAR; /* clear flag and flag buffer */ if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [OTx%s] Command %03o parameter %06o scheduled, " - "time = %d\n", hold_or_clear, mpx_cmd, mpx_obuf, CMD_DELAY); - } - - else if (mpx_state == exec) /* else if this is output data word */ - sim_activate (&mpx_cntl, DATA_DELAY); /* then do transmission */ - break; + fputs (">>MPX cmds: [CLF] Flag cleared\n", sim_deb); + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ + case ioSTF: /* set flag flip-flop */ + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: [STF] Flag set\n", sim_deb); + /* fall into ENF */ - case ioCRS: /* control reset */ - controller_reset (); /* reset firmware to power-on defaults */ - mpx_obuf = 0; /* clear output buffer */ - - mpx_control = CLEAR; /* clear control */ - mpx_flagbuf = CLEAR; /* clear flag buffer */ - mpx_flag = CLEAR; /* clear flag */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [CRS] Controller reset\n", sim_deb); - break; + case ioENF: /* enable flag */ + mpx.flag = mpx.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioCLC: /* clear control flip-flop */ - mpx_control = CLEAR; /* clear control */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [CLC%s] Control cleared\n", hold_or_clear); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (mpx); + break; - case ioSTC: /* set control flip-flop */ - mpx_control = SET; /* set control */ - - if (mpx_cmd == CMD_BINARY_READ) /* executing fast binary read? */ - break; /* further command execution inhibited */ - - mpx_cmd = GET_OPCODE (mpx_obuf); /* get command opcode */ - mpx_portkey = GET_KEY (mpx_obuf); /* get port key */ - - if (mpx_state == cmd) /* already scheduled? */ - sim_cancel (&mpx_cntl); /* cancel to get full delay */ - - mpx_state = cmd; /* set command state */ - - if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */ - delay = PARAM_DELAY; /* specify parameter wait */ - else /* one-word command */ - delay = CMD_DELAY; /* specify command wait */ - - sim_activate (&mpx_cntl, delay); /* schedule command */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [STC%s] Command %03o key %d scheduled, " - "time = %d\n", hold_or_clear, mpx_cmd, mpx_portkey, delay); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (mpx); + break; - case ioEDT: /* end data transfer */ - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fputs (">>MPX cpu: [EDT] DCPC transfer ended\n", sim_deb); - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, mpx_ibuf); /* return info */ + + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fprintf (sim_deb, ">>MPX cpu: [LIx%s] %s = %06o\n", + hold_or_clear, input_state [mpx_state], mpx_ibuf); + + if (mpx_state == exec) /* if this is input data word */ + sim_activate (&mpx_cntl, DATA_DELAY); /* continue transmission */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, mpx); /* set standard PRL signal */ - setstdIRQ (select_code, mpx); /* set standard IRQ signal */ - setstdSRQ (select_code, mpx); /* set standard SRQ signal */ - break; + case ioIOO: /* I/O data output */ + mpx_obuf = IODATA (stat_data); /* save word */ + + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fprintf (sim_deb, ">>MPX cpu: [OTx%s] %s = %06o\n", + hold_or_clear, output_state [mpx_state], mpx_obuf); + + if (mpx_state == param) { /* if this is parameter word */ + sim_activate (&mpx_cntl, CMD_DELAY); /* do command now */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [OTx%s] Command %03o parameter %06o scheduled, " + "time = %d\n", hold_or_clear, mpx_cmd, mpx_obuf, CMD_DELAY); + } + + else if (mpx_state == exec) /* else if this is output data word */ + sim_activate (&mpx_cntl, DATA_DELAY); /* then do transmission */ + break; - case ioIAK: /* interrupt acknowledge */ - mpx_flagbuf = CLEAR; /* clear flag buffer */ - break; + case ioCRS: /* control reset */ + controller_reset (); /* reset firmware to power-on defaults */ + mpx_obuf = 0; /* clear output buffer */ + + mpx.control = CLEAR; /* clear control */ + mpx.flagbuf = CLEAR; /* clear flag buffer */ + mpx.flag = CLEAR; /* clear flag */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: [CRS] Controller reset\n", sim_deb); + break; - default: /* all other signals */ - break; /* are ignored */ + case ioCLC: /* clear control flip-flop */ + mpx.control = CLEAR; /* clear control */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [CLC%s] Control cleared\n", hold_or_clear); + break; + + + case ioSTC: /* set control flip-flop */ + mpx.control = SET; /* set control */ + + if (mpx_cmd == CMD_BINARY_READ) /* executing fast binary read? */ + break; /* further command execution inhibited */ + + mpx_cmd = GET_OPCODE (mpx_obuf); /* get command opcode */ + mpx_portkey = GET_KEY (mpx_obuf); /* get port key */ + + if (mpx_state == cmd) /* already scheduled? */ + sim_cancel (&mpx_cntl); /* cancel to get full delay */ + + mpx_state = cmd; /* set command state */ + + if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */ + delay = PARAM_DELAY; /* specify parameter wait */ + else /* one-word command */ + delay = CMD_DELAY; /* specify command wait */ + + sim_activate (&mpx_cntl, delay); /* schedule command */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [STC%s] Command %03o key %d scheduled, " + "time = %d\n", hold_or_clear, mpx_cmd, mpx_portkey, delay); + break; + + + case ioEDT: /* end data transfer */ + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fputs (">>MPX cpu: [EDT] DCPC transfer ended\n", sim_deb); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (mpx); /* set standard PRL signal */ + setstdIRQ (mpx); /* set standard IRQ signal */ + setstdSRQ (mpx); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + mpx.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - mpx_io (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - mpx_io (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -1591,7 +1588,7 @@ if (DEBUG_PRI (mpx_dev, DEB_CMDS) && /* debug print? */ } if (set_flag) { - mpx_io (mpx_dib.devno, ioENF, 0); /* set device flag */ + mpx_io (&mpx_dib, ioENF, 0); /* set device flag */ if (DEBUG_PRI (mpx_dev, DEB_CMDS)) fputs (">>MPX cmds: Flag set\n", sim_deb); @@ -1909,7 +1906,7 @@ if (fast_binary_read) { /* fast binary read mpx_ibuf = mpx_ibuf | (chx & DMASK8); /* merge it into word */ mpx_flags [0] |= FL_HAVEBUF; /* mark buffer as ready */ - mpx_io (mpx_dib.devno, ioENF, 0); /* set device flag */ + mpx_io (&mpx_dib, ioENF, 0); /* set device flag */ if (DEBUG_PRI (mpx_dev, DEB_CMDS)) fputs (">>MPX cmds: Flag and SRQ set\n", sim_deb); @@ -2021,14 +2018,14 @@ return SCPE_OK; t_stat mpx_reset (DEVICE *dptr) { -if (sim_switches & SWMASK ('P')) { /* PON reset? */ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ emptying_flags [ioread] = FL_RDEMPT; /* initialize buffer flags constants */ emptying_flags [iowrite] = FL_WREMPT; filling_flags [ioread] = FL_RDFILL; filling_flags [iowrite] = FL_WRFILL; } -mpx_io (mpx_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&mpx_dib); /* PRESET device (does not use PON) */ mpx_ibuf = 0; /* clear input buffer */ diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index fc0490b7..d9f44416 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-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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 @@ MS 13181A 7970B 800bpi nine track magnetic tape 13183A 7970E 1600bpi nine track magnetic tape + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 11-Aug-08 JDB Revised to use AR instead of saved_AR in boot 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -152,9 +154,11 @@ enum { A13181, A13183 } ms_ctype = A13181; /* ctrl type */ int32 ms_timing = 1; /* timing type */ -FLIP_FLOP msc_control = CLEAR; -FLIP_FLOP msc_flag = CLEAR; -FLIP_FLOP msc_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } msc = { CLEAR, CLEAR, CLEAR }; int32 msc_sta = 0; /* status */ int32 msc_buf = 0; /* buffer */ @@ -162,9 +166,11 @@ int32 msc_usl = 0; /* unit select */ int32 msc_1st = 0; /* first service */ int32 msc_stopioe = 1; /* stop on error */ -FLIP_FLOP msd_control = CLEAR; -FLIP_FLOP msd_flag = CLEAR; -FLIP_FLOP msd_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } msd = { CLEAR, CLEAR, CLEAR }; int32 msd_buf = 0; /* data buffer */ uint8 msxb[DBSIZE] = { 0 }; /* data buffer */ @@ -206,8 +212,10 @@ const TIMESET msc_times[3] = { }; DEVICE msd_dev, msc_dev; -uint32 msdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 mscio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER msdio; +IOHANDLER mscio; + t_stat msc_svc (UNIT *uptr); t_stat msc_reset (DEVICE *dptr); t_stat msc_attach (UNIT *uptr, char *cptr); @@ -235,8 +243,8 @@ t_stat ms_clear (void); */ DIB ms_dib[] = { - { MSD, &msdio }, - { MSC, &mscio } + { &msdio, MSD }, + { &mscio, MSC } }; #define msd_dib ms_dib[0] @@ -246,13 +254,13 @@ UNIT msd_unit = { UDATA (NULL, 0, 0) }; REG msd_reg[] = { { ORDATA (BUF, msd_buf, 16) }, - { FLDATA (CTL, msd_control, 0) }, - { FLDATA (FLG, msd_flag, 0) }, - { FLDATA (FBF, msd_flagbuf, 0) }, + { FLDATA (CTL, msd.control, 0) }, + { FLDATA (FLG, msd.flag, 0) }, + { FLDATA (FBF, msd.flagbuf, 0) }, { BRDATA (DBUF, msxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) }, { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) }, - { ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, msd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -295,9 +303,9 @@ REG msc_reg[] = { { ORDATA (BUF, msc_buf, 16) }, { ORDATA (USEL, msc_usl, 2) }, { FLDATA (FSVC, msc_1st, 0) }, - { FLDATA (CTL, msc_control, 0) }, - { FLDATA (FLG, msc_flag, 0) }, - { FLDATA (FBF, msc_flagbuf, 0) }, + { FLDATA (CTL, msc.control, 0) }, + { FLDATA (FLG, msc.flag, 0) }, + { FLDATA (FBF, msc.flagbuf, 0) }, { URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) }, { URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) }, { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) }, @@ -311,7 +319,7 @@ REG msc_reg[] = { { FLDATA (TIMING, ms_timing, 0), REG_HRO }, { FLDATA (STOP_IOE, msc_stopioe, 0) }, { FLDATA (CTYPE, ms_ctype, 0), REG_HRO }, - { ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, msc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -362,75 +370,77 @@ DEVICE msc_dev = { /* Data channel I/O signal handler */ -uint32 msdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 msdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - msd_flag = msd_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + case ioCLF: /* clear flag flip-flop */ + msd.flag = msd.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - msd_flag = msd_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + msd.flag = msd.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (msd); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (msd); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (msd); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (msd); + break; - case ioIOI: /* I/O data input */ - data = msd_buf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, msd_buf); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - msd_buf = data; /* store data */ - break; + case ioIOO: /* I/O data output */ + msd_buf = IODATA (stat_data); /* store data */ + break; - case ioPOPIO: /* power-on preset to I/O */ - ms_clear (); /* issue CLR to controller */ - /* fall into CRS handler */ - case ioCRS: /* control reset */ - msd_flag = msd_flagbuf = SET; /* set flag and flag buffer */ + case ioPOPIO: /* power-on preset to I/O */ + ms_clear (); /* issue CLR to controller */ + break; + + case ioCRS: /* control reset */ + msd.flag = msd.flagbuf = SET; /* set flag and flag buffer */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - msd_control = CLEAR; - break; + case ioCLC: /* clear control flip-flop */ + msd.control = CLEAR; + break; - case ioSTC: /* set control flip-flop */ - msd_control = SET; - break; + case ioSTC: /* set control flip-flop */ + msd.control = SET; + break; - case ioEDT: /* end data transfer */ - msd_flag = msd_flagbuf = CLEAR; /* same as CLF */ - break; + case ioEDT: /* end data transfer */ + msd.flag = msd.flagbuf = CLEAR; /* same as CLF */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, msd); /* set standard PRL signal */ - setstdIRQ (select_code, msd); /* set standard IRQ signal */ - setstdSRQ (select_code, msd); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (msd); /* set standard PRL signal */ + setstdIRQ (msd); /* set standard IRQ signal */ + setstdSRQ (msd); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - msd_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + msd.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - msdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - msdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -453,195 +463,197 @@ return data; the command card under simulation to allow the command card to interrupt. */ -uint32 mscio (uint32 select_code, IOSIG signal, uint32 data) +uint32 mscio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { static const uint8 map_sel[16] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; int32 sched_time; UNIT *uptr = msc_dev.units + msc_usl; -switch (base_signal) { /* dispatch base I/O signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - case ioCLF: /* clear flag flip-flop */ - msc_flag = msc_flagbuf = CLEAR; - break; +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - msc_flag = msc_flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (msc); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (msc); - break; - - - case ioIOI: /* I/O data input */ - data = msc_sta & ~STA_DYN; /* get card status */ - - if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */ - data = data | uptr->UST; /* add unit status */ - - if (sim_tape_bot (uptr)) /* BOT? */ - data = data | STA_BOT; - - if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */ - !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr))) - data = data | STA_TBSY; - - if (sim_tape_wrp (uptr)) /* write prot? */ - data = data | STA_WLK; - - if (sim_tape_eot (uptr)) /* EOT? */ - data = data | STA_EOT; - } - - else - data = data | STA_TBSY | STA_LOCAL; - - if (ms_ctype == A13183) /* 13183A? */ - data = data | STA_PE | (msc_usl << STA_V_SEL); - - if (DEBUG_PRI (msc_dev, DEB_CPU)) - fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data); - - break; - - - case ioIOO: /* I/O data output */ - if (DEBUG_PRI (msc_dev, DEB_CPU)) - fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", data); - - msc_buf = data; - msc_sta = msc_sta & ~STA_REJ; /* clear reject */ - - if ((data & 0377) == FNC_CLR) /* clear always ok */ + case ioCLF: /* clear flag flip-flop */ + msc.flag = msc.flagbuf = CLEAR; break; - if (msc_sta & STA_BUSY) { /* busy? reject */ - msc_sta = msc_sta | STA_REJ; /* dont chg select */ + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + msc.flag = msc.flagbuf = SET; break; - } - - if (data & FNF_CHS) { /* select change */ - msc_usl = map_sel[FNC_GETSEL (data)]; /* is immediate */ - uptr = msc_dev.units + msc_usl; - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl); - } - - if (((data & FNF_MOT) && sim_is_active (uptr)) || - ((data & FNF_REV) && sim_tape_bot (uptr)) || - ((data & FNF_WRT) && sim_tape_wrp (uptr))) - msc_sta = msc_sta | STA_REJ; /* reject? */ - - break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ + case ioSFC: /* skip if flag is clear */ + setstdSKF (msc); + break; - case ioCRS: /* control reset */ - msc_flag = msc_flagbuf = SET; /* set flag and flag buffer */ + + case ioSFS: /* skip if flag is set */ + setstdSKF (msc); + break; + + + case ioIOI: /* I/O data input */ + data = msc_sta & ~STA_DYN; /* get card status */ + + if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */ + data = data | uptr->UST; /* add unit status */ + + if (sim_tape_bot (uptr)) /* BOT? */ + data = data | STA_BOT; + + if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */ + !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr))) + data = data | STA_TBSY; + + if (sim_tape_wrp (uptr)) /* write prot? */ + data = data | STA_WLK; + + if (sim_tape_eot (uptr)) /* EOT? */ + data = data | STA_EOT; + } + + else + data = data | STA_TBSY | STA_LOCAL; + + if (ms_ctype == A13183) /* 13183A? */ + data = data | STA_PE | (msc_usl << STA_V_SEL); + + if (DEBUG_PRI (msc_dev, DEB_CPU)) + fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data); + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + msc_buf = IODATA (stat_data); /* clear supplied status */ + + if (DEBUG_PRI (msc_dev, DEB_CPU)) + fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", msc_buf); + + msc_sta = msc_sta & ~STA_REJ; /* clear reject */ + + if ((msc_buf & 0377) == FNC_CLR) /* clear always ok */ + break; + + if (msc_sta & STA_BUSY) { /* busy? reject */ + msc_sta = msc_sta | STA_REJ; /* dont chg select */ + break; + } + + if (msc_buf & FNF_CHS) { /* select change */ + msc_usl = map_sel[FNC_GETSEL (msc_buf)]; /* is immediate */ + uptr = msc_dev.units + msc_usl; + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl); + } + + if (((msc_buf & FNF_MOT) && sim_is_active (uptr)) || + ((msc_buf & FNF_REV) && sim_tape_bot (uptr)) || + ((msc_buf & FNF_WRT) && sim_tape_wrp (uptr))) + msc_sta = msc_sta | STA_REJ; /* reject? */ + + break; + + + case ioCRS: /* control reset */ + msc.flag = msc.flagbuf = SET; /* set flag and flag buffer */ /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - msc_control = CLEAR; - break; + case ioCLC: /* clear control flip-flop */ + msc.control = CLEAR; + break; - case ioSTC: /* set control flip-flop */ - if (!(msc_sta & STA_REJ)) { /* last cmd rejected? */ - if ((msc_buf & 0377) == FNC_CLR) { /* clear? */ - ms_clear (); /* issue CLR to controller */ + case ioSTC: /* set control flip-flop */ + if (!(msc_sta & STA_REJ)) { /* last cmd rejected? */ + if ((msc_buf & 0377) == FNC_CLR) { /* clear? */ + ms_clear (); /* issue CLR to controller */ - msc_control = SET; /* set CTL for STC */ - msc_flag = msc_flagbuf = SET; /* set FLG for completion */ + msc.control = SET; /* set CTL for STC */ + msc.flag = msc.flagbuf = SET; /* set FLG for completion */ - signal = ioSTC; /* eliminate possible CLF */ + working_set = working_set & ~ioCLF; /* eliminate possible CLF */ - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fputs (">>MSC STC: Controller cleared\n", sim_deb); + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fputs (">>MSC STC: Controller cleared\n", sim_deb); - break; /* command completes immediately */ + break; /* command completes immediately */ + } + + uptr->FNC = msc_buf & 0377; /* save function */ + + if (uptr->FNC & FNF_RWD) { /* rewind? */ + if (!sim_tape_bot (uptr)) /* not at BOT? */ + uptr->UST = STA_REW; /* set rewinding */ + + sched_time = msc_rtime; /* set response time */ + } + + else { + if (sim_tape_bot (uptr)) /* at BOT? */ + sched_time = msc_btime; /* use BOT start time */ + + else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM)) + sched_time = msc_gtime; /* use gap traversal time */ + + else sched_time = 0; + + if (uptr->FNC != FNC_GAP) + sched_time += msc_ctime; /* add base command time */ + } + + if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */ + sim_activate (uptr, sched_time); /* else schedule op */ + + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MSC STC: Unit %d command %03o (%s) scheduled, " + "pos = %d, time = %d\n", + msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC), + uptr->pos, sched_time); + } + + else if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fputs (">>MSC STC: Unit select (NOP)\n", sim_deb); + + msc_sta = STA_BUSY; /* ctrl is busy */ + msc_1st = 1; + msc.control = SET; /* go */ } - - uptr->FNC = msc_buf & 0377; /* save function */ - - if (uptr->FNC & FNF_RWD) { /* rewind? */ - if (!sim_tape_bot (uptr)) /* not at BOT? */ - uptr->UST = STA_REW; /* set rewinding */ - - sched_time = msc_rtime; /* set response time */ - } - - else { - if (sim_tape_bot (uptr)) /* at BOT? */ - sched_time = msc_btime; /* use BOT start time */ - - else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM)) - sched_time = msc_gtime; /* use gap traversal time */ - - else sched_time = 0; - - if (uptr->FNC != FNC_GAP) - sched_time += msc_ctime; /* add base command time */ - } - - if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */ - sim_activate (uptr, sched_time); /* else schedule op */ - - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MSC STC: Unit %d command %03o (%s) scheduled, " - "pos = %d, time = %d\n", - msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC), - uptr->pos, sched_time); - } - - else if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fputs (">>MSC STC: Unit select (NOP)\n", sim_deb); - - msc_sta = STA_BUSY; /* ctrl is busy */ - msc_1st = 1; - msc_control = SET; /* go */ - } - break; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, msc); /* set standard PRL signal */ - setstdIRQ (select_code, msc); /* set standard IRQ signal */ - setstdSRQ (select_code, msc); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (msc); /* set standard PRL signal */ + setstdIRQ (msc); /* set standard IRQ signal */ + setstdSRQ (msc); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - msc_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + msc.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - mscio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - mscio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -671,8 +683,8 @@ unum = uptr - msc_dev.units; /* get unit number */ if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) { /* offline? */ msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */ - mscio (msc_dib.devno, ioENF, 0); /* set flag */ - return IORETURN (msc_stopioe, SCPE_UNATT); + mscio (&msc_dib, ioENF, 0); /* set flag */ + return IOERROR (msc_stopioe, SCPE_UNATT); } switch (uptr->FNC) { /* case on function */ @@ -779,12 +791,12 @@ switch (uptr->FNC) { /* case on function */ if (ms_ctype == A13183) msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */ } - if (msd_control && (ms_ptr < ms_max)) { /* DCH on, more data? */ - if (msd_flag) msc_sta = msc_sta | STA_TIM | STA_PAR; + if (msd.control && (ms_ptr < ms_max)) { /* DCH on, more data? */ + if (msd.flag) msc_sta = msc_sta | STA_TIM | STA_PAR; msd_buf = ((uint16) msxb[ms_ptr] << 8) | ((ms_ptr + 1 == ms_max) ? 0 : msxb[ms_ptr + 1]); ms_ptr = ms_ptr + 2; - msdio (msd_dib.devno, ioENF, 0); /* set flag */ + msdio (&msd_dib, ioENF, 0); /* set flag */ sim_activate (uptr, msc_xtime); /* re-activate */ return SCPE_OK; } @@ -822,8 +834,8 @@ switch (uptr->FNC) { /* case on function */ } else msc_sta = msc_sta | STA_PAR; } - if (msd_control) { /* xfer flop set? */ - msdio (msd_dib.devno, ioENF, 0); /* set flag */ + if (msd.control) { /* xfer flop set? */ + msdio (&msd_dib, ioENF, 0); /* set flag */ sim_activate (uptr, msc_xtime); /* re-activate */ return SCPE_OK; } @@ -853,7 +865,7 @@ switch (uptr->FNC) { /* case on function */ break; } -mscio (msc_dib.devno, ioENF, 0); /* set flag */ +mscio (&msc_dib, ioENF, 0); /* set flag */ msc_sta = msc_sta & ~STA_BUSY; /* update status */ if (DEBUG_PRI (msc_dev, DEB_CMDS)) fprintf (sim_deb, @@ -973,17 +985,15 @@ t_stat msc_reset (DEVICE *dptr) { int32 i; UNIT *uptr; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &msd_dev) ? &msc_dev : &msd_dev); -if (sim_switches & SWMASK ('P')) /* PON reset? */ +if (sim_switches & SWMASK ('P')) /* initialization reset? */ ms_config_timing (); -if (dptr == &msc_dev) /* command channel reset? */ - mscio (msc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - msdio (msd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ msc_buf = msd_buf = 0; msc_sta = msc_usl = 0; @@ -1247,7 +1257,7 @@ t_stat msc_boot (int32 unitno, DEVICE *dptr) int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = msd_dib.devno; /* get data chan dev */ +dev = msd_dib.select_code; /* get data chan dev */ if (ibl_copy (ms_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & IBL_OPT) | IBL_MS | (dev << IBL_V_DEV); /* set SR */ if ((sim_switches & SWMASK ('S')) && AR) SR = SR | 1; /* skip? */ diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index d0360aa7..32c0f072 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-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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 @@ MT 12559A 3030 nine track magnetic tape + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB Fixed error in command scan in mtcio ioIOO handler + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 04-Sep-08 JDB Fixed missing flag after CLR command 02-Sep-08 JDB Moved write enable and format commands from MTD to MTC 26-Jun-08 JDB Rewrote device I/O to model backplane signals @@ -105,12 +108,16 @@ #define STA_PAR 0002 /* parity error */ #define STA_BUSY 0001 /* busy (d) */ -FLIP_FLOP mtd_flag = CLEAR; -FLIP_FLOP mtd_flagbuf = CLEAR; +struct { + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mtd = { CLEAR, CLEAR }; -FLIP_FLOP mtc_control = CLEAR; -FLIP_FLOP mtc_flag = CLEAR; -FLIP_FLOP mtc_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mtc = { CLEAR, CLEAR, CLEAR }; int32 mtc_fnc = 0; /* function */ int32 mtc_sta = 0; /* status register */ @@ -124,10 +131,13 @@ uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */ t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */ static const uint32 mtc_cmd[] = { FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM }; +static const uint32 mtc_cmd_count = sizeof (mtc_cmd) / sizeof (mtc_cmd[0]); DEVICE mtd_dev, mtc_dev; -uint32 mtdio (uint32 select_code, IOSIG signal, uint32 data); -uint32 mtcio (uint32 select_code, IOSIG signal, uint32 data); + +IOHANDLER mtdio; +IOHANDLER mtcio; + t_stat mtc_svc (UNIT *uptr); t_stat mt_reset (DEVICE *dptr); t_stat mtc_attach (UNIT *uptr, char *cptr); @@ -143,8 +153,8 @@ t_stat mt_clear (void); */ DIB mt_dib[] = { - { MTD, &mtdio }, - { MTC, &mtcio } + { &mtdio, MTD }, + { &mtcio, MTC } }; #define mtd_dib mt_dib[0] @@ -153,12 +163,12 @@ DIB mt_dib[] = { UNIT mtd_unit = { UDATA (NULL, 0, 0) }; REG mtd_reg[] = { - { FLDATA (FLG, mtd_flag, 0) }, - { FLDATA (FBF, mtd_flagbuf, 0) }, + { FLDATA (FLG, mtd.flag, 0) }, + { FLDATA (FBF, mtd.flagbuf, 0) }, { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) }, { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) }, - { ORDATA (DEVNO, mtd_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, mtd_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -190,9 +200,9 @@ REG mtc_reg[] = { { ORDATA (FNC, mtc_fnc, 8) }, { ORDATA (STA, mtc_sta, 9) }, { ORDATA (BUF, mtc_unit.buf, 8) }, - { FLDATA (CTL, mtc_control, 0) }, - { FLDATA (FLG, mtc_flag, 0) }, - { FLDATA (FBF, mtc_flagbuf, 0) }, + { FLDATA (CTL, mtc.control, 0) }, + { FLDATA (FLG, mtc.flag, 0) }, + { FLDATA (FBF, mtc.flagbuf, 0) }, { FLDATA (DTF, mtc_dtf, 0) }, { FLDATA (FSVC, mtc_1st, 0) }, { DRDATA (POS, mtc_unit.pos, T_ADDR_W), PV_LEFT }, @@ -200,7 +210,7 @@ REG mtc_reg[] = { { DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT }, { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, mtc_stopioe, 0) }, - { ORDATA (DEVNO, mtc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, mtc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -240,63 +250,63 @@ DEVICE mtc_dev = { so the flag buffer serves no other purpose. */ -uint32 mtdio (uint32 select_code, IOSIG signal, uint32 data) +uint32 mtdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - mtd_flag = mtd_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - mtd_flag = mtd_flagbuf = SET; - break; + case ioCLF: /* clear flag flip-flop */ + mtd.flag = mtd.flagbuf = CLEAR; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (mtd); - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + mtd.flag = mtd.flagbuf = SET; + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (mtd); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (mtd); + break; - case ioIOI: /* I/O data input */ - data = mtc_unit.buf; - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (mtd); + break; - case ioIOO: /* I/O data output */ - mtc_unit.buf = data & 0377; /* store data */ - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, mtc_unit.buf); /* merge in return status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - mt_clear (); /* issue CLR to controller */ - mtd_flag = mtd_flagbuf = CLEAR; /* clear flag and flag buffer */ - /* fall into CRS handler */ - case ioCRS: /* control reset */ - break; + case ioIOO: /* I/O data output */ + mtc_unit.buf = IODATA (stat_data) & DMASK8; /* store data */ + break; - case ioCLC: /* clear control flip-flop */ - mtc_dtf = 0; /* clr xfer flop */ - mtd_flag = mtd_flagbuf = CLEAR; /* clear flag and flag buffer */ - break; + case ioPOPIO: /* power-on preset to I/O */ + mt_clear (); /* issue CLR to controller */ + mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; - case ioSIR: /* set interrupt request */ - setstdSRQ (select_code, mtd); /* set standard SRQ signal */ - break; + case ioCLC: /* clear control flip-flop */ + mtc_dtf = 0; /* clr xfer flop */ + mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioSIR: /* set interrupt request */ + setstdSRQ (mtd); /* set standard SRQ signal */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - mtdio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - mtdio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -322,126 +332,131 @@ return data; complete immediately, and the BUSY bit never sets.. */ -uint32 mtcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 mtcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; uint32 i; int32 valid; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - mtc_flag = mtc_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + mtc.flag = mtc.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - mtc_flag = mtc_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + mtc.flag = mtc.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (mtc); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (mtc); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (mtc); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (mtc); + break; - case ioIOI: /* I/O data input */ - data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY); + case ioIOI: /* I/O data input */ + data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY); - if (mtc_unit.flags & UNIT_ATT) { /* construct status */ - if (sim_is_active (&mtc_unit)) - data = data | STA_BUSY; + if (mtc_unit.flags & UNIT_ATT) { /* construct status */ + if (sim_is_active (&mtc_unit)) + data = data | STA_BUSY; - if (sim_tape_wrp (&mtc_unit)) - data = data | STA_WLK; - } - else - data = data | STA_BUSY | STA_LOCAL; - break; + if (sim_tape_wrp (&mtc_unit)) + data = data | STA_WLK; + } + else + data = data | STA_BUSY | STA_LOCAL; + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - data = data & 0377; - mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ + case ioIOO: /* I/O data output */ + data = IODATA (stat_data) & DMASK8; + mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ - if (data == FNC_CLR) { /* clear? */ - mt_clear (); /* send CLR to controller */ + if (data == FNC_CLR) { /* clear? */ + mt_clear (); /* send CLR to controller */ - mtd_flag = mtd_flagbuf = CLEAR; /* clear data flag and flag buffer */ - mtc_flag = mtc_flagbuf = SET; /* set command flag and flag buffer */ - break; /* command completes immediately */ - } + mtd.flag = mtd.flagbuf = CLEAR; /* clear data flag and flag buffer */ + mtc.flag = mtc.flagbuf = SET; /* set command flag and flag buffer */ + break; /* command completes immediately */ + } - for (i = valid = 0; i < sizeof (mtc_cmd); i++) /* is fnc valid? */ - if (data == mtc_cmd[i]) - valid = 1; + for (i = valid = 0; i < mtc_cmd_count; i++) /* is fnc valid? */ + if (data == mtc_cmd[i]) { + valid = 1; + break; + } - if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ - ((mtc_sta & STA_BOT) && (data == FNC_BSR)) || - (sim_tape_wrp (&mtc_unit) && - ((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM)))) - mtc_sta = mtc_sta | STA_REJ; + if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ + ((mtc_sta & STA_BOT) && (data == FNC_BSR)) || + (sim_tape_wrp (&mtc_unit) && + ((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM)))) + mtc_sta = mtc_sta | STA_REJ; - else { - sim_activate (&mtc_unit, mtc_ctime); /* start tape */ - mtc_fnc = data; /* save function */ - mtc_sta = STA_BUSY; /* unit busy */ - mt_ptr = 0; /* init buffer ptr */ + else { + sim_activate (&mtc_unit, mtc_ctime); /* start tape */ + mtc_fnc = data; /* save function */ + mtc_sta = STA_BUSY; /* unit busy */ + mt_ptr = 0; /* init buffer ptr */ - mtcio (select_code, ioCLF, 0); /* clear flags */ - mtcio (mtd_dib.devno, ioCLF, 0); + mtcio (&mtc_dib, ioCLF, 0); /* clear flags */ + mtcio (&mtd_dib, ioCLF, 0); - mtc_1st = 1; /* set 1st flop */ - mtc_dtf = 1; /* set xfer flop */ - } - break; + mtc_1st = 1; /* set 1st flop */ + mtc_dtf = 1; /* set xfer flop */ + } + break; - case ioPOPIO: /* power-on preset to I/O */ - mtc_flag = mtc_flagbuf = CLEAR; /* clear flag and flag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - mtc_control = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + mtc.flag = mtc.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; - case ioSTC: /* set control flip-flop */ - mtc_control = SET; - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + mtc.control = CLEAR; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, mtc); /* set standard PRL signal */ - setstdIRQ (select_code, mtc); /* set standard IRQ signal */ - setstdSRQ (select_code, mtc); /* set standard SRQ signal */ - break; - - case ioIAK: /* interrupt acknowledge */ - mtc_flagbuf = CLEAR; - break; + case ioSTC: /* set control flip-flop */ + mtc.control = SET; + break; - default: /* all other signals */ - break; /* are ignored */ + case ioSIR: /* set interrupt request */ + setstdPRL (mtc); /* set standard PRL signal */ + setstdIRQ (mtc); /* set standard IRQ signal */ + setstdSRQ (mtc); /* set standard SRQ signal */ + break; + + case ioIAK: /* interrupt acknowledge */ + mtc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - mtcio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - mtcio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -460,8 +475,8 @@ t_stat st, r = SCPE_OK; if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ - mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */ - return IORETURN (mtc_stopioe, SCPE_UNATT); + mtcio (&mtc_dib, ioENF, 0); /* set cch flg */ + return IOERROR (mtc_stopioe, SCPE_UNATT); } switch (mtc_fnc) { /* case on function */ @@ -514,9 +529,9 @@ switch (mtc_fnc) { /* case on function */ } } if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */ - if (mtd_flag) mtc_sta = mtc_sta | STA_TIM; + if (mtd.flag) mtc_sta = mtc_sta | STA_TIM; mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ - mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */ + mtdio (&mtd_dib, ioENF, 0); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } @@ -534,7 +549,7 @@ switch (mtc_fnc) { /* case on function */ else mtc_sta = mtc_sta | STA_PAR; } if (mtc_dtf) { /* xfer flop set? */ - mtdio (mtd_dib.devno, ioENF, 0); /* set dch flg */ + mtdio (&mtd_dib, ioENF, 0); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } @@ -552,7 +567,7 @@ switch (mtc_fnc) { /* case on function */ break; } -mtcio (mtc_dib.devno, ioENF, 0); /* set cch flg */ +mtcio (&mtc_dib, ioENF, 0); /* set cch flg */ mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ return r; } @@ -626,13 +641,12 @@ return SCPE_OK; t_stat mt_reset (DEVICE *dptr) { +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + hp_enbdis_pair (dptr, /* make pair cons */ (dptr == &mtd_dev) ? &mtc_dev : &mtd_dev); -if (dptr == &mtc_dev) /* command channel reset? */ - mtcio (mtc_dib.devno, ioPOPIO, 0); /* send POPIO signal to command channel */ -else /* data channel reset */ - mtdio (mtd_dib.devno, ioPOPIO, 0); /* send POPIO signal to data channel */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ mtc_fnc = 0; mtc_1st = mtc_dtf = 0; diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index ecd89e87..2712f1c4 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-2008, Robert M Supnik + Copyright (c) 2002-2011, Robert 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 @@ MUX,MUXL,MUXM 12920A terminal multiplexor + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines 09-Oct-08 JDB "muxl_unit" defined one too many units (17 instead of 16) 10-Sep-08 JDB SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed @@ -265,9 +267,11 @@ static const uint8 odd_par [256] = { /* Multiplexer controller state variables */ -FLIP_FLOP muxl_control = CLEAR; -FLIP_FLOP muxl_flag = CLEAR; -FLIP_FLOP muxl_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } muxl = { CLEAR, CLEAR, CLEAR }; uint32 muxl_ibuf = 0; /* low in: rcv data */ uint32 muxl_obuf = 0; /* low out: param */ @@ -275,9 +279,11 @@ uint32 muxl_obuf = 0; /* low out: param */ uint32 muxu_ibuf = 0; /* upr in: status */ uint32 muxu_obuf = 0; /* upr out: chan */ -FLIP_FLOP muxc_control = CLEAR; -FLIP_FLOP muxc_flag = CLEAR; -FLIP_FLOP muxc_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } muxc = { CLEAR, CLEAR, CLEAR }; uint32 muxc_chan = 0; /* ctrl chan */ uint32 muxc_scan = 0; /* ctrl scan */ @@ -311,9 +317,10 @@ void mux_diag (int32 c); /* Multiplexer global routines */ -uint32 muxlio (uint32 select_code, IOSIG signal, uint32 data); -uint32 muxuio (uint32 select_code, IOSIG signal, uint32 data); -uint32 muxcio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER muxlio; +IOHANDLER muxuio; +IOHANDLER muxcio; + t_stat muxi_svc (UNIT *uptr); t_stat muxo_svc (UNIT *uptr); t_stat muxc_reset (DEVICE *dptr); @@ -334,8 +341,8 @@ TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */ DIB mux_dib[] = { - { MUXL, &muxlio }, - { MUXU, &muxuio } + { &muxlio, MUXL }, + { &muxuio, MUXU } }; #define muxl_dib mux_dib[0] @@ -373,9 +380,9 @@ UNIT muxl_unit[] = { }; REG muxl_reg[] = { - { FLDATA (CTL, muxl_control, 0) }, - { FLDATA (FLG, muxl_flag, 0) }, - { FLDATA (FBF, muxl_flagbuf, 0) }, + { FLDATA (CTL, muxl.control, 0) }, + { FLDATA (FLG, muxl.flag, 0) }, + { FLDATA (FBF, muxl.flagbuf, 0) }, { BRDATA (STA, mux_sta, 8, 16, MUX_LINES + MUX_ILINES) }, { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) }, { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) }, @@ -386,7 +393,7 @@ REG muxl_reg[] = { { BRDATA (BDFR, mux_defer, 8, 1, MUX_LINES) }, { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, MUX_LINES, REG_NZ + PV_LEFT) }, - { ORDATA (DEVNO, muxl_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, muxl_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -450,7 +457,7 @@ UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST }; REG muxu_reg[] = { { ORDATA (IBUF, muxu_ibuf, 16) }, { ORDATA (OBUF, muxu_obuf, 16) }, - { ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, muxu_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -512,19 +519,19 @@ DEVICE muxu_dev = { DEVICE muxc_dev; -DIB muxc_dib = { MUXC, &muxcio }; +DIB muxc_dib = { &muxcio, MUXC }; UNIT muxc_unit = { UDATA (NULL, 0, 0) }; REG muxc_reg[] = { - { FLDATA (CTL, muxc_control, 0) }, - { FLDATA (FLG, muxc_flag, 0) }, - { FLDATA (FBF, muxc_flagbuf, 0) }, + { FLDATA (CTL, muxc.control, 0) }, + { FLDATA (FLG, muxc.flag, 0) }, + { FLDATA (FBF, muxc.flagbuf, 0) }, { FLDATA (SCAN, muxc_scan, 0) }, { ORDATA (CHAN, muxc_chan, 4) }, { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) }, { BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) }, - { ORDATA (DEVNO, muxc_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, muxc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -570,191 +577,190 @@ DEVICE muxc_dev = { to these 128K CRS invocations. */ -uint32 muxlio (uint32 select_code, IOSIG signal, uint32 data) +uint32 muxlio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { int32 ln; -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); static uint32 crs_count = 0; /* cntr for ioCRS repeat */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - muxl_flag = muxl_flagbuf = CLEAR; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb); - - mux_data_int (); /* look for new int */ - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - muxl_flag = muxl_flagbuf = SET; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb); - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (muxl); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (muxl); - break; - - - case ioIOI: /* I/O data input */ - data = muxl_ibuf; - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, data); - break; - - - case ioIOO: /* I/O data output */ - muxl_obuf = data; /* store data */ - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - if (data & OTL_P) - fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, data); - else - fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, data); - break; - - - case ioPOPIO: /* power-on preset to I/O */ - muxl_flag = muxl_flagbuf = SET; /* set flag andflag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - if (crs_count) /* already reset? */ - break; /* skip redundant clear */ - - muxl_control = CLEAR; /* clear control flip-flop */ - - for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */ - mux_xbuf[ln] = mux_xpar[ln] = 0; - muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0; - } - - for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) { - mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */ - mux_sta[ln] = mux_rchp[ln] = 0; - } - break; - - - case ioCLC: /* clear control flip-flop */ - muxl_control = CLEAR; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear); - break; - - - case ioSTC: /* set control flip-flop */ - muxl_control = SET; /* set control */ - - ln = MUX_CHAN (muxu_obuf); /* get chan # */ - - if (muxl_obuf & OTL_TX) { /* transmit? */ - if (ln < MUX_LINES) { /* line valid? */ - if (muxl_obuf & OTL_P) { /* parameter? */ - mux_xpar[ln] = muxl_obuf; /* store param value */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n", - hold_or_clear, ln, muxl_obuf); - } - - else { /* data */ - if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */ - muxl_obuf = /* add parity bit */ - muxl_obuf & ~OTL_PAR | - XMT_PAR(muxl_obuf); - mux_xbuf[ln] = muxl_obuf; /* load buffer */ - - if (sim_is_active (&muxl_unit[ln])) { /* still working? */ - mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n", - hold_or_clear, ln); - } - else { - if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ - mux_ldsc[ln].conn = 1; /* connect this line */ - sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n", - hold_or_clear, ln, muxl_obuf); - } - } - } - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln); - } - - else /* receive */ - if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */ - if (muxl_obuf & OTL_P) { /* parameter? */ - mux_rpar[ln] = muxl_obuf; /* store param value */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n", - hold_or_clear, ln, muxl_obuf); - } - - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */ - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n", - hold_or_clear, ln, muxl_obuf); - } - - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, muxl); /* set standard PRL signal */ - setstdIRQ (select_code, muxl); /* set standard IRQ signal */ - setstdSRQ (select_code, muxl); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - muxl_flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - -if (signal > ioCLF) /* multiple signals? */ - muxlio (select_code, ioCLF, 0); /* issue CLF */ - -else if (signal > ioSIR) /* signal affected interrupt status? */ - muxlio (select_code, ioSIR, 0); /* set interrupt request */ - - -if (signal == ioCRS) /* control reset? */ - crs_count = crs_count + 1; /* increment count */ - -else if (crs_count && (signal != ioSIR)) { /* counting CRSes? */ +if (crs_count && !(signal_set & ioCRS)) { /* counting CRSes and not present? */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* report reset count */ fprintf (sim_deb, ">>MUXl cmds: [CRS] Multiplexer reset %d times\n", crs_count); + crs_count = 0; /* clear counter */ } -return data; +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + muxl.flag = muxl.flagbuf = CLEAR; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb); + + mux_data_int (); /* look for new int */ + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + muxl.flag = muxl.flagbuf = SET; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb); + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (muxl); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (muxl); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, muxl_ibuf); /* merge in return status */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, muxl_ibuf); + break; + + + case ioIOO: /* I/O data output */ + muxl_obuf = IODATA (stat_data); /* store data */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + if (muxl_obuf & OTL_P) + fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, muxl_obuf); + else + fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, muxl_obuf); + break; + + + case ioPOPIO: /* power-on preset to I/O */ + muxl.flag = muxl.flagbuf = SET; /* set flag andflag buffer */ + break; + + + case ioCRS: /* control reset */ + if (crs_count == 0) { /* first reset? */ + muxl.control = CLEAR; /* clear control flip-flop */ + + for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */ + mux_xbuf[ln] = mux_xpar[ln] = 0; + muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0; + } + + for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) { + mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */ + mux_sta[ln] = mux_rchp[ln] = 0; + } + } + + crs_count = crs_count + 1; /* increment count */ + break; + + + case ioCLC: /* clear control flip-flop */ + muxl.control = CLEAR; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear); + break; + + + case ioSTC: /* set control flip-flop */ + muxl.control = SET; /* set control */ + + ln = MUX_CHAN (muxu_obuf); /* get chan # */ + + if (muxl_obuf & OTL_TX) { /* transmit? */ + if (ln < MUX_LINES) { /* line valid? */ + if (muxl_obuf & OTL_P) { /* parameter? */ + mux_xpar[ln] = muxl_obuf; /* store param value */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n", + hold_or_clear, ln, muxl_obuf); + } + + else { /* data */ + if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */ + muxl_obuf = /* add parity bit */ + muxl_obuf & ~OTL_PAR | + XMT_PAR(muxl_obuf); + mux_xbuf[ln] = muxl_obuf; /* load buffer */ + + if (sim_is_active (&muxl_unit[ln])) { /* still working? */ + mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n", + hold_or_clear, ln); + } + else { + if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ + mux_ldsc[ln].conn = 1; /* connect this line */ + sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n", + hold_or_clear, ln, muxl_obuf); + } + } + } + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln); + } + + else /* receive */ + if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */ + if (muxl_obuf & OTL_P) { /* parameter? */ + mux_rpar[ln] = muxl_obuf; /* store param value */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n", + hold_or_clear, ln, muxl_obuf); + } + + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */ + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n", + hold_or_clear, ln, muxl_obuf); + } + + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (muxl); /* set standard PRL signal */ + setstdIRQ (muxl); /* set standard IRQ signal */ + setstdSRQ (muxl); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + muxl.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; } @@ -771,34 +777,41 @@ return data; the lower data card CRS handler. */ -uint32 muxuio (uint32 select_code, IOSIG signal, uint32 data) +uint32 muxuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioIOI: /* I/O data input */ - data = muxu_ibuf; + switch (signal) { /* dispatch I/O signal */ - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n", - data, MUX_CHAN(data)); - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, muxu_ibuf); /* merge in return status */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n", + muxu_ibuf, MUX_CHAN(muxu_ibuf)); + break; - case ioIOO: /* I/O data output */ - muxu_obuf = data; /* store data */ + case ioIOO: /* I/O data output */ + muxu_obuf = IODATA (stat_data); /* store data */ - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(data)); - break; + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(muxu_obuf)); + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -return data; +return stat_data; } @@ -809,139 +822,142 @@ return data; test is performed after IOO processing. */ -uint32 muxcio (uint32 select_code, IOSIG signal, uint32 data) +uint32 muxcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); +uint16 data; int32 ln, old; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - muxc_flag = muxc_flagbuf = CLEAR; + switch (signal) { /* dispatch I/O signal */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb); + case ioCLF: /* clear flag flip-flop */ + muxc.flag = muxc.flagbuf = CLEAR; - mux_ctrl_int (); /* look for new int */ - break; + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb); + + mux_ctrl_int (); /* look for new int */ + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - muxc_flag = muxc_flagbuf = SET; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + muxc.flag = muxc.flagbuf = SET; - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb); - break; + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb); + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (muxc); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (muxc); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (muxc); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (muxc); + break; - case ioIOI: /* I/O data input */ - data = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */ - LIC_TSTI (muxc_chan) | /* I2, I1 */ - (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */ - (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */ + case ioIOI: /* I/O data input */ + data = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */ + LIC_TSTI (muxc_chan) | /* I2, I1 */ + (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */ + (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */ - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n", - hold_or_clear, data, muxc_chan); + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n", + hold_or_clear, data, muxc_chan); - muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ - break; + muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - ln = muxc_chan = OTC_CHAN (data); /* set channel */ + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ + ln = muxc_chan = OTC_CHAN (data); /* set channel */ - if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */ - else muxc_scan = 0; + if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */ + else muxc_scan = 0; - if (data & OTC_UPD) { /* update? */ - old = muxc_ota[ln]; /* save prior val */ - muxc_ota[ln] = /* save ESn,SSn */ - (muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW); + if (data & OTC_UPD) { /* update? */ + old = muxc_ota[ln]; /* save prior val */ + muxc_ota[ln] = /* save ESn,SSn */ + (muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW); - if (data & OTC_EC2) /* if EC2, upd C2 */ - muxc_ota[ln] = - (muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2); + if (data & OTC_EC2) /* if EC2, upd C2 */ + muxc_ota[ln] = + (muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2); - if (data & OTC_EC1) /* if EC1, upd C1 */ - muxc_ota[ln] = - (muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1); + if (data & OTC_EC1) /* if EC1, upd C1 */ + muxc_ota[ln] = + (muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1); - if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ - muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */ - (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) | - (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C; + if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ + muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */ + (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) | + (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C; - else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ - (old & DTR) && /* DTR drop? */ - !(muxc_ota[ln] & DTR)) { - 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 */ + else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (old & DTR) && /* DTR drop? */ + !(muxc_ota[ln] & DTR)) { + 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 */ - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n", - hold_or_clear, data, ln); + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n", + hold_or_clear, data, ln); - if ((muxu_unit.flags & UNIT_DIAG) && (!muxc_flag)) /* loopback and flag clear? */ - mux_ctrl_int (); /* status chg may interrupt */ - break; + if ((muxu_unit.flags & UNIT_DIAG) && (!muxc.flag)) /* loopback and flag clear? */ + mux_ctrl_int (); /* status chg may interrupt */ + break; - case ioPOPIO: /* power-on preset to I/O */ - muxc_flag = muxc_flagbuf = SET; /* set flag and flag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - muxc_control = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + muxc.flag = muxc.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioSTC: /* set control flip-flop */ - muxc_control = SET; - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + muxc.control = CLEAR; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, muxc); /* set standard PRL signal */ - setstdIRQ (select_code, muxc); /* set standard IRQ signal */ - setstdSRQ (select_code, muxc); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + muxc.control = SET; + break; - case ioIAK: /* interrupt acknowledge */ - muxc_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (muxc); /* set standard PRL signal */ + setstdIRQ (muxc); /* set standard IRQ signal */ + setstdSRQ (muxc); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + muxc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - muxcio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - muxcio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -1004,8 +1020,8 @@ for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ muxc_lia[ln] = 0; /* line disconnected */ } -if (!muxl_flag) mux_data_int (); /* scan for data int */ -if (!muxc_flag) mux_ctrl_int (); /* scan modem */ +if (!muxl.flag) mux_data_int (); /* scan for data int */ +if (!muxc.flag) mux_ctrl_int (); /* scan modem */ return SCPE_OK; } @@ -1066,7 +1082,7 @@ if (mux_ldsc[ln].conn) { /* connected? */ } } -if (!muxl_flag) mux_data_int (); /* scan for int */ +if (!muxl.flag) mux_data_int (); /* scan for int */ return SCPE_OK; } @@ -1143,7 +1159,7 @@ for (i = 0; i < MUX_LINES; i++) { /* rcv lines */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i); - muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */ + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ return; } } @@ -1159,7 +1175,7 @@ for (i = 0; i < MUX_LINES; i++) { /* xmt lines */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) fprintf (sim_deb, ">>MUXl cmds: Transmit channel %d interrupt requested\n", i); - muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */ + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ return; } } @@ -1175,7 +1191,7 @@ for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i); - muxlio (muxl_dib.devno, ioENF, 0); /* interrupt */ + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ return; } } @@ -1208,7 +1224,7 @@ for (i = 0; i < line_count; i++) { ">>MUXc cmds: Control channel %d interrupt requested (poll = %d)\n", muxc_chan, i + 1); - muxcio (muxc_dib.devno, ioENF, 0); /* set flag */ + muxcio (&muxc_dib, ioENF, 0); /* set flag */ break; } } @@ -1260,6 +1276,7 @@ return; t_stat muxc_reset (DEVICE *dptr) { int32 i; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ if (dptr == &muxc_dev) { /* make all consistent */ hp_enbdis_pair (dptr, &muxl_dev); @@ -1274,12 +1291,7 @@ else { hp_enbdis_pair (dptr, &muxl_dev); } -if (dptr == &muxl_dev) /* lower data reset? */ - muxlio (muxl_dib.devno, ioPOPIO, 0); /* send POPIO signal to lower data card */ -else if (dptr == &muxu_dev) /* upper data reset? */ - muxuio (muxu_dib.devno, ioPOPIO, 0); /* send POPIO signal to upper data card */ -else /* control card reset */ - muxcio (muxc_dib.devno, ioPOPIO, 0); /* send POPIO signal to control card */ +IOPRESET (dibptr); /* PRESET device (does not use PON) */ muxc_chan = muxc_scan = 0; /* init modem scan */ diff --git a/HP2100/hp2100_pif.c b/HP2100/hp2100_pif.c index 6ce98a00..494f5860 100644 --- a/HP2100/hp2100_pif.c +++ b/HP2100/hp2100_pif.c @@ -1,6 +1,6 @@ /* hp2100_pif.c: HP 12620A/12936A privileged interrupt fence simulator - Copyright (c) 2008, J. David Bryan + Copyright (c) 2008-2011, J. David Bryan 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 @@ PIF 12620A/12936A privileged interrupt fence + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals 18-Jun-08 JDB Created PIF device @@ -103,14 +105,16 @@ /* PIF state variables */ -FLIP_FLOP pif_control = CLEAR; /* control flip-flop */ -FLIP_FLOP pif_flag = CLEAR; /* flag flip-flop */ -FLIP_FLOP pif_flagbuf = CLEAR; /* flag buffer flip-flop */ +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } pif = { CLEAR, CLEAR, CLEAR }; /* PIF global routines */ -uint32 pif_io (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER pif_io; t_stat pif_reset (DEVICE *dptr); t_stat pif_set_card (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -136,17 +140,17 @@ t_stat pif_show_card (FILE *st, UNIT *uptr, int32 val, void *desc); DEVICE pif_dev; -DIB pif_dib = { PIF, &pif_io }; +DIB pif_dib = { &pif_io, PIF }; UNIT pif_unit = { UDATA (NULL, 0, 0) /* dummy unit */ }; REG pif_reg [] = { - { FLDATA (CTL, pif_control, 0) }, - { FLDATA (FLG, pif_flag, 0) }, - { FLDATA (FBF, pif_flagbuf, 0) }, - { ORDATA (DEVNO, pif_dib.devno, 6), REG_HRO }, + { FLDATA (CTL, pif.control, 0) }, + { FLDATA (FLG, pif.flag, 0) }, + { FLDATA (FBF, pif.flagbuf, 0) }, + { ORDATA (DEVNO, pif_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -155,7 +159,6 @@ MTAB pif_mod [] = { { MTAB_XTD | MTAB_VDV, 1, NULL, "12936A", &pif_set_card, NULL, NULL }, { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &pif_show_card, NULL }, { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &pif_dev }, - { 0 } }; @@ -184,7 +187,6 @@ DEVICE pif_dev = { NULL }; /* logical device name */ - /* I/O signal handler. Operation of the 12620A and the 12936A is different. The I/O responses of @@ -210,118 +212,120 @@ DEVICE pif_dev = { Note that PRL and IRQ are non-standard for the 12936A. */ -uint32 pif_io (uint32 select_code, IOSIG signal, uint32 data) +uint32 pif_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const char *hold_or_clear = (signal > ioCLF ? ",C" : ""); +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); const t_bool is_rte_pif = (pif_dev.flags & DEV_12936) == 0; -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ -switch (base_signal) { /* dispatch base I/O signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - case ioCLF: /* clear flag flip-flop */ - pif_flag = pif_flagbuf = CLEAR; /* clear flag buffer and flag */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - if (DEBUG_PRS (pif_dev)) - fputs (">>PIF: [CLF] Flag cleared\n", sim_deb); - break; + switch (signal) { /* dispatch I/O signal */ - - case ioSTF: /* set flag flip-flop */ - if (is_rte_pif) { /* RTE PIF? */ - pif_flag = pif_flagbuf = SET; /* set flag buffer and flag */ + case ioCLF: /* clear flag flip-flop */ + pif.flag = pif.flagbuf = CLEAR; /* clear flag buffer and flag */ if (DEBUG_PRS (pif_dev)) - fputs (">>PIF: [STF] Flag set\n", sim_deb); - } - break; + fputs (">>PIF: [CLF] Flag cleared\n", sim_deb); + break; - case ioSFC: /* skip if flag is clear */ - if (is_rte_pif) /* RTE PIF? */ - setstdSKF (pif); /* card responds to SFC */ - break; + case ioSTF: /* set flag flip-flop */ + if (is_rte_pif) { /* RTE PIF? */ + pif.flag = pif.flagbuf = SET; /* set flag buffer and flag */ + + if (DEBUG_PRS (pif_dev)) + fputs (">>PIF: [STF] Flag set\n", sim_deb); + } + break; - case ioSFS: /* skip if flag is set */ - if (is_rte_pif) /* RTE PIF? */ - setstdSKF (pif); /* card responds to SFS */ - break; + case ioSFC: /* skip if flag is clear */ + if (is_rte_pif) /* RTE PIF? */ + setstdSKF (pif); /* card responds to SFC */ + break; - case ioIOO: /* I/O data output */ - if (!is_rte_pif) { /* DOS PIF? */ - pif_flag = pif_flagbuf = SET; /* set flag buffer and flag */ - pif_io (select_code, ioSIR, 0); /* set IRQ (not normally done for IOO) */ + case ioSFS: /* skip if flag is set */ + if (is_rte_pif) /* RTE PIF? */ + setstdSKF (pif); /* card responds to SFS */ + break; + + + case ioIOO: /* I/O data output */ + if (!is_rte_pif) { /* DOS PIF? */ + pif.flag = pif.flagbuf = SET; /* set flag buffer and flag */ + working_set = working_set | ioSIR; /* set SIR (not normally done for IOO) */ + + if (DEBUG_PRS (pif_dev)) + fprintf (sim_deb, ">>PIF: [OTx%s] Flag set\n", hold_or_clear); + } + break; + + + case ioPOPIO: /* power-on preset to I/O */ + pif.flag = pif.flagbuf = /* set or clear flag and flag buffer */ + (is_rte_pif ? SET : CLEAR); if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [OTx%s] Flag set\n", hold_or_clear); - } - break; + fprintf (sim_deb, ">>PIF: [POPIO] Flag %s\n", + (is_rte_pif ? "set" : "cleared")); + break; - case ioPOPIO: /* power-on preset to I/O */ - pif_flag = pif_flagbuf = /* set or clear flag and flag buffer */ - (is_rte_pif ? SET : CLEAR); + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + pif.control = CLEAR; /* clear control */ - if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [POPIO] Flag %s\n", - (is_rte_pif ? "set" : "cleared")); - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - pif_control = CLEAR; /* clear control */ - - if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [%s%s] Control cleared\n", - (signal == ioCRS ? "CRS" : "CLC"), hold_or_clear); - break; + if (DEBUG_PRS (pif_dev)) + fprintf (sim_deb, ">>PIF: [%s%s] Control cleared\n", + (signal == ioCRS ? "CRS" : "CLC"), hold_or_clear); + break; - case ioSTC: /* set control flip-flop */ - pif_control = SET; /* set control */ + case ioSTC: /* set control flip-flop */ + pif.control = SET; /* set control */ - if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [STC%s] Control set\n", hold_or_clear); - break; + if (DEBUG_PRS (pif_dev)) + fprintf (sim_deb, ">>PIF: [STC%s] Control set\n", hold_or_clear); + break; - case ioSIR: /* set interrupt request */ - if (is_rte_pif) { /* RTE PIF? */ - setstdPRL (select_code, pif); /* set standard PRL signal */ - setstdIRQ (select_code, pif); /* set standard IRQ signal */ - setstdSRQ (select_code, pif); /* set standard SRQ signal */ - } + case ioSIR: /* set interrupt request */ + if (is_rte_pif) { /* RTE PIF? */ + setstdPRL (pif); /* set standard PRL signal */ + setstdIRQ (pif); /* set standard IRQ signal */ + setstdSRQ (pif); /* set standard SRQ signal */ + } - else { /* DOS PIF */ - setPRL (select_code, !(pif_control | pif_flag)); - setIRQ (select_code, !pif_control & pif_flag & pif_flagbuf); - } + else { /* DOS PIF */ + setPRL (dibptr->select_code, !(pif.control | pif.flag)); + setIRQ (dibptr->select_code, !pif.control & pif.flag & pif.flagbuf); + } - if (DEBUG_PRS (pif_dev)) - fprintf (sim_deb, ">>PIF: [SIR] PRL = %d, IRQ = %d\n", - PRL (select_code), IRQ (select_code)); - break; + if (DEBUG_PRS (pif_dev)) + fprintf (sim_deb, ">>PIF: [SIR] PRL = %d, IRQ = %d\n", + PRL (dibptr->select_code), + IRQ (dibptr->select_code)); + break; - case ioIAK: /* interrupt acknowledge */ - pif_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + pif.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - pif_io (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - pif_io (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -329,7 +333,7 @@ return data; t_stat pif_reset (DEVICE *dptr) { -pif_io (pif_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&pif_dib); /* PRESET device (does not use PON) */ return SCPE_OK; } diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index 5389bdf2..ebc8c04f 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -1,6 +1,6 @@ /* hp2100_stddev.c: HP2100 standard devices simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2011, Robert 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 @@ TTY 12531C buffered teleprinter interface CLK 12539C time base generator + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals 25-Apr-08 JDB Changed TTY output wait from 100 to 200 for MSU BASIC 18-Apr-08 JDB Removed redundant control char handling definitions @@ -125,23 +127,29 @@ #define CLK_V_ERROR 4 /* clock overrun */ #define CLK_ERROR (1 << CLK_V_ERROR) -FLIP_FLOP ptr_control = CLEAR; -FLIP_FLOP ptr_flag = CLEAR; -FLIP_FLOP ptr_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } ptr = { CLEAR, CLEAR, CLEAR }; int32 ptr_stopioe = 0; /* stop on error */ int32 ptr_trlcnt = 0; /* trailer counter */ int32 ptr_trllim = 40; /* trailer to add */ -FLIP_FLOP ptp_control = CLEAR; -FLIP_FLOP ptp_flag = CLEAR; -FLIP_FLOP ptp_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } ptp = { CLEAR, CLEAR, CLEAR }; int32 ptp_stopioe = 0; -FLIP_FLOP tty_control = CLEAR; -FLIP_FLOP tty_flag = CLEAR; -FLIP_FLOP tty_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } tty = { CLEAR, CLEAR, CLEAR }; int32 ttp_stopioe = 0; int32 tty_buf = 0; /* tty buffer */ @@ -149,9 +157,11 @@ int32 tty_mode = 0; /* tty mode */ int32 tty_shin = 0377; /* tty shift in */ int32 tty_lf = 0; /* lf flag */ -FLIP_FLOP clk_control = CLEAR; -FLIP_FLOP clk_flag = CLEAR; -FLIP_FLOP clk_flagbuf = CLEAR; +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } clk = { CLEAR, CLEAR, CLEAR }; int32 clk_select = 0; /* clock time select */ int32 clk_error = 0; /* clock error */ @@ -169,17 +179,17 @@ uint32 clk_tick = 0; /* instructions per tick DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev; -uint32 ptrio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER ptrio; t_stat ptr_svc (UNIT *uptr); t_stat ptr_attach (UNIT *uptr, char *cptr); t_stat ptr_reset (DEVICE *dptr); t_stat ptr_boot (int32 unitno, DEVICE *dptr); -uint32 ptpio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER ptpio; t_stat ptp_svc (UNIT *uptr); t_stat ptp_reset (DEVICE *dptr); -uint32 ttyio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER ttyio; t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tty_reset (DEVICE *dptr); @@ -188,7 +198,7 @@ t_stat tty_set_alf (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat tto_out (int32 c); t_stat ttp_out (int32 c); -uint32 clkio (uint32 select_code, IOSIG signal, uint32 data); +IOHANDLER clkio; t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); int32 clk_delay (int32 flg); @@ -201,7 +211,7 @@ int32 clk_delay (int32 flg); ptr_reg PTR register list */ -DIB ptr_dib = { PTR, &ptrio }; +DIB ptr_dib = { &ptrio, PTR }; UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), @@ -210,15 +220,15 @@ UNIT ptr_unit = { REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, - { FLDATA (CTL, ptr_control, 0) }, - { FLDATA (FLG, ptr_flag, 0) }, - { FLDATA (FBF, ptr_flagbuf, 0) }, + { FLDATA (CTL, ptr.control, 0) }, + { FLDATA (FLG, ptr.flag, 0) }, + { FLDATA (FBF, ptr.flagbuf, 0) }, { DRDATA (TRLCTR, ptr_trlcnt, 8), REG_HRO }, { DRDATA (TRLLIM, ptr_trllim, 8), PV_LEFT }, { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { ORDATA (DEVNO, ptr_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, ptr_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -246,7 +256,7 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ -DIB ptp_dib = { PTP, &ptpio }; +DIB ptp_dib = { &ptpio, PTP }; UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT @@ -254,13 +264,13 @@ UNIT ptp_unit = { REG ptp_reg[] = { { ORDATA (BUF, ptp_unit.buf, 8) }, - { FLDATA (CTL, ptp_control, 0) }, - { FLDATA (FLG, ptp_flag, 0) }, - { FLDATA (FBF, ptp_flagbuf, 0) }, + { FLDATA (CTL, ptp.control, 0) }, + { FLDATA (FLG, ptp.flag, 0) }, + { FLDATA (FBF, ptp.flagbuf, 0) }, { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { ORDATA (DEVNO, ptp_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, ptp_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -290,7 +300,7 @@ DEVICE ptp_dev = { #define TTO 1 #define TTP 2 -DIB tty_dib = { TTY, &ttyio }; +DIB tty_dib = { &ttyio, TTY }; UNIT tty_unit[] = { { UDATA (&tti_svc, UNIT_IDLE | TT_MODE_UC, 0), POLL_WAIT }, @@ -302,9 +312,9 @@ REG tty_reg[] = { { ORDATA (BUF, tty_buf, 8) }, { ORDATA (MODE, tty_mode, 16) }, { ORDATA (SHIN, tty_shin, 8), REG_HRO }, - { FLDATA (CTL, tty_control, 0) }, - { FLDATA (FLG, tty_flag, 0) }, - { FLDATA (FBF, tty_flagbuf, 0) }, + { FLDATA (CTL, tty.control, 0) }, + { FLDATA (FLG, tty.flag, 0) }, + { FLDATA (FBF, tty.flagbuf, 0) }, { FLDATA (KLFP, tty_lf, 0), REG_HRO }, { DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT }, { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, @@ -312,7 +322,7 @@ REG tty_reg[] = { { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, { DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT }, { FLDATA (STOP_IOE, ttp_stopioe, 0) }, - { ORDATA (DEVNO, tty_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, tty_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -344,20 +354,20 @@ DEVICE tty_dev = { clk_reg CLK register list */ -DIB clk_dib = { CLK, &clkio }; +DIB clk_dib = { &clkio, CLK }; UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0) }; REG clk_reg[] = { { ORDATA (SEL, clk_select, 3) }, { DRDATA (CTR, clk_ctr, 14) }, - { FLDATA (CTL, clk_control, 0) }, - { FLDATA (FLG, clk_flag, 0) }, - { FLDATA (FBF, clk_flagbuf, 0) }, + { FLDATA (CTL, clk.control, 0) }, + { FLDATA (FLG, clk.flag, 0) }, + { FLDATA (FBF, clk.flagbuf, 0) }, { FLDATA (ERR, clk_error, CLK_V_ERROR) }, { BRDATA (TIME, clk_time, 10, 24, 8) }, { DRDATA (IPTICK, clk_tick, 24), PV_RSPC | REG_RO }, - { ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO }, + { ORDATA (DEVNO, clk_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -392,78 +402,79 @@ DEVICE clk_dev = { simulation, we omit the buffer clear. */ -uint32 ptrio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ptrio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - ptr_flag = ptr_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ptr.flag = ptr.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ptr_flag = ptr_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ptr.flag = ptr.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (ptr); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (ptr); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (ptr); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (ptr); + break; - case ioIOI: /* I/O data input */ - data = ptr_unit.buf; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, ptr_unit.buf); /* merge in return status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - ptr_flag = ptr_flagbuf = SET; /* set flag and flag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - ptr_control = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + ptr.flag = ptr.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioSTC: /* set control flip-flop */ - ptr_control = SET; - sim_activate (&ptr_unit, ptr_unit.wait); - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + ptr.control = CLEAR; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, ptr); /* set standard PRL signal */ - setstdIRQ (select_code, ptr); /* set standard IRQ signal */ - setstdSRQ (select_code, ptr); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + ptr.control = SET; + sim_activate (&ptr_unit, ptr_unit.wait); + break; - case ioIAK: /* interrupt acknowledge */ - ptr_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (ptr); /* set standard PRL signal */ + setstdIRQ (ptr); /* set standard IRQ signal */ + setstdSRQ (ptr); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + ptr.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - ptrio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - ptrio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -474,7 +485,7 @@ t_stat ptr_svc (UNIT *uptr) int32 temp; if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptr_stopioe, SCPE_UNATT); + return IOERROR (ptr_stopioe, SCPE_UNATT); while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ if (feof (ptr_unit.fileref)) { /* end of file? */ if ((ptr_unit.flags & UNIT_DIAG) && (ptr_unit.pos > 0)) { @@ -501,7 +512,7 @@ while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ } } -ptrio (ptr_dib.devno, ioENF, 0); /* set flag */ +ptrio (&ptr_dib, ioENF, 0); /* set flag */ ptr_unit.buf = temp & 0377; /* put byte in buf */ ptr_unit.pos = ftell (ptr_unit.fileref); @@ -526,7 +537,7 @@ return attach_unit (uptr, cptr); t_stat ptr_reset (DEVICE *dptr) { -ptrio (ptr_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&ptr_dib); /* PRESET device (does not use PON) */ sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; } @@ -591,7 +602,7 @@ t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int32 dev; -dev = ptr_dib.devno; /* get device no */ +dev = ptr_dib.select_code; /* get device no */ if (ibl_copy (ptr_rom, dev)) return SCPE_IERR; /* copy boot to memory */ SR = (SR & IBL_OPT) | IBL_PTR | (dev << IBL_V_DEV); /* set SR */ return SCPE_OK; @@ -608,87 +619,88 @@ return SCPE_OK; state is implied by the activation of the PTP unit. */ -uint32 ptpio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ptpio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - ptp_flag = ptp_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ptp.flag = ptp.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ptp_flag = ptp_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ptp.flag = ptp.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (ptp); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (ptp); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (ptp); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (ptp); + break; - case ioIOI: /* I/O data input */ - if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */ - data = PTP_LOW; /* report as out of tape */ - else - data = 0; - break; + case ioIOI: /* I/O data input */ + if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */ + stat_data = IORETURN (SCPE_OK, PTP_LOW); /* report as out of tape */ + else + stat_data = IORETURN (SCPE_OK, 0); + break; - case ioIOO: /* I/O data output */ - ptp_unit.buf = data; - break; + case ioIOO: /* I/O data output */ + ptp_unit.buf = IODATA (stat_data); /* clear supplied status */ + break; - case ioPOPIO: /* power-on preset to I/O */ - ptp_flag = ptp_flagbuf = SET; /* set flag and flag buffer */ - ptp_unit.buf = 0; /* clear output buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - ptp_control = CLEAR; - break; + case ioPOPIO: /* power-on preset to I/O */ + ptp.flag = ptp.flagbuf = SET; /* set flag and flag buffer */ + ptp_unit.buf = 0; /* clear output buffer */ + break; - case ioSTC: /* set control flip-flop */ - ptp_control = SET; - sim_activate (&ptp_unit, ptp_unit.wait); - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + ptp.control = CLEAR; + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, ptp); /* set standard PRL signal */ - setstdIRQ (select_code, ptp); /* set standard IRQ signal */ - setstdSRQ (select_code, ptp); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + ptp.control = SET; + sim_activate (&ptp_unit, ptp_unit.wait); + break; - case ioIAK: /* interrupt acknowledge */ - ptp_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (ptp); /* set standard PRL signal */ + setstdIRQ (ptp); /* set standard IRQ signal */ + setstdSRQ (ptp); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + ptp.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } -if (signal > ioCLF) /* multiple signals? */ - ptpio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - ptpio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -696,10 +708,10 @@ return data; t_stat ptp_svc (UNIT *uptr) { -ptpio (ptp_dib.devno, ioENF, 0); /* set flag */ +ptpio (&ptp_dib, ioENF, 0); /* set flag */ if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptp_stopioe, SCPE_UNATT); + return IOERROR (ptp_stopioe, SCPE_UNATT); if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */ perror ("PTP I/O error"); clearerr (ptp_unit.fileref); @@ -714,7 +726,7 @@ return SCPE_OK; t_stat ptp_reset (DEVICE *dptr) { -ptpio (ptp_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&ptp_dib); /* PRESET device (does not use PON) */ sim_cancel (&ptp_unit); /* deactivate unit */ return SCPE_OK; } @@ -722,97 +734,100 @@ return SCPE_OK; /* Terminal I/O signal handler */ -uint32 ttyio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ttyio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - tty_flag = tty_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + tty.flag = tty.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - tty_flag = tty_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + tty.flag = tty.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (tty); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (tty); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (tty); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (tty); + break; - case ioIOI: /* I/O data input */ - data = tty_buf; + case ioIOI: /* I/O data input */ + data = tty_buf; - if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO])) - data = data | TP_BUSY; - break; + if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO])) + data = data | TP_BUSY; + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - if (data & TM_MODE) - tty_mode = data & (TM_KBD|TM_PRI|TM_PUN); + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ - tty_buf = data & 0377; - break; + if (data & TM_MODE) + tty_mode = data & (TM_KBD|TM_PRI|TM_PUN); + + tty_buf = data & 0377; + break; - case ioPOPIO: /* power-on preset to I/O */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - tty_control = CLEAR; /* clear control */ - tty_flag = tty_flagbuf = SET; /* set flag and flag buffer */ - tty_mode = TM_KBD; /* set tty, clear print/punch */ - tty_shin = 0377; /* input inactive */ - tty_lf = 0; /* no lf pending */ - break; + case ioCRS: /* control reset */ + tty.control = CLEAR; /* clear control */ + tty.flag = tty.flagbuf = SET; /* set flag and flag buffer */ + tty_mode = TM_KBD; /* set tty, clear print/punch */ + tty_shin = 0377; /* input inactive */ + tty_lf = 0; /* no lf pending */ + break; - case ioCLC: /* clear control flip-flop */ - tty_control = CLEAR; - break; + case ioCLC: /* clear control flip-flop */ + tty.control = CLEAR; + break; - case ioSTC: /* set control flip-flop */ - tty_control = SET; + case ioSTC: /* set control flip-flop */ + tty.control = SET; - if (!(tty_mode & TM_KBD)) /* output? */ - sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); - break; + if (!(tty_mode & TM_KBD)) /* output? */ + sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, tty); /* set standard PRL signal */ - setstdIRQ (select_code, tty); /* set standard IRQ signal */ - setstdSRQ (select_code, tty); /* set standard SRQ signal */ - break; + case ioSIR: /* set interrupt request */ + setstdPRL (tty); /* set standard PRL signal */ + setstdIRQ (tty); /* set standard IRQ signal */ + setstdSRQ (tty); /* set standard SRQ signal */ + break; - case ioIAK: /* interrupt acknowledge */ - tty_flagbuf = CLEAR; - break; + case ioIAK: /* interrupt acknowledge */ + tty.flagbuf = CLEAR; + break; - default: /* all other signals */ - break; /* are ignored */ + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - ttyio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - ttyio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -880,7 +895,7 @@ if (tty_mode & TM_KBD) { /* keyboard enabled? */ tty_buf = c; /* put char in buf */ uptr->pos = uptr->pos + 1; - ttyio (tty_dib.devno, ioENF, 0); /* set flag */ + ttyio (&tty_dib, ioENF, 0); /* set flag */ if (c) { tto_out (c); /* echo? */ @@ -907,7 +922,7 @@ if ((r = tto_out (c)) != SCPE_OK) { /* output; error? */ return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ } -ttyio (tty_dib.devno, ioENF, 0); /* set flag */ +ttyio (&tty_dib, ioENF, 0); /* set flag */ return ttp_out (c); /* punch if enabled */ } @@ -932,7 +947,7 @@ t_stat ttp_out (int32 c) { if (tty_mode & TM_PUN) { /* punching? */ if ((tty_unit[TTP].flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ttp_stopioe, SCPE_UNATT); + return IOERROR (ttp_stopioe, SCPE_UNATT); if (putc (c, tty_unit[TTP].fileref) == EOF) { /* output char */ perror ("TTP I/O error"); clearerr (tty_unit[TTP].fileref); @@ -948,10 +963,10 @@ return SCPE_OK; t_stat tty_reset (DEVICE *dptr) { -if (sim_switches & SWMASK ('P')) /* PON reset? */ +if (sim_switches & SWMASK ('P')) /* initialization reset? */ tty_buf = 0; /* clear buffer */ -ttyio (tty_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&tty_dib); /* PRESET device (does not use PON) */ tty_unit[TTI].wait = POLL_WAIT; /* reset initial poll */ sim_rtcn_init (tty_unit[TTI].wait, TMR_POLL); /* init poll timer */ @@ -1024,105 +1039,105 @@ int32 poll_time; expected. */ -uint32 clkio (uint32 select_code, IOSIG signal, uint32 data) +uint32 clkio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -switch (base_signal) { /* dispatch base I/O signal */ +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ - case ioCLF: /* clear flag flip-flop */ - clk_flag = clk_flagbuf = CLEAR; - break; + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + clk.flag = clk.flagbuf = CLEAR; + break; - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - clk_flag = clk_flagbuf = SET; - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + clk.flag = clk.flagbuf = SET; + break; - case ioSFC: /* skip if flag is clear */ - setstdSKF (clk); - break; + case ioSFC: /* skip if flag is clear */ + setstdSKF (clk); + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (clk); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (clk); + break; - case ioIOI: /* I/O data input */ - data = clk_error; - break; + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, clk_error); /* merge in return status */ + break; - case ioIOO: /* I/O data output */ - clk_select = data & 07; /* save select */ - sim_cancel (&clk_unit); /* stop the clock */ - clk_control = CLEAR; /* clear control */ - clkio (select_code, ioSIR, 0); /* set interrupt request (IOO normally doesn't) */ - break; + case ioIOO: /* I/O data output */ + clk_select = IODATA (stat_data) & 07; /* save select */ + sim_cancel (&clk_unit); /* stop the clock */ + clk.control = CLEAR; /* clear control */ + working_set = working_set | ioSIR; /* set interrupt request (IOO normally doesn't) */ + break; - case ioPOPIO: /* power-on preset to I/O */ - clk_flag = clk_flagbuf = SET; /* set flag and flag buffer */ - /* fall into CRS handler */ - - case ioCRS: /* control reset */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - clk_control = CLEAR; - sim_cancel (&clk_unit); /* deactivate unit */ - break; + case ioPOPIO: /* power-on preset to I/O */ + clk.flag = clk.flagbuf = SET; /* set flag and flag buffer */ + break; - case ioSTC: /* set control flip-flop */ - clk_control = SET; - if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ - clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */ - else - clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */ - - if (!sim_is_active (&clk_unit)) { /* clock running? */ - clk_tick = clk_delay (0); /* get tick count */ - - if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */ - if (clk_select == 2) /* 10 msec. interval? */ - clk_tick = sync_poll (INITIAL); /* sync poll */ - else - sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */ - - sim_activate (&clk_unit, clk_tick); /* start clock */ - clk_ctr = clk_delay (1); /* set repeat ctr */ - } - clk_error = 0; /* clear error */ - break; + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + clk.control = CLEAR; + sim_cancel (&clk_unit); /* deactivate unit */ + break; - case ioSIR: /* set interrupt request */ - setstdPRL (select_code, clk); /* set standard PRL signal */ - setstdIRQ (select_code, clk); /* set standard IRQ signal */ - setstdSRQ (select_code, clk); /* set standard SRQ signal */ - break; + case ioSTC: /* set control flip-flop */ + clk.control = SET; + if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ + clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */ + else + clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */ + + if (!sim_is_active (&clk_unit)) { /* clock running? */ + clk_tick = clk_delay (0); /* get tick count */ + + if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */ + if (clk_select == 2) /* 10 msec. interval? */ + clk_tick = sync_poll (INITIAL); /* sync poll */ + else + sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */ + + sim_activate (&clk_unit, clk_tick); /* start clock */ + clk_ctr = clk_delay (1); /* set repeat ctr */ + } + clk_error = 0; /* clear error */ + break; - case ioIAK: /* interrupt acknowledge */ - clk_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + setstdPRL (clk); /* set standard PRL signal */ + setstdIRQ (clk); /* set standard IRQ signal */ + setstdSRQ (clk); /* set standard SRQ signal */ + break; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + clk.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ } - -if (signal > ioCLF) /* multiple signals? */ - clkio (select_code, ioCLF, 0); /* issue CLF */ -else if (signal > ioSIR) /* signal affected interrupt status? */ - clkio (select_code, ioSIR, 0); /* set interrupt request */ - -return data; +return stat_data; } @@ -1134,7 +1149,7 @@ return data; t_stat clk_svc (UNIT *uptr) { -if (!clk_control) /* control clear? */ +if (!clk.control) /* control clear? */ return SCPE_OK; /* done */ if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ @@ -1147,10 +1162,10 @@ else sim_activate (uptr, clk_tick); /* reactivate */ clk_ctr = clk_ctr - 1; /* decrement counter */ if (clk_ctr <= 0) { /* end of interval? */ - if (clk_flag) + if (clk.flag) clk_error = CLK_ERROR; /* overrun? error */ else - clkio (clk_dib.devno, ioENF, 0); /* set flag */ + clkio (&clk_dib, ioENF, 0); /* set flag */ clk_ctr = clk_delay (1); /* reset counter */ } return SCPE_OK; @@ -1161,13 +1176,13 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { -if (sim_switches & SWMASK ('P')) { /* PON reset? */ +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ clk_error = 0; /* clear error */ clk_select = 0; /* clear select */ clk_ctr = 0; /* clear counter */ } -clkio (clk_dib.devno, ioPOPIO, 0); /* send POPIO signal */ +IOPRESET (&clk_dib); /* PRESET device (does not use PON) */ return SCPE_OK; } diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index 98e0e76d..044c2825 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-2008, Robert M. Supnik + Copyright (c) 1993-2010, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation + 26-Oct-10 JDB Changed DIB access for revised signal model 03-Sep-08 JDB Fixed IAK instruction dual-use mnemonic display 07-Aug-08 JDB Moved hp_setdev, hp_showdev from hp2100_cpu.c Changed sim_load to use WritePW instead of direct M[] access @@ -60,7 +62,7 @@ extern UNIT cpu_unit; extern REG cpu_reg[]; extern DEVICE mp_dev; -extern DEVICE dma0_dev, dma1_dev; +extern DEVICE dma1_dev, dma2_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tty_dev, clk_dev; extern DEVICE lps_dev; @@ -98,8 +100,7 @@ int32 sim_emax = 3; DEVICE *sim_devices[] = { &cpu_dev, &mp_dev, - &dma0_dev, - &dma1_dev, + &dma1_dev, &dma2_dev, &ptr_dev, &ptp_dev, &tty_dev, @@ -772,18 +773,18 @@ else { /* printable character * t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) { DEVICE *dptr = (DEVICE *) desc; -DIB *dibp; +DIB *dibptr; int32 i, newdev; t_stat r; if (cptr == NULL) return SCPE_ARG; if ((desc == NULL) || (num > 1)) return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) return SCPE_IERR; +dibptr = (DIB *) dptr->ctxt; +if (dibptr == NULL) return SCPE_IERR; newdev = get_uint (cptr, 8, I_DEVMASK - num, &r); if (r != SCPE_OK) return r; if (newdev < VARDEV) return SCPE_ARG; -for (i = 0; i <= num; i++, dibp++) dibp->devno = newdev + i; +for (i = 0; i <= num; i++, dibptr++) dibptr->select_code = newdev + i; return SCPE_OK; } @@ -793,13 +794,13 @@ return SCPE_OK; t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc) { DEVICE *dptr = (DEVICE *) desc; -DIB *dibp; +DIB *dibptr; int32 i; if ((desc == NULL) || (num > 1)) return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) return SCPE_IERR; -fprintf (st, "devno=%o", dibp->devno); -for (i = 1; i <= num; i++) fprintf (st, "/%o", dibp->devno + i); +dibptr = (DIB *) dptr->ctxt; +if (dibptr == NULL) return SCPE_IERR; +fprintf (st, "devno=%o", dibptr->select_code); +for (i = 1; i <= num; i++) fprintf (st, "/%o", dibptr->select_code + i); return SCPE_OK; } diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index b07d272f..71d49610 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -266,6 +266,7 @@ REG cpu_reg[] = { { FLDATA (IOCHK, iochk, 0) }, { FLDATA (PRCHK, prchk, 0) }, { FLDATA (HBPEND, hb_pend, 0) }, + { BRDATA (IND, ind, 8, 32, 64), REG_HIDDEN + PV_LEFT }, { BRDATA (ISQ, pcq, 10, 14, PCQ_SIZE), REG_RO+REG_CIRC }, { DRDATA (ISQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c index 2d299e4d..e0fa7eb9 100644 --- a/I1401/i1401_iq.c +++ b/I1401/i1401_iq.c @@ -93,8 +93,8 @@ ind[IN_INC] = 0; /* clear inq clear */ switch (mod) { /* case on mod */ case BCD_R: /* input */ -/* if (ind[IN_INR] == 0) /* return if no req */ - return SCPE_OK; +/* if (ind[IN_INR] == 0) +/* return SCPE_OK; /* return if no req */ ind[IN_INR] = 0; /* clear req */ puts_tty ("[Enter]\r\n"); /* prompt */ for (i = 0; M[BS] != (BCD_GRPMRK + WM); i++) { /* until GM + WM */ diff --git a/I7094/i7094_clk.c b/I7094/i7094_clk.c index f516819a..d3020093 100644 --- a/I7094/i7094_clk.c +++ b/I7094/i7094_clk.c @@ -1,6 +1,6 @@ /* i7094_clk.c: IBM 7094 clock - Copyright (c) 2003-2008, Robert M. Supnik + Copyright (c) 2003-2011, Robert 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 @@ clk RPQ F89349 interval timer Chronolog calendar clock + + 25-Mar-11 RMS According to RPQ, clock clears on RESET */ #include "i7094_defs.h" @@ -68,9 +70,9 @@ t_uint64 ctr; if ((clk_dev.flags & DEV_DIS) == 0) { /* clock enabled? */ ctr = ReadP (CLK_CTR); - ctr = (ctr + 1) & DMASK; /* increment */ + ctr = (ctr + 1) & MMASK; /* increment */ WriteP (CLK_CTR, ctr); - if ((ctr & MMASK) == 0) /* overflow? req trap */ + if (ctr == 0) /* overflow? req trap */ chtr_clk = 1; sim_activate (uptr, sim_rtcn_calb (CLK_TPS, TMR_CLK)); /* reactivate unit */ } @@ -126,6 +128,9 @@ t_stat clk_reset (DEVICE *dptr) chtr_clk = 0; if (clk_dev.flags & DEV_DIS) sim_cancel (&clk_unit); -else sim_activate (&clk_unit, sim_rtcn_init (clk_unit.wait, TMR_CLK)); +else { + sim_activate (&clk_unit, sim_rtcn_init (clk_unit.wait, TMR_CLK)); + WriteP (CLK_CTR, 0); + } return SCPE_OK; } diff --git a/I7094/i7094_com_old.c b/I7094/i7094_com_old.c deleted file mode 100644 index 4a665453..00000000 --- a/I7094/i7094_com_old.c +++ /dev/null @@ -1,1179 +0,0 @@ -/* i7094_com.c: IBM 7094 7750 communications interface simulator - - Copyright (c) 2005-2008, Robert 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. - - com 7750 controller - coml 7750 lines - - 19-Nov-2008 RMS Revised for common TMXR show routines - - This module implements an abstract simulator for the IBM 7750 communications - computer as used by the CTSS system. The 7750 supports up to 112 lines; - the simulator supports 33. The 7750 can handle both high-speed lines, in - 6b and 12b mode, and normal terminals, in 12b mode only; the simulator - supports only terminals. The 7750 can handle many different kinds of - terminals; the simulator supports only a limited subset. - - Input is asynchronous. The 7750 sets ATN1 to signal availability of input. - When the 7094 issues a CTLRN, the 7750 gathers available input characters - into a message. The message has a 12b sequence number, followed by 12b line - number/character pairs, followed by end-of-medium (03777). Input characters - can either be control characters (bit 02000 set) or data characters. Data - characters are 1's complemented and are 8b wide: 7 data bits and 1 parity - bit (which may be 0). - - Output is synchronous. When the 7094 issues a CTLWN, the 7750 interprets - the channel output as a message. The message has a 12b line number, followed - by a 12b character count, followed by characters, followed by end-of-medium. - If bit 02000 of the line number is set, the characters are 12b wide. If - bit 01000 is set, the message is a control message. 12b characters consist - of 7 data bits, 1 parity bit, and 1 start bit. Data characters are 1's - complemented. Data character 03777 is special and causes the 7750 to - repeat the previous bit for the number of bit times specified in the next - character. This is used to generate delays for positioning characters. - - The 7750 supports flow control for output. To help the 7094 account for - usage of 7750 buffer memory, the 7750 sends 'character output completion' - messages for every 'n' characters output on a line, where n <= 31. - - Note that the simulator console is mapped in as line n+1. -*/ - -#include "i7094_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" -#include - -#define COM_MLINES 32 /* mux lines */ -#define COM_TLINES (COM_MLINES + 1) /* total lines */ -#define COM_BUFSIZ 120 /* max chan transfer */ -#define COM_PKTSIZ 16384 /* character buffer */ - -#define UNIT_V_2741 (TTUF_V_UF + 0) /* 2741 - ni */ -#define UNIT_V_K35 (TTUF_V_UF + 1) /* KSR-35 */ -#define UNIT_2741 (1 << UNIT_V_2741) -#define UNIT_K35 (1 << UNIT_V_K35) - -#define CONN u3 /* line is connected */ -#define NEEDID u4 /* need to send ID */ - -#define COM_INIT_POLL 8000 /* polling interval */ -#define COMC_WAIT 2 /* channel delay time */ -#define COML_WAIT 1000 /* char delay time */ -#define COM_LBASE 4 /* start of lines */ - -/* Input threads */ - -#define COM_PLU 0 /* multiplexor poll */ -#define COM_CIU 1 /* console input */ -#define COM_CHU 2 /* channel transfer */ -#define COM_SNS 3 /* sense transfer */ - -/* Communications input */ - -#define COMI_VALIDL 02000 /* valid line flag */ -#define COMI_PARITY 00200 /* parity bit */ -#define COMI_DIALUP 02001 /* dialup */ -#define COMI_ENDID 02002 /* end ID */ -#define COMI_INTR 02003 /* interrupt */ -#define COMI_QUIT 02004 /* quit */ -#define COMI_HANGUP 02005 /* hangup */ -#define COMI_EOM 03777 /* end of medium */ -#define COMI_COMP(x) ((uint16) (03000 + ((x) & COMI_CMAX))) -#define COMI_K35 1 /* KSR-35 ID */ -#define COMI_K37 7 /* KSR-37 ID */ -#define COMI_2741 8 /* 2741 ID */ -#define COMI_CMAX 31 /* max chars returned */ -#define COMI_BMAX 50 /* buffer max, words */ -#define COMI_12BMAX ((3 * COMI_BMAX) - 1) /* last 12b char */ - -/* Communications output */ - -#define COMO_LIN12B 0200000000000 /* line is 12b */ -#define COMO_LINCTL 0100000000000 /* control msg */ -#define COMO_GETLN(x) (((uint32) ((x) >> 24)) & 0777) -#define COMO_CTLRST 0000077770000 /* control reset */ -#define COMO_BITRPT 03777 /* bit repeat */ -#define COMO_EOM12B 07777 /* end of medium */ -#define COMO_BMAX 94 /* buffer max, words */ -#define COMO_12BMAX ((3 * COMO_BMAX) - 1) - -/* Status word (60b) */ - -#define COMS_PCHK 004000000000000000000 /* prog check */ -#define COMS_DCHK 002000000000000000000 /* data check */ -#define COMS_EXCC 001000000000000000000 /* exc cond */ -#define COMS_MLNT 000040000000000000000 /* message length check */ -#define COMS_CHNH 000020000000000000000 /* channel hold */ -#define COMS_CHNQ 000010000000000000000 /* channel queue full */ -#define COMS_ITMO 000000100000000000000 /* interface timeout */ -#define COMS_DATR 000000004000000000000 /* data message ready */ -#define COMS_INBF 000000002000000000000 /* input buffer free */ -#define COMS_SVCR 000000001000000000000 /* service message ready */ -#define COMS_PALL 000000000000000000000 -#define COMS_DALL 000000000000000000000 -#define COMS_EALL 000000000000000000000 -#define COMS_DYN 000000007000000000000 - -/* Report variables */ - -#define COMR_FQ 1 /* free queue */ -#define COMR_IQ 2 /* input queue */ -#define COMR_OQ 4 /* output queue */ - -/* List heads and entries */ - -typedef struct { - uint16 head; - uint16 tail; - } LISTHD; - -typedef struct { - uint16 next; - uint16 data; - } LISTENT; - -/* The 7750 character buffer is maintained as linked lists. The lists are: - - free free list - inpq input queue - outq[ln] output queue for line ln - - The input queue has two entries for each character; the first is the - line number, the second the character. The output queues have only - one entry for each character. - - Links are done as subscripts in array com_pkt. This allows the list - headers and the queues themselves to be saved and restored. */ - -uint32 com_ch = CH_E; /* saved channel */ -uint32 com_enab = 0; /* 7750 enabled */ -uint32 com_msgn = 0; /* next input msg num */ -uint32 com_sta = 0; /* 7750 state */ -uint32 com_stop = 0; /* channel stop */ -uint32 com_quit = 0; /* quit code */ -uint32 com_intr = 0; /* interrupt code */ -uint32 com_bptr = 0; /* buffer pointer */ -uint32 com_blim = 0; /* buffer count */ -uint32 com_tps = 50; /* polls/second */ -uint32 com_not_ret[COM_TLINES] = { 0 }; /* chars not returned */ -t_uint64 com_sns = 0; /* sense word */ -t_uint64 com_chob = 0; /* chan output buf */ -uint32 com_chob_v = 0; /* valid flag */ -t_uint64 com_buf[COM_BUFSIZ]; /* channel buffer */ -LISTHD com_free; /* free list */ -LISTHD com_inpq; /* input queue */ -LISTHD com_outq[COM_TLINES]; /* output queue */ -LISTENT com_pkt[COM_PKTSIZ]; /* character packets */ -TMLN com_ldsc[COM_MLINES] = { 0 }; /* line descriptors */ -TMXR com_desc = { COM_MLINES, 0, 0, com_ldsc }; /* mux descriptor */ - -/* Even parity truth table */ - -static const uint8 com_epar[128] = { - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1 - }; - -extern uint32 ch_req; - -t_stat com_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat com_chwr (uint32 ch, t_uint64 val, uint32 flags); -t_stat comi_svc (UNIT *uptr); -t_stat comc_svc (UNIT *uptr); -t_stat como_svc (UNIT *uptr); -t_stat coms_svc (UNIT *uptr); -t_stat comti_svc (UNIT *uptr); -t_stat comto_svc (UNIT *uptr); -t_stat com_reset (DEVICE *dptr); -t_stat com_attach (UNIT *uptr, char *cptr); -t_stat com_detach (UNIT *uptr); -t_stat com_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_freeq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_inq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_aoutq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_outq (FILE *st, UNIT *uptr, int32 val, void *desc); -void com_reset_ln (uint32 i); -uint16 com_gethd_free (LISTHD *lh); -uint16 com_gethd (LISTHD *lh); -t_bool com_new_puttl (LISTHD *lh, uint16 val); -void com_puttl (LISTHD *lh, uint16 ent); -t_bool com_inp_msg (uint32 ln, uint16 msg); -void com_skip_outc (uint32 ln); -t_stat com_test_atn (uint32 ch); -t_uint64 com_getob (uint32 ch); -t_bool com_qdone (uint32 ch); -void com_end (uint32 ch, uint32 fl, uint32 st); -t_stat com_send_id (uint32 ln); -t_stat com_send_ccmp (uint32 ln); -t_stat com_queue_in (uint32 ln, uint32 ch); -uint32 com_queue_out (uint32 ln, uint32 *c1); -void com_set_sns (t_uint64 stat); - -/* COM data structures - - com_dev COM device descriptor - com_unit COM unit descriptor - com_reg COM register list - com_mod COM modifiers list -*/ - -DIB com_dib = { &com_chsel, &com_chwr }; - -UNIT com_unit[] = { - { UDATA (&comi_svc, UNIT_ATTABLE, 0), COM_INIT_POLL }, - { UDATA (&comti_svc, UNIT_DIS, 0), KBD_POLL_WAIT }, - { UDATA (&comc_svc, UNIT_DIS, 0), COMC_WAIT }, - { UDATA (&coms_svc, UNIT_DIS, 0), COMC_WAIT } - }; - -REG com_reg[] = { - { FLDATA (ENABLE, com_enab, 0) }, - { ORDATA (STATE, com_sta, 6) }, - { ORDATA (MSGNUM, com_msgn, 12) }, - { ORDATA (SNS, com_sns, 60) }, - { ORDATA (CHOB, com_chob, 36) }, - { FLDATA (CHOBV, com_chob_v, 0) }, - { FLDATA (STOP, com_stop, 0) }, - { BRDATA (BUF, com_buf, 8, 36, COM_BUFSIZ) }, - { DRDATA (BPTR, com_bptr, 7), REG_RO }, - { DRDATA (BLIM, com_blim, 7), REG_RO }, - { BRDATA (NRET, com_not_ret, 10, 32, COM_TLINES), REG_RO + PV_LEFT }, - { BRDATA (FREEQ, &com_free, 10, 16, 2) }, - { BRDATA (INPQ, &com_inpq, 10, 16, 2) }, - { BRDATA (OUTQ, com_outq, 10, 16, 2 * COM_TLINES) }, - { BRDATA (PKTB, com_pkt, 10, 16, 2 * COM_PKTSIZ) }, - { DRDATA (TTIME, com_unit[COM_CIU].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (WTIME, com_unit[COM_CHU].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (CHAN, com_ch, 3), REG_HRO }, - { NULL } - }; - -MTAB com_mod[] = { - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &com_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &com_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &com_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_FQ, "FREEQ", NULL, - NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_IQ, "INQ", NULL, - NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_OQ, "OUTQ", NULL, - NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, -1, "ALL", NULL, - NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "OUTQ", NULL, - NULL, &com_show_outq, 0 }, - { 0 } - }; - -DEVICE com_dev = { - "COM", com_unit, com_reg, com_mod, - 3, 10, 31, 1, 16, 8, - &tmxr_ex, &tmxr_dep, &com_reset, - NULL, &com_attach, &com_detach, - &com_dib, DEV_NET | DEV_DIS - }; - -/* COML data structures - - coml_dev COML device descriptor - coml_unit COML unit descriptor - coml_reg COML register list - coml_mod COML modifiers list -*/ - -UNIT coml_unit[] = { - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&comto_svc, 0, 0), COML_WAIT }, - }; - -MTAB coml_mod[] = { - { UNIT_K35+UNIT_2741, 0 , "KSR-37", "KSR-37", NULL }, - { UNIT_K35+UNIT_2741, UNIT_K35 , "KSR-35", "KSR-35", NULL }, -// { UNIT_K35+UNIT_2741, UNIT_2741, "2741", "2741", NULL }, - { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, (void *) &com_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", - &tmxr_set_log, &tmxr_show_log, (void*) &com_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", - &tmxr_set_nolog, NULL, (void *) &com_desc }, - { 0 } - }; - -REG coml_reg[] = { - { URDATA (TIME, coml_unit[0].wait, 10, 24, 0, - COM_TLINES, REG_NZ + PV_LEFT) }, - { NULL } - }; - -DEVICE coml_dev = { - "COML", coml_unit, coml_reg, coml_mod, - COM_TLINES, 10, 31, 1, 16, 8, - NULL, NULL, &com_reset, - NULL, NULL, NULL, - NULL, DEV_DIS - }; - -/* COM: channel select */ - -t_stat com_chsel (uint32 ch, uint32 sel, uint32 unit) -{ -com_ch = ch; /* save channel */ -if (sim_is_active (&com_unit[COM_CHU]) || /* not idle? */ - sim_is_active (&com_unit[COM_SNS])) { - com_end (ch, CHINT_SEQC, 0); /* end, seq check */ - return SCPE_OK; - } - -switch (sel) { /* case on select */ - - case CHSL_RDS: /* read */ - case CHSL_WRS: /* write */ - com_sns = 0; /* clear status */ - sim_activate (&com_unit[COM_CHU], com_unit[COM_CHU].wait); - break; - - case CHSL_SNS: /* sense */ - sim_activate (&com_unit[COM_SNS], com_unit[COM_SNS].wait); - break; - - case CHSL_CTL: /* control */ - default: /* other */ - return STOP_ILLIOP; - } - -com_stop = 0; /* clear stop */ -com_sta = sel; /* set initial state */ -return SCPE_OK; -} - -/* Channel write, from 7909 channel program */ - -t_stat com_chwr (uint32 ch, t_uint64 val, uint32 stopf) -{ -if (stopf) - com_stop = 1; -else { - com_chob = val; /* store data */ - com_chob_v = 1; /* set valid */ - } -return SCPE_OK; -} - -/* Unit service - SNS */ - -t_stat coms_svc (UNIT *uptr) -{ -t_uint64 dat; - -switch (com_sta) { /* case on state */ - - case CHSL_SNS: /* prepare data */ - com_sns &= ~COMS_DYN; /* clear dynamic flags */ - if (com_free.head) /* free space? */ - com_set_sns (COMS_INBF); - if (com_inpq.head) /* pending input? */ - com_set_sns (COMS_DATR); - com_buf[0] = (com_sns >> 24) & DMASK; /* buffer is 2 words */ - com_buf[1] = (com_sns << 12) & DMASK; - com_bptr = 0; - com_blim = 2; - com_sta = CHSL_SNS|CHSL_2ND; /* 2nd state */ - break; - - case CHSL_SNS|CHSL_2ND: /* second state */ - if (com_bptr >= com_blim) { /* end of buffer? */ - ch9_set_end (com_ch, 0); /* set end */ - ch_req |= REQ_CH (com_ch); /* request channel */ - com_sta = CHSL_SNS|CHSL_3RD; /* 3rd state */ - sim_activate (uptr, 10 * uptr->wait); /* longer wait */ - return SCPE_OK; - } - dat = com_buf[com_bptr++]; /* get word */ - if (!com_stop) /* send wd to chan */ - ch9_req_rd (com_ch, dat); - break; - - case CHSL_SNS|CHSL_3RD: /* 3rd state */ - if (com_qdone (com_ch)) /* done? exit */ - return SCPE_OK; - com_sta = CHSL_SNS; /* repeat sequence */ - break; - } - -sim_activate (uptr, uptr->wait); /* sched next */ -return SCPE_OK; -} - -/* Unit service - channel program */ - -t_stat comc_svc (UNIT *uptr) -{ -uint32 i, j, k, ccnt, ln, uln, ent; -uint16 chr; -t_uint64 dat; - -switch (com_sta) { /* case on state */ - - case CHSL_RDS: /* read start */ - for (i = 0; i < COM_BUFSIZ; i++) /* clear chan buf */ - com_buf[i] = 0; - com_buf[0] = com_msgn; /* 1st char is msg num */ - com_msgn = (com_msgn + 1) & 03777; /* incr msg num */ - for (i = 1, j = 0; i < COMI_12BMAX; i++) { /* fill buffer */ - ent = com_gethd_free (&com_inpq); /* get next entry */ - if (ent == 0) /* q empty, done */ - break; - if ((i % 3) == 0) /* next word? */ - j++; - com_buf[j] = (com_buf[j] << 12) | /* pack data */ - ((t_uint64) (com_pkt[ent].data & 07777)); - } - for (k = i % 3; k < 3; k++) { /* fill with EOM */ - if (k == 0) /* next word? */ - j++; - com_buf[j] = (com_buf[j] << 12) | COMI_EOM; - } - com_bptr = 0; /* init buf ptr */ - com_blim = j + 1; /* save buf size */ - com_sta = CHSL_RDS|CHSL_2ND; /* next state */ - break; - - case CHSL_RDS|CHSL_2ND: /* read xmit word */ - if (com_bptr >= com_blim) /* transfer done? */ - com_end (com_ch, 0, CHSL_RDS|CHSL_3RD); /* end, next state */ - else { /* more to do */ - dat = com_buf[com_bptr++]; /* get word */ - if (!com_stop) /* give to channel */ - ch9_req_rd (com_ch, dat); - } - break; - - case CHSL_RDS|CHSL_3RD: /* read end */ - if (com_qdone (com_ch)) /* done? */ - return com_test_atn (com_ch); /* test atn, exit */ - com_sta = CHSL_RDS; /* repeat sequence */ - break; - - case CHSL_WRS: /* write start */ - for (i = 0; i < COM_BUFSIZ; i++) /* clear chan buf */ - com_buf[i] = 0; - com_bptr = 0; /* init buf ptr */ - com_sta = CHSL_WRS|CHSL_2ND; /* next state */ - ch_req |= REQ_CH (com_ch); /* request channel */ - com_chob = 0; /* clr, inval buf */ - com_chob_v = 0; - break; - - case CHSL_WRS|CHSL_2ND: /* write first word */ - dat = com_getob (com_ch); /* get word? */ - if (dat == 0777777777777) { /* turn on? */ - com_enab = 1; /* enable 7750 */ - com_msgn = 0; /* init message # */ - com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */ - } - else if (dat & COMO_LINCTL) { /* control message? */ - ln = COMO_GETLN (dat); /* line number */ - if (ln >= (COM_TLINES + COM_LBASE)) /* invalid line? */ - return STOP_INVLIN; - if (dat & COMO_CTLRST) /* char must be 0 */ - return STOP_INVMSG; - if (ln >= COM_LBASE) - com_reset_ln (ln - COM_LBASE); - com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */ - } - else { /* data message */ - ccnt = (((uint32) dat >> 12) & 07777) + 1; /* char count plus EOM */ - if (dat & COMO_LIN12B) /* 12b? double */ - ccnt = ccnt << 1; - com_blim = (ccnt + 6 + 5) / 6; /* buffer limit */ - if ((com_blim == 1) || (com_blim >= COMO_BMAX)) - return STOP_INVMSG; - com_buf[com_bptr++] = dat; /* store word */ - com_sta = CHSL_WRS|CHSL_3RD; /* next state */ - ch_req |= REQ_CH (com_ch); /* request channel */ - } - break; - - case CHSL_WRS|CHSL_3RD: /* other words */ - dat = com_getob (com_ch); /* get word */ - com_buf[com_bptr++] = dat; /* store word */ - if (com_bptr >= com_blim) { /* transfer done? */ - ln = COMO_GETLN (com_buf[0]); /* line number */ - if (ln >= (COM_TLINES + COM_LBASE)) /* invalid line? */ - return STOP_INVLIN; - if ((com_buf[0] & COMO_LIN12B) && /* 12b message? */ - (ln >= COM_LBASE)) { - uln = ln - COM_LBASE; /* unit number */ - for (i = 2, j = 0; i < COMO_12BMAX; i++) { /* unpack 12b char */ - if ((i % 3) == 0) - j++; - chr = (uint16) (com_buf[j] >> ((2 - (i % 3)) * 12)) & 07777; - if (chr == COMO_EOM12B) /* EOM? */ - break; - if (!com_new_puttl (&com_outq[uln], chr)) - return STOP_NOOFREE; /* append to outq */ - } - sim_activate (&coml_unit[uln], coml_unit[uln].wait); - } - com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */ - } - else if (!com_stop) /* request channel */ - ch_req |= REQ_CH (com_ch); - break; - - case CHSL_WRS|CHSL_4TH: /* buffer done */ - if (com_qdone (com_ch)) /* done? */ - return com_test_atn (com_ch); /* test atn, exit */ - com_sta = CHSL_WRS; /* repeat sequence */ - break; - - default: - return SCPE_IERR; - } - -sim_activate (uptr, uptr->wait); -return SCPE_OK; -} - -/* Unit service - console receive - always running, even if device is not */ - -t_stat comti_svc (UNIT *uptr) -{ -int32 c; -t_stat r; - -sim_activate (uptr, uptr->wait); /* continue poll */ -c = sim_poll_kbd (); /* get character */ -if (c && !(c & (SCPE_BREAK|SCPE_KFLAG))) /* error? */ - return c; -if (!com_enab || (c & SCPE_BREAK)) /* !enab, break? done */ - return SCPE_OK; -if (coml_unit[COM_MLINES].NEEDID) /* ID needed? */ - return com_send_id (COM_MLINES); -if ((c & SCPE_KFLAG) && ((c = c & 0177) != 0)) { /* char input? */ - if (r = com_queue_in (COM_MLINES, c)) - return r; - if (sim_tt_outcvt (c, TT_MODE_7P) >= 0) - sim_putchar (c); - if (c == '\r') - sim_putchar ('\n'); - } -return com_test_atn (com_ch); /* set ATN if input */ -} - -/* Unit service - receive side - - Poll all active lines for input - Poll for new connections */ - -t_stat comi_svc (UNIT *uptr) -{ -int32 c, ln, t; -t_stat r; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_OK; -t = sim_rtcn_calb (com_tps, TMR_COM); /* calibrate */ -sim_activate (uptr, t); /* continue poll */ -if (!com_enab) /* not enabled? exit */ - return SCPE_OK; -ln = tmxr_poll_conn (&com_desc); /* look for connect */ -if (ln >= 0) { /* got one? */ - com_ldsc[ln].rcve = 1; /* rcv enabled */ - coml_unit[ln].CONN = 1; /* flag connected */ - coml_unit[ln].NEEDID = 1; /* need ID */ - } -tmxr_poll_rx (&com_desc); /* poll for input */ -for (ln = 0; ln < COM_MLINES; ln++) { /* loop thru mux */ - if (com_ldsc[ln].conn) { /* connected? */ - if (coml_unit[ln].NEEDID) - return com_send_id (ln); - c = tmxr_getc_ln (&com_ldsc[ln]); /* get char */ - if (c) { /* any char? */ - c = c & 0177; /* mask to 7b */ - if (r = com_queue_in (ln, c)) /* queue char, err? */ - return r; - if (com_ldsc[ln].xmte) { /* output enabled? */ - if (sim_tt_outcvt (c, TT_MODE_7P) >= 0) /* echo char */ - tmxr_putc_ln (&com_ldsc[ln], c); - if (c == '\r') /* add LF after CR */ - tmxr_putc_ln (&com_ldsc[ln], '\n'); - tmxr_poll_tx (&com_desc); /* poll xmt */ - } /* end if enabled */ - } /* end if char */ - } /* end if conn */ - else if (coml_unit[ln].CONN) { /* not conn, was conn? */ - coml_unit[ln].CONN = 0; /* clear connected */ - coml_unit[ln].NEEDID = 0; /* clear need id */ - if (!com_inp_msg (ln, COMI_HANGUP)) /* hangup message */ - return STOP_NOIFREE; - } - } /* end for */ -return com_test_atn (com_ch); /* set ATN if input */ -} - -/* Unit service - console transmit */ - -t_stat comto_svc (UNIT *uptr) -{ -uint32 c, c1; - -if (com_outq[COM_MLINES].head == 0) /* no more characters? */ - return com_send_ccmp (COM_MLINES); /* free any remaining */ -c = com_queue_out (COM_MLINES, &c1); /* get character, cvt */ -if (c) /* printable? output */ - sim_putchar (c); -if (c1) /* second char? output */ - sim_putchar (c1); -sim_activate (uptr, uptr->wait); /* next char */ -if (com_not_ret[COM_MLINES] >= COMI_CMAX) /* completion needed? */ - return com_send_ccmp (COM_MLINES); /* generate msg */ -return SCPE_OK; -} - -/* Unit service - transmit side */ - -t_stat como_svc (UNIT *uptr) -{ -uint32 c, c1; -int32 ln = uptr - coml_unit; /* line # */ - -if (com_outq[ln].head == 0) /* no more characters? */ - return com_send_ccmp (ln); /* free any remaining */ -if (com_ldsc[ln].conn) { /* connected? */ - if (com_ldsc[ln].xmte) { /* output enabled? */ - c = com_queue_out (ln, &c1); /* get character, cvt */ - if (c) /* printable? output */ - tmxr_putc_ln (&com_ldsc[ln], c); - if (c1) /* print second */ - tmxr_putc_ln (&com_ldsc[ln], c1); - } /* end if */ - tmxr_poll_tx (&com_desc); /* poll xmt */ - sim_activate (uptr, uptr->wait); /* next char */ - if (com_not_ret[ln] >= COMI_CMAX) /* completion needed? */ - return com_send_ccmp (ln); /* generate msg */ - } /* end if conn */ -return SCPE_OK; -} - -/* Send ID sequence on input */ - -t_stat com_send_id (uint32 ln) -{ -com_inp_msg (ln, COMI_DIALUP); /* input message: */ -if (coml_unit[ln].flags & UNIT_K35) /* dialup, ID, endID */ - com_inp_msg (ln, COMI_K35); -else com_inp_msg (ln, COMI_K37); -com_inp_msg (ln, 0); -com_inp_msg (ln, 0); -com_inp_msg (ln, 0); -com_inp_msg (ln, 0); -com_inp_msg (ln, (uint16) (ln + COM_LBASE)); -if (!com_inp_msg (ln, COMI_ENDID)) /* make sure there */ - return STOP_NOIFREE; /* was room for msg */ -coml_unit[ln].NEEDID = 0; -return SCPE_OK; -} - -/* Translate and queue input character */ - -t_stat com_queue_in (uint32 ln, uint32 c) -{ -uint16 out; - -if (c == com_intr) - out = COMI_INTR; -else if (c == com_quit) - out = COMI_QUIT; -else { - if (coml_unit[ln].flags & UNIT_K35) { /* KSR-35? */ - if (islower (c)) /* convert LC to UC */ - c = toupper (c); - } - else c |= (com_epar[c]? COMI_PARITY: 0); /* add even parity */ - out = (~c) & 0377; /* 1's complement */ - } -if (!com_inp_msg (ln, out)) /* input message */ - return STOP_NOIFREE; -return SCPE_OK; -} - -/* Retrieve and translate output character */ - -uint32 com_queue_out (uint32 ln, uint32 *c1) -{ -uint32 c, ent, raw; - -*c1 = 0; /* assume non-printing */ -ent = com_gethd_free (&com_outq[ln]); /* get character */ -if (ent == 0) /* nothing? */ - return 0; -raw = com_pkt[ent].data; /* get 12b character */ -com_not_ret[ln]++; -if (raw == COMO_BITRPT) { /* insert delay? */ - com_skip_outc (ln); - return 0; - } -c = (~raw >> 1) & 0177; /* remove start, parity */ -if (c >= 040) { /* printable? */ - if (c == 0177) /* DEL? ignore */ - return 0; - if ((coml_unit[ln].flags & UNIT_K35) && islower (c)) /* KSR-35 LC? */ - c = toupper (c); /* cvt to UC */ - return c; - } -switch (c) { - - case '\t': case '\f': case '\b': case '\a': /* valid ctrls */ - return c; - - case '\r': /* carriage return? */ - if (coml_unit[ln].flags & UNIT_K35) /* KSR-35? */ - *c1 = '\n'; /* lf after cr */ - return c; - - case '\n': /* line feed? */ - if (!(coml_unit[ln].flags & UNIT_K35)) { /* KSR-37? */ - *c1 = '\n'; /* lf after cr */ - return '\r'; - } - return c; /* print lf */ - - case 022: /* DC2 */ - if (!(com_unit[ln].flags & UNIT_K35)) { /* KSR-37? */ - com_skip_outc (ln); /* skip next */ - return '\n'; /* print lf */ - } - break; - - case 023: /* DC3 */ - if (!(com_unit[ln].flags & UNIT_K35)) /* KSR-37? */ - com_skip_outc (ln); /* skip next */ - break; - } - -return 0; /* ignore others */ -} - -/* Generate completion message, if needed */ - -t_stat com_send_ccmp (uint32 ln) -{ -uint32 t; - -if (t = com_not_ret[ln]) { /* chars not returned? */ - if (t > COMI_CMAX) /* limit to max */ - t = COMI_CMAX; - com_not_ret[ln] -= t; /* keep count */ - if (!com_inp_msg (ln, COMI_COMP (t))) /* gen completion msg */ - return STOP_NOIFREE; - } -return SCPE_OK; -} - -/* Skip next char in output queue */ - -void com_skip_outc (uint32 ln) -{ -if (com_gethd_free (&com_outq[ln])) /* count it */ - com_not_ret[ln]++; -return; -} - -/* Read and validate output buffer */ - -t_uint64 com_getob (uint32 ch) -{ -if (com_chob_v) /* valid? clear */ - com_chob_v = 0; -else if (!com_stop) { /* not stopped? */ - ch9_set_ioc (com_ch); /* IO check */ - com_set_sns (COMS_ITMO); /* set sense bit */ - } -return com_chob; -} - -/* Set attention if input pending */ - -t_stat com_test_atn (uint32 ch) -{ -if (com_inpq.head) - ch9_set_atn (ch); -return SCPE_OK; -} - -/* Test for done */ - -t_bool com_qdone (uint32 ch) -{ -if (com_stop || !ch9_qconn (ch)) { /* stop or err disc? */ - com_sta = 0; /* ctrl is idle */ - return TRUE; - } -return FALSE; -} - -/* Channel end */ - -void com_end (uint32 ch, uint32 fl, uint32 st) -{ -ch9_set_end (ch, fl); /* set end */ -ch_req |= REQ_CH (ch); -com_sta = st; /* next state */ -return; -} - -/* List routines - remove from head and free */ - -uint16 com_gethd_free (LISTHD *lh) -{ -uint16 ent; - -if ((ent = com_gethd (lh)) != 0) - com_puttl (&com_free, ent); -return ent; -} - -/* Get free entry and insert at tail */ - -t_bool com_new_puttl (LISTHD *lh, uint16 val) -{ -uint16 ent; - -if ((ent = com_gethd (&com_free)) != 0) { - com_pkt[ent].data = val; - com_puttl (lh, ent); - return TRUE; - } -return FALSE; -} - -/* Remove from head */ - -uint16 com_gethd (LISTHD *lh) -{ -uint16 ent; - -if ((ent = lh->head) != 0) { - lh->head = com_pkt[ent].next; - if (lh->head == 0) - lh->tail = 0; - } -else lh->tail = 0; -return ent; -} - -/* Insert at tail */ - -void com_puttl (LISTHD *lh, uint16 ent) -{ -if (lh->tail == 0) - lh->head = ent; -else com_pkt[lh->tail].next = ent; -com_pkt[ent].next = 0; -lh->tail = ent; -return; -} - -/* Insert line and message into input queue */ - -t_bool com_inp_msg (uint32 ln, uint16 msg) -{ -uint16 ent1, ent2; - -if ((ent1 = com_gethd (&com_free)) != 0) { /* pkt avail? */ - if ((ent2 = com_gethd (&com_free)) != 0) { /* 2nd pkt avail? */ - com_pkt[ent1].data = (ln + COM_LBASE) | COMI_VALIDL; /* 1st pkt = line# */ - com_pkt[ent2].data = msg; /* 2nd pkt = char */ - com_puttl (&com_inpq, ent1); /* queue pkts */ - com_puttl (&com_inpq, ent2); - return TRUE; - } - com_puttl (&com_free, ent1); /* free 1st */ - } -return FALSE; /* failed */ -} - -/* Set flag in sense */ - -void com_set_sns (t_uint64 stat) -{ -com_sns |= stat; -com_sns &= ~(COMS_PCHK|COMS_DCHK|COMS_EXCC); -if (com_sns & COMS_PALL) - com_sns |= COMS_PCHK; -if (com_sns & COMS_DALL) - com_sns |= COMS_DCHK; -if (com_sns & COMS_EALL) - com_sns |= COMS_EXCC; -return; -} - -/* Reset routine */ - -t_stat com_reset (DEVICE *dptr) -{ -uint32 i; - -if (dptr->flags & DEV_DIS) { /* disabled? */ - com_dev.flags = com_dev.flags | DEV_DIS; /* disable lines */ - coml_dev.flags = coml_dev.flags | DEV_DIS; - } -else { - com_dev.flags = com_dev.flags & ~DEV_DIS; /* enable lines */ - coml_dev.flags = coml_dev.flags & ~DEV_DIS; - } -sim_activate (&com_unit[COM_CIU], com_unit[COM_CIU].wait); /* console */ -sim_cancel (&com_unit[COM_PLU]); -sim_cancel (&com_unit[COM_CHU]); -if (com_unit[COM_PLU].flags & UNIT_ATT) { /* master att? */ - int32 t = sim_rtcn_init (com_unit[COM_PLU].wait, TMR_COM); - sim_activate (&com_unit[COM_PLU], t); - } -com_enab = 0; -com_sns = 0; -com_msgn = 0; -com_sta = 0; -com_chob = 0; -com_chob_v = 0; -com_stop = 0; -com_bptr = 0; -com_blim = 0; -for (i = 0; i < COM_BUFSIZ; i++) - com_buf[i] = 0; -com_inpq.head = 0; /* init queues */ -com_inpq.tail = 0; -for (i = 0; i < COM_TLINES; i++) { - com_outq[i].head = 0; - com_outq[i].tail = 0; - com_reset_ln (i); - } -com_pkt[0].next = 0; /* init free list */ -for (i = 1; i < COM_PKTSIZ; i++) { - com_pkt[i].next = i + 1; - com_pkt[i].data = 0; - } -com_pkt[COM_PKTSIZ - 1].next = 0; /* end of free list */ -com_free.head = 1; -com_free.tail = COM_PKTSIZ - 1; -coml_unit[COM_MLINES].CONN = 1; /* console always conn */ -coml_unit[COM_MLINES].NEEDID = 1; -return SCPE_OK; -} - -/* Attach master unit */ - -t_stat com_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = tmxr_attach (&com_desc, uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error */ - return r; -sim_rtcn_init (uptr->wait, TMR_COM); -sim_activate (uptr, 100); /* quick poll */ -return SCPE_OK; -} - -/* Detach master unit */ - -t_stat com_detach (UNIT *uptr) -{ -uint32 i; -t_stat r; - -r = tmxr_detach (&com_desc, uptr); /* detach */ -for (i = 0; i < COM_MLINES; i++) /* disable rcv */ - com_ldsc[i].rcve = 0; -sim_cancel (uptr); /* stop poll */ -return r; -} - -/* Reset an individual line */ - -void com_reset_ln (uint32 ln) -{ -while (com_gethd_free (&com_outq[ln])) ; -com_not_ret[ln] = 0; -sim_cancel (&coml_unit[ln]); -if ((ln < COM_MLINES) && (com_ldsc[ln].conn == 0)) - coml_unit[ln].CONN = 0; -return; -} - -/* Special show commands */ - -uint32 com_show_qsumm (FILE *st, LISTHD *lh, char *name) -{ -uint32 i, next; - -next = lh->head; -for (i = 0; i < COM_PKTSIZ; i++) { - if (next == 0) { - if (i == 0) - fprintf (st, "%s is empty\n", name); - else if (i == 1) - fprintf (st, "%s has 1 entry\n", name); - else fprintf (st, "%s had %d entries\n", name, i); - return i; - } - next = com_pkt[next].next; - } -fprintf (st, "%s is corrupt\n", name); -return 0; -} - -void com_show_char (FILE *st, uint32 ch) -{ -uint32 c; - -fprintf (st, "%03o", ch); -c = (~ch) & 0177; -if (((ch & 07400) == 0) && (c >= 040) && (c != 0177)) - fprintf (st, "[%c]", c); -return; -} - -t_stat com_show_freeq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -com_show_qsumm (st, &com_free, "Free queue"); -return SCPE_OK; -} - -t_stat com_show_inq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 entc, ln, i, next; - -if (entc = com_show_qsumm (st, &com_inpq, "Input queue")) { - for (i = 0, next = com_inpq.head; next != 0; - i++, next = com_pkt[next].next) { - if ((i % 4) == 0) - fprintf (st, "%d:\t", i); - ln = com_pkt[next].data; - next = com_pkt[next].next; - if (next == 0) { - fprintf (st, "Line number without data\n"); - return SCPE_OK; - } - fprintf (st, "%d/", ln); - com_show_char (st, com_pkt[next].data); - fputc ((((i % 4) == 3)? '\n': '\t'), st); - } - if (i % 4) - fputc ('\n', st); - } -return SCPE_OK; -} - -t_stat com_show_outq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 entc, ln, i, next; -char name[20]; - -ln = uptr - com_dev.units; -sprintf (name, "Output queue %d", ln); -if (entc = com_show_qsumm (st, &com_outq[ln], name)) { - for (i = 0, next = com_outq[ln].head; next != 0; - i++, next = com_pkt[next].next) { - if ((i % 8) == 0) - fprintf (st, "%d:\t", i); - com_show_char (st, com_pkt[next].data >> 1); - fputc ((((i % 8) == 7)? '\n': '\t'), st); - } - if (i % 8) - fputc ('\n', st); - } -return SCPE_OK; -} - -t_stat com_show_aoutq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 i; - -for (i = 0; i < COM_TLINES; i++) - com_show_outq (st, com_dev.units + i, 1, desc); -return SCPE_OK; -} - -t_stat com_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (!com_enab) - fprintf (st, "Controller is not initialized\n"); -if (val & COMR_FQ) - com_show_freeq (st, uptr, 1, desc); -if (val & COMR_IQ) - com_show_inq (st, uptr, 1, desc); -if (val & COMR_OQ) - com_show_aoutq (st, uptr, 1, desc); -return SCPE_OK; -} diff --git a/I7094/i7094_cpu.c b/I7094/i7094_cpu.c index 2ea5d8fe..3719999b 100644 --- a/I7094/i7094_cpu.c +++ b/I7094/i7094_cpu.c @@ -1,6 +1,6 @@ /* i7094_cpu.c: IBM 7094 CPU simulator - Copyright (c) 2003-2010, Robert M. Supnik + Copyright (c) 2003-2011, Robert 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,7 +25,10 @@ cpu 7094 central processor - 16-Jul-10 RMS Fixed PSE, MSE user mode protection (found by Dave Pitts) + 31-Dec-11 RMS Select traps have priority over protect traps + Added SRI, SPI + Fixed user mode and relocation from CTSS RPQ documentation + 16-Jul-10 RMS Fixed user mode protection (found by Dave Pitts) Fixed issues in storage nullification mode 28-Apr-07 RMS Removed clock initialization 29-Oct-06 RMS Added additional expanded core instructions @@ -57,6 +60,9 @@ protection, and relocation. Additional state: USER user mode + RELOCM relocation mode + USER_BUF user mode buffer + RELOC_BUF relocation buffer INST_BASE instruction memory select (A vs B core) DATA_BASE data memory select (A vs B core) IND_RELOC<0:6> relocation value (block number) @@ -121,8 +127,8 @@ ch_flags[0..7] flags for channels A..H chtr_enab channel trap enables chtr_inht channel trap inhibit due to trap (cleared by RCT) - chtr_inhi channel trap inhibit due to XEC, ENAB, RCT, RDS, - or WDS (cleared after one instruction) + chtr_inhi channel trap inhibit due to XEC, ENB, RCT, LRI, + LPI, SEA, SEB (cleared after one instruction) Channel traps are summarized in variable chtr_pend. @@ -179,6 +185,9 @@ uint32 ind_dvc = 0; /* divide check */ uint32 ind_ioc = 0; /* IO check */ uint32 cpu_model = I_9X|I_94; /* CPU type */ uint32 mode_user = 0; /* (CTSS) user mode */ +uint32 mode_reloc = 0; /* (CTSS) relocation mode */ +uint32 user_buf = 0; /* (CTSS) user mode buffer */ +uint32 reloc_buf = 0; /* (CTSS) reloc mode buffer */ uint32 ind_reloc = 0; /* (CTSS) relocation */ uint32 ind_start = 0; /* (CTSS) prot start */ uint32 ind_limit = 0; /* (CTSS) prot limit */ @@ -307,6 +316,9 @@ REG cpu_reg[] = { { FLDATA (CHTR_INHI, chtr_inhi, 0) }, { ORDATA (CHTR_ENAB, chtr_enab, 30) }, { FLDATA (USERM, mode_user, 0) }, + { FLDATA (RELOCM, mode_reloc, 0) }, + { FLDATA (USERBUF, user_buf, 0) }, + { FLDATA (RELOCBUF, reloc_buf, 0) }, { FLDATA (IMEM, inst_base, BCORE_V) }, { FLDATA (DMEM, data_base, BCORE_V) }, { GRDATA (RELOC, ind_reloc, 8, VA_N_BLK, VA_V_BLK) }, @@ -572,8 +584,8 @@ const uint8 op_flags[1024] = { I_XNR|I_CT, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - I_XN , 0 , I_XNR|I_9X, I_XN|I_94 , /* -600 */ - 0 , 0 , 0 , 0 , + I_XN , I_CT , I_XNR|I_9X, I_XN|I_94 , /* -600 */ + I_CT , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , I_XNR|I_9X, 0 , 0 , 0 , /* -620 */ @@ -685,6 +697,10 @@ while (reason == SCPE_OK) { /* loop until error */ chtr_inhi = 0; /* clear */ chtr_pend = chtr_eval (NULL); /* re-evaluate */ } + else if (cpu_model & I_CT) { /* CTSS? */ + mode_user = user_buf; /* load modes from buffers */ + mode_reloc = reloc_buf; + } oldPC = PC; /* save current PC */ PC = (PC + 1) & EAMASK; /* increment PC */ if (!ReadI (oldPC, &IR)) /* get inst; trap? */ @@ -945,9 +961,15 @@ while (reason == SCPE_OK) { /* loop until error */ case 00101: /* (CTSS) TIA */ if (prot_trap (0)) /* not user mode? */ break; - PCQ_ENTRY; - PC = ea; - inst_base = 0; + if (mode_ttrap) { /* trap? */ + WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ + TrapXfr (TRAP_TRA_PC); /* trap */ + } + else { + PCQ_ENTRY; + PC = ea; + inst_base = 0; + } break; case 00114: case 00115: case 00116: case 00117: /* CVR */ @@ -1267,6 +1289,9 @@ while (reason == SCPE_OK) { /* loop until error */ if (prot_trap (0)) /* user mode? */ break; ind_reloc = ((uint32) SR) & VA_BLK; + reloc_buf = 1; /* set mode buffer */ + chtr_inhi = 1; /* delay traps */ + chtr_pend = 0; /* no trap now */ break; case 00564: /* ENB */ @@ -1380,6 +1405,8 @@ while (reason == SCPE_OK) { /* loop until error */ /* Negative instructions */ case 01021: /* ESNT */ + if (prot_trap (0)) /* user mode? */ + break; mode_storn = 1; /* enter nullification */ PCQ_ENTRY; PC = ea; /* branch, no trap */ @@ -1431,10 +1458,15 @@ while (reason == SCPE_OK) { /* loop until error */ case 01101: /* (CTSS) TIB */ if (prot_trap (0)) /* user mode? */ break; - PCQ_ENTRY; - PC = ea; - mode_user = 1; - inst_base = BCORE_BASE; + if (mode_ttrap) { /* trap? */ + WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ + TrapXfr (TRAP_TRA_PC); /* trap */ + } + else { + PCQ_ENTRY; + PC = ea; + inst_base = BCORE_BASE; + } break; case 01114: case 01115: case 01116: case 01117: /* CAQ */ @@ -1624,12 +1656,21 @@ while (reason == SCPE_OK) { /* loop until error */ break; ind_start = ((uint32) SR) & VA_BLK; ind_limit = (GET_DEC (SR) & VA_BLK) | VA_OFF; + user_buf = 1; /* set mode buffer */ + chtr_inhi = 1; /* delay traps */ + chtr_pend = 0; /* no trap now */ break; case 01600: /* STQ */ Write (ea, MQ); break; + case 01601: /* SRI (CTSS) */ + SR = ind_reloc & VA_BLK; + /* add reloc mode in bit 1 */ + Write (ea, SR); + break; + case 01602: /* ORS */ SR = SR | (AC & DMASK); Write (ea, SR); @@ -1642,6 +1683,13 @@ while (reason == SCPE_OK) { /* loop until error */ Write ((ea + 1) & EAMASK, MQ); break; + case 01604: /* SPI (CTSS) */ + SR = (((t_uint64) (ind_limit & VA_BLK)) << INST_V_DEC) | + ((t_uint64) (ind_start & VA_BLK)); + /* add prot mode in bit 2 */ + Write (ea, SR); + break; + case 01620: /* SLQ */ SR = (SR & RMASK) | (MQ & LMASK); Write (ea, SR); @@ -1833,10 +1881,8 @@ while (reason == SCPE_OK) { /* loop until error */ case 00640: case 00641: case 00642: case 00643: /* SCHx */ case 01640: case 01641: case 01642: case 01643: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - if ((reason = ch_op_store (ch, &SR)) == SCPE_OK) + ch = ((op & 03) << 1) | ((op >> 9) & 01); + if ((reason = ch_op_store (ch, &SR)) == SCPE_OK) Write (ea, SR); break; @@ -1848,7 +1894,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00762: /* RDS */ - if (prot_trap (0) || sel_trap (PC)) + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (IR); reason = ch_op_ds (ch, CHSL_RDS, GET_U_UNIT (ea)); @@ -1856,7 +1902,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00764: /* BSR */ - if (prot_trap (0) || sel_trap (PC)) + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (IR); reason = ch_op_nds (ch, CHSL_BSR, GET_U_UNIT (ea)); @@ -1864,7 +1910,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00766: /* WRS */ - if (prot_trap (0) || sel_trap (PC)) + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (IR); reason = ch_op_ds (ch, CHSL_WRS, GET_U_UNIT (ea)); @@ -1872,7 +1918,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00770: /* WEF */ - if (prot_trap (0) || sel_trap (PC)) + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (IR); reason = ch_op_nds (ch, CHSL_WEF, GET_U_UNIT (ea)); @@ -1880,7 +1926,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00772: /* REW */ - if (prot_trap (0) || sel_trap (PC)) + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (IR); reason = ch_op_nds (ch, CHSL_REW, GET_U_UNIT (ea)); @@ -1888,7 +1934,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 01764: /* BSF */ - if (prot_trap (0) || sel_trap (PC)) + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (IR); reason = ch_op_nds (ch, CHSL_BSF, GET_U_UNIT (ea)); @@ -1896,7 +1942,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 01772: /* RUN */ - if (prot_trap (0) || sel_trap (PC)) + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (IR); reason = ch_op_nds (ch, CHSL_RUN, GET_U_UNIT (ea)); @@ -1904,7 +1950,7 @@ while (reason == SCPE_OK) { /* loop until error */ break; case 00776: /* SDN */ - if (prot_trap (0) || sel_trap (PC)) + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (IR); reason = ch_op_nds (ch, CHSL_SDN, GET_U_UNIT (ea)); @@ -2069,7 +2115,8 @@ WriteP (pa, mem); mode_ctrap = 0; mode_strap = 0; mode_storn = 0; -mode_user = 0; +mode_user = user_buf = 0; +mode_reloc = reloc_buf = 0; inst_base = 0; data_base = 0; return; @@ -2121,7 +2168,8 @@ PC = newpc; mode_ctrap = 0; mode_strap = 0; mode_storn = 0; -mode_user = 0; +mode_user = user_buf = 0; +mode_reloc = reloc_buf = 0; inst_base = 0; data_base = 0; return; @@ -2131,12 +2179,11 @@ return; t_bool ReadI (uint32 va, t_uint64 *val) { -if (mode_user) { +if (mode_reloc) va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } +if (mode_user && ((va < ind_start) || (va > ind_limit))) { + prot_trap (0); + return FALSE; } *val = M[va | inst_base]; return TRUE; @@ -2146,12 +2193,11 @@ return TRUE; t_bool Read (uint32 va, t_uint64 *val) { -if (mode_user) { +if (mode_reloc) va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } +if (mode_user && ((va < ind_start) || (va > ind_limit))) { + prot_trap (0); + return FALSE; } *val = M[va | data_base]; return TRUE; @@ -2161,12 +2207,11 @@ return TRUE; t_bool Write (uint32 va, t_uint64 dat) { -if (mode_user) { +if (mode_reloc) va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } +if (mode_user && ((va < ind_start) || (va > ind_limit))) { + prot_trap (0); + return FALSE; } M[va | data_base] = dat; return TRUE; @@ -2191,7 +2236,8 @@ mode_storn = 0; if (cpu_model & (I_94|I_CT)) mode_multi = 0; else mode_multi = 1; -mode_user = 0; +mode_user = user_buf = 0; +mode_reloc = reloc_buf = 0; inst_base = 0; data_base = 0; ch_req = 0; @@ -2220,8 +2266,7 @@ if (vptr == NULL) return SCPE_ARG; if ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE)) return SCPE_NXM; -if ((sw & SWMASK ('B')) || - ((sw & SWMASK ('V')) && mode_user && inst_base)) +if (sw & SWMASK ('B')) ea = ea | BCORE_BASE; *vptr = M[ea] & DMASK; return SCPE_OK; diff --git a/I7094/i7094_cpu1.c b/I7094/i7094_cpu1.c index c5c4ea12..1b682eb0 100644 --- a/I7094/i7094_cpu1.c +++ b/I7094/i7094_cpu1.c @@ -1,6 +1,6 @@ /* i7094_cpu1.c: IBM 7094 CPU complex instructions - Copyright (c) 2003-2010, Robert M. Supnik + Copyright (c) 2003-2011, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 31-Dec-11 RMS Refined PSE and MSE user-mode protection based on + CTSS RPQ specification + Select traps have priority over protection traps 16-Jul-10 RMS Fixed PSE and MSE user-mode protection (from Dave Pitts) Added SPUx, SPTx, SPRx */ @@ -296,10 +299,11 @@ switch (addr) { break; case 00007: /* ETM */ - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) /* 709X only */ + if (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_ttrap = 1; + } break; case 00010: /* RND */ @@ -322,6 +326,8 @@ switch (addr) { break; case 00014: /* RCT */ + if (prot_trap (0)) /* user mode? */ + break; chtr_inhi = 1; /* 1 cycle delay */ chtr_inht = 0; /* clr inhibit trap */ chtr_pend = 0; /* no trap now */ @@ -350,10 +356,8 @@ switch (addr) { case 001000: case 002000: case 003000: case 004000: /* BTT */ case 005000: case 060000: case 070000: case 010000: - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) { /* 709X only */ - if (sel_trap (PC)) /* sel trap? */ + if (cpu_model & I_9X) { /* 709X only */ + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (addr); /* get channel */ if (ch_flags[ch] & CHF_BOT) /* BOT? */ @@ -437,32 +441,43 @@ switch (addr) { break; case 00004: /* LFTM */ - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) /* 709X only */ + if (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_ftrap = 0; + } break; case 00005: /* ESTM */ - if (cpu_model & I_9X) /* 709X only */ + if (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_strap = 1; + } break; case 00006: /* ECTM */ - if (cpu_model & I_9X) /* 709X only */ + if (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_ctrap = 1; + } break; case 00007: /* LTM */ - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) /* 709X only */ + if (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_ttrap = 0; + } break; case 00010: /* LSNM */ - if (cpu_model & I_9X) /* 709X only */ + if (cpu_model & I_9X) { /* 709X only */ + if (prot_trap (0)) /* user mode? */ + break; mode_storn = 0; + } break; case 00012: /* RTT (704) */ @@ -497,7 +512,7 @@ switch (addr) { case 001000: case 002000: case 003000: case 004000: /* ETT */ case 005000: case 006000: case 007000: case 010000: - if (sel_trap (PC)) /* sel trap? */ + if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ break; ch = GET_U_CH (addr); /* get channel */ if (ch_flags[ch] & CHF_EOT) /* EOT? */ diff --git a/I7094/i7094_cpu1_old.c b/I7094/i7094_cpu1_old.c deleted file mode 100644 index 18afca55..00000000 --- a/I7094/i7094_cpu1_old.c +++ /dev/null @@ -1,887 +0,0 @@ -/* i7094_cpu1.c: IBM 7094 CPU complex instructions - - Copyright (c) 2003-2008, Robert 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 "i7094_defs.h" - -#define FP_HIFRAC(x) ((uint32) ((x) >> FP_N_FR) & FP_FMASK) -#define FP_LOFRAC(x) ((uint32) (x) & FP_FMASK) - -#define FP_PACK38(s,e,f) (((s)? AC_S: 0) | ((t_uint64) (f)) | \ - (((t_uint64) ((e) & FP_M_ACCH)) << FP_V_CH)) -#define FP_PACK36(s,e,f) (((s)? SIGN: 0) | ((t_uint64) (f)) | \ - (((t_uint64) ((e) & FP_M_CH)) << FP_V_CH)) - -extern t_uint64 AC, MQ, SI, KEYS; -extern uint32 PC; -extern uint32 SLT, SSW; -extern uint32 cpu_model, stop_illop; -extern uint32 ind_ovf, ind_dvc, ind_ioc, ind_mqo; -extern uint32 mode_ttrap, mode_strap, mode_ctrap, mode_ftrap; -extern uint32 mode_storn, mode_multi; -extern uint32 chtr_pend, chtr_inht, chtr_inhi; -extern uint32 ch_flags[NUM_CHAN]; - -typedef struct { /* unpacked fp */ - uint32 s; /* sign: 0 +, 1 - */ - int32 ch; /* exponent */ - t_uint64 fr; /* fraction (54b) */ - } UFP; - -uint32 op_frnd (void); -t_uint64 fp_fracdiv (t_uint64 dvd, t_uint64 dvr, t_uint64 *rem); -void fp_norm (UFP *op); -void fp_unpack (t_uint64 h, t_uint64 l, t_bool q_ac, UFP *op); -uint32 fp_pack (UFP *op, uint32 mqs, int32 mqch); - -extern t_bool fp_trap (uint32 spill); -extern t_bool sel_trap (uint32 va); -extern t_stat ch_op_reset (uint32 ch, t_bool ch7909); - -/* Integer add - - Sherman: "As the result of an addition or subtraction, if the C(AC) is - zero, the sign of AC is unchanged." */ - -void op_add (t_uint64 op) -{ -t_uint64 mac = AC & AC_MMASK; /* get magnitudes */ -t_uint64 mop = op & MMASK; - -AC = AC & AC_S; /* isolate AC sign */ -if ((AC? 1: 0) ^ ((op & SIGN)? 1: 0)) { /* signs diff? sub */ - if (mac >= mop) /* AC >= MQ */ - AC = AC | (mac - mop); - else AC = (AC ^ AC_S) | (mop - mac); /* <, sign change */ - } -else { - AC = AC | ((mac + mop) & AC_MMASK); /* signs same, add */ - if ((AC ^ mac) & AC_P) /* P change? overflow */ - ind_ovf = 1; - } -return; -} - -/* Multiply */ - -void op_mpy (t_uint64 ac, t_uint64 sr, uint32 sc) -{ -uint32 sign; - -if (sc == 0) /* sc = 0? nop */ - return; -sign = ((MQ & SIGN)? 1: 0) ^ ((sr & SIGN)? 1: 0); /* result sign */ -ac = ac & AC_MMASK; /* clear AC sign */ -sr = sr & MMASK; /* mpy magnitude */ -MQ = MQ & MMASK; /* MQ magnitude */ -if (sr && MQ) { /* mpy != 0? */ - while (sc--) { /* for sc */ - if (MQ & 1) /* MQ35? AC += mpy */ - ac = (ac + sr) & AC_MMASK; - MQ = (MQ >> 1) | ((ac & 1) << 34); /* AC'MQ >> 1 */ - ac = ac >> 1; - } - } -else ac = MQ = 0; /* result = 0 */ -if (sign) { /* negative? */ - ac = ac | AC_S; /* insert signs */ - MQ = MQ | SIGN; - } -AC = ac; /* update AC */ -return; -} - -/* Divide */ - -t_bool op_div (t_uint64 sr, uint32 sc) -{ -uint32 signa, signm; - -if (sc == 0) /* sc = 0? nop */ - return FALSE; -signa = (AC & AC_S)? 1: 0; /* get signs */ -signm = (sr & SIGN)? 1: 0; -sr = sr & MMASK; /* get dvr magn */ -if ((AC & AC_MMASK) >= sr) /* |AC| >= |sr|? */ - return TRUE; -AC = AC & AC_MMASK; /* AC, MQ magn */ -MQ = MQ & MMASK; -while (sc--) { /* for sc */ - AC = ((AC << 1) & AC_MMASK) | (MQ >> 34); /* AC'MQ << 1 */ - MQ = (MQ << 1) & MMASK; - if (AC >= sr) { /* AC >= dvr? */ - AC = AC - sr; /* AC -= dvr */ - MQ = MQ | 1; /* set quo bit */ - } - } -if (signa ^ signm) /* quo neg? */ - MQ = MQ | SIGN; -if (signa) /* rem neg? */ - AC = AC | AC_S; -return FALSE; /* div ok */ -} - -/* Shifts */ - -void op_als (uint32 addr) -{ -uint32 sc = addr & SCMASK; - -if ((sc >= 35)? /* shift >= 35? */ - ((AC & MMASK) != 0): /* test all bits for ovf */ - (((AC & MMASK) >> (35 - sc)) != 0)) /* test only 35-sc bits */ - ind_ovf = 1; -if (sc >= 37) /* sc >= 37? result 0 */ - AC = AC & AC_S; -else AC = (AC & AC_S) | ((AC << sc) & AC_MMASK); /* shift, save sign */ -return; -} - -void op_ars (uint32 addr) -{ -uint32 sc = addr & SCMASK; - -if (sc >= 37) /* sc >= 37? result 0 */ - AC = AC & AC_S; -else AC = (AC & AC_S) | ((AC & AC_MMASK) >> sc); /* shift, save sign */ -return; -} - -void op_lls (uint32 addr) -{ -uint32 sc; /* get sc */ - -AC = AC & AC_MMASK; /* clear AC sign */ -for (sc = addr & SCMASK; sc != 0; sc--) { /* for SC */ - AC = ((AC << 1) & AC_MMASK) | ((MQ >> 34) & 1); /* AC'MQ << 1 */ - MQ = (MQ & SIGN) | ((MQ << 1) & MMASK); /* preserve MQ sign */ - if (AC & AC_P) /* if P, overflow */ - ind_ovf = 1; - } -if (MQ & SIGN) /* set ACS from MQS */ - AC = AC | AC_S; -return; -} - -void op_lrs (uint32 addr) -{ -uint32 sc = addr & SCMASK; -t_uint64 mac; - -MQ = MQ & MMASK; /* get MQ magnitude */ -if (sc != 0) { - mac = AC & AC_MMASK; /* get AC magnitude, */ - AC = AC & AC_S; /* sign */ - if (sc < 35) { /* sc [1,34]? */ - MQ = ((MQ >> sc) | (mac << (35 - sc))) & MMASK; /* MQ has AC'MQ */ - AC = AC | (mac >> sc); /* AC has AC only */ - } - else if (sc < 37) { /* sc [35:36]? */ - MQ = (mac >> (sc - 35)) & MMASK; /* MQ has AC only */ - AC = AC | (mac >> sc); /* AC has */ - } - else if (sc < 72) /* sc [37:71]? */ - MQ = (mac >> (sc - 35)) & MMASK; /* MQ has AC only */ - else MQ = 0; /* >72? MQ = 0 */ - } -if (AC & AC_S) /* set MQS from ACS */ - MQ = MQ | SIGN; -return; -} - -void op_lgl (uint32 addr) -{ -uint32 sc; /* get sc */ - -for (sc = addr & SCMASK; sc != 0; sc--) { /* for SC */ - AC = (AC & AC_S) | ((AC << 1) & AC_MMASK) | /* AC'MQ << 1 */ - ((MQ >> 35) & 1); /* preserve AC sign */ - MQ = (MQ << 1) & DMASK; - if (AC & AC_P) /* if P, overflow */ - ind_ovf = 1; - } -return; -} - -void op_lgr (uint32 addr) -{ -uint32 sc = addr & SCMASK; -t_uint64 mac; - -if (sc != 0) { - mac = AC & AC_MMASK; /* get AC magnitude, */ - AC = AC & AC_S; /* sign */ - if (sc < 36) { /* sc [1,35]? */ - MQ = ((MQ >> sc) | (mac << (36 - sc))) & DMASK; /* MQ has AC'MQ */ - AC = AC | (mac >> sc); /* AC has AC only */ - } - else if (sc == 36) { /* sc [36]? */ - MQ = mac & DMASK; /* MQ = AC */ - AC = AC | (mac >> 36); /* AC = AC */ - } - else if (sc < 73) /* sc [37, 72]? */ - MQ = (mac >> (sc - 36)) & DMASK; /* MQ has AC only */ - else MQ = 0; /* >72, AC,MQ = 0 */ - } -return; -} - -/* Plus sense - undefined operations are NOPs */ - -t_stat op_pse (uint32 addr) -{ -uint32 ch, spill; - -switch (addr) { - - case 00000: /* CLM */ - if (cpu_model & I_9X) /* 709X only */ - AC = AC & AC_S; - break; - - case 00001: /* LBT */ - if ((AC & 1) != 0) - PC = (PC + 1) & AMASK; - break; - - case 00002: /* CHS */ - AC = AC ^ AC_S; - break; - - case 00003: /* SSP */ - AC = AC & ~AC_S; - break; - - case 00004: /* ENK */ - MQ = KEYS; - break; - - case 00005: /* IOT */ - if (ind_ioc) - ind_ioc = 0; - else PC = (PC + 1) & AMASK; - break; - - case 00006: /* COM */ - AC = AC ^ AC_MMASK; - break; - - case 00007: /* ETM */ - if (cpu_model & I_9X) /* 709X only */ - mode_ttrap = 1; - break; - - case 00010: /* RND */ - if ((cpu_model & I_9X) && (MQ & B1)) /* 709X only, MQ1 set? */ - op_add ((t_uint64) 1); /* incr AC */ - break; - - case 00011: /* FRN */ - if (cpu_model & I_9X) { /* 709X only */ - spill = op_frnd (); - if (spill) - fp_trap (spill); - } - break; - - case 00012: /* DCT */ - if (ind_dvc) - ind_dvc = 0; - else PC = (PC + 1) & AMASK; - break; - - case 00014: /* RCT */ - chtr_inhi = 1; /* 1 cycle delay */ - chtr_inht = 0; /* clr inhibit trap */ - chtr_pend = 0; /* no trap now */ - break; - - case 00016: /* LMTM */ - if (cpu_model & I_94) /* 709X only */ - mode_multi = 0; - break; - - case 00140: /* SLF */ - if (cpu_model & I_9X) /* 709X only */ - SLT = 0; - break; - - case 00141: case 00142: case 00143: case 00144: /* SLN */ - if (cpu_model & I_9X) /* 709X only */ - SLT = SLT | (1u << (00144 - addr)); - break; - - case 00161: case 00162: case 00163: /* SWT */ - case 00164: case 00165: case 00166: - if ((SSW & (1u << (00166 - addr))) != 0) - PC = (PC + 1) & AMASK; - break; - - case 01000: case 02000: case 03000: case 04000: /* BTT */ - case 05000: case 06000: case 07000: case 10000: - if (cpu_model & I_9X) { /* 709X only */ - if (sel_trap (PC)) /* sel trap? */ - break; - ch = GET_U_CH (addr); /* get channel */ - if (ch_flags[ch] & CHF_BOT) /* BOT? */ - ch_flags[ch] &= ~CHF_BOT; /* clear */ - else PC = (PC + 1) & AMASK; /* else skip */ - } - break; - - case 001350: case 002350: case 003350: case 004350: /* RICx */ - case 005350: case 006350: case 007350: case 010350: - ch = GET_U_CH (addr); /* get channel */ - return ch_op_reset (ch, 1); - - case 001352: case 002352: case 003352: case 004352: /* RDCx */ - case 005352: case 006352: case 007352: case 010352: - ch = GET_U_CH (addr); /* get channel */ - return ch_op_reset (ch, 0); - } /* end case */ - -return SCPE_OK; -} - -/* Minus sense */ - -t_stat op_mse (uint32 addr) -{ -uint32 t, ch; - -switch (addr) { - - case 00000: /* CLM */ - if (cpu_model & I_9X) /* 709X only */ - AC = AC & AC_S; - break; - - case 00001: /* PBT */ - if ((AC & AC_P) != 0) - PC = (PC + 1) & AMASK; - break; - - case 00002: /* EFTM */ - if (cpu_model & I_9X) { /* 709X only */ - mode_ftrap = 1; - ind_mqo = 0; /* clears MQ ovf */ - } - break; - - case 00003: /* SSM */ - if (cpu_model & I_9X) /* 709X only */ - AC = AC | AC_S; - break; - - case 00004: /* LFTM */ - if (cpu_model & I_9X) /* 709X only */ - mode_ftrap = 0; - break; - - case 00005: /* ESTM */ - if (cpu_model & I_9X) /* 709X only */ - mode_strap = 1; - break; - - case 00006: /* ECTM */ - if (cpu_model & I_9X) /* 709X only */ - mode_ctrap = 1; - break; - - case 00007: /* LTM */ - if (cpu_model & I_9X) /* 709X only */ - mode_ttrap = 0; - break; - - case 00010: /* LSNM */ - if (cpu_model & I_9X) /* 709X only */ - mode_storn = 0; - break; - - case 00012: /* RTT (704) */ - if (cpu_model & I_9X) /* 709X only */ - sel_trap (PC); - break; - - case 00016: /* EMTM */ - mode_multi = 1; - break; - - case 00140: /* SLF */ - if (cpu_model & I_9X) /* 709X only */ - SLT = 0; - break; - - case 00141: case 00142: case 00143: case 00144: /* SLT */ - if (cpu_model & I_9X) { /* 709X only */ - t = SLT & (1u << (00144 - addr)); - SLT = SLT & ~t; - if (t != 0) - PC = (PC + 1) & AMASK; - } - break; - - case 00161: case 00162: case 00163: /* SWT */ - case 00164: case 00165: case 00166: - if ((cpu_model & I_9X) && /* 709X only */ - ((SSW & (1u << (00166 - addr))) != 0)) - PC = (PC + 1) & AMASK; - break; - - case 001000: case 002000: case 003000: case 004000: /* ETT */ - case 005000: case 006000: case 007000: case 010000: - if (sel_trap (PC)) /* sel trap? */ - break; - ch = GET_U_CH (addr); /* get channel */ - if (ch_flags[ch] & CHF_EOT) /* EOT? */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOT; /* clear */ - else PC = (PC + 1) & AMASK; /* else skip */ - break; - } - -return SCPE_OK; -} - -/* Floating add - - Notes: - - AC enter into the initial exponent comparison. If either is set, - the numbers are always swapped. AC

gets OR'd into AC during the - swap, and AC are cleared afterwards - - The early end test is actually > 077 if AC <= SR and > 100 if - AC > SR. However, any shift >= 54 will produce a zero fraction, - so the difference can be ignored */ - -uint32 op_fad (t_uint64 sr, t_bool norm) -{ -UFP op1, op2, t; -int32 mqch, diff; - -MQ = 0; /* clear MQ */ -fp_unpack (AC, 0, 1, &op1); /* unpack AC */ -fp_unpack (sr, 0, 0, &op2); /* unpack sr */ -if (op1.ch > op2.ch) { /* AC exp > SR exp? */ - if (AC & AC_P) /* AC P or's with S */ - op1.s = 1; - t = op1; /* swap operands */ - op1 = op2; - op2 = t; - op2.ch = op2.ch & FP_M_CH; /* clear P,Q */ - } -diff = op2.ch - op1.ch; /* exp diff */ -if (diff) { /* any shift? */ - if ((diff < 0) || (diff > 077)) /* diff > 63? */ - op1.fr = 0; - else op1.fr = op1.fr >> diff; /* no, denormalize */ - } -if (op1.s ^ op2.s) { /* subtract? */ - if (op1.fr >= op2.fr) { /* op1 > op2? */ - op2.fr = op1.fr - op2.fr; /* op1 - op2 */ - op2.s = op1.s; /* op2 sign is result */ - } - else op2.fr = op2.fr - op1.fr; /* else op2 - op1 */ - } -else { - op2.fr = op2.fr + op1.fr; /* op2 + op1 */ - if (op2.fr & FP_FCRY) { /* carry? */ - op2.fr = op2.fr >> 1; /* renormalize */ - op2.ch++; /* incr exp */ - } - } -if (norm) { /* normalize? */ - if (op2.fr) { /* non-zero frac? */ - fp_norm (&op2); - mqch = op2.ch - FP_N_FR; - } - else op2.ch = mqch = 0; /* else true zero */ - } -else mqch = op2.ch - FP_N_FR; -return fp_pack (&op2, op2.s, mqch); /* pack AC, MQ */ -} - -/* Floating multiply */ - -uint32 op_fmp (t_uint64 sr, t_bool norm) -{ -UFP op1, op2; -int32 mqch; -uint32 f1h, f2h; - -fp_unpack (MQ, 0, 0, &op1); /* unpack MQ */ -fp_unpack (sr, 0, 0, &op2); /* unpack sr */ -op1.s = op1.s ^ op2.s; /* result sign */ -if ((op2.ch == 0) && (op2.fr == 0)) { /* sr a normal 0? */ - AC = op1.s? AC_S: 0; /* result is 0 */ - MQ = op1.s? SIGN: 0; - return 0; - } -f1h = FP_HIFRAC (op1.fr); /* get hi fracs */ -f2h = FP_HIFRAC (op2.fr); -op1.fr = ((t_uint64) f1h) * ((t_uint64) f2h); /* f1h * f2h */ -op1.ch = (op1.ch & FP_M_CH) + op2.ch - FP_BIAS; /* result exponent */ -if (norm) { /* normalize? */ - if (!(op1.fr & FP_FNORM)) { /* not normalized? */ - op1.fr = op1.fr << 1; /* shift frac left 1 */ - op1.ch--; /* decr exp */ - } - if (FP_HIFRAC (op1.fr)) /* hi result non-zero? */ - mqch = op1.ch - FP_N_FR; /* set MQ exp */ - else op1.ch = mqch = 0; /* clear AC, MQ exp */ - } -else mqch = op1.ch - FP_N_FR; /* set MQ exp */ -return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */ -} - -/* Floating divide */ - -uint32 op_fdv (t_uint64 sr) -{ -UFP op1, op2; -int32 mqch; -uint32 spill, quos; -t_uint64 rem; - -fp_unpack (AC, 0, 1, &op1); /* unpack AC */ -fp_unpack (sr, 0, 0, &op2); /* unpack sr */ -quos = op1.s ^ op2.s; /* quotient sign */ -if (op1.fr >= (2 * op2.fr)) { /* |AC| >= 2*|sr|? */ - MQ = quos? SIGN: 0; /* MQ = sign only */ - return TRAP_F_DVC; /* divide check */ - } -if (op1.fr == 0) { /* |AC| == 0? */ - MQ = quos? SIGN: 0; /* MQ = sign only */ - AC = 0; /* AC = +0 */ - return 0; /* done */ - } -op1.ch = op1.ch & FP_M_CH; /* remove AC */ -if (op1.fr >= op2.fr) { /* |AC| >= |sr|? */ - op1.fr = op1.fr >> 1; /* denorm AC */ - op1.ch++; - } -op1.fr = fp_fracdiv (op1.fr, op2.fr, &rem); /* fraction divide */ -op1.fr = op1.fr | (rem << FP_N_FR); /* rem'quo */ -mqch = op1.ch - op2.ch + FP_BIAS; /* quotient exp */ -op1.ch = op1.ch - FP_N_FR; /* remainder exp */ -spill = fp_pack (&op1, quos, mqch); /* pack up */ -return (spill? (spill | TRAP_F_SGL): 0); /* if spill, set SGL */ -} - -/* Double floating add - - Notes: - - AC enter into the initial exponent comparison. If either is set, - the numbers are always swapped. AC

gets OR'd into AC during the - swap, and AC are cleared afterwards - - For most cases, SI ends up with the high order part of the larger number - - The 'early end' cases (smaller number is shifted away) must be tracked - exactly for SI impacts. The early end cases are: - - (a) AC > SR, diff > 0100, and AC normalized - (b) AC <= SR, diff > 077, and SR normalized - - In case (a), SI is unchanged. In case (b), SI ends up with the SR sign - and characteristic but the MQ (!) fraction */ - -uint32 op_dfad (t_uint64 sr, t_uint64 sr1, t_bool norm) -{ -UFP op1, op2, t; -int32 mqch, diff; - -fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */ -fp_unpack (sr, sr1, 0, &op2); /* unpack sr'sr1 */ -if (op1.ch > op2.ch) { /* AC exp > SR exp? */ - if (((op1.ch - op2.ch) > 0100) && (AC & B9)) ; /* early out */ - else SI = FP_PACK36 (op1.s, op1.ch, FP_HIFRAC (op1.fr)); - if (AC & AC_P) /* AC P or's with S */ - op1.s = 1; - t = op1; /* swap operands */ - op1 = op2; - op2 = t; - op2.ch = op2.ch & FP_M_CH; /* clear P,Q */ - } -else { /* AC <= SR */ - if (((op2.ch - op1.ch) > 077) && (sr & B9)) /* early out */ - SI = FP_PACK36 (op2.s, op2.ch, FP_LOFRAC (MQ)); - else SI = FP_PACK36 (op2.s, op2.ch, FP_HIFRAC (op2.fr)); - } -diff = op2.ch - op1.ch; /* exp diff */ -if (diff) { /* any shift? */ - if ((diff < 0) || (diff > 077)) /* diff > 63? */ - op1.fr = 0; - else op1.fr = op1.fr >> diff; /* no, denormalize */ - } -if (op1.s ^ op2.s) { /* subtract? */ - if (op1.fr >= op2.fr) { /* op1 > op2? */ - op2.fr = op1.fr - op2.fr; /* op1 - op2 */ - op2.s = op1.s; /* op2 sign is result */ - } - else op2.fr = op2.fr - op1.fr; /* op2 - op1 */ - } -else { - op2.fr = op2.fr + op1.fr; /* op2 + op1 */ - if (op2.fr & FP_FCRY) { /* carry? */ - op2.fr = op2.fr >> 1; /* renormalize */ - op2.ch++; /* incr exp */ - } - } -if (norm) { /* normalize? */ - if (op2.fr) { /* non-zero frac? */ - fp_norm (&op2); - mqch = op2.ch - FP_N_FR; - } - else op2.ch = mqch = 0; /* else true zero */ - } -else mqch = op2.ch - FP_N_FR; -return fp_pack (&op2, op2.s, mqch); /* pack AC, MQ */ -} - -/* Double floating multiply - - Notes (notation is A+B' * C+D', where ' denotes 2^-27): - - The instruction returns 0 if A and C are both zero, because B*D is never - done as part of the algorithm - - For most cases, SI ends up with B*C, with a zero sign and exponent - - For the A+B' both zero 'early end' case SI ends up with A or C, - depending on whether the operation is normalized or not */ - -uint32 op_dfmp (t_uint64 sr, t_uint64 sr1, t_bool norm) -{ -UFP op1, op2; -int32 mqch; -uint32 f1h, f2h, f1l, f2l; -t_uint64 tx; - -fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */ -fp_unpack (sr, sr1, 0, &op2); /* unpack sr'sr1 */ -op1.s = op1.s ^ op2.s; /* result sign */ -f1h = FP_HIFRAC (op1.fr); /* A */ -f1l = FP_LOFRAC (op1.fr); /* B */ -f2h = FP_HIFRAC (op2.fr); /* C */ -f2l = FP_LOFRAC (op2.fr); /* D */ -if (((op1.ch == 0) && (op1.fr == 0)) || /* AC'MQ normal 0? */ - ((op2.ch == 0) && (op2.fr == 0)) || /* sr'sr1 normal 0? */ - ((f1h == 0) && (f2h == 0))) { /* both hi frac zero? */ - AC = op1.s? AC_S: 0; /* result is 0 */ - MQ = op1.s? SIGN: 0; - SI = sr; /* SI has C */ - return 0; - } -op1.ch = (op1.ch & FP_M_CH) + op2.ch - FP_BIAS; /* result exponent */ -if (op1.fr) { /* A'B != 0? */ - op1.fr = ((t_uint64) f1h) * ((t_uint64) f2h); /* A * C */ - tx = ((t_uint64) f1h) * ((t_uint64) f2l); /* A * D */ - op1.fr = op1.fr + (tx >> FP_N_FR); /* add in hi 27b */ - tx = ((t_uint64) f1l) * ((t_uint64) f2h); /* B * C */ - op1.fr = op1.fr + (tx >> FP_N_FR); /* add in hi 27b */ - SI = tx >> FP_N_FR; /* SI keeps B * C */ - } -else { - if (norm) /* early out */ - SI = sr; - else SI = FP_PACK36 (op2.s, op2.ch, 0); - } -if (norm) { /* normalize? */ - if (!(op1.fr & FP_FNORM)) { /* not normalized? */ - op1.fr = op1.fr << 1; /* shift frac left 1 */ - op1.ch--; /* decr exp */ - } - if (FP_HIFRAC (op1.fr)) { /* non-zero? */ - mqch = op1.ch - FP_N_FR; /* set MQ exp */ - } - else op1.ch = mqch = 0; /* clear AC, MQ exp */ - } -else mqch = op1.ch - FP_N_FR; /* set MQ exp */ -return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */ -} - -/* Double floating divide - - - Notes: - - This is a Taylor series expansion (where ' denotes >> 27): - - (A+B') * (C+D')^-1 = (A+B') * C^-1 - (A+B') * D'* C^-2 +... - - to two terms, which can be rewritten as terms Q1, Q2: - - Q1 = (A+B')/C - Q2' = (R - Q1*D)'/C - - - Tracking the sign of Q2' is complicated: - - Q1 has the sign of the quotient, s_AC ^ s_SR - D has the sign of the divisor, s_SR - R has the sign of the dividend, s_AC - Q1*D sign is s_AC ^ s_SR ^ s^SR = s^AC - Therefore, R and Q1*D have the same sign, s_AC - Q2' sign is s^AC ^ s_SR, which is the sign of the quotient - - - For first divide check, SI is 0 - - For other cases, including second divide check, SI ends up with Q1 - - R-Q1*D is only calculated to the high 27b; using the full 54b - throws off the result - - The second divide must check for divd >= divr, otherwise an extra - bit of quotient would be devloped, throwing off the result - - A late ECO added full post-normalization; single precision divide - does no normalization */ - -uint32 op_dfdv (t_uint64 sr, t_uint64 sr1) -{ -UFP op1, op2; -int32 mqch; -uint32 csign, ac_s; -t_uint64 f1h, f2h, tr, tq1, tq1d, trmq1d, tq2; - -fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */ -fp_unpack (sr, 0, 0, &op2); /* unpack sr only */ -ac_s = op1.s; /* save AC sign */ -op1.s = op1.s ^ op2.s; /* sign of result */ -f1h = FP_HIFRAC (op1.fr); -f2h = FP_HIFRAC (op2.fr); -if (f1h >= (2 * f2h)) { /* |A| >= 2*|C|? */ - SI = 0; /* clear SI */ - return TRAP_F_DVC; /* divide check */ - } -if (f1h == 0) { /* |AC| == 0? */ - SI = MQ = op1.s? SIGN: 0; /* MQ, SI = sign only */ - AC = op1.s? AC_S: 0; /* AC = sign only */ - return 0; /* done */ - } -op1.ch = op1.ch & FP_M_CH; /* remove AC */ -if (f1h >= f2h) { /* |A| >= |C|? */ - op1.fr = op1.fr >> 1; /* denorm AC */ - op1.ch++; - } -op1.ch = op1.ch - op2.ch + FP_BIAS; /* exp of quotient */ -tq1 = fp_fracdiv (op1.fr, op2.fr, &tr); /* |A+B| / |C| */ -tr = tr << FP_N_FR; /* R << 27 */ -tq1d = (tq1 * ((t_uint64) FP_LOFRAC (sr1))) & /* Q1 * D */ - ~((t_uint64) FP_FMASK); /* top 27 bits */ -csign = (tr < tq1d); /* correction sign */ -if (csign) /* |R|<|Q1*D|? compl */ - trmq1d = tq1d - tr; -else trmq1d = tr - tq1d; /* no, subtr ok */ -SI = FP_PACK36 (op1.s, op1.ch, tq1); /* SI has Q1 */ -if (trmq1d >= (2 * op2.fr)) { /* |R-Q1*D| >= 2*|C|? */ - AC = FP_PACK38 (csign ^ ac_s, 0, FP_HIFRAC (trmq1d)); /* AC has R-Q1*D */ - MQ = (csign ^ ac_s)? SIGN: 0; /* MQ = sign only */ - return TRAP_F_DVC; /* divide check */ - } -tq2 = fp_fracdiv (trmq1d, op2.fr, NULL); /* |R-Q1*D| / |C| */ -if (trmq1d >= op2.fr) /* can only gen 27b quo */ - tq2 &= ~((t_uint64) 1); -op1.fr = tq1 << FP_N_FR; /* shift Q1 into place */ -if (csign) /* sub or add Q2 */ - op1.fr = op1.fr - tq2; -else op1.fr = op1.fr + tq2; -fp_norm (&op1); /* normalize */ -if (op1.fr) /* non-zero? */ - mqch = op1.ch - FP_N_FR; -else op1.ch = mqch = 0; /* clear AC, MQ exp */ -return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */ -} - -/* Floating round */ - -uint32 op_frnd (void) -{ -UFP op; -uint32 spill; - -spill = 0; /* no error */ -if (MQ & B9) { /* MQ9 set? */ - fp_unpack (AC, 0, 1, &op); /* unpack AC */ - op.fr = op.fr + ((t_uint64) (1 << FP_N_FR)); /* round up */ - if (op.fr & FP_FCRY) { /* carry out? */ - op.fr = op.fr >> 1; /* renormalize */ - op.ch++; /* incr exp */ - if (op.ch == (FP_M_CH + 1)) /* ovf with QP = 0? */ - spill = TRAP_F_OVF | TRAP_F_AC; - } - AC = FP_PACK38 (op.s, op.ch, FP_HIFRAC (op.fr)); /* pack AC */ - } -return spill; -} - -/* Fraction divide - 54/27'0 yielding quotient and remainder */ - -t_uint64 fp_fracdiv (t_uint64 dvd, t_uint64 dvr, t_uint64 *rem) -{ -dvr = dvr >> FP_N_FR; -if (rem) - *rem = dvd % dvr; -return (dvd / dvr); -} - -/* Floating point normalize */ - -void fp_norm (UFP *op) -{ -op->fr = op->fr & FP_DFMASK; /* mask fraction */ -if (op->fr == 0) /* zero? */ - return; -while ((op->fr & FP_FNORM) == 0) { /* until norm */ - op->fr = op->fr << 1; /* lsh 1 */ - op->ch--; /* decr exp */ - } -return; -} - -/* Floating point unpack */ - -void fp_unpack (t_uint64 h, t_uint64 l, t_bool q_ac, UFP *op) -{ -if (q_ac) { /* AC? */ - op->s = (h & AC_S)? 1: 0; /* get sign */ - op->ch = (uint32) ((h >> FP_V_CH) & FP_M_ACCH); /* get exp */ - } -else { - op->s = (h & SIGN)? 1: 0; /* no, mem */ - op->ch = (uint32) ((h >> FP_V_CH) & FP_M_CH); - } -op->fr = (((t_uint64) FP_LOFRAC (h)) << FP_N_FR) | /* get frac hi */ - ((t_uint64) FP_LOFRAC (l)); /* get frac lo */ -return; -} - -/* Floating point pack */ - -uint32 fp_pack (UFP *op, uint32 mqs, int32 mqch) -{ -uint32 spill; - -AC = FP_PACK38 (op->s, op->ch, FP_HIFRAC (op->fr)); /* pack AC */ -MQ = FP_PACK36 (mqs, mqch, FP_LOFRAC (op->fr)); /* pack MQ */ -if (op->ch > FP_M_CH) /* check AC exp */ - spill = TRAP_F_OVF | TRAP_F_AC; -else if (op->ch < 0) - spill = TRAP_F_AC; -else spill = 0; -if (mqch > FP_M_CH) /* check MQ exp */ - spill |= (TRAP_F_OVF | TRAP_F_MQ); -else if (mqch < 0) - spill |= TRAP_F_MQ; -return spill; -} diff --git a/I7094/i7094_cpu_old.c b/I7094/i7094_cpu_old.c deleted file mode 100644 index 87c46fca..00000000 --- a/I7094/i7094_cpu_old.c +++ /dev/null @@ -1,2439 +0,0 @@ -/* i7094_cpu.c: IBM 7094 CPU simulator - - Copyright (c) 2003-2007, Robert 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 7094 central processor - - 28-Apr-07 RMS Removed clock initialization - 29-Oct-06 RMS Added additional expanded core instructions - 17-Oct-06 RMS Fixed the fix in halt IO wait loop - 16-Jun-06 RMS Fixed bug in halt IO wait loop - - The register state for the 7094 is: - - AC accumulator - MQ multiplier-quotient register - SI storage indicators - KEYS<0:35> front panel keys (switches) - IC<0:14> instruction counter (called PC here) - XR<0:14>[8] index registers (XR[0] is always 0) - SSW<0:5> sense switches - SLT<0:3> sense lights - OVF AC overflow - MQO MQ overflow - DVC divide check - IOC I/O check - TTRAP transfer trap mode - CTRAP copy trap mode (for 709 compatibility) - FTRAP floating trap mode (off is 704 compatibility) - STRAP select trap mode - STORN storage nullifcation mode - MULTI multi-tag mode (7090 compatibility) - - CTSS required a set of special features: memory extension (to 65K), - protection, and relocation. Additional state: - - USER user mode - INST_BASE instruction memory select (A vs B core) - DATA_BASE data memory select (A vs B core) - IND_RELOC<0:6> relocation value (block number) - IND_START<0:6> start address block - IND_LIMIT<0:6> limit address block - - The 7094 had five instruction formats: memory reference, - memory reference with count, convert, decrement, and immediate. - - 00000000011 11 1111 112 222222222333333 - S12345678901 23 4567 890 123456789012345 - +------------+--+----+---+---------------+ - | opcode |ND|0000|tag| address | memory reference - +------------+--+----+---+---------------+ - - 00000000011 111111 112 222222222333333 - S12345678901 234567 890 123456789012345 - +------------+------+---+---------------+ - | opcode | count|tag| address | memory reference - +------------+------+---+---------------+ with count - - 000000000 11111111 11 2 222222222333333 - S123456789 01234567 89 0 123456789012345 - +----------+--------+--+-+---------------+ - | opcode | count |00|X| address | convert - +----------+--------+--+-+---------------+ - - 00 000000011111111 112 222222222333333 - S12 345678901234567 890 123456789012345 - +---+---------------+---+---------------+ - |opc| decrement |tag| address | decrement - +---+---------------+---+---------------+ - - 00000000011 111111 112222222222333333 - S12345678901 234567 890123456789012345 - +------------+------+------------------+ - | opcode |000000| immediate | immediate - +------------+------+------------------+ - - This routine is the instruction decode routine for the 7094. - It is called from the simulator control program to execute - instructions in simulated memory, starting at the simulated PC. - It runs until a stop condition occurs. - - General notes: - - 1. Reasons to stop. The simulator can be stopped by: - - HALT instruction - illegal instruction - illegal I/O operation for device - illegal I/O operation for channel - breakpoint encountered - nested XEC's exceeding limit - divide check - I/O error in I/O simulator - - 2. Data channel traps. The 7094 is a channel-based system. - Channels can generate traps for errors and status conditions. - Channel trap state: - - ch_flags[0..7] flags for channels A..H - chtr_enab channel trap enables - chtr_inht channel trap inhibit due to trap (cleared by RCT) - chtr_inhi channel trap inhibit due to XEC, ENAB, RCT, RDS, - or WDS (cleared after one instruction) - - Channel traps are summarized in variable chtr_pend. - - 3. Arithmetic. The 7094 uses signed magnitude arithmetic for - integer and floating point calculations, and 2's complement - arithmetic for indexing calculations. - - 4. Adding I/O devices. These modules must be modified: - - i7094_defs.h add device definitions - i7094_io.c add device address mapping - i7094_sys.c add sim_devices table entry -*/ - -#include "i7094_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 | inst_base) - -#define HIST_MIN 64 -#define HIST_MAX (2 << 18) -#define HIST_CH_C 1 /* include channel */ -#define HIST_CH_I 2 /* include IO */ - -#define HALT_IO_LIMIT ((2 << 18) + 1) /* max wait to stop */ - -t_uint64 *M = NULL; /* memory */ -t_uint64 AC = 0; /* AC */ -t_uint64 MQ = 0; /* MQ */ -t_uint64 SI = 0; /* indicators */ -t_uint64 KEYS = 0; /* storage keys */ -uint32 PC = 0; /* PC (IC) */ -uint32 oldPC = 0; /* prior PC */ -uint32 XR[8] = { 0 }; /* index registers */ -uint32 SSW = 0; /* sense switches */ -uint32 SLT = 0; /* sense lights */ -uint32 ch_req = 0; /* channel requests */ -uint32 chtr_pend = 0; /* chan trap pending */ -uint32 chtr_inht = 0; /* chan trap inhibit trap */ -uint32 chtr_inhi = 0; /* chan trap inhibit inst */ -uint32 chtr_enab = 0; /* chan trap enables */ -uint32 mode_ttrap = 0; /* transfer trap mode */ -uint32 mode_ctrap = 0; /* copy trap mode */ -uint32 mode_strap = 0; /* select trap mode */ -uint32 mode_ftrap = 0; /* floating trap mode */ -uint32 mode_storn = 0; /* storage nullification */ -uint32 mode_multi = 0; /* multi-index mode */ -uint32 ind_ovf = 0; /* overflow */ -uint32 ind_mqo = 0; /* MQ overflow */ -uint32 ind_dvc = 0; /* divide check */ -uint32 ind_ioc = 0; /* IO check */ -uint32 cpu_model = I_9X|I_94; /* CPU type */ -uint32 mode_user = 0; /* (CTSS) user mode */ -uint32 ind_reloc = 0; /* (CTSS) relocation */ -uint32 ind_start = 0; /* (CTSS) prot start */ -uint32 ind_limit = 0; /* (CTSS) prot limit */ -uint32 inst_base = 0; /* (CTSS) inst A/B sel */ -uint32 data_base = 0; /* (CTSS) data A/B sel */ -uint32 xec_max = 16; /* XEC chain limit */ -uint32 ht_pend = 0; /* HTR pending */ -uint32 ht_addr = 0; /* HTR address */ -uint32 stop_illop = 1; /* stop on ill op */ -uint32 cpu_astop = 0; /* address stop */ -static uint32 eamask = AMASK; /* (dynamic) addr mask */ - -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -int32 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -uint32 hst_ch = 0; /* channel history */ -InstHistory *hst = NULL; /* instruction history */ - -extern uint32 ch_sta[NUM_CHAN]; -extern uint32 ch_flags[NUM_CHAN]; -extern DEVICE mt_dev[NUM_CHAN]; -extern DEVICE ch_dev[NUM_CHAN]; -extern FILE *sim_deb; -extern int32 sim_int_char; -extern int32 sim_interval; -extern int32 sim_switches; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ - -/* Forward and external declarations */ - -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_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -t_bool ReadI (uint32 va, t_uint64 *dat); -t_bool Read (uint32 va, t_uint64 *dat); -t_bool Write (uint32 va, t_uint64 dat); -void WriteTA (uint32 pa, uint32 addr); -void WriteTAD (uint32 pa, uint32 addr, uint32 decr); -void TrapXfr (uint32 newpc); -t_bool fp_trap (uint32 spill); -t_bool prot_trap (uint32 decr); -t_bool sel_trap (uint32 va); -t_bool cpy_trap (uint32 va); -uint32 get_xri (uint32 tag); -uint32 get_xrx (uint32 tag); -void put_xr (uint32 tag, uint32 dat); -t_stat cpu_fprint_one_inst (FILE *st, uint32 pc, uint32 rpt, uint32 ea, - t_uint64 ir, t_uint64 ac, t_uint64 mq, t_uint64 si, t_uint64 opnd); - -extern uint32 chtr_eval (uint32 *decr); -extern void op_add (t_uint64 sr); -extern void op_mpy (t_uint64 ac, t_uint64 sr, uint32 sc); -extern t_bool op_div (t_uint64 sr, uint32 sc); -extern uint32 op_fad (t_uint64 sr, t_bool norm); -extern uint32 op_fmp (t_uint64 sr, t_bool norm); -extern uint32 op_fdv (t_uint64); -extern uint32 op_dfad (t_uint64 shi, t_uint64 slo, t_bool norm); -extern uint32 op_dfmp (t_uint64 shi, t_uint64 slo, t_bool norm); -extern uint32 op_dfdv (t_uint64 shi, t_uint64 slo); -extern void op_als (uint32 ea); -extern void op_ars (uint32 ea); -extern void op_lls (uint32 ea); -extern void op_lrs (uint32 ea); -extern void op_lgl (uint32 ea); -extern void op_lgr (uint32 ea); -extern t_stat op_pse (uint32 ea); -extern t_stat op_mse (uint32 ea); -extern t_stat ch_op_ds (uint32 ch, uint32 ds, uint32 unit); -extern t_stat ch_op_nds (uint32 ch, uint32 ds, uint32 unit); -extern t_stat ch_op_start (uint32 ch, uint32 clc, t_bool reset); -extern t_stat ch_op_store (uint32 ch, t_uint64 *dat); -extern t_stat ch_op_store_diag (uint32 ch, t_uint64 *dat); -extern t_stat ch_proc (uint32 ch); - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit - cpu_reg CPU register list - cpu_mod CPU modifier list -*/ - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BINK, STDMEMSIZE) }; - -REG cpu_reg[] = { - { ORDATA (PC, PC, ASIZE) }, - { ORDATA (AC, AC, 38) }, - { ORDATA (MQ, MQ, 36) }, - { ORDATA (SI, SI, 36) }, - { ORDATA (KEYS, KEYS, 36) }, - { ORDATA (XR1, XR[1], 15) }, - { ORDATA (XR2, XR[2], 15) }, - { ORDATA (XR3, XR[3], 15) }, - { ORDATA (XR4, XR[4], 15) }, - { ORDATA (XR5, XR[5], 15) }, - { ORDATA (XR6, XR[6], 15) }, - { ORDATA (XR7, XR[7], 15) }, - { FLDATA (SS1, SSW, 5) }, - { FLDATA (SS2, SSW, 4) }, - { FLDATA (SS3, SSW, 3) }, - { FLDATA (SS4, SSW, 2) }, - { FLDATA (SS5, SSW, 1) }, - { FLDATA (SS6, SSW, 0) }, - { FLDATA (SL1, SLT, 3) }, - { FLDATA (SL2, SLT, 2) }, - { FLDATA (SL3, SLT, 1) }, - { FLDATA (SL4, SLT, 0) }, - { FLDATA (OVF, ind_ovf, 0) }, - { FLDATA (MQO, ind_mqo, 0) }, - { FLDATA (DVC, ind_dvc, 0) }, - { FLDATA (IOC, ind_ioc, 0) }, - { FLDATA (TTRAP, mode_ttrap, 0) }, - { FLDATA (CTRAP, mode_ctrap, 0) }, - { FLDATA (STRAP, mode_strap, 0) }, - { FLDATA (FTRAP, mode_ftrap, 0) }, - { FLDATA (STORN, mode_storn, 0) }, - { FLDATA (MULTI, mode_multi, 0) }, - { ORDATA (CHREQ, ch_req, NUM_CHAN) }, - { FLDATA (CHTR_PEND, chtr_pend, 0) }, - { FLDATA (CHTR_INHT, chtr_inht, 0) }, - { FLDATA (CHTR_INHI, chtr_inhi, 0) }, - { ORDATA (CHTR_ENAB, chtr_enab, 30) }, - { FLDATA (USERM, mode_user, 0) }, - { FLDATA (IMEM, inst_base, BCORE_V) }, - { FLDATA (DMEM, data_base, BCORE_V) }, - { GRDATA (RELOC, ind_reloc, 8, VA_N_BLK, VA_V_BLK) }, - { GRDATA (START, ind_start, 8, VA_N_BLK, VA_V_BLK) }, - { GRDATA (LIMIT, ind_limit, 8, VA_N_BLK, VA_V_BLK) }, - { ORDATA (OLDPC, oldPC, ASIZE), REG_RO }, - { BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { FLDATA (HTPEND, ht_pend, 0) }, - { ORDATA (HTADDR, ht_addr, ASIZE) }, - { DRDATA (XECMAX, xec_max, 8), PV_LEFT + REG_NZ }, - { ORDATA (WRU, sim_int_char, 8) }, - { FLDATA (STOP_ILL, stop_illop, 0) }, - { ORDATA (MODEL, cpu_model, 4), REG_HRO }, - { NULL } - }; - -MTAB cpu_mod[] = { - { MTAB_XTD | MTAB_VDV, I_9X|I_94|I_CT, "MODEL", "CTSS", - &cpu_set_model, &cpu_show_model, NULL }, - { MTAB_XTD | MTAB_VDV, I_9X|I_94, NULL, "7094", - &cpu_set_model, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, I_9X, NULL, "7090", - &cpu_set_model, NULL, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, PASIZE, 1, 8, 36, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - NULL, DEV_DEBUG - }; - -/* Instruction decode table */ - -const uint8 op_flags[1024] = { - I_XN , 0 , 0 , 0 , /* +000 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN|I_9X , I_XN , 0 , /* +020 */ - I_XN , 0 , I_XN , I_XN , - I_XN , I_XN , I_XN , I_XN , - 0 , 0 , 0 , 0 , - I_XN|I_9X , I_9X , I_XN|I_9X , I_9X , /* +040 */ - I_9X , 0 , I_XN|I_9X , 0 , - 0 , I_9X , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - I_XN , I_XN , I_XN , I_XN , /* +060 */ - I_XN , I_XN , I_XN , I_XN , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN|I_CT , 0 , 0 , /* +100 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - I_XN , 0 , 0 , 0 , /* +120 */ - 0 , 0 , 0 , 0 , - 0 , I_9X , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , 0 , 0 , 0 , /* +140 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , I_XN|I_9X , I_XN|I_9X , 0 , /* +160 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , 0 , 0 , /* +200 */ - I_XNR , I_XNR , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, I_XNR , 0 , 0 , /* +220 */ - I_XNR|I_9X, I_XNR , I_XNR|I_9X, I_XNR , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, I_XNR , 0 , 0 , /* +240 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XND|I_94, 0 , 0 , /* +260 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XND|I_94, I_XNR , I_XND|I_94, /* +300 */ - I_XNR|I_9X, I_XND|I_94, I_XNR|I_9X, I_XND|I_94, - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , I_XNR|I_9X, 0 , /* +320 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , 0 , 0 , /* +340 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , I_XNR , 0 , 0 , /* +360 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XNR|I_9X, I_XNR , 0 , /* +400 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* +420 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_94, /* +440 */ - I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_9X, 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , 0 , 0 , 0 , /* +460 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , I_XNR , 0 , /* +500 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , I_XNR , 0 , /* +520 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_R , I_R , 0 , 0 , - I_XN , I_XN , I_XN , I_XN , /* +540 */ - I_XN , I_XN , I_XN , I_XN , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , I_XNR|I_CT, 0 , /* +560 */ - I_XNR , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN , I_XN , 0 , /* +600 */ - I_XN|I_9X , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , I_XNR , I_XNR , 0 , /* +620 */ - 0 , I_XNR|I_9X, 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , - I_R , 0 , I_R|I_94 , 0 , - I_XN , I_XN , I_XN , I_XN , /* +640 */ - I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* +660 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , 0 , 0 , 0 , /* +700 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* +720 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* +740 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , I_94 , 0 , - I_X , 0 , I_X , I_X , /* +760 */ - I_X , I_X , I_X , I_X , - I_X , I_X , I_X , 0 , - 0 , 0 , 0 , 0 , - - I_XN , 0 , 0 , 0 , /* -000 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN|I_9X , I_XN , 0 , /* -020 */ - I_XN , 0 , I_XN , I_XN , - I_XN , I_XN , I_XN , I_XN , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -040 */ - 0 , 0 , I_9X , 0 , - 0 , I_9X , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , /* -060 */ - I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN|I_CT , 0 , 0 , /* -100 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - I_XN , 0 , 0 , 0 , /* -120 */ - 0 , 0 , 0 , 0 , - I_9X , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN|I_9X , 0 , 0 , 0 , /* -140 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - 0 , 0 , 0 , 0 , /* -160 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , /* -200 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -220 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XND|I_94, I_XND|I_94, 0 , 0 , /* -240 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XND|I_94, 0 , 0 , /* -260 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XND|I_94, I_XNR , I_XND|I_94, /* -300 */ - I_XNR|I_9X, I_XND|I_94, I_XNR|I_9X, I_XND|I_94, - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , 0 , 0 , /* -320 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , 0 , 0 , /* -340 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -360 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , /* -400 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -420 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -440 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -460 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XNR , 0 , 0 , /* -500 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , /* -520 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_R , I_R , 0 , 0 , - I_XN , I_XN , I_XN , I_XN , /* -540 */ - I_XN , I_XN , I_XNR , I_XN , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -560 */ - I_XNR|I_CT, 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , 0 , I_XNR|I_9X, I_XN|I_94 , /* -600 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , /* -620 */ - 0 , I_XNR , 0 , 0 , - 0 , 0 , 0 , 0 , - I_R , 0 , I_R|I_94 , 0 , - I_XN , I_XN , I_XN , I_XN , /* -640 */ - I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -660 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , 0 , 0 , 0 , /* -700 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -720 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -740 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , I_94 , 0 , - I_X , I_X|I_CT , 0 , I_X , /* -760 */ - 0 , I_X , 0 , 0 , - 0 , 0 , I_X , I_X , - I_9X , 0 , 0 , 0 - }; - -/* Instruction execution routine */ - -t_stat sim_instr (void) -{ -t_stat reason = SCPE_OK; -t_uint64 IR, SR, t, t1, t2, sr1; -uint32 op, fl, tag, tagi, addr, ea; -uint32 ch, dec, xr, xec_cnt, trp; -uint32 i, j, sc, s1, s2, spill; -t_bool tracing; - -/* Restore register state */ - -ch_set_map (); /* set dispatch map */ -if (!(cpu_model & (I_94|I_CT))) /* ~7094? MTM always on */ - mode_multi = 1; -eamask = mode_storn? A704_MASK: AMASK; /* set eff addr mask */ -inst_base = inst_base & ~AMASK; /* A/B sel is 1b */ -data_base = data_base & ~AMASK; -ind_reloc = ind_reloc & VA_BLK; /* canonical form */ -ind_start = ind_start & VA_BLK; -ind_limit = (ind_limit & VA_BLK) | VA_OFF; -chtr_pend = chtr_eval (NULL); /* eval chan traps */ -tracing = ((hst_lnt != 0) || DEBUG_PRS (cpu_dev)); - -if (ht_pend) { /* HTR pending? */ - oldPC = (PC - 1) & AMASK; - ht_pend = 0; /* clear flag */ - PCQ_ENTRY; - if (mode_ttrap) { /* trap? */ - WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ - TrapXfr (TRAP_TRA_PC); /* trap */ - } - else PC = ht_addr; /* branch */ - } - -/* Main instruction fetch/decode loop */ - -while (reason == SCPE_OK) { /* loop until error */ - - if (cpu_astop) { /* debug stop? */ - cpu_astop = 0; - reason = SCPE_STOP; - break; - } - - if (sim_interval <= 0) { /* intv cnt expired? */ - if (reason = sim_process_event ()) /* process events */ - break; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - } - - for (i = 0; ch_req && (i < NUM_CHAN); i++) { /* loop thru channels */ - if (ch_req & REQ_CH (i)) { /* channel request? */ - if (reason = ch_proc (i)) - break; - } - chtr_pend = chtr_eval (NULL); - if (reason) /* error? */ - break; - } - - if (chtr_pend) { /* channel trap? */ - addr = chtr_eval (&trp); /* get trap info, clr */ - chtr_inht = 1; /* inhibit traps */ - chtr_pend = 0; /* no trap pending */ - WriteTAD (addr, PC, trp); /* wr trap addr,flag */ - IR = ReadP (addr + 1); /* get trap instr */ - oldPC = PC; /* save current PC */ - } - - else { - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - if (chtr_inhi) { /* 1 cycle inhibit? */ - chtr_inhi = 0; /* clear */ - chtr_pend = chtr_eval (NULL); /* re-evaluate */ - } - oldPC = PC; /* save current PC */ - PC = (PC + 1) & eamask; /* increment PC */ - if (!ReadI (oldPC, &IR)) /* get inst; trap? */ - continue; - } - - sim_interval = sim_interval - 1; - xec_cnt = 0; /* clear XEC cntr */ - - XEC: - - tag = GET_TAG (IR); /* get tag */ - addr = (uint32) IR & eamask; /* get base addr */ - -/* Decrement format instructions */ - - if (IR & INST_T_DEC) { /* decrement type? */ - op = GET_OPD (IR); /* get opcode */ - dec = GET_DEC (IR); /* get decrement */ - xr = get_xrx (tag); /* get xr, upd MTM */ - if (tracing) { /* trace or history? */ - if (hst_lnt) /* history enabled? */ - cpu_ent_hist (oldPC|HIST_PC, xr, IR, 0); - if (DEBUG_PRS (cpu_dev)) - cpu_fprint_one_inst (sim_deb, oldPC|HIST_PC, 0, xr, - IR, AC, MQ, SI, 0); - } - switch (op) { - - case 01: /* TXI */ - put_xr (tag, xr + dec); /* xr += decr */ - PCQ_ENTRY; - if (mode_ttrap) { /* trap? */ - WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ - TrapXfr (TRAP_TRA_PC); /* trap */ - } - else PC = addr; /* branch */ - break; - - case 02: /* TIX */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (xr > dec) { /* if xr > decr */ - put_xr (tag, xr - dec); /* xr -= decr */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = addr; /* branch */ - } - break; - - case 03: /* TXH */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (xr > dec) { /* if xr > decr */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = addr; /* branch */ - } - break; - - case 05: /* STR */ - WriteTA (TRAP_STD_SAV, PC); /* save inst+1 */ - PCQ_ENTRY; - PC = TRAP_STR_PC; /* branch to 2 */ - break; - - case 06: /* TNX */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (xr > dec) /* if xr > decr */ - put_xr (tag, xr - dec); - else { /* xr -= decr */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = addr; /* branch */ - } - break; - - case 07: /* TXL */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (xr <= dec) { /* if xr <= decr */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = addr; /* branch */ - } - break; - } - } /* end if */ - -/* Normal format instructions */ - - else { - op = GET_OPC (IR); /* get opcode */ - fl = op_flags[op]; /* get flags */ - if (fl & I_MODEL & ~cpu_model) { /* invalid for model? */ - if (stop_illop) /* possible stop */ - reason = STOP_ILLEG; - continue; - } - if (tag && (fl & I_X)) /* tag and indexable? */ - ea = (addr - get_xri (tag)) & eamask; /* do indexing */ - else ea = addr; - if (TST_IND (IR) && (fl & I_N)) { /* indirect? */ - if (!ReadI (ea, &SR)) /* get ind; trap? */ - continue; - addr = (uint32) SR & eamask; /* get address */ - tagi = GET_TAG (SR); /* get tag */ - if (tagi) /* tag? */ - ea = (addr - get_xri (tagi)) & eamask; /* do indexing */ - else ea = addr; - } - if ((fl & I_R) && !Read (ea, &SR)) /* read opnd; trap? */ - continue; - else if (fl & I_D) { /* double prec? */ - if ((ea & 1) && fp_trap (TRAP_F_ODD)) - continue; - if (!Read (ea, &SR)) /* SR gets high */ - continue; - if (!Read (ea | 1, &sr1)) /* "sr1" gets low */ - continue; - } - if (tracing) { /* tracing or history? */ - if (hst_lnt) /* history enabled? */ - cpu_ent_hist (oldPC|HIST_PC, ea, IR, SR); - if (DEBUG_PRS (cpu_dev)) - cpu_fprint_one_inst (sim_deb, oldPC|HIST_PC, 0, ea, - IR, AC, MQ, SI, SR); - } - switch (op) { /* case on opcode */ - -/* Positive instructions */ - - case 00000: /* HTR */ - case 01000: /* also -HTR */ - if (prot_trap (0)) /* user mode? */ - break; - ht_pend = 1; /* transfer pending */ - ht_addr = ea; /* save address */ - reason = STOP_HALT; /* halt if I/O done */ - break; - - case 00020: /* TRA */ - case 01020: /* also -TRA */ - PCQ_ENTRY; - if (mode_ttrap) { /* trap? */ - WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ - TrapXfr (TRAP_TRA_PC); /* trap */ - } - else PC = ea; /* branch */ - break; - - case 00021: /* TTR */ - PCQ_ENTRY; - PC = ea; /* branch, no trap */ - break; - - case 00040: /* TLQ */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - s1 = (AC & AC_S)? 1: 0; /* get AC, MQ sign, */ - s2 = (MQ & SIGN)? 1: 0; /* magnitude */ - t1 = AC & AC_MMASK; - t2 = MQ & MMASK; /* signs differ? */ - if ((s1 != s2)? s2: /* y, br if MQ- */ - ((t1 != t2) && (s2 ^ (t1 > t2)))) { /* n, br if sgn-^AC>MQ */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00041: /* IIA */ - SI = SI ^ (AC & DMASK); - break; - - case 00042: /* TIO */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((SI & AC) == (AC & DMASK)) { /* if ind on */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00043: /* OAI */ - SI = SI | (AC & DMASK); - break; - - case 00044: /* PAI */ - SI = AC & DMASK; - break; - - case 00046: /* TIF */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((SI & AC) == 0) { /* if ind off */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00051: /* IIR */ - SI = SI ^ (IR & RMASK); - break; - - case 00054: /* RFT */ - t = IR & RMASK; - if ((SI & t) == 0) /* if ind off, skip */ - PC = (PC + 1) & eamask; - break; - - case 00055: /* SIR */ - SI = SI | (IR & RMASK); - break; - - case 00056: /* RNT */ - t = IR & RMASK; - if ((SI & t) == t) /* if ind on, skip */ - PC = (PC + 1) & eamask; - break; - - case 00057: /* RIR */ - SI = SI & ~(IR & RMASK); - break; - - case 00074: /* TSX */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (tag) /* save -inst loc */ - put_xr (tag, ~oldPC + 1); - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - break; - - case 00100: /* TZE */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((AC & AC_MMASK) == 0) { /* if AC Q,P,1-35 = 0 */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00101: /* (CTSS) TIA */ - if (prot_trap (0)) /* not user mode? */ - break; - PCQ_ENTRY; - PC = ea; - inst_base = 0; - break; - - case 00114: case 00115: case 00116: case 00117: /* CVR */ - sc = GET_CCNT (IR); - SR = ea; - while (sc) { - ea = (uint32) ((AC & 077) + SR) & eamask; - if (!Read (ea, &SR)) - break; - AC = (AC & AC_S) | ((AC >> 6) & 0017777777777) | - (SR & 0770000000000); - sc--; - } - if ((sc == 0) && (IR & INST_T_CXR1)) - put_xr (1, (uint32) SR); - break; - - case 00120: /* TPL */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((AC & AC_S) == 0) { /* if AC + */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00131: /* XCA */ - t = MQ; - MQ = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); - AC = (t & MMASK) | ((t & SIGN)? AC_S: 0); - break; - - case 00140: /* TOV */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (ind_ovf) { /* if overflow */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ind_ovf = 0; /* clear overflow */ - } - break; - - case 00161: /* TQO */ - if (!mode_ftrap) { /* only in 704 mode */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (ind_mqo) { /* if MQ overflow */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ind_mqo = 0; /* clear overflow */ - } - } - break; - - case 00162: /* TQP */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((MQ & SIGN) == 0) { /* if MQ + */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00200: /* MPY */ - op_mpy (0, SR, 043); - break; - - case 00204: /* VLM */ - case 00205: /* for diagnostic */ - sc = GET_VCNT (IR); - op_mpy (0, SR, sc); - break; - - case 00220: /* DVH */ - if (op_div (SR, 043)) { - ind_dvc = 1; - if (!prot_trap (0)) - reason = STOP_DIVCHK; - } - break; - - case 00221: /* DVP */ - if (op_div (SR, 043)) - ind_dvc = 1; - break; - - case 00224: /* VDH */ - case 00226: /* for diagnostic */ - sc = GET_VCNT (IR); - if (op_div (SR, sc)) { - ind_dvc = 1; - if (!prot_trap (0)) - reason = STOP_DIVCHK; - } - break; - - case 00225: /* VDP */ - case 00227: /* for diagnostic */ - sc = GET_VCNT (IR); - if (op_div (SR, sc)) - ind_dvc = 1; - break; - - case 00240: /* FDH */ - spill = op_fdv (SR); - if (spill == TRAP_F_DVC) { - ind_dvc = 1; - if (!prot_trap (0)) - reason = STOP_DIVCHK; - } - else if (spill) - fp_trap (spill); - break; - - case 00241: /* FDP */ - spill = op_fdv (SR); - if (spill == TRAP_F_DVC) - ind_dvc = 1; - else if (spill) - fp_trap (spill); - break; - - case 00260: /* FMP */ - spill = op_fmp (SR, 1); /* MQ * SR */ - if (spill) - fp_trap (spill); - break; - - case 00261: /* DFMP */ - spill = op_dfmp (SR, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00300: /* FAD */ - spill = op_fad (SR, 1); - if (spill) - fp_trap (spill); - break; - - case 00301: /* DFAD */ - spill = op_dfad (SR, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00302: /* FSB */ - spill = op_fad (SR ^ SIGN, 1); - if (spill) - fp_trap (spill); - break; - - case 00303: /* DFSB */ - spill = op_dfad (SR ^ SIGN, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00304: /* FAM */ - spill = op_fad (SR & ~SIGN, 1); - if (spill) - fp_trap (spill); - break; - - case 00305: /* DFAM */ - spill = op_dfad (SR & ~SIGN, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00306: /* FSM */ - spill = op_fad (SR | SIGN, 1); - if (spill) - fp_trap (spill); - break; - - case 00307: /* DFSM */ - spill = op_dfad (SR | SIGN, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00320: /* ANS */ - SR = AC & SR; - Write (ea, SR); - break; - - case 00322: /* ERA */ - AC = (AC ^ SR) & DMASK; /* AC S,Q cleared */ - break; - - case 00340: /* CAS */ - s1 = (AC & AC_S)? 1: 0; /* get AC, MQ signs, */ - s2 = (SR & SIGN)? 1: 0; - t1 = AC & AC_MMASK; /* magnitudes */ - t2 = SR & MMASK; - if (s1 ^ s2) { /* diff signs? */ - if (s1) /* AC < mem? skip 2 */ - PC = (PC + 2) & eamask; - } - else if (t1 == t2) /* equal? skip 1 */ - PC = (PC + 1) & eamask; - else if ((t1 < t2) ^ s1) /* AC < mem, AC +, or */ - PC = (PC + 2) & eamask; /* AC > mem, AC -? */ - break; - - case 00361: /* ACL */ - t = (AC + SR) & DMASK; /* AC P,1-35 + SR */ - if (t < SR) /* end around carry */ - t = (t + 1) & DMASK; - AC = (AC & (AC_S | AC_Q)) | t; /* preserve AC S,Q */ - break; - - case 00400: /* ADD */ - op_add (SR); - break; - - case 00401: /* ADM */ - op_add (SR & MMASK); - break; - - case 00402: /* SUB */ - op_add (SR ^ SIGN); - break; - - case 00420: /* HPR */ - if (prot_trap (0)) /* user mode? */ - break; - reason = STOP_HALT; /* halt if I/O done */ - break; - - case 00440: /* IIS */ - SI = SI ^ SR; - break; - - case 00441: /* LDI */ - SI = SR; - break; - - case 00442: /* OSI */ - SI = SI | SR; - break; - - case 00443: /* DLD */ - AC = (SR & MMASK) | ((SR & SIGN)? AC_S: 0); /* normal load */ - if (!Read (ea | 1, &SR)) /* second load */ - break; - MQ = SR; - if (ea & 1) /* trap after exec */ - fp_trap (TRAP_F_ODD); - break; - - case 00444: /* OFT */ - if ((SI & SR) == 0) /* skip if ind off */ - PC = (PC + 1) & eamask; - break; - - case 00445: /* RIS */ - SI = SI & ~SR; - break; - - case 00446: /* ONT */ - if ((SI & SR) == SR) /* skip if ind on */ - PC = (PC + 1) & eamask; - break; - - case 00460: /* LDA (704) */ - cpy_trap (PC); - break; - - case 00500: /* CLA */ - AC = (SR & MMASK) | ((SR & SIGN)? AC_S: 0); - break; - - case 00502: /* CLS */ - AC = (SR & MMASK) | ((SR & SIGN)? 0: AC_S); - break; - - case 00520: /* ZET */ - if ((SR & MMASK) == 0) /* skip if M 1-35 = 0 */ - PC = (PC + 1) & eamask; - break; - - case 00522: /* XEC */ - if (xec_cnt++ >= xec_max) { /* xec chain limit? */ - reason = STOP_XEC; /* stop */ - break; - } - IR = SR; /* operand is new inst */ - chtr_inhi = 1; /* delay traps */ - chtr_pend = 0; /* no trap now */ - goto XEC; /* start over */ - - case 00534: /* LXA */ - if (tag) /* M addr -> xr */ - put_xr (tag, (uint32) SR); - break; - - case 00535: /* LAC */ - if (tag) /* -M addr -> xr */ - put_xr (tag, NEG ((uint32) SR)); - break; - - case 00560: /* LDQ */ - MQ = SR; - break; - - case 00562: /* (CTSS) LRI */ - if (prot_trap (0)) /* user mode? */ - break; - ind_reloc = ((uint32) SR) & VA_BLK; - break; - - case 00564: /* ENB */ - if (prot_trap (0)) /* user mode? */ - break; - chtr_enab = (uint32) SR; /* set enables */ - chtr_inht = 0; /* clear inhibit */ - chtr_inhi = 1; /* 1 cycle delay */ - chtr_pend = 0; /* no traps now */ - break; - - case 00600: /* STZ */ - Write (ea, 0); - break; - - case 00601: /* STO */ - SR = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); - Write (ea, SR); - break; - - case 00602: /* SLW */ - Write (ea, AC & DMASK); - break; - - case 00604: /* STI */ - Write (ea, SI); - break; - - case 00621: /* STA */ - SR = (SR & ~AMASK) | (AC & AMASK); - Write (ea, SR); - break; - - case 00622: /* STD */ - SR = (SR & ~XMASK) | (AC & XMASK); - Write (ea, SR); - break; - - case 00625: /* STT */ - SR = (SR & ~TMASK) | (AC & TMASK); - Write (ea, SR); - break; - - case 00630: /* STP */ - SR = (SR & ~PMASK) | (AC & PMASK); - Write (ea, SR); - break; - - case 00634: /* SXA */ - SR = (SR & ~AMASK) | /* xr -> M addr */ - ((t_uint64) get_xrx (tag)); - Write (ea, SR); - break; - - case 00636: /* SCA */ - SR = (SR & ~AMASK) | /* -xr -> M addr */ - ((t_uint64) (NEG (get_xrx (tag)) & AMASK)); - Write (ea, SR); - break; - - case 00700: /* CPY (704) */ - cpy_trap (PC); - break; - - case 00734: /* PAX */ - if (tag) /* AC addr -> xr */ - put_xr (tag, (uint32) AC); - break; - - case 00737: /* PAC */ - if (tag) /* -AC addr -> xr */ - put_xr (tag, NEG ((uint32) AC)); - break; - - case 00754: /* PXA */ - AC = get_xrx (tag); /* xr -> AC */ - break; - - case 00756: /* PCA */ - AC = NEG (get_xrx (tag)) & AMASK; /* -xr -> AC */ - break; - - case 00760: /* PSE */ - if (prot_trap (0)) /* user mode? */ - break; - reason = op_pse (ea); - break; - - case 00761: /* NOP */ - break; - - case 00763: /* LLS */ - op_lls (ea); - break; - - case 00765: /* LRS */ - op_lrs (ea); - break; - - case 00767: /* ALS */ - op_als (ea); - break; - - case 00771: /* ARS */ - op_ars (ea); - break; - - case 00774: /* AXT */ - if (tag) /* IR addr -> xr */ - put_xr (tag, addr); - break; - -/* Negative instructions */ - - case 01021: /* ESNT */ - mode_storn = 1; /* enter nullification */ - PCQ_ENTRY; - PC = ea; /* branch, no trap */ - break; - - case 01042: /* RIA */ - SI = SI & ~AC; - break; - - case 01046: /* PIA */ - AC = SI; - break; - - case 01051: /* IIL */ - SI = SI ^ ((IR & RMASK) << 18); - break; - - case 01054: /* LFT */ - t = (IR & RMASK) << 18; - if ((SI & t) == 0) /* if ind off, skip */ - PC = (PC + 1) & eamask; - break; - - case 01055: /* SIL */ - SI = SI | ((IR & RMASK) << 18); - break; - - case 01056: /* LNT */ - t = (IR & RMASK) << 18; - if ((SI & t) == t) /* if ind on, skip */ - PC = (PC + 1) & eamask; - break; - - case 01057: /* RIL */ - SI = SI & ~((IR & RMASK) << 18); - break; - - case 01100: /* TNZ */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((AC & AC_MMASK) != 0) { /* if AC != 0 */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 01101: /* (CTSS) TIB */ - if (prot_trap (0)) /* user mode? */ - break; - PCQ_ENTRY; - PC = ea; - mode_user = 1; - inst_base = BCORE_BASE; - break; - - case 01114: case 01115: case 01116: case 01117: /* CAQ */ - sc = GET_CCNT (IR); - SR = ea; - while (sc) { - ea = (uint32) ((MQ >> 30) + SR) & eamask; - if (!Read (ea, &SR)) - break; - MQ = ((MQ << 6) & DMASK) | (MQ >> 30); - AC = (AC & AC_S) | ((AC + SR) & AC_MMASK); - sc--; - } - if ((sc == 0) && (IR & INST_T_CXR1)) - put_xr (1, (uint32) SR); - break; - - case 01120: /* TMI */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((AC & AC_S) != 0) { /* if AC - */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 01130: /* XCL */ - t = MQ; - MQ = AC & DMASK; - AC = t; - break; - - case 01140: /* TNO */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (!ind_ovf) { /* if no overflow */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - ind_ovf = 0; /* clear overflow */ - break; - - case 01154: case 01155: case 01156: case 01157: /* CRQ */ - sc = GET_CCNT (IR); - SR = ea; - while (sc) { - ea = (uint32) ((MQ >> 30) + SR) & eamask; - if (!Read (ea, &SR)) - break; - MQ = ((MQ << 6) & DMASK) | (SR >> 30); - sc--; - } - if ((sc == 0) && (IR & INST_T_CXR1)) - put_xr (1, (uint32) SR); - break; - - case 01200: /* MPR */ - op_mpy (0, SR, 043); - if (MQ & B1) - AC = (AC & AC_S) | ((AC + 1) & AC_MMASK); - break; - - case 01240: /* DFDH */ - spill = op_dfdv (SR, sr1); - if (spill == TRAP_F_DVC) { - ind_dvc = 1; - if (!prot_trap (0)) - reason = STOP_DIVCHK; - } - else if (spill) - fp_trap (spill); - break; - - case 01241: /* DFDP */ - spill = op_dfdv (SR, sr1); - if (spill == TRAP_F_DVC) - ind_dvc = 1; - else if (spill) - fp_trap (spill); - break; - - case 01260: /* UFM */ - spill = op_fmp (SR, 0); - if (spill) - fp_trap (spill); - break; - - case 01261: /* DUFM */ - spill = op_dfmp (SR, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01300: /* UFA */ - spill = op_fad (SR, 0); - if (spill) - fp_trap (spill); - break; - - case 01301: /* DUFA */ - spill = op_dfad (SR, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01302: /* UFS */ - spill = op_fad (SR ^ SIGN, 0); - if (spill) - fp_trap (spill); - break; - - case 01303: /* DUFS */ - spill = op_dfad (SR ^ SIGN, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01304: /* UAM */ - spill = op_fad (SR & ~SIGN, 0); - if (spill) - fp_trap (spill); - break; - - case 01305: /* DUAM */ - spill = op_dfad (SR & ~SIGN, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01306: /* USM */ - spill = op_fad (SR | SIGN, 0); - if (spill) - fp_trap (spill); - break; - - case 01307: /* DUSM */ - spill = op_dfad (SR | SIGN, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01320: /* ANA */ - AC = AC & SR; - break; - - case 01340: /* LAS */ - t = AC & AC_MMASK; /* AC Q,P,1-35 */ - if (t < SR) - PC = (PC + 2) & eamask; - else if (t == SR) - PC = (PC + 1) & eamask; - break; - - case 01400: /* SBM */ - op_add (SR | SIGN); - break; - - case 01500: /* CAL */ - AC = SR; - break; - - case 01501: /* ORA */ - AC = AC | SR; - break; - - case 01520: /* NZT */ - if ((SR & MMASK) != 0) - PC = (PC + 1) & eamask; - break; - - case 01534: /* LXD */ - if (tag) /* M decr -> xr */ - put_xr (tag, GET_DEC (SR)); - break; - - case 01535: /* LDC */ - if (tag) /* -M decr -> xr */ - put_xr (tag, NEG (GET_DEC (SR))); - break; - - case 01564: /* (CTSS) LPI */ - if (prot_trap (0)) /* user mode? */ - break; - ind_start = ((uint32) SR) & VA_BLK; - ind_limit = (GET_DEC (SR) & VA_BLK) | VA_OFF; - break; - - case 01600: /* STQ */ - Write (ea, MQ); - break; - - case 01602: /* ORS */ - SR = SR | (AC & DMASK); - Write (ea, SR); - break; - - case 01603: /* DST */ - SR = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); - if (!Write (ea, SR)) - break; - Write ((ea + 1) & eamask, MQ); - break; - - case 01620: /* SLQ */ - SR = (SR & RMASK) | (MQ & LMASK); - Write (ea, SR); - break; - - case 01625: /* STL */ - SR = (SR & ~AMASK) | PC; - Write (ea, SR); - break; - - case 01634: /* SXD */ - SR = (SR & ~XMASK) | /* xr -> M decr */ - (((t_uint64) get_xrx (tag)) << INST_V_DEC); - Write (ea, SR); - break; - - case 01636: /* SCD */ - SR = (SR & ~XMASK) | /* -xr -> M decr */ - (((t_uint64) (NEG (get_xrx (tag)) & AMASK)) << INST_V_DEC); - Write (ea, SR); - break; - - case 01700: /* CAD (704) */ - cpy_trap (PC); - break; - - case 01734: /* PDX */ - if (tag) /* AC decr -> xr */ - put_xr (tag, GET_DEC (AC)); - break; - - case 01737: /* PDC */ - if (tag) /* -AC decr -> xr */ - put_xr (tag, NEG (GET_DEC (AC))); - break; - - case 01754: /* PXD */ - AC = ((t_uint64) get_xrx (tag)) << INST_V_DEC; - break; /* xr -> AC decr */ - - case 01756: /* PCD */ - AC = ((t_uint64) (NEG (get_xrx (tag)) & AMASK)) << INST_V_DEC; - break; /* -xr -> AC decr */ - - case 01760: /* MSE */ - if (prot_trap (0)) /* user mode? */ - break; - reason = op_mse (ea); - break; - - case 01761: /* (CTSS) ext core */ - if (prot_trap (0)) /* user mode? */ - break; - if (ea == 041) /* SEA? */ - data_base = 0; - else if (ea == 042) /* SEB? */ - data_base = BCORE_BASE; - else if (ea == 043) { /* IFT? */ - if (inst_base == 0) - PC = (PC + 1) & eamask; - } - else if (ea == 044) { /* EFT? */ - if (data_base == 0) - PC = (PC + 1) & eamask; - } - else if (stop_illop) - reason = STOP_ILLEG; - break; - - case 01763: /* LGL */ - op_lgl (ea); - break; - - case 01765: /* LGR */ - op_lgr (ea); - break; - - case 01773: /* RQL */ - sc = (ea & SCMASK) % 36; - if (sc) - MQ = ((MQ << sc) | (MQ >> (36 - sc))) & DMASK; - break; - - case 01774: /* AXC */ - if (tag) /* -IR addr -> xr */ - put_xr (tag, NEG (addr)); - break; - -/* IO instructions */ - - case 00022: case 00024: case 00026: /* TRCx */ - case 01022: case 01024: case 01026: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 077) - 00022) | ((op >> 9) & 01); - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (!BIT_TST (chtr_enab, CHTR_V_TRC + ch) && - (ch_flags[ch] & CHF_TRC)) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ch_flags[ch] = ch_flags[ch] & ~CHF_TRC; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - } - break; - - case 00027: case 01027: - if (prot_trap (0)) /* user mode? */ - break; - ch = 6 + ((op >> 9) & 01); - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (!BIT_TST (chtr_enab, CHTR_V_TRC + ch) && - (ch_flags[ch] & CHF_TRC)) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ch_flags[ch] = ch_flags[ch] & ~CHF_TRC; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - } - break; - - case 00030: case 00031: case 00032: case 00033: /* TEFx */ - case 01030: case 01031: case 01032: case 01033: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (!BIT_TST (chtr_enab, CHTR_V_CME + ch) && - (ch_flags[ch] & CHF_EOF)) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOF; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - } - break; - - case 00060: case 00061: case 00062: case 00063: /* TCOx */ - case 00064: case 00065: case 00066: case 00067: - if (prot_trap (0)) /* user mode? */ - break; - ch = op & 07; - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (ch_sta[ch] != CHXS_IDLE) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 01060: case 01061: case 01062: case 01063: /* TCNx */ - case 01064: case 01065: case 01066: case 01067: - if (prot_trap (0)) /* user mode? */ - break; - ch = op & 07; - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (ch_sta[ch] == CHXS_IDLE) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00540: case 00541: case 00542: case 00543: /* RCHx */ - case 01540: case 01541: case 01542: case 01543: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - reason = ch_op_start (ch, ea, TRUE); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00544: case 00545: case 00546: case 00547: /* LCHx */ - case 01544: case 01545: case 01546: case 01547: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - reason = ch_op_start (ch, ea, FALSE); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00640: case 00641: case 00642: case 00643: /* SCHx */ - case 01640: case 01641: case 01642: case 01643: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - if ((reason = ch_op_store (ch, &SR)) == SCPE_OK) - Write (ea, SR); - break; - - case 00644: case 00645: case 00646: case 00647: /* SCDx */ - case 01644: case 01645: case 01646: case 01647: - ch = ((op & 03) << 1) | ((op >> 9) & 01); - if ((reason = ch_op_store_diag (ch, &SR)) == SCPE_OK) - Write (ea, SR); - break; - - case 00762: /* RDS */ - if (prot_trap (0) || sel_trap (PC)) - break; - ch = GET_U_CH (IR); - reason = ch_op_ds (ch, CHSL_RDS, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00764: /* BSR */ - if (prot_trap (0) || sel_trap (PC)) - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_BSR, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00766: /* WRS */ - if (prot_trap (0) || sel_trap (PC)) - break; - ch = GET_U_CH (IR); - reason = ch_op_ds (ch, CHSL_WRS, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00770: /* WEF */ - if (prot_trap (0) || sel_trap (PC)) - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_WEF, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00772: /* REW */ - if (prot_trap (0) || sel_trap (PC)) - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_REW, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 01764: /* BSF */ - if (prot_trap (0) || sel_trap (PC)) - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_BSF, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 01772: /* RUN */ - if (prot_trap (0) || sel_trap (PC)) - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_RUN, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00776: /* SDN */ - if (prot_trap (0) || sel_trap (PC)) - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_SDN, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - default: - if (stop_illop) - reason = STOP_ILLEG; - break; - } - } /* end else */ - - if (reason) { /* reason code? */ - if (reason == ERR_STALL) { /* stall? */ - PC = oldPC; /* back up PC */ - reason = 0; - } - else if (reason == STOP_HALT) { /* halt? wait for IO */ - t_stat r; - for (i = 0; (i < HALT_IO_LIMIT) && !ch_qidle (); i++) { - sim_interval = 0; - if (r = sim_process_event ()) /* process events */ - return r; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - while (ch_req) { /* until no ch req */ - for (j = 0; j < NUM_CHAN; j++) { /* loop thru channels */ - if (ch_req & REQ_CH (j)) { /* channel request? */ - if (r = ch_proc (j)) - return r; - } - chtr_pend = chtr_eval (NULL); - } - } /* end while ch_req */ - } /* end for wait */ - if (chtr_pend) /* trap? cancel HALT */ - reason = 0; - } /* end if HALT */ - } /* end if reason */ - } /* end while */ - -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; -} - -/* Get index register for indexing */ - -uint32 get_xri (uint32 tag) -{ -tag = tag & INST_M_TAG; - -if (tag) { - if (mode_multi) { - uint32 r = 0; - if (tag & 1) - r = r | XR[1]; - if (tag & 2) - r = r | XR[2]; - if (tag & 4) - r = r | XR[4]; - return r & eamask; - } - return XR[tag] & eamask; - } -return 0; -} - -/* Get index register for instruction execution - - Instructions which are 'executing directly' on index registers rewrite - the index register value. In multi-tag mode, this causes all registers - involved in the OR function to receive the OR'd value. */ - -uint32 get_xrx (uint32 tag) -{ -tag = tag & INST_M_TAG; - -if (tag) { - if (mode_multi) { - uint32 r = 0; - if (tag & 1) - r = r | XR[1]; - if (tag & 2) - r = r | XR[2]; - if (tag & 4) - r = r | XR[4]; - put_xr (tag, r); - return r & eamask; - } - return XR[tag] & eamask; - } -return 0; -} - -/* Store index register */ - -void put_xr (uint32 tag, uint32 dat) -{ -tag = tag & INST_M_TAG; -dat = dat & eamask; - -if (tag) { - if (mode_multi) { - if (tag & 1) - XR[1] = dat; - if (tag & 2) - XR[2] = dat; - if (tag & 4) - XR[4] = dat; - } - else XR[tag] = dat; - } -return; -} - -/* Floating point trap */ - -t_bool fp_trap (uint32 spill) -{ -if (mode_ftrap) { - WriteTAD (TRAP_STD_SAV, PC, spill); - PCQ_ENTRY; - PC = TRAP_FP_PC; - return TRUE; - } -else { - if (spill & TRAP_F_AC) - ind_ovf = 1; - if (spill & TRAP_F_MQ) - ind_mqo = 1; - } -return FALSE; -} - -/* (CTSS) Protection trap */ - -t_bool prot_trap (uint32 decr) -{ -if (mode_user) { - WriteTAD (TRAP_PROT_SAV, PC, decr); - PCQ_ENTRY; - PC = TRAP_PROT_PC; - return TRUE; - } -return FALSE; -} - -/* Store trap address and decrement, with A/B select flags; clear A/B, user mode */ - -void WriteTAD (uint32 pa, uint32 addr, uint32 decr) -{ -t_uint64 mem; - -if (inst_base) - decr |= TRAP_F_BINST; -if (data_base) - decr |= TRAP_F_BDATA; -mem = ReadP (pa) & ~(XMASK | AMASK); -mem |= (((t_uint64) (decr & AMASK)) << INST_V_DEC) | - ((t_uint64) (addr & AMASK)); -WriteP (pa, mem); -mode_ctrap = 0; -mode_strap = 0; -mode_storn = 0; -mode_user = 0; -inst_base = 0; -data_base = 0; -return; -} - -/* Copy trap */ - -t_bool cpy_trap (uint32 va) -{ -if (mode_ctrap) { - WriteTA (TRAP_704_SAV, va); - PCQ_ENTRY; - TrapXfr (TRAP_CPY_PC); - return TRUE; - } -return FALSE; -} - -/* Select trap */ - -t_bool sel_trap (uint32 va) -{ -if (mode_strap) { - WriteTA (TRAP_704_SAV, va); - PCQ_ENTRY; - TrapXfr (TRAP_SEL_PC); - return TRUE; - } -return FALSE; -} - -/* Store trap address - do not alter state yet (might be TRA) */ - -void WriteTA (uint32 pa, uint32 dat) -{ -t_uint64 mem; - -mem = ReadP (pa) & ~AMASK; -mem |= (dat & AMASK); -WriteP (pa, mem); -return; -} - -/* Set trap PC - second half of address-only trap */ - -void TrapXfr (uint32 newpc) -{ -PC = newpc; -mode_ctrap = 0; -mode_strap = 0; -mode_storn = 0; -mode_user = 0; -inst_base = 0; -data_base = 0; -return; -} - -/* Read instruction and indirect */ - -t_bool ReadI (uint32 va, t_uint64 *val) -{ -if (mode_user) { - va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } - } -*val = M[va | inst_base]; -return TRUE; -} - -/* Read */ - -t_bool Read (uint32 va, t_uint64 *val) -{ -if (mode_user) { - va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } - } -*val = M[va | data_base]; -return TRUE; -} - -/* Write */ - -t_bool Write (uint32 va, t_uint64 dat) -{ -if (mode_user) { - va = (va + ind_reloc) & AMASK; - if ((va < ind_start) || (va > ind_limit)) { - prot_trap (0); - return FALSE; - } - } -M[va | data_base] = dat; -return TRUE; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -ind_ovf = 0; -ind_mqo = 0; -ind_dvc = 0; -ind_ioc = 0; -ind_reloc = 0; -ind_start = 0; -ind_limit = 0; -mode_ttrap = 0; -mode_ctrap = 0; -mode_strap = 0; -mode_ftrap = 1; -mode_storn = 0; -if (cpu_model & (I_94|I_CT)) - mode_multi = 0; -else mode_multi = 1; -mode_user = 0; -inst_base = 0; -data_base = 0; -ch_req = 0; -chtr_pend = chtr_enab = 0; -chtr_inht = chtr_inhi = 0; -ht_pend = 0; -SLT = 0; -XR[0] = 0; -if (M == NULL) - M = (t_uint64 *) calloc (MAXMEMSIZE, sizeof (t_uint64)); -if (M == NULL) - return SCPE_MEM; -pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); -return SCPE_OK; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr ea, UNIT *uptr, int32 sw) -{ -if (vptr == NULL) - return SCPE_ARG; -if ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE)) - return SCPE_NXM; -if ((sw & SWMASK ('B')) || - ((sw & SWMASK ('V')) && mode_user && inst_base)) - ea = ea | BCORE_BASE; -*vptr = M[ea] & DMASK; -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw) -{ -if ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE)) - return SCPE_NXM; -if (sw & SWMASK ('B')) - ea = ea | BCORE_BASE; -M[ea] = val & DMASK; -return SCPE_OK; -} - -/* Set model */ - -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -UNIT *chuptr = mt_dev[CHRONO_CH].units + CHRONO_UNIT; -extern DEVICE clk_dev; - -cpu_model = val; -if (val & I_CT) { - uptr->capac = MAXMEMSIZE; - detach_unit (uptr); - chuptr->flags &= ~UNIT_ATTABLE; - clk_dev.flags &= ~DEV_DIS; - } -else { - uptr->capac = STDMEMSIZE; - chuptr->flags |= UNIT_ATTABLE; - } -if (!(cpu_model & I_94)) - mode_multi = 1; -return SCPE_OK; -} - -/* Show CTSS */ - -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (cpu_model & I_CT) - fputs ("CTSS", st); -else if (cpu_model & I_94) - fputs ("7094", st); -else fputs ("7090", st); -return SCPE_OK; -} - -/* Insert history entry */ - -static uint32 inst_io_tab[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0000 - 0377 */ - 0, 0, 0, 0x000000FF, 0, 0, 0, 0x45540000, /* 0400 - 0777 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 1000 - 1400 */ - 0, 0, 0, 0x000000FF, 0, 0, 0, 0 /* 1400 - 1777 */ - }; - -void cpu_ent_hist (uint32 pc, uint32 ea, t_uint64 ir, t_uint64 opnd) -{ -int32 prv_p; - -if (pc & HIST_PC) { - if ((pc == hst[hst_p].pc) && (ir == hst[hst_p].ir)) { /* repeat last? */ - hst[hst_p].rpt++; - return; - } - prv_p = hst_p? hst_p - 1: hst_lnt - 1; - if ((pc == hst[prv_p].pc) && (ir == hst[prv_p].ir)) { /* 2 line loop? */ - hst[prv_p].rpt++; - return; - } - if (hst_ch & HIST_CH_I) { /* IO only? */ - uint32 op = GET_OPC (ir); /* get opcode */ - if ((ir & INST_T_DEC) || - !(inst_io_tab[op / 32] & (1u << (op & 037)))) - return; - } - } -hst_p = (hst_p + 1); /* next entry */ -if (hst_p >= hst_lnt) - hst_p = 0; -hst[hst_p].pc = pc; -hst[hst_p].ir = ir; -hst[hst_p].ac = AC; -hst[hst_p].mq = MQ; -hst[hst_p].si = SI; -hst[hst_p].ea = ea; -hst[hst_p].opnd = opnd; -hst[hst_p].rpt = 0; -return; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].pc = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = hst_ch = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - if (sim_switches & SWMASK ('I')) - hst_ch = HIST_CH_I|HIST_CH_C; - else if (sim_switches & SWMASK ('C')) - hst_ch = HIST_CH_C; - else hst_ch = 0; - } -return SCPE_OK; -} - -/* Print one instruction */ - -t_stat cpu_fprint_one_inst (FILE *st, uint32 pc, uint32 rpt, uint32 ea, - t_uint64 ir, t_uint64 ac, t_uint64 mq, t_uint64 si, t_uint64 opnd) -{ -int32 ch; -t_value sim_eval; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); - -sim_eval = ir; -if (pc & HIST_PC) { /* instruction? */ - fputs ("CPU ", st); - fprintf (st, "%05o ", pc & AMASK); - if (rpt == 0) - fprintf (st, " "); - else if (rpt < 1000000) - fprintf (st, "%6d ", rpt); - else fprintf (st, "%5dM ", rpt / 1000000); - fprint_val (st, ac, 8, 38, PV_RZRO); - fputc (' ', st); - fprint_val (st, mq, 8, 36, PV_RZRO); - fputc (' ', st); - fprint_val (st, si, 8, 36, PV_RZRO); - fputc (' ', st); - if (ir & INST_T_DEC) - fprintf (st, " "); - else fprintf (st, "%05o ", ea); - if (fprint_sym (st, pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M')) > 0) { - fputs ("(undefined) ", st); - fprint_val (st, ir, 8, 36, PV_RZRO); - } - else if (!(ir & INST_T_DEC) && (op_flags[GET_OPC (ir)] & I_R)) { - fputs (" [", st); - fprint_val (st, opnd, 8, 36, PV_RZRO); - fputc (']', st); - } - fputc ('\n', st); /* end line */ - } /* end if instruction */ -else if (ch = HIST_CH (pc)) { /* channel? */ - fprintf (st, "CH%c ", 'A' + ch - 1); - fprintf (st, "%05o ", pc & AMASK); - fputs (" ", st); - fprintf (st, "%05o ", ea & AMASK); - if (fprint_sym (st, pc & AMASK, &sim_eval, &cpu_unit, - (ch_dev[ch - 1].flags & DEV_7909)? SWMASK ('N'): SWMASK ('I')) > 0) { - fputs ("(undefined) ", st); - fprint_val (st, ir, 8, 36, PV_RZRO); - } - fputc ('\n', st); /* end line */ - } /* end else channel */ -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 k, di, lnt; -char *cptr = (char *) desc; -t_stat r; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, " PC repeat AC MQ SI EA IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(++di) % hst_lnt]; /* entry pointer */ - cpu_fprint_one_inst (st, h->pc, h->rpt, h->ea, h->ir, h->ac, h->mq, h->si, h->opnd); - } /* end for */ -return SCPE_OK; -} diff --git a/I7094/i7094_defs.h b/I7094/i7094_defs.h index 929f8b73..b100989e 100644 --- a/I7094/i7094_defs.h +++ b/I7094/i7094_defs.h @@ -1,6 +1,6 @@ /* i7094_defs.h: IBM 7094 simulator definitions - Copyright (c) 2003-2010, Robert M Supnik + Copyright (c) 2003-2011, Robert 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 @@ helped to reconstruct the CTSS hardware RPQ's. Dave Pitts gets special thanks for patiently coaching me through IBSYS debug. + 25-Mar-11 RMS Updated SDC mask based on 7230 documentation 22-May-10 RMS Added check for 64b addresses */ @@ -419,7 +420,7 @@ typedef struct { #define CHF_M_LCC 077 #define CHF_CLR_7909 07775000177 /* 7909 clear flags */ -#define CHF_SDC_7909 07776000000 /* 7909 SDC flags */ +#define CHF_SDC_7909 07777600000 /* 7909 SDC flags */ /* Channel characteristics (in dev.flags) */ diff --git a/I7094/i7094_drm.c b/I7094/i7094_drm.c index f8a15306..d7d91da9 100644 --- a/I7094/i7094_drm.c +++ b/I7094/i7094_drm.c @@ -1,6 +1,6 @@ /* i7094_drm.c: 7289/7320A drum simulator - Copyright (c) 2005-2008, Robert M Supnik + Copyright (c) 2005-2011, Robert 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,31 +25,29 @@ drm 7289/7320A "fast" drum - Very little is known about this device; the behavior simulated here is - what is used by CTSS. + 25-Mar-11 RMS Updated based on RPQ + + This simulator implements a subset of the functionality of the 7289, as + required by CTSS. - The drum channel/controller behaves like a hybrid of the 7607 and the 7909. It responds to SCD (like the 7909), gets its address from the channel program (like the 7909), but responds to IOCD/IOCP (like the 7607) and sets channel flags (like the 7607). - - The drum channel supports at least 2 drums. The maximum is 8 or less. + - The drum channel supports at least 2 drums. The maximum is 4 or less. Physical drums are numbered from 0. - Each drum has a capacity of 192K 36b words. This is divided into 6 "logical" drum of 32KW each. Each "logical" drum has 16 2048W "sectors". Logical drums are numbered from 1. - - The drum's behavior if a sector boundary is crossed in mid-transfer is - unknown. CTSS never does this. - - The drum's behavior with record operations is unknown. CTSS only uses - IOCD and IOCP. - - The drum's error indicators are unknown. CTSS regards bits <0:2,13> of - the returned SCD data as errors, as well as the normal 7607 trap flags. - - The drum's rotational speed is unknown. + - The drum allows transfers across sector boundaries, but not logical + drum boundaries. + - The drum's only supports IOCD, IOCP, and IOCT. IOCT (and chaining mode) + are not used by CTSS. - Assumptions in this simulator: + Limitations in this simulator: - - Transfers may not cross a sector boundary. An attempt to do so sets - the EOF flag and causes an immediate disconnect. - - The hardware never sets end of record. + - Chain mode is not implemented. + - Write protect switches are not implemented. For speed, the entire drum is buffered in memory. */ @@ -65,6 +63,7 @@ #define DRM_SCMASK (DRM_NUMWDS - 1) /* sector mask */ #define DRM_NUMSC 16 /* sectors/log drum */ #define DRM_NUMWDL (DRM_NUMWDS * DRM_NUMSC) /* words/log drum */ +#define DRM_LDMASK (DRM_NUMWDL - 1) /* logical disk mask */ #define DRM_NUMLD 6 /* log drums/phys drum */ #define DRM_SIZE (DRM_NUMLD * DRM_NUMWDL) /* words/phys drum */ #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ @@ -73,7 +72,7 @@ /* Drum address from channel */ #define DRM_V_PHY 30 /* physical drum sel */ -#define DRM_M_PHY 07 +#define DRM_M_PHY 03 #define DRM_V_LOG 18 /* logical drum sel */ #define DRM_M_LOG 07 #define DRM_V_WDA 0 /* word address */ @@ -83,15 +82,30 @@ #define DRM_GETWDA(x) ((((uint32) (x)) >> DRM_V_WDA) & DRM_M_WDA) #define DRM_GETDA(x) (((DRM_GETLOG(x) - 1) * DRM_NUMWDL) + DRM_GETWDA(x)) +/* SCD word */ + +#define DRMS_V_IOC 35 /* IO check */ +#define DRMS_V_INV 33 /* invalid command */ +#define DRMS_V_PHY 31 /* physical drum */ +#define DRMS_V_LOG 28 /* logical drum */ +#define DRMS_V_HWDA 24 /* high word addr */ +#define DRMS_M_HWDA 017 +#define DRMS_V_GRP 23 /* group */ +#define DRMS_V_WRP 22 /* write protect */ +#define DRMS_V_LPCR 18 /* LPRCR */ +#define DRMS_M_LPCR 017 + /* Drum controller states */ #define DRM_IDLE 0 #define DRM_1ST 1 -#define DRM_DATA 2 -#define DRM_EOS 3 +#define DRM_FILL 2 +#define DRM_DATA 3 +#define DRM_EOD 4 uint32 drm_ch = CH_G; /* drum channel */ uint32 drm_da = 0; /* drum address */ +uint32 drm_phy = 0; /* physical drum */ uint32 drm_sta = 0; /* state */ uint32 drm_op = 0; /* operation */ t_uint64 drm_chob = 0; /* output buf */ @@ -131,13 +145,14 @@ UNIT drm_unit[] = { { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) } + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, }; REG drm_reg[] = { - { ORDATA (STATE, drm_sta, 2) }, + { ORDATA (STATE, drm_sta, 3) }, { ORDATA (DA, drm_da, 18) }, { FLDATA (OP, drm_op, 0) }, + { ORDATA (UNIT,drm_phy, 3) }, { ORDATA (CHOB, drm_chob, 36) }, { FLDATA (CHOBV, drm_chob_v, 0) }, { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, @@ -188,14 +203,14 @@ return SCPE_OK; t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags) { -uint32 u, l; +uint32 l; int32 cp, dp; if (drm_sta == DRM_1ST) { - u = DRM_GETPHY (val); /* get unit */ + drm_phy = DRM_GETPHY (val); /* get unit */ l = DRM_GETLOG (val); /* get logical address */ - if ((u >= DRM_NUMDR) || /* invalid unit? */ - (drm_unit[u].flags & UNIT_DIS) || /* disabled unit? */ + if ((drm_phy >= DRM_NUMDR) || /* invalid unit? */ + (drm_unit[drm_phy].flags & UNIT_DIS) || /* disabled unit? */ (l == 0) || (l > DRM_NUMLD)) { /* invalid log drum? */ ch6_err_disc (ch, U_DRM, CHF_TRC); /* disconnect */ drm_sta = DRM_IDLE; @@ -206,10 +221,12 @@ if (drm_sta == DRM_1ST) { dp = (drm_da & DRM_SCMASK) - cp; /* delta to desired pos */ if (dp <= 0) /* if neg, add rev */ dp = dp + DRM_NUMWDS; - sim_activate (&drm_unit[u], dp * drm_time); /* schedule */ - if (drm_op) /* if write, get word */ + sim_activate (&drm_unit[drm_phy], dp * drm_time); /* schedule */ + if (drm_op) { /* if write, get word */ ch6_req_wr (ch, U_DRM); - drm_sta = DRM_DATA; + drm_sta = DRM_FILL; /* sector fill */ + } + else drm_sta = DRM_DATA; /* data transfer */ drm_chob = 0; /* clr, inval buffer */ drm_chob_v = 0; } @@ -224,6 +241,7 @@ return SCPE_OK; t_stat drm_svc (UNIT *uptr) { +uint32 i; t_uint64 *fbuf = (t_uint64 *) uptr->filebuf; if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? */ @@ -239,6 +257,13 @@ if (drm_da >= DRM_SIZE) { /* nx logical drum? */ switch (drm_sta) { /* case on state */ + case DRM_FILL: /* write, clr sector */ + for (i = drm_da & ~DRM_SCMASK; i <= (drm_da | DRM_SCMASK); i++) + fbuf[i] = 0; /* clear sector */ + if (i >= uptr-> hwmark) + uptr->hwmark = i + 1; + drm_sta = DRM_DATA; /* now data */ + /* fall through */ case DRM_DATA: /* data */ if (drm_op) { /* write? */ if (drm_chob_v) /* valid? clear */ @@ -258,7 +283,7 @@ switch (drm_sta) { /* case on state */ sim_activate (uptr, drm_time); /* next word */ break; - case DRM_EOS: /* end sector */ + case DRM_EOD: /* end logical disk */ if (ch6_qconn (drm_ch, U_DRM)) /* drum still conn? */ ch6_err_disc (drm_ch, U_DRM, CHF_EOF); /* set EOF, disc */ drm_sta = DRM_IDLE; /* drum is idle */ @@ -272,10 +297,10 @@ return SCPE_OK; t_bool drm_da_incr (void) { -drm_da = drm_da + 1; -if (drm_da & DRM_SCMASK) +drm_da = (drm_da & ~DRM_LDMASK) | ((drm_da + 1) & DRM_LDMASK); +if ((drm_da & DRM_LDMASK) != 0) return FALSE; -drm_sta = DRM_EOS; +drm_sta = DRM_EOD; return TRUE; } @@ -285,6 +310,7 @@ t_stat drm_reset (DEVICE *dptr) { uint32 i; +drm_phy = 0; drm_da = 0; drm_op = 0; drm_sta = DRM_IDLE; diff --git a/I7094/i7094_mt_old.c b/I7094/i7094_mt_old.c deleted file mode 100644 index 6c8f9cf4..00000000 --- a/I7094/i7094_mt_old.c +++ /dev/null @@ -1,861 +0,0 @@ -/* i7094_mt.c: IBM 7094 magnetic tape simulator - - Copyright (c) 2003-2008, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - mt magtape simulator -*/ - -#include "i7094_defs.h" -#include "sim_tape.h" - -#define UST u3 /* unit state */ -#define UCH u4 /* channel number */ -#define MTUF_V_LDN (MTUF_V_UF + 0) -#define MTUF_LDN (1 << MTUF_V_LDN) -#define MT_MAXFR ((1 << 18) + 2) - -#define QCHRONO(c,u) ((cpu_model & I_CT) && \ - ((c) == CHRONO_CH) && ((u) == CHRONO_UNIT)) - -uint8 *mtxb[NUM_CHAN] = { NULL }; /* xfer buffer */ -uint32 mt_unit[NUM_CHAN]; /* unit */ -uint32 mt_bptr[NUM_CHAN]; -uint32 mt_blnt[NUM_CHAN]; -t_uint64 mt_chob[NUM_CHAN]; -uint32 mt_chob_v[NUM_CHAN]; -uint32 mt_tshort = 2; -uint32 mt_twef = 25000; /* 50 msec */ -uint32 mt_tstart = 29000; /* 58 msec */ -uint32 mt_tstop = 10000; /* 20 msec */ -uint32 mt_tword = 50; /* 125 usec */ - -static const uint8 odd_par[64] = { - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1 - }; - -static const char *tape_stat[] = { - "OK", "TMK", "UNATT", "IOERR", "INVRECLNT", - "FMT", "BOT", "EOM", "RECERR", "WRPROT" - }; - -extern uint32 PC; -extern uint32 cpu_model; -extern uint32 ind_ioc; -extern FILE *sim_deb; -extern char *sel_name[]; - -t_stat mt_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 flags); -t_stat mt_rec_end (UNIT *uptr); -t_stat mt_svc (UNIT *uptr); -t_stat mt_reset (DEVICE *dptr); -t_stat mt_attach (UNIT *uptr, char *cptr); -t_stat mt_boot (int32 unitno, DEVICE *dptr); -t_stat mt_map_err (UNIT *uptr, t_stat st); - -extern uint32 chrono_rd (uint8 *buf, uint32 bufsiz); - -/* MT data structures - - mt_dev MT device descriptor - mt_unit MT unit list - mt_reg MT register list - mt_mod MT modifier list -*/ - -DIB mt_dib = { &mt_chsel, &mt_chwr }; - -MTAB mt_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTUF_LDN, 0, "high density", "HIGH", NULL }, - { MTUF_LDN, MTUF_LDN, "low density", "LOW", NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { 0 } - }; - -UNIT mta_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mta_reg[] = { - { ORDATA (UNIT, mt_unit[0], 5) }, - { ORDATA (CHOB, mt_chob[0], 36) }, - { FLDATA (CHOBV, mt_chob_v[0], 0) }, - { DRDATA (BPTR, mt_bptr[0], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[0], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mta_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mta_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtb_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtb_reg[] = { - { ORDATA (UNIT, mt_unit[1], 5) }, - { ORDATA (CHOB, mt_chob[1], 36) }, - { FLDATA (CHOBV, mt_chob_v[1], 0) }, - { DRDATA (BPTR, mt_bptr[1], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[1], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtb_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtb_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtc_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtc_reg[] = { - { ORDATA (UNIT, mt_unit[2], 5) }, - { ORDATA (CHOB, mt_chob[2], 36) }, - { FLDATA (CHOBV, mt_chob_v[2], 0) }, - { DRDATA (BPTR, mt_bptr[2], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[2], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtc_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtc_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtd_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtd_reg[] = { - { ORDATA (UNIT, mt_unit[3], 5) }, - { ORDATA (CHOB, mt_chob[3], 36) }, - { FLDATA (CHOBV, mt_chob_v[3], 0) }, - { DRDATA (BPTR, mt_bptr[3], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[3], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtd_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtd_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mte_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mte_reg[] = { - { ORDATA (UNIT, mt_unit[4], 5) }, - { ORDATA (CHOB, mt_chob[4], 36) }, - { FLDATA (CHOBV, mt_chob_v[4], 0) }, - { DRDATA (BPTR, mt_bptr[4], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[4], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mte_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mte_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtf_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtf_reg[] = { - { ORDATA (UNIT, mt_unit[5], 5) }, - { ORDATA (CHOB, mt_chob[5], 36) }, - { FLDATA (CHOBV, mt_chob_v[5], 0) }, - { DRDATA (BPTR, mt_bptr[5], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[5], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtf_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtf_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtg_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtg_reg[] = { - { ORDATA (UNIT, mt_unit[6], 5) }, - { ORDATA (CHOB, mt_chob[6], 36) }, - { FLDATA (CHOBV, mt_chob_v[6], 0) }, - { DRDATA (BPTR, mt_bptr[6], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[6], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtg_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtg_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mth_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mth_reg[] = { - { ORDATA (UNIT, mt_unit[7], 5) }, - { ORDATA (CHOB, mt_chob[7], 36) }, - { FLDATA (CHOBV, mt_chob_v[7], 0) }, - { DRDATA (BPTR, mt_bptr[7], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[7], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mth_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mth_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -DEVICE mt_dev[NUM_CHAN] = { - { - "MTA", mta_unit, mta_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - &mt_boot, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DEBUG - }, - { - "MTB", mtb_unit, mtb_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTC", mtc_unit, mtc_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTD", mtd_unit, mtd_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTE", mte_unit, mte_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTF", mtf_unit, mtf_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTG", mtg_unit, mtg_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTH", mth_unit, mth_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - } - }; - -/* Select controller - - Inputs: - ch = channel - cmd = select command - unit = unit - Outputs: - status = SCPE_OK if ok - STOP_STALL if busy - error code if error -*/ - -static const int mt_must_att[CHSL_NUM] = { - 0, 1, 1, 0, 1, 1, 0, 0, - 1, 1, 1, 1, 1, 1, 0, 0 - }; - -static const int mt_will_wrt[CHSL_NUM] = { - 0, 0, 1, 0, 0, 1, 0, 0, - 1, 1, 0, 0, 0, 0, 0, 0 - }; - -t_stat mt_chsel (uint32 ch, uint32 cmd, uint32 unit) -{ -UNIT *uptr; -uint32 u = unit & 017; - -if ((ch >= NUM_CHAN) || (cmd == 0) || (cmd >= CHSL_NUM)) - return SCPE_IERR; /* invalid arg? */ -if (mt_dev[ch].flags & DEV_DIS) /* disabled? */ - return STOP_NXDEV; -if ((u == 0) || (u > MT_NUMDR)) /* valid unit? */ - return STOP_NXDEV; -uptr = mt_dev[ch].units + u; /* get unit ptr */ -if (uptr->flags & UNIT_DIS) /* disabled? */ - return STOP_NXDEV; -if (mt_unit[ch] || sim_is_active (uptr)) /* ctrl or unit busy? */ - return ERR_STALL; /* stall */ -if (QCHRONO (ch, u)) { /* Chronolog clock? */ - if (cmd != CHSL_RDS) /* only reads */ - return STOP_ILLIOP; - sim_activate (uptr, mt_tword); /* responds quickly */ - } -else { /* real tape */ - if (!(uptr->flags & UNIT_ATT) && mt_must_att[cmd]) /* unit unatt? */ - return SCPE_UNATT; - if (sim_tape_wrp (uptr) && mt_will_wrt[cmd]) /* unit wrp && write? */ - return STOP_WRP; - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d %s, pos = %d\n", - mt_dev[ch].name, u, sel_name[cmd], uptr->pos); - - switch (cmd) { /* case on cmd */ - - case CHSL_RDS: - case CHSL_WRS: - case CHSL_BSR: - case CHSL_BSF: /* rd, wr, backspace */ - sim_activate (uptr, mt_tstart); /* schedule op */ - break; - - case CHSL_WEF: /* write eof? */ - sim_activate (uptr, mt_twef); /* schedule op */ - break; - - case CHSL_RUN: - sim_activate (uptr, mt_tshort); /* schedule quick event */ - break; - case CHSL_REW: - case CHSL_SDN: /* rew, rew/unl, set det */ - sim_activate (uptr, mt_tshort); /* schedule quick event */ - break; - - default: - return SCPE_IERR; - } /* end switch */ - } /* end else */ - -uptr->UST = cmd; /* set cmd */ -mt_unit[ch] = unit & 0777; /* save unit */ -return SCPE_OK; -} - -/* Channel write routine */ - -t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 eorfl) -{ -int32 k, u; -uint8 by, *xb; -UNIT *uptr; - -if (ch >= NUM_CHAN) /* invalid chan? */ - return SCPE_IERR; -xb = mtxb[ch]; /* get xfer buf */ -u = mt_unit[ch] & 017; -if ((xb == NULL) || (u > MT_NUMDR)) /* invalid args? */ - return SCPE_IERR; -uptr = mt_dev[ch].units + u; /* get unit */ -mt_chob[ch] = val & DMASK; /* save word from chan */ -mt_chob_v[ch] = 1; /* set valid */ - -if (uptr->UST == (CHSL_WRS|CHSL_2ND)) { /* data write? */ - for (k = 30; /* proc 6 bytes */ - (k >= 0) && (mt_bptr[ch] < MT_MAXFR); - k = k - 6) { - by = (uint8) ((val >> k) & 077); /* get byte */ - if ((mt_unit[ch] & 020) == 0) { /* BCD? */ - if (by == 0) /* cvt bin 0 */ - by = BCD_ZERO; - else if (by & 020) /* invert zones */ - by = by ^ 040; - if (!odd_par[by]) /* even parity */ - by = by | 0100; - } - else if (odd_par[by]) /* bin, odd par */ - by = by | 0100; - xb[mt_bptr[ch]++] = by; /* put in buffer */ - } - if (eorfl) - return mt_rec_end (uptr); /* EOR? write rec */ - return SCPE_OK; - } -return SCPE_IERR; -} - -/* Unit timeout */ - -t_stat mt_svc (UNIT *uptr) -{ -uint32 i, u, ch = uptr->UCH; /* get channel number */ -uint8 by, *xb = mtxb[ch]; /* get xfer buffer */ -t_uint64 dat; -t_mtrlnt bc; -t_stat r; - -if (xb == NULL) /* valid buffer? */ - return SCPE_IERR; -u = uptr - mt_dev[ch].units; -switch (uptr->UST) { /* case on state */ - - case CHSL_RDS: /* read start */ - if (QCHRONO (ch, mt_unit[ch] & 017)) /* Chronolog clock? */ - bc = chrono_rd (xb, MT_MAXFR); /* read clock */ - else { /* real tape */ - r = sim_tape_rdrecf (uptr, xb, &bc, MT_MAXFR); /* read record */ - if (r = mt_map_err (uptr, r)) /* map status */ - return r; - if (mt_unit[ch] == 0) /* disconnected? */ - return SCPE_OK; - } /* end else Chrono */ - if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */ - mt_unit[ch] = 0; /* clr ctrl busy */ - return SCPE_OK; - } - for (i = bc; i < (bc + 6); i++) /* extra 0's */ - xb[i] = 0; - mt_bptr[ch] = 0; /* set ptr, lnt */ - mt_blnt[ch] = bc; - uptr->UST = CHSL_RDS|CHSL_2ND; /* next state */ - sim_activate (uptr, mt_tword); - break; - - case CHSL_RDS|CHSL_2ND: /* read word */ - for (i = 0, dat = 0; i < 6; i++) { /* proc 6 bytes */ - by = xb[mt_bptr[ch]++] & 077; /* get next byte */ - if ((mt_unit[ch] & 020) == 0) { /* BCD? */ - if (by == BCD_ZERO) /* cvt BCD 0 */ - by = 0; - else if (by & 020) /* invert zones */ - by = by ^ 040; - } - dat = (dat << 6) | ((t_uint64) by); - } - if (mt_bptr[ch] >= mt_blnt[ch]) { /* end of record? */ - ch6_req_rd (ch, mt_unit[ch], dat, CH6DF_EOR); - uptr->UST = CHSL_RDS|CHSL_3RD; /* next state */ - sim_activate (uptr, mt_tstop); /* long timing */ - } - else { - ch6_req_rd (ch, mt_unit[ch], dat, 0); /* send to channel */ - sim_activate (uptr, mt_tword); /* next word */ - } - break; - - case CHSL_RDS|CHSL_3RD: /* end record */ - if (ch6_qconn (ch, mt_unit[ch])) { /* ch still conn? */ - uptr->UST = CHSL_RDS; /* initial state */ - sim_activate (uptr, mt_tshort); /* sched next record */ - } - else mt_unit[ch] = 0; /* clr ctrl busy */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d RDS complete, pos = %d, %s\n", - mt_dev[ch].name, u, uptr->pos, - mt_unit[ch]? "continuing": "disconnecting"); - return SCPE_OK; - - case CHSL_WRS: /* write start */ - if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */ - mt_unit[ch] = 0; /* clr ctrl busy */ - return SCPE_OK; /* (writes blank tape) */ - } - mt_bptr[ch] = 0; /* init buffer */ - uptr->UST = CHSL_WRS|CHSL_2ND; /* next state */ - ch6_req_wr (ch, mt_unit[ch]); /* request channel */ - mt_chob[ch] = 0; /* clr, inval buffer */ - mt_chob_v[ch] = 0; - sim_activate (uptr, mt_tword); /* wait for word */ - break; - - case CHSL_WRS|CHSL_2ND: /* write word */ - if (!ch6_qconn (ch, mt_unit[ch])) /* disconnected? */ - return mt_rec_end (uptr); /* write record */ - if (mt_chob_v[ch]) /* valid? clear */ - mt_chob_v[ch] = 0; - else ind_ioc = 1; /* no, io check */ - ch6_req_wr (ch, mt_unit[ch]); /* request channel */ - sim_activate (uptr, mt_tword); /* next word */ - break; - - case CHSL_WRS|CHSL_3RD: /* write stop */ - if (ch6_qconn (ch, mt_unit[ch])) { /* chan active? */ - uptr->UST = CHSL_WRS; /* initial state */ - sim_activate (uptr, mt_tshort); /* sched next record */ - } - else mt_unit[ch] = 0; /* clr ctrl busy */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d WRS complete, pos = %d, %s\n", - mt_dev[ch].name, u, uptr->pos, - mt_unit[ch]? "continuing": "disconnecting"); - return SCPE_OK; - - case CHSL_BSR: /* backspace rec */ - r = sim_tape_sprecr (uptr, &bc); /* space backwards */ - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d BSR complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - if (r == MTSE_TMK) /* allow tape mark */ - return SCPE_OK; - return mt_map_err (uptr, r); - - case CHSL_BSF: /* backspace file */ - while ((r = sim_tape_sprecr (uptr, &bc)) == MTSE_OK) ; - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d BSF complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - if (r == MTSE_TMK) /* allow tape mark */ - return SCPE_OK; - return mt_map_err (uptr, r); /* map others */ - - case CHSL_WEF: /* write eof */ - r = sim_tape_wrtmk (uptr); /* write tape mark */ - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d WEF complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - return mt_map_err (uptr, r); - - case CHSL_REW: case CHSL_RUN: /* rewind, unload */ - uptr->UST = uptr->UST | CHSL_2ND; /* set 2nd state */ - sim_activate (uptr, mt_tstart); /* reactivate */ - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - return SCPE_OK; - - case CHSL_REW | CHSL_2ND: - sim_tape_rewind (uptr); - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d REW complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - return SCPE_OK; - - case CHSL_RUN | CHSL_2ND: - sim_tape_detach (uptr); - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d RUN complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - return SCPE_OK; - - case CHSL_SDN: - if (mt_unit[ch] & 020) /* set density flag */ - uptr->flags = uptr-> flags & ~MTUF_LDN; - else uptr->flags = uptr->flags | MTUF_LDN; - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d SDN complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - return SCPE_OK; - - default: - return SCPE_IERR; - } - -return SCPE_OK; -} - -/* End record routine */ - -t_stat mt_rec_end (UNIT *uptr) -{ -uint32 ch = uptr->UCH; -uint8 *xb = mtxb[ch]; -t_stat r; - -if (mt_bptr[ch]) { /* any data? */ - if (xb == NULL) - return SCPE_IERR; - r = sim_tape_wrrecf (uptr, xb, mt_bptr[ch]); /* write record */ - if (r = mt_map_err (uptr, r)) /* map error */ - return r; - } -uptr->UST = CHSL_WRS|CHSL_3RD; /* next state */ -sim_cancel (uptr); /* cancel current */ -sim_activate (uptr, mt_tstop); /* long timing */ -return SCPE_OK; -} - -/* Map tape error status */ - -t_stat mt_map_err (UNIT *uptr, t_stat st) -{ -uint32 ch = uptr->UCH; -uint32 u = mt_unit[ch]; -uint32 up = uptr - mt_dev[ch].units; - -if ((st != MTSE_OK) && DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d status = %s, pos = %d\n", - mt_dev[ch].name, up, tape_stat[st], uptr->pos); - -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* not attached */ - ch6_err_disc (ch, u, CHF_TRC); - mt_unit[ch] = 0; /* disconnect */ - return SCPE_IERR; - - case MTSE_IOERR: /* IO error */ - ch6_err_disc (ch, u, CHF_TRC); - mt_unit[ch] = 0; /* disconnect */ - return SCPE_IOERR; - - case MTSE_INVRL: /* invalid rec lnt */ - ch6_err_disc (ch, u, CHF_TRC); - mt_unit[ch] = 0; /* disconnect */ - return SCPE_MTRLNT; - - case MTSE_WRP: /* write protect */ - ch6_err_disc (ch, u, 0); - mt_unit[ch] = 0; /* disconnect */ - return STOP_WRP; - - case MTSE_EOM: /* end of medium */ - case MTSE_TMK: /* tape mark */ - ch6_err_disc (ch, u, CHF_EOF); - mt_unit[ch] = 0; /* disconnect */ - break; - - case MTSE_RECE: /* record in error */ - ch6_set_flags (ch, u, CHF_TRC); - break; - - case MTSE_BOT: /* reverse into BOT */ - ch6_set_flags (ch, u, CHF_BOT); - break; - - case MTSE_OK: /* no error */ - break; - } - -return SCPE_OK; -} - -/* Magtape reset */ - -t_stat mt_reset (DEVICE *dptr) -{ -uint32 ch = dptr - &mt_dev[0]; -uint32 j; -REG *rptr; -UNIT *uptr; - -if (mtxb[ch] == NULL) - mtxb[ch] = (uint8 *) calloc (MT_MAXFR + 6, sizeof (uint8)); -if (mtxb[ch] == NULL) /* allocate buffer */ - return SCPE_MEM; -rptr = find_reg ("BUF", NULL, dptr); /* update reg ptr */ -if (rptr == NULL) - return SCPE_IERR; -rptr->loc = (void *) mtxb[ch]; -mt_unit[ch] = 0; /* clear busy */ -mt_bptr[ch] = 0; /* clear buf ptrs */ -mt_blnt[ch] = 0; -mt_chob[ch] = 0; -mt_chob_v[ch] = 0; -for (j = 1; j <= MT_NUMDR; j++) { /* for all units */ - uptr = dptr->units + j; - uptr->UST = 0; /* clear state */ - uptr->UCH = ch; - sim_cancel (uptr); /* stop activity */ - } /* end for */ -return SCPE_OK; /* done */ -} - -/* Magtape attach */ - -t_stat mt_attach (UNIT *uptr, char *cptr) -{ -uptr->flags = uptr->flags & ~MTUF_LDN; /* start as hi den */ -return sim_tape_attach (uptr, cptr); -} - -/* Magtape boot */ - -#define BOOT_START 01000 - -static const t_uint64 boot_rom[5] = { - 0076200000000 + U_MTBIN - 1, /* RDS MT_binary */ - 0054000000000 + BOOT_START + 4, /* RCHA *+3 */ - 0054400000000, /* LCHA 0 */ - 0002100000001, /* TTR 1 */ - 0500003000000, /* IOCT 0,,3 */ - }; - -t_stat mt_boot (int32 unitno, DEVICE *dptr) -{ -uint32 i, chan; -extern t_uint64 *M; - -chan = dptr - &mt_dev[0] + 1; -WriteP (BOOT_START, boot_rom[0] + unitno + (chan << 9)); -for (i = 1; i < 5; i++) - WriteP (BOOT_START + i, boot_rom[i]); -PC = BOOT_START; -return SCPE_OK; -} diff --git a/I7094/i7094_sys.c b/I7094/i7094_sys.c index 0c818061..0b757f91 100644 --- a/I7094/i7094_sys.c +++ b/I7094/i7094_sys.c @@ -1,6 +1,6 @@ /* i7094_sys.c: IBM 7094 simulator interface - Copyright (c) 2003-2010, Robert M Supnik + Copyright (c) 2003-2011, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 31-Dec-11 RMS Added SPI, SPI 16-Jul-10 RMS Added SPUx, SPTx, SPRx 29-Oct-06 RMS Added additional expanded core instructions 08-Jun-06 RMS Added Dave Pitts' binary loader @@ -362,7 +363,8 @@ static const char *opcode[] = { "RSCF", "RSCH", "STCB", "STCD", "STCF", "STCH", - "STQ", "ORS", "DST", + "STQ", "SRI", "ORS", "DST", + "SPI", "SLQ", "STL", "SXD", "SCD", "SCHB", "SCHD", @@ -533,7 +535,8 @@ static const t_uint64 opc_v[] = { 0454200000000+I_MXN, 0454300000000+I_MXN, 0454400000000+I_MXN, 0454500000000+I_MXN, 0454600000000+I_MXN, 0454700000000+I_MXN, - 0460000000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN, + 0460000000000+I_MXN, 0460100000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN, + 0460400000000+I_MXN, 0462000000000+I_MXN, 0462500000000+I_MXN, 0463400000000+I_MXR, 0463600000000+I_MXR, 0464000000000+I_MXN, 0464000000000+I_MXN, diff --git a/I7094/i7094_sys_old.c b/I7094/i7094_sys_old.c deleted file mode 100644 index 1d36e3bc..00000000 --- a/I7094/i7094_sys_old.c +++ /dev/null @@ -1,748 +0,0 @@ -/* i7094_sys.c: IBM 7094 simulator interface - - Copyright (c) 2003-2008, Robert 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. - - 29-Oct-06 RMS Added additional expanded core instructions - 08-Jun-06 RMS Added Dave Pitts' binary loader -*/ - -#include "i7094_defs.h" -#include -#include "i7094_dat.h" - -extern DEVICE cpu_dev; -extern DEVICE ch_dev[NUM_CHAN]; -extern DEVICE mt_dev[NUM_CHAN]; -extern DEVICE drm_dev; -extern DEVICE dsk_dev; -extern DEVICE com_dev, coml_dev; -extern DEVICE cdr_dev, cdp_dev; -extern DEVICE lpt_dev; -extern DEVICE clk_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; - -uint32 cvt_code_to_ascii (uint32 c, int32 sw); -uint32 cvt_ascii_to_code (uint32 c, int32 sw); - -/* SCP data structures and interface routines - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax number of words 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[] = "IBM 7094"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 1; - -DEVICE *sim_devices[] = { - &cpu_dev, - &clk_dev, - &ch_dev[0], - &ch_dev[1], - &ch_dev[2], - &ch_dev[3], - &ch_dev[4], - &ch_dev[5], - &ch_dev[6], - &ch_dev[7], - &mt_dev[0], - &mt_dev[1], - &mt_dev[2], - &mt_dev[3], - &mt_dev[4], - &mt_dev[5], - &mt_dev[6], - &mt_dev[7], - &cdr_dev, - &cdp_dev, - &lpt_dev, - &dsk_dev, - &drm_dev, - &com_dev, - &coml_dev, - NULL - }; - -char ch_bkpt_msg[] = "Channel A breakpoint, CLC: xxxxxx"; - -const char *sim_stop_messages[] = { - "Unknown error", - "HALT instruction", - "Breakpoint", - "Undefined instruction", - "Divide check", - "Nested XEC limit exceeded", - "Address stop", - "Non-existent channel", - "Illegal instruction for 7909 channel", - "Illegal instruction for non-7909 channel", - "Non-existent device", - "Undefined channel instruction", - "Write to protected device", - "Illegal instruction for device", - "Invalid 7631 track format", - "7750 buffer pool empty on input", - "7750 buffer pool empty on output", - "7750 invalid line number", - "7750 invalid message", - ch_bkpt_msg - }; - -/* Modify channel breakpoint message */ - -t_stat ch_bkpt (uint32 ch, uint32 clc) -{ -ch_bkpt_msg[8] = 'A' + ch; -sprintf (&ch_bkpt_msg[27], "%06o", clc); -return STOP_CHBKPT; -} - -/* Binary loader, not implemented */ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -extern t_stat binloader (FILE *fd, char *file, int loadpt); - -if (flag == 0) - return binloader (fileref, cptr, 0); -return SCPE_NOFNC; -} - -/* Symbol tables */ - -#define I_V_FL 39 /* inst class */ -#define I_M_FL 017 /* class mask */ -#define I_NOP 0000000000000000 /* no operand */ -#define I_MXR 0010000000000000 /* addr(tag) */ -#define I_MXN 0020000000000000 /* *addr(tag) */ -#define I_MXV 0030000000000000 /* var mul/div */ -#define I_MXC 0040000000000000 /* convert */ -#define I_DNP 0050000000000000 /* decr, no oper */ -#define I_DEC 0060000000000000 /* decrement */ -#define I_SNS 0070000000000000 /* sense */ -#define I_IMM 0100000000000000 /* 18b immediate */ -#define I_TAG 0110000000000000 /* tag only */ -#define I_IOX 0120000000000000 /* IO channel */ -#define I_TCH 0130000000000000 /* transfer channel */ -#define I_I9N 0140000000000000 /* 7909 with nostore */ -#define I_I9S 0150000000000000 /* 7909 */ -#define IFAKE_7607 0001000000000000 /* fake op extensions */ -#define IFAKE_7909 0002000000000000 -#define DFAKE (DMASK|IFAKE_7607|IFAKE_7909) -#define I_N_NOP 000 -#define I_N_MXR 001 -#define I_N_MXN 002 -#define I_N_MXV 003 -#define I_N_MXC 004 -#define I_N_DNP 005 -#define I_N_DEC 006 -#define I_N_SNS 007 -#define I_N_IMM 010 -#define I_N_TAG 011 -#define I_N_IOX 012 -#define I_N_TCH 013 -#define I_N_I9N 014 -#define I_N_I9S 015 - -#define INST_P_XIT 0 /* exit */ -#define INST_P_SKP 1 /* do not print */ -#define INST_P_PRA 2 /* print always */ -#define INST_P_PNZ 3 /* print if nz */ -#define INST_P_PNT 4 /* print if nz, term */ - -static const t_uint64 masks[14] = { - 03777700000000, 03777700000000, - 03777700000000, 03777700000000, - 03777400000000, 03700000000000, - 03700000000000, 03777700077777, - 03777700000000, 03777700000000, - 03700000200000, 03700000200000, - 03760000200000, 03740000200000 }; - -static const uint32 fld_max[14][3] = { /* addr,tag,decr limit */ - { INST_M_ADDR, INST_M_TAG, 0 }, - { INST_M_ADDR, INST_M_TAG, 0 }, - { INST_M_ADDR, INST_M_TAG, 0 }, - { INST_M_ADDR, INST_M_TAG, INST_M_VCNT }, - { INST_M_ADDR, INST_M_TAG, INST_M_CCNT }, - { INST_M_ADDR, INST_M_TAG, INST_M_DEC }, - { INST_M_ADDR, INST_M_TAG, INST_M_DEC }, - { 0, INST_M_TAG, 0 }, - { RMASK, 0, 0 }, - { INST_M_ADDR, INST_M_TAG, 0 }, - { INST_M_ADDR, 1, INST_M_DEC }, - { INST_M_ADDR, 1, 0 }, - { INST_M_ADDR, 1, 0 }, - { INST_M_ADDR, 1, 0 } - }; - -static const uint32 fld_fmt[14][3] = { /* addr,tag,decr print */ - { INST_P_PNT, INST_P_PNT, INST_P_XIT }, /* nop: all optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* mxr: tag optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* mxn: tag optional */ - { INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* mxv: tag optional */ - { INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* cvt: tag optional */ - { INST_P_PNT, INST_P_PNT, INST_P_PNT }, /* dnp: all optional */ - { INST_P_PRA, INST_P_PRA, INST_P_PRA }, /* dec: print all */ - { INST_P_SKP, INST_P_PNT, INST_P_XIT }, /* sns: skip addr, tag opt */ - { INST_P_PRA, INST_P_XIT, INST_P_XIT }, /* immediate: addr only */ - { INST_P_PNZ, INST_P_PRA, INST_P_XIT }, /* tag: addr optional */ - { INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* iox: tag optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* tch: tag optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* i9n: tag optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT } /* i9s: tag optional */ - }; - -static const t_uint64 ind_test[14] = { - 0, 0, INST_IND, 0, 0, 0, 0, - 0, 0, 0, CHI_IND, CHI_IND, CHI_IND, CHI_IND - }; - -static const char *opcode[] = { - "TXI", "TIX", "TXH", - "STR", "TNX", "TXL", - "HTR", "TRA", "TTR", - - "CLM", "LBT", "CHS", - "SSP", "ENK", "IOT", - "COM", "ETM", "RND", - "FRN", "DCT", "RCT", - "LMTM", "SLF", "SLN1", - "SLN2", "SLN3", "SLN4", - "SWT1", "SWT2", "SWT3", - "SWT4", "SWT5", "SWT6", - "BTTA", "BTTB", "BTTC", - "BTTD", "BTTE", "BTTF", - "BTTG", "BTTH", - "RICA", "RICB", "RICC", - "RICD", "RICE", "RICF", - "RICG", "RICH", - "RDCA", "RDCB", "RDCC", - "RDCD", "RDCE", "RDCF", - "RDCG", "RDCH", - - "TRCA", "TRCC", - "TRCE", "TRCG", - "TEFA", "TEFC", - "TEFE", "TEFG", - "TLQ", "IIA", "TIO", - "OAI", "PAI", "TIF", - "IIR", "RFT", "SIR", - "RNT", "RIR", - "TCOA", "TCOB", "TCOC", - "TCOD", "TCOE", "TCOF", - "TCOG", "TCOH", "TSX", - "TZE", "CVR", "TPL", - "XCA", "TOV", - "TQO", "TQP", - "MPY", "VLM", "VLM1", - "DVH", "DVP", - "VDH", "VDP", - "VDH2", "VDP2", - "FDH", "FDP", - "FMP", "DFMP", - "FAD", "DFAD", - "FSB", "DFSB", - "FAM", "DFAM", - "FSM", "DFSM", - "ANS", "ERA", - "CAS", "ACL", - "ADD", "ADM", - "SUB", "SBM", - "HPR", "IIS", "LDI", - "OSI", "DLD", "OFT", - "RIS", "ONT", - "CLA", "CLS", - "ZET", "XEC", - "LXA", "LAC", - "RCHA", "RCHC", - "RCHE", "RCHG", - "LCHA", "LCHC", - "LCHE", "LCHG", - "RSCA", "RSCC", - "RSCE", "RSCG", - "STCA", "STCC", - "STCE", "STCG", - "LDQ", "ENB", - "STZ", "STO", "SLW", - "STI", "STA", "STD", - "STT", "STP", - "SXA", "SCA", - "SCHA", "SCHC", - "SCHE", "SCHG", - "SCDA", "SCDC", - "SCDE", "SCDG", - "PAX", "PAC", - "PXA", "PCA", - "PSE", "NOP", "RDS", - "LLS", "BSR", "LRS", - "WRS", "ALS", "WEF", - "ARS", "REW", "AXT", - "SDN", - - "CLM", "PBT", "EFTM", - "SSM", "LFTM", "ESTM", - "ECTM", "LTM", "LSNM", - "EMTM", "SLT1", "SLT2", - "SLT3", "SLT4", - "ETTA", "ETTB", "ETTC", - "ETTD", "ETTE", "ETTF", - "ETTG", "ETTH", - - "ESNT", - "TRCB", "TRCD", - "TRCF", "TRCH", - "TEFB", "TEFD", - "TEFF", "TEFH", - "RIA", "PIA", - "IIL", "LFT", "SIL", - "LNT", "RIL", - "TCNA", "TCNB", "TCNC", - "TCND", "TCNE", "TCNF", - "TCNG", "TCNH", - "TNZ", "CVR", "TMI", - "XCL", "TNO", "CRQ", - "MPR", "DFDH", "DFDP", - "UFM", "DUFM", - "UFA", "DUFA", - "UFS", "DUFS", - "UAM", "DUAM", - "USM", "DUSM", - "ANA", "LAS", - "CAL", "ORA", "NZT", - "LXD", "LXC", - "RCHB", "RCHD", - "RCHF", "RCHH", - "LCHB", "LCHD", - "LCHF", "LCHH", - "RSCB", "RSCD", - "RSCF", "RSCH", - "STCB", "STCD", - "STCF", "STCH", - "STQ", "ORS", "DST", - "SLQ", "STL", - "SXD", "SCD", - "SCHB", "SCHD", - "SCHF", "SCHH", - "SCDB", "SCDD", - "SCDF", "SCDH", - "PDX", "PDC", - "PXD", "PCD", - "MSE", "LGL", "BSF", - "LGR", "RQL", "RUN", - "AXC", - - "TIA", "TIB", - "LRI", "LPI", - "SEA", "SEB", - "IFT", "EFT", - - "IOCD", "IOCDN", "TCH", - "IORP", "IORPN", - "IORT", "IORTN", - "IOCP", "IOCPN", - "IOCT", "IOCTN", - "IOSP", "IOSPN", - "IOST", "IOSTN", - - "WTR", "XMT", - "TCH", "LIPT", - "CTL", "CTLN", - "CTLR", "CTLRN", - "CTLW", "CTLWN", - "SNS", - "LAR", "SAR", "TWT", - "CPYP", - "CPYD", "TCM", - "LIP", "TDC", "LCC", - "SMS", "ICC", - - NULL - }; - -static const t_uint64 opc_v[] = { - 0100000000000+I_DEC, 0200000000000+I_DEC, 0300000000000+I_DEC, - 0500000000000+I_DNP, 0600000000000+I_DEC, 0700000000000+I_DEC, - 0000000000000+I_MXN, 0002000000000+I_MXN, 0002100000000+I_MXN, - - 0076000000000+I_SNS, 0076000000001+I_SNS, 0076000000002+I_SNS, - 0076000000003+I_SNS, 0076000000004+I_SNS, 0076000000005+I_SNS, - 0076000000006+I_SNS, 0076000000007+I_SNS, 0076000000010+I_SNS, - 0076000000011+I_SNS, 0076000000012+I_SNS, 0076000000014+I_SNS, - 0076000000016+I_SNS, 0076000000140+I_SNS, 0076000000141+I_SNS, - 0076000000142+I_SNS, 0076000000143+I_SNS, 0076000000144+I_SNS, - 0076000000161+I_SNS, 0076000000162+I_SNS, 0076000000163+I_SNS, - 0076000000164+I_SNS, 0076000000165+I_SNS, 0076000000166+I_SNS, - 0076000001000+I_SNS, 0076000002000+I_SNS, 0076000003000+I_SNS, - 0076000004000+I_SNS, 0076000005000+I_SNS, 0076000006000+I_SNS, - 0076000007000+I_SNS, 0076000010000+I_SNS, - 0076000001350+I_SNS, 0076000002350+I_SNS, 0076000003350+I_SNS, - 0076000004350+I_SNS, 0076000005350+I_SNS, 0076000006350+I_SNS, - 0076000007350+I_SNS, 0076000010350+I_SNS, - 0076000001352+I_SNS, 0076000002352+I_SNS, 0076000003352+I_SNS, - 0076000004352+I_SNS, 0076000005352+I_SNS, 0076000006352+I_SNS, - 0076000007352+I_SNS, 0076000010352+I_SNS, - - 0002200000000+I_MXN, 0002400000000+I_MXN, - 0002600000000+I_MXN, 0002700000000+I_MXN, - 0003000000000+I_MXN, 0003100000000+I_MXN, - 0003200000000+I_MXN, 0003300000000+I_MXN, - 0004000000000+I_MXN, 0004100000000+I_NOP, 0004200000000+I_MXR, - 0004300000000+I_NOP, 0004400000000+I_NOP, 0004600000000+I_MXR, - 0005100000000+I_IMM, 0005400000000+I_IMM, 0005500000000+I_IMM, - 0005600000000+I_IMM, 0005700000000+I_IMM, - 0006000000000+I_MXN, 0006100000000+I_MXN, 0006200000000+I_MXN, - 0006300000000+I_MXN, 0006400000000+I_MXN, 0006500000000+I_MXN, - 0006600000000+I_MXN, 0006700000000+I_MXN, 0007400000000+I_MXR, - 0010000000000+I_MXN, 0011400000000+I_MXC, 0012000000000+I_MXN, - 0013100000000+I_NOP, 0014000000000+I_MXN, - 0016100000000+I_MXN, 0016200000000+I_MXN, - 0020000000000+I_MXN, 0020400000000+I_MXV, 0020500000000+I_MXV, - 0022000000000+I_MXN, 0022100000000+I_MXN, - 0022400000000+I_MXV, 0022500000000+I_MXV, - 0022600000000+I_MXV, 0022700000000+I_MXV, - 0024000000000+I_MXN, 0024100000000+I_MXN, - 0026000000000+I_MXN, 0026100000000+I_MXN, - 0030000000000+I_MXN, 0030100000000+I_MXN, - 0030200000000+I_MXN, 0030300000000+I_MXN, - 0030400000000+I_MXN, 0030500000000+I_MXN, - 0030600000000+I_MXN, 0030700000000+I_MXN, - 0032000000000+I_MXN, 0032200000000+I_MXN, - 0034000000000+I_MXN, 0036100000000+I_MXN, - 0040000000000+I_MXN, 0040100000000+I_MXN, - 0040200000000+I_MXN, 0440000000000+I_MXN, - 0042000000000+I_NOP, 0044000000000+I_MXN, 0044100000000+I_MXN, - 0044200000000+I_MXN, 0044300000000+I_MXN, 0044400000000+I_MXN, - 0044500000000+I_MXN, 0044600000000+I_MXN, - 0050000000000+I_MXN, 0050200000000+I_MXN, - 0052000000000+I_MXN, 0052200000000+I_MXN, - 0053400000000+I_MXR, 0053500000000+I_MXR, - 0054000000000+I_MXN, 0054100000000+I_MXN, - 0054200000000+I_MXN, 0054300000000+I_MXN, - 0054400000000+I_MXN, 0054500000000+I_MXN, - 0054600000000+I_MXN, 0054700000000+I_MXN, - 0054000000000+I_MXN, 0054100000000+I_MXN, - 0054200000000+I_MXN, 0054300000000+I_MXN, - 0054400000000+I_MXN, 0054500000000+I_MXN, - 0054600000000+I_MXN, 0054700000000+I_MXN, - 0056000000000+I_MXN, 0056400000000+I_MXN, - 0060000000000+I_MXN, 0060100000000+I_MXN, 0060200000000+I_MXN, - 0060400000000+I_MXN, 0062100000000+I_MXN, 0062200000000+I_MXN, - 0062500000000+I_MXN, 0063000000000+I_MXN, - 0063400000000+I_MXR, 0063600000000+I_MXR, - 0064000000000+I_MXN, 0064000000000+I_MXN, - 0064200000000+I_MXN, 0064300000000+I_MXN, - 0064400000000+I_MXN, 0064500000000+I_MXN, - 0064600000000+I_MXN, 0064700000000+I_MXN, - 0073400000000+I_TAG, 0073700000000+I_TAG, - 0075400000000+I_TAG, 0075600000000+I_TAG, - 0076000000000+I_MXR, 0076100000000+I_NOP, 0076200000000+I_MXR, - 0076300000000+I_MXR, 0076400000000+I_MXR, 0076500000000+I_MXR, - 0076600000000+I_MXR, 0076700000000+I_MXR, 0077000000000+I_MXR, - 0077100000000+I_MXR, 0077200000000+I_MXR, 0077400000000+I_MXR, - 0077600000000+I_MXR, - - 0476000000000+I_SNS, 0476000000001+I_SNS, 0476000000002+I_SNS, - 0476000000003+I_SNS, 0476000000004+I_SNS, 0476000000005+I_SNS, - 0476000000006+I_SNS, 0476000000007+I_SNS, 0476000000010+I_SNS, - 0476000000016+I_SNS, 0476000000141+I_SNS, 0476000000142+I_SNS, - 0476000000143+I_SNS, 0476000000144+I_SNS, - 0476000001000+I_SNS, 0476000002000+I_SNS, 0476000003000+I_SNS, - 0476000004000+I_SNS, 0476000005000+I_SNS, 0476000006000+I_SNS, - 0476000007000+I_SNS, 0476000010000+I_SNS, - - 0402100000000+I_MXN, - 0402200000000+I_MXN, 0402400000000+I_MXN, - 0402600000000+I_MXN, 0402700000000+I_MXN, - 0403000000000+I_MXN, 0403100000000+I_MXN, - 0403200000000+I_MXN, 0403300000000+I_MXN, - 0404200000000+I_NOP, 0404600000000+I_NOP, - 0405100000000+I_IMM, 0405400000000+I_IMM, 0405500000000+I_IMM, - 0405600000000+I_IMM, 0405700000000+I_IMM, - 0406000000000+I_MXN, 0406100000000+I_MXN, 0406200000000+I_MXN, - 0406300000000+I_MXN, 0406400000000+I_MXN, 0406500000000+I_MXN, - 0406600000000+I_MXN, 0406700000000+I_MXN, - 0410000000000+I_MXN, 0411400000000+I_MXC, 0412000000000+I_MXN, - 0413000000000+I_NOP, 0414000000000+I_MXN, 0415400000000+I_MXC, - 0420000000000+I_MXN, 0424000000000+I_MXN, 0424100000000+I_MXN, - 0426000000000+I_MXN, 0426100000000+I_MXN, - 0430000000000+I_MXN, 0430100000000+I_MXN, - 0430200000000+I_MXN, 0430300000000+I_MXN, - 0430400000000+I_MXN, 0430500000000+I_MXN, - 0430600000000+I_MXN, 0430700000000+I_MXN, - 0432000000000+I_MXN, 0434000000000+I_MXN, - 0450000000000+I_MXN, 0450100000000+I_MXN, 0452000000000+I_MXN, - 0453400000000+I_MXR, 0453500000000+I_MXR, - 0454000000000+I_MXN, 0454100000000+I_MXN, - 0454200000000+I_MXN, 0454300000000+I_MXN, - 0454400000000+I_MXN, 0454500000000+I_MXN, - 0454600000000+I_MXN, 0454700000000+I_MXN, - 0454000000000+I_MXN, 0454100000000+I_MXN, - 0454200000000+I_MXN, 0454300000000+I_MXN, - 0454400000000+I_MXN, 0454500000000+I_MXN, - 0454600000000+I_MXN, 0454700000000+I_MXN, - 0460000000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN, - 0462000000000+I_MXN, 0462500000000+I_MXN, - 0463400000000+I_MXR, 0463600000000+I_MXR, - 0464000000000+I_MXN, 0464000000000+I_MXN, - 0464200000000+I_MXN, 0464300000000+I_MXN, - 0464400000000+I_MXN, 0464500000000+I_MXN, - 0464600000000+I_MXN, 0464700000000+I_MXN, - 0473400000000+I_TAG, 0473700000000+I_TAG, - 0475400000000+I_TAG, 0475600000000+I_TAG, - 0476000000000+I_MXR, 0476300000000+I_MXR, 0476400000000+I_MXR, - 0476500000000+I_MXR, 0477300000000+I_MXR, 0477200000000+I_MXR, - 0477400000000+I_MXR, - - 0010100000000+I_MXN, 0410100000000+I_MXN, - 0056200000000+I_MXN, 0456400000000+I_MXN, - 0476100000041+I_SNS, 0476100000042+I_SNS, - 0476100000043+I_SNS, 0476100000044+I_SNS, - - 01000000000000+I_IOX, 01000000200000+I_IOX, 01100000000000+I_TCH, - 01200000000000+I_IOX, 01200000200000+I_IOX, - 01300000000000+I_IOX, 01300000200000+I_IOX, - 01400000000000+I_IOX, 01400000200000+I_IOX, - 01500000000000+I_IOX, 01500000200000+I_IOX, - 01600000000000+I_IOX, 01600000200000+I_IOX, - 01700000000000+I_IOX, 01700000200000+I_IOX, - - 02000000000000+I_TCH, 02000000200000+I_IOX, - 02100000000000+I_TCH, 02100000200000+I_TCH, - 02200000000000+I_I9N, 02220000000000+I_TCH, - 02200000200000+I_I9N, 02220000200000+I_TCH, - 02240000000000+I_I9N, 02260000000000+I_TCH, - 02240000200000+I_I9N, - 02300000000000+I_I9S, 02300000200000+I_I9S, - 02340000000000+I_I9S, - 02400000000000+I_IOX, - 02500000000000+I_IOX, 02500000200000+I_IOX, - 02600000200000+I_I9S, 02640000000000+I_I9S, 02640000200000+I_I9S, - 02700000000000+I_I9S, 02700000200000+I_IOX, - - 0 - }; - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = pointer to values - *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) -{ -uint32 i, j, k, l, fmt, c, fld[3]; -DEVICE *dptr; -t_uint64 inst; - -inst = val[0]; -if (uptr == NULL) - uptr = &cpu_unit; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; - -if (sw & SWMASK ('C')) { /* character? */ - c = (uint32) (inst & 077); - fprintf (of, "%c", cvt_code_to_ascii (c, sw)); - return SCPE_OK; - } -if (sw & SWMASK ('S')) { /* string? */ - for (i = 36; i > 0; i = i - 6) { - c = (uint32) ((inst >> (i - 6)) & 077); - fprintf (of, "%c", cvt_code_to_ascii (c, sw)); - } - return SCPE_OK; - } -if (!(sw & (SWMASK ('M')|SWMASK ('I')|SWMASK ('N'))) || /* M, N or I? */ - (dptr->dwidth != 36)) - return SCPE_ARG; - -/* Instruction decode */ - -fld[0] = ((uint32) inst & 0777777); -fld[1] = GET_TAG (inst); /* get 3 fields */ -fld[2] = GET_DEC (inst); -if (sw & SWMASK ('I')) /* decode as 7607? */ - inst |= IFAKE_7607; -if (sw & SWMASK ('N')) /* decode as 7909? */ - inst |= IFAKE_7909; - -for (i = 0; opc_v[i] > 0; i++) { /* loop thru ops */ - j = (int32) ((opc_v[i] >> I_V_FL) & I_M_FL); /* get class */ - if ((opc_v[i] & DFAKE) == (inst & masks[j])) { /* match? */ - if (inst & ind_test[j]) /* indirect? */ - fprintf (of, "%s*", opcode[i]); - else fprintf (of, "%s", opcode[i]); /* opcode */ - for (k = 0; k < 3; k++) - fld[k] = fld[k] & fld_max[j][k]; - for (k = 0; k < 3; k++) { /* loop thru fields */ - fmt = fld_fmt[j][k]; /* get format */ - if (fmt == INST_P_XIT) - return SCPE_OK; - switch (fmt) { /* case on format */ - - case INST_P_PNT: /* print nz, else term */ - for (l = k, c = 0; l < 3; l++) c |= fld[k]; - if (c == 0) - return SCPE_OK; - case INST_P_PNZ: /* print non-zero */ - fputc (k? ',': ' ', of); - if (fld[k]) - fprintf (of, "%-o", fld[k]); - break; - case INST_P_PRA: /* print always */ - fputc (k? ',': ' ', of); - fprintf (of, "%-o", fld[k]); - break; - case INST_P_SKP: /* skip */ - break; - } /* end switch */ - } /* end for k */ - return SCPE_OK; /* done */ - } /* end if */ - } /* end for i */ -return SCPE_ARG; -} - -/* Convert character to code to ASCII - - -b BCD - -a business-chain */ - -uint32 cvt_code_to_ascii (uint32 c, int32 sw) -{ -if (sw & SWMASK ('B')) { - if (sw & SWMASK ('A')) - return bcd_to_ascii_a[c]; - else return bcd_to_ascii_h[c]; - } -else if (sw & SWMASK ('A')) - return nine_to_ascii_a[c]; -else return nine_to_ascii_h[c]; -} - -/* 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) -{ -uint32 i, j, c; -t_uint64 fld[3]; -t_bool ind; -t_stat r; -char gbuf[CBUFSIZE]; - -while (isspace (*cptr)) cptr++; -if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = (t_value) cvt_ascii_to_code (cptr[0] & 0177, sw); - return SCPE_OK; - } -if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - for (i = 0; i < 6; i++) { - c = cptr[0] & 0177; - if (c) - val[0] = (val[0] << 6) | ((t_value) cvt_ascii_to_code (c, sw)); - else { - val[0] = val[0] << (6 * (6 - i)); - break; - } - } - return SCPE_OK; - } - -cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ -j = strlen (gbuf); /* get length */ -if (gbuf[j - 1] == '*') { /* indirect? */ - ind = TRUE; - gbuf[j - 1] = 0; - } -else ind = FALSE; -for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; -if (opcode[i] == NULL) - return SCPE_ARG; -j = (uint32) ((opc_v[i] >> I_V_FL) & I_M_FL); /* get class */ -val[0] = opc_v[i] & DMASK; -if (ind) { - if (ind_test[j]) - val[0] |= ind_test[j]; - else return SCPE_ARG; - } - -for (i = 0; i < 3; i++) /* clear inputs */ - fld[i] = 0; -for (i = 0; (i < 3) && *cptr; i++) { /* parse inputs */ - if (i < 2) /* get glyph */ - cptr = get_glyph (cptr, gbuf, ','); - else cptr = get_glyph (cptr, gbuf, 0); - if (gbuf[0]) { /* anything? */ - fld[i] = get_uint (gbuf, 8, fld_max[j][i], &r); - if ((r != SCPE_OK) || (fld_max[j][i] == 0)) - return SCPE_ARG; - } - } -if (*cptr != 0) /* junk at end? */ - return SCPE_ARG; - -val[0] = val[0] | fld[0] | (fld[1] << INST_V_TAG) | (fld[2] << INST_V_DEC); -return SCPE_OK; -} - -/* Convert ASCII to character code - - -b BCD */ - -uint32 cvt_ascii_to_code (uint32 c, int32 sw) -{ -if (sw & SWMASK ('B')) - return ascii_to_bcd[c]; -else return ascii_to_nine[c]; -} diff --git a/LGP/lgp_defs.h b/LGP/lgp_defs.h index aed3fe04..ebe442ed 100644 --- a/LGP/lgp_defs.h +++ b/LGP/lgp_defs.h @@ -24,7 +24,6 @@ in this Software without prior written authorization from Robert M Supnik. 22-May-10 RMS Added check for 64b definitions - */ #ifndef _LGP_DEFS_H_ diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 78b1d2c0..061f0e40 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-2008, Robert M Supnik + Copyright (c) 1993-2011, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 04-Apr-11 RMS Removed DEUNA/DELUA support - never implemented 01-Feb-07 RMS Added CD support 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn) 09-Jan-03 RMS Added DEUNA/DELUA support @@ -54,7 +55,6 @@ extern DEVICE dz_dev; extern DEVICE ry_dev; extern DEVICE cr_dev; extern DEVICE lp20_dev; -extern DEVICE xu_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern d10 *M; @@ -90,7 +90,6 @@ DEVICE *sim_devices[] = { &rp_dev, &tu_dev, &dz_dev, - &xu_dev, NULL }; diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c index 1228538e..b1def4a7 100644 --- a/PDP11/pdp11_dc.c +++ b/PDP11/pdp11_dc.c @@ -1,6 +1,6 @@ /* pdp11_dc.c: PDP-11 DC11 multiple terminal interface simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2011, Robert 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 @@ dci,dco DC11 terminal input/output + 17-Aug-2011 RMS Added AUTOCONFIGURE modifier 19-Nov-2008 RMS Revised for common TMXR show routines Revised to autoconfigure vectors @@ -175,6 +176,8 @@ MTAB dci_mod[] = { NULL, &tmxr_show_cstat, (void *) &dcx_desc }, { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, &set_addr, &show_addr, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 1, "VECTOR", NULL, &set_vec, &show_vec_mux, (void *) &dcx_desc }, { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", diff --git a/PDP11/pdp11_dl.c b/PDP11/pdp11_dl.c index 00dff0ec..aebd38f4 100644 --- a/PDP11/pdp11_dl.c +++ b/PDP11/pdp11_dl.c @@ -1,6 +1,6 @@ /* pdp11_dl.c: PDP-11 multiple terminal interface simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2011, Robert 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 @@ dli,dlo DL11 terminal input/output + 17-Aug-2011 RMS Added AUTOCONFIGURE modifier 19-Nov-2008 RMS Revised for common TMXR show routines Revised to autoconfigure vectors 20-May-2008 RMS Added modem control support @@ -142,6 +143,8 @@ MTAB dli_mod[] = { NULL, &tmxr_show_cstat, (void *) &dlx_desc }, { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, &set_addr, &show_addr, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 1, "VECTOR", NULL, &set_vec, &show_vec_mux, (void *) &dlx_desc }, { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index 45c08891..1e687530 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 12-Dec-11 RMS Fixed interrupts to treat all Qbus devices as BR4 + 12-Dec-11 RMS Fixed Qbus interrupts to treat all IO devices as BR4 19-Nov-08 RMS Moved I/O support routines to I/O library 16-May-08 RMS Added multiple DC11 support Renamed DL11 in autoconfigure diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 19944926..9c97888d 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-2009, Robert M Supnik + Copyright (c) 1993-2008, Robert 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,7 +25,20 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk - 10-Oct-09 RMS Added debug support + 24-Mar-11 JAD Various changes to support diagnostics, including: + - distinguish between RLV11 & 12 + - more complete drive state + - improved head position tracking + - implement MAINT command of RLV11/12 + - always respect unit disable flag + New commands added: + SHOW RLn DSTATE + SET RLn LOAD/UNLOAD + SET RLn OPEN/CLOSED + SET RLn BRUSH/NOBRUSH + SET RLn ONLINE/OFFLINE + SET RL RLV11/RLV12 (PDP-11 only) + SET RL DEBUG/NODEBUG 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs @@ -82,26 +95,36 @@ #else /* PDP-11 version */ #include "pdp11_defs.h" extern uint32 cpu_opt; +extern UNIT cpu_unit; #endif /* Constants */ -#define RL_NUMWD 128 /* words/sector */ -#define RL_NUMSC 40 /* sectors/surface */ -#define RL_NUMSF 2 /* surfaces/cylinder */ -#define RL_NUMCY 256 /* cylinders/drive */ -#define RL_NUMDR 4 /* drives/controller */ -#define RL_MAXFR (1 << 16) /* max transfer */ -#define RL01_SIZE (RL_NUMCY * RL_NUMSF * RL_NUMSC * RL_NUMWD) /* words/drive */ +#define RL_NUMWD (128) /* words/sector */ +#define RL_NUMSC (40) /* sectors/surface */ +#define RL_NUMSF (2) /* surfaces/cylinder */ +#define RL_NUMCY (256) /* cylinders/drive */ +#define RL_NUMDR (4) /* drives/controller */ +#define RL_MAXFR (RL_NUMSC * RL_NUMWD) /* max transfer */ +#define RL01_SIZE (RL_NUMCY * RL_NUMSF * RL_NUMSC * RL_NUMWD) /* words/drive */ #define RL02_SIZE (RL01_SIZE * 2) /* words/drive */ +/* Device flags */ + +#define DEV_V_RLV11 (DEV_V_UF + 7) /* RLV11 */ +#define DEV_RLV11 (1u << DEV_V_RLV11) + /* Flags in the unit flags word */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */ #define UNIT_V_RL02 (UNIT_V_UF + 1) /* RL01 vs RL02 */ #define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize enable */ -#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */ -#define UNIT_DUMMY (1 << UNIT_V_DUMMY) +#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag, for SET BADBLOCK */ +#define UNIT_V_OFFL (UNIT_V_UF + 4) /* unit off line */ +#define UNIT_V_BRUSH (UNIT_V_UF + 5) /* unit has brushes */ +#define UNIT_BRUSH (1u << UNIT_V_BRUSH) +#define UNIT_OFFL (1u << UNIT_V_OFFL) +#define UNIT_DUMMY (1u << UNIT_V_DUMMY) #define UNIT_WLK (1u << UNIT_V_WLK) #define UNIT_RL02 (1u << UNIT_V_RL02) #define UNIT_AUTO (1u << UNIT_V_AUTO) @@ -109,74 +132,85 @@ extern uint32 cpu_opt; /* Parameters in the unit descriptor */ -#define TRK u3 /* current track */ +#define TRK u3 /* current track:head:sector */ #define STAT u4 /* status */ +#define FNC u5 /* function */ -/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */ +/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK , ! = kept in uptr */ -#define RLDS_LOAD 0 /* no cartridge */ -#define RLDS_LOCK 5 /* lock on */ -#define RLDS_BHO 0000010 /* brushes home NI */ -#define RLDS_HDO 0000020 /* heads out NI */ -#define RLDS_CVO 0000040 /* cover open NI */ -#define RLDS_HD 0000100 /* head select ^ */ -#define RLDS_RL02 0000200 /* RL02 */ -#define RLDS_DSE 0000400 /* drv sel err NI */ -#define RLDS_VCK 0001000 /* vol check * */ -#define RLDS_WGE 0002000 /* wr gate err * */ -#define RLDS_SPE 0004000 /* spin err * */ -#define RLDS_STO 0010000 /* seek time out NI */ -#define RLDS_WLK 0020000 /* wr locked */ -#define RLDS_HCE 0040000 /* hd curr err NI */ -#define RLDS_WDE 0100000 /* wr data err NI */ -#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */ -#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */ -#define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \ - RLDS_VCK+RLDS_DSE) /* errors bits */ +#define RLDS_M_STATE (07) +#define RLDS_LOAD (0) /* no cartridge */ +#define RLDS_SPIN (1) /* spin-up */ +#define RLDS_BRUSH (2) /* brush cycle *! */ +#define RLDS_HLOAD (3) /* load heads */ +#define RLDS_SEEK (4) /* drive seeking * */ +#define RLDS_LOCK (5) /* lock on * */ +#define RLDS_UNL (6) /* unload heads */ +#define RLDS_DOWN (7) /* spin-down */ +#define RLDS_BHO (0000010) /* brushes home * */ +#define RLDS_HDO (0000020) /* heads out * */ +#define RLDS_CVO (0000040) /* cover open * */ +#define RLDS_HD (0000100) /* head select ^ */ +#define RLDS_RL02 (0000200) /* RL02 ! */ +#define RLDS_DSE (0000400) /* drv sel err */ +#define RLDS_VCK (0001000) /* vol check * */ +#define RLDS_WGE (0002000) /* wr gate err * */ +#define RLDS_SPE (0004000) /* spin err * */ +#define RLDS_STO (0010000) /* seek time out * */ +#define RLDS_WLK (0020000) /* wr locked ! */ +#define RLDS_HCE (0040000) /* hd curr err NI */ +#define RLDS_WDE (0100000) /* wr data err NI */ +#define RLDS_ERR (RLDS_WDE|RLDS_HCE|RLDS_STO|RLDS_SPE|RLDS_WGE| \ + RLDS_VCK|RLDS_DSE) /* errors bits */ /* RLCS */ -#define RLCS_DRDY 0000001 /* drive ready */ -#define RLCS_M_FUNC 0000007 /* function */ -#define RLCS_NOP 0 -#define RLCS_WCHK 1 -#define RLCS_GSTA 2 -#define RLCS_SEEK 3 -#define RLCS_RHDR 4 -#define RLCS_WRITE 5 -#define RLCS_READ 6 -#define RLCS_RNOHDR 7 -#define RLCS_V_FUNC 1 -#define RLCS_M_MEX 03 /* memory extension */ -#define RLCS_V_MEX 4 +#define RLCS_DRDY (0000001) /* drive ready */ +#define RLCS_M_FUNC (0000007) /* function */ +#define RLCS_NOP (0) +#define RLCS_WCHK (1) +#define RLCS_GSTA (2) +#define RLCS_SEEK (3) +#define RLCS_RHDR (4) +#define RLCS_WRITE (5) +#define RLCS_READ (6) +#define RLCS_RNOHDR (7) +#define RLCS_SPECIAL (8) /* internal function, drive state */ +#define RLCS_V_FUNC (1) +#define RLCS_M_MEX (03) /* memory extension */ +#define RLCS_V_MEX (4) #define RLCS_MEX (RLCS_M_MEX << RLCS_V_MEX) -#define RLCS_M_DRIVE 03 -#define RLCS_V_DRIVE 8 -#define RLCS_INCMP 0002000 /* incomplete */ -#define RLCS_CRC 0004000 /* CRC error */ -#define RLCS_HDE 0010000 /* header error */ -#define RLCS_NXM 0020000 /* non-exist memory */ -#define RLCS_DRE 0040000 /* drive error */ -#define RLCS_ERR 0100000 /* error summary */ -#define RLCS_ALLERR (RLCS_ERR+RLCS_DRE+RLCS_NXM+RLCS_HDE+RLCS_CRC+RLCS_INCMP) -#define RLCS_RW 0001776 /* read/write */ +#define RLCS_M_DRIVE (03) +#define RLCS_V_DRIVE (8) +#define RLCS_INCMP (0002000) /* incomplete */ +#define RLCS_CRC (0004000) /* CRC error */ +#define RLCS_HCRC (RLCS_CRC|RLCS_INCMP) /* header CRC error */ +#define RLCS_DLT (0010000) /* data late */ +#define RLCS_HDE (RLCS_DLT|RLCS_INCMP) /* header not found error */ +#define RLCS_NXM (0020000) /* non-exist memory */ +#define RLCS_PAR (RLCS_NXM|RLCS_INCMP) /* parity error */ +#define RLCS_DRE (0040000) /* drive error */ +#define RLCS_ERR (0100000) /* error summary */ +#define RLCS_ALLERR (RLCS_ERR|RLCS_DRE|RLCS_NXM|RLCS_HDE|RLCS_CRC|RLCS_INCMP) +#define RLCS_RW (0001776) /* read/write */ #define GET_FUNC(x) (((x) >> RLCS_V_FUNC) & RLCS_M_FUNC) #define GET_DRIVE(x) (((x) >> RLCS_V_DRIVE) & RLCS_M_DRIVE) /* RLDA */ -#define RLDA_SK_DIR 0000004 /* direction */ -#define RLDA_GS_CLR 0000010 /* clear errors */ -#define RLDA_SK_HD 0000020 /* head select */ +#define RLDA_GS (0000002) /* get status */ +#define RLDA_SK_DIR (0000004) /* direction */ +#define RLDA_GS_CLR (0000010) /* clear errors */ +#define RLDA_SK_HD (0000020) /* head select */ -#define RLDA_V_SECT 0 /* sector */ -#define RLDA_M_SECT 077 -#define RLDA_V_TRACK 6 /* track */ -#define RLDA_M_TRACK 01777 +#define RLDA_V_SECT (0) /* sector */ +#define RLDA_M_SECT (077) +#define RLDA_V_TRACK (6) /* track */ +#define RLDA_M_TRACK (01777) #define RLDA_HD0 (0 << RLDA_V_TRACK) #define RLDA_HD1 (1u << RLDA_V_TRACK) -#define RLDA_V_CYL 7 /* cylinder */ -#define RLDA_M_CYL 0777 +#define RLDA_V_CYL (7) /* cylinder */ +#define RLDA_M_CYL (0777) #define RLDA_TRACK (RLDA_M_TRACK << RLDA_V_TRACK) #define RLDA_CYL (RLDA_M_CYL << RLDA_V_CYL) #define GET_SECT(x) (((x) >> RLDA_V_SECT) & RLDA_M_SECT) @@ -186,11 +220,11 @@ extern uint32 cpu_opt; /* RLBA */ -#define RLBA_IMP 0177776 /* implemented */ +#define RLBA_IMP (0177777) /* implemented */ /* RLBAE */ -#define RLBAE_IMP 0000077 /* implemented */ +#define RLBAE_IMP (0000077) /* implemented */ extern int32 int_req[IPL_HLVL]; extern FILE *sim_deb; @@ -205,6 +239,7 @@ int32 rl_swait = 10; /* seek wait */ int32 rl_rwait = 10; /* rotate wait */ int32 rl_stopioe = 1; /* stop on error */ +/* forward references */ DEVICE rl_dev; t_stat rl_rd (int32 *data, int32 PA, int32 access); t_stat rl_wr (int32 data, int32 PA, int32 access); @@ -215,31 +250,42 @@ t_stat rl_boot (int32 unitno, DEVICE *dptr); t_stat rl_attach (UNIT *uptr, char *cptr); t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); +static void rlv_maint (void); +t_stat rl_detach (UNIT *uptr); +t_stat rl_set_cover (UNIT *, int32, char *, void *); +t_stat rl_show_cover (FILE *, UNIT *, int, void *); +t_stat rl_set_load (UNIT *, int32, char *, void *); +t_stat rl_show_load (FILE *, UNIT *, int, void *); +t_stat rl_show_dstate (FILE *, UNIT *, int, void *); +#if defined (VM_PDP11) +t_stat rl_set_ctrl (UNIT *uptr, int32 val, char *cptr, void *desc); +#endif +t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int val, void *desc); /* RL11 data structures - rl_dev RL device descriptor - rl_unit RL unit list - rl_reg RL register list - rl_mod RL modifier list + rl_dev RL device descriptor + rl_unit RL unit list + rl_reg RL register list + rl_mod RL modifier list */ -DIB rl_dib = { +static DIB rl_dib = { IOBA_RL, IOLN_RL, &rl_rd, &rl_wr, 1, IVCL (RL), VEC_RL, { NULL } }; -UNIT rl_unit[] = { +static UNIT rl_unit[] = { { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) } + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) } }; -REG rl_reg[] = { +static const REG rl_reg[] = { { GRDATA (RLCS, rlcs, DEV_RDX, 16, 0) }, { GRDATA (RLDA, rlda, DEV_RDX, 16, 0) }, { GRDATA (RLBA, rlba, DEV_RDX, 16, 0) }, @@ -261,7 +307,22 @@ REG rl_reg[] = { { NULL } }; -MTAB rl_mod[] = { +static const MTAB rl_mod[] = { +#if defined (VM_PDP11) + { MTAB_XTD|MTAB_VDV, (DEV_RLV11|DEV_Q18), "", "RLV11", &rl_set_ctrl, &rl_show_ctrl, NULL}, + { MTAB_XTD|MTAB_VDV, 0, NULL, "RLV12", &rl_set_ctrl, NULL, NULL}, +#endif + { UNIT_OFFL, 0, "on line", "ONLINE", NULL, NULL }, + { UNIT_OFFL, UNIT_OFFL, "off line", "OFFLINE", NULL, NULL }, + { UNIT_BRUSH, 0, NULL, "NOBRUSH", NULL, NULL }, + { UNIT_BRUSH, UNIT_BRUSH, "has brushes", "BRUSH", NULL, NULL }, + + { MTAB_XTD|MTAB_VUN|MTAB_NMO, RLDS_CVO, "open", "OPEN", &rl_set_cover, &rl_show_cover, NULL }, + { MTAB_XTD|MTAB_VUN, 0, NULL, "CLOSED", &rl_set_cover, NULL, NULL }, + { MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "load", "LOAD", &rl_set_load, &rl_show_load, NULL }, + { MTAB_XTD|MTAB_VUN, 1, NULL, "UNLOAD", &rl_set_load, NULL, NULL }, + { MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "DSTATE", NULL, NULL, &rl_show_dstate, NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad }, @@ -281,20 +342,26 @@ MTAB rl_mod[] = { }; DEVICE rl_dev = { - "RL", rl_unit, rl_reg, rl_mod, + "RL", (UNIT *) &rl_unit, (REG *) rl_reg, (MTAB *) rl_mod, RL_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16, NULL, NULL, &rl_reset, - &rl_boot, &rl_attach, NULL, - &rl_dib, DEV_DEBUG | DEV_DISABLE | DEV_UBUS | DEV_QBUS + &rl_boot, &rl_attach, &rl_detach, + &rl_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; -/* I/O dispatch routines, I/O addresses 17774400 - 17774407 +/* Drive states */ +static const char * const state[] = { + "Load Cartridge", "Spin Up", "Brush", "Load Heads", + "Seek", "Lock On", "Unload Heads", "Spin Down" +}; - 17774400 RLCS read/write - 17774402 RLBA read/write - 17774404 RLDA read/write - 17774406 RLMP read/write - 17774410 RLBAE read/write +/* I/O dispatch routines, I/O addresses 17774400 - 17774411 + + 17774400 RLCS read/write + 17774402 RLBA read/write + 17774404 RLDA read/write + 17774406 RLMP read/write + 17774410 RLBAE read/write */ t_stat rl_rd (int32 *data, int32 PA, int32 access) @@ -304,15 +371,37 @@ UNIT *uptr; switch ((PA >> 1) & 07) { /* decode PA<2:1> */ case 0: /* RLCS */ - rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); - if (rlcs & RLCS_ALLERR) - rlcs = rlcs | RLCS_ERR; - uptr = rl_dev.units + GET_DRIVE (rlcs); - if (sim_is_active (uptr)) - rlcs = rlcs & ~RLCS_DRDY; - else rlcs = rlcs | RLCS_DRDY; /* see if ready */ - *data = rlcs; - break; + rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); +/* +The DRDY signal is sent by the selected drive to indicate that it +is ready to read or write or seek. It is sent when the heads are +not moving and are locked onto a cylinder. This is continuously +monitored by the drive and controller. [EK-0RL11-TD-001, p. 3-8] +Use the DS bits to determine if the drive has any outstanding I/O +operations and set DRDY as appropriate. + +This seems to imply that only a Seek operation (not Read/Write) +causes ready to be false. +*/ + uptr = rl_dev.units + GET_DRIVE (rlcs); + if ((uptr->flags & UNIT_OFFL) || (uptr->STAT & RLDS_VCK)) { + rlcs |= RLCS_DRE; + rlcs &= ~RLCS_DRDY; + } else if (sim_is_active (uptr) || (uptr->flags & UNIT_DIS) || + ((uptr->STAT & RLDS_M_STATE) != RLDS_LOCK)) + rlcs &= ~RLCS_DRDY; + else + rlcs |= RLCS_DRDY; /* see if ready */ +/* +Make sure the error summary bit properly reflects the sum of other +errors. +*/ + if (rlcs & RLCS_ALLERR) + rlcs |= RLCS_ERR; + *data = rlcs; + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL rd: RLCS %06o\n", rlcs); + break; case 1: /* RLBA */ *data = rlba & RLBA_IMP; @@ -329,111 +418,278 @@ switch ((PA >> 1) & 07) { /* decode PA<2:1> */ break; case 4: /* RLBAE */ - if (UNIBUS) /* not in RL11 */ + if (UNIBUS || (rl_dev.flags & DEV_RLV11)) /* not in RL11/RLV11 */ return SCPE_NXM; *data = rlbae & RLBAE_IMP; break; - } /* end switch */ -if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL read: reg%d=%o\n", (PA >> 1) & 07, *data); + default: + return (SCPE_NXM); + } /* end switch */ return SCPE_OK; } t_stat rl_wr (int32 data, int32 PA, int32 access) { -int32 curr, offs, newc, maxc; +int32 curr, offs, newc, maxc, tim; UNIT *uptr; -if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL write: reg%d=%o\n", (PA >> 1) & 07, data); - switch ((PA >> 1) & 07) { /* decode PA<2:1> */ case 0: /* RLCS */ rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); - if (rlcs & RLCS_ALLERR) - rlcs = rlcs | RLCS_ERR; uptr = rl_dev.units + GET_DRIVE (data); /* get new drive */ - if (sim_is_active (uptr)) - rlcs = rlcs & ~RLCS_DRDY; - else rlcs = rlcs | RLCS_DRDY; /* see if ready */ - if (access == WRITEB) data = (PA & 1)? (rlcs & 0377) | (data << 8): (rlcs & ~0377) | data; + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL wr: RLCS %06o new %06o\n", rlcs, data); rlcs = (rlcs & ~RLCS_RW) | (data & RLCS_RW); rlbae = (rlbae & ~RLCS_M_MEX) | ((rlcs >> RLCS_V_MEX) & RLCS_M_MEX); - if (data & CSR_DONE) { /* ready set? */ - if ((data & CSR_IE) == 0) - CLR_INT (RL); - else if ((rlcs & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (RL); - return SCPE_OK; - } +/* +Commands to the controller are only executed with the CRDY (DONE) +bit is cleared by software. If set, check for interrupts and return. +*/ + if (data & CSR_DONE) { /* ready set? */ + if ((data & CSR_IE) == 0) + CLR_INT (RL); + else if ((rlcs & (CSR_DONE + CSR_IE)) == CSR_DONE) + SET_INT (RL); + return SCPE_OK; + } CLR_INT (RL); /* clear interrupt */ - rlcs = rlcs & ~RLCS_ALLERR; /* clear errors */ + rlcs &= ~RLCS_ALLERR; /* clear errors */ switch (GET_FUNC (rlcs)) { /* case on RLCS<3:1> */ case RLCS_NOP: /* nop */ + if (!UNIBUS) /* RLV1x has MAINT command */ + rlv_maint (); rl_set_done (0); break; case RLCS_SEEK: /* seek */ - curr = GET_CYL (uptr->TRK); /* current cylinder */ - offs = GET_CYL (rlda); /* offset */ - if (rlda & RLDA_SK_DIR) { /* in or out? */ - newc = curr + offs; /* out */ + if ((uptr->flags & (UNIT_DIS|UNIT_OFFL)) || (!(uptr->flags & UNIT_ATT))) { + rl_set_done (RLCS_ERR | RLCS_INCMP); + uptr->STAT |= RLDS_STO; + break; + } + curr = GET_CYL (uptr->TRK); /* current cylinder */ + offs = GET_CYL (rlda); /* offset */ + if (rlda & RLDA_SK_DIR) { /* in or out? */ + newc = curr + offs; /* out */ maxc = (uptr->flags & UNIT_RL02)? RL_NUMCY * 2: RL_NUMCY; if (newc >= maxc) newc = maxc - 1; - } - else { - newc = curr - offs; /* in */ + } else { + newc = curr - offs; /* in */ if (newc < 0) newc = 0; - } - uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ + } + /* enter velocity mode? only if a different cylinder */ + if (newc != curr) + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_SEEK; /* move the positioner */ +/* TBD: if a head switch, sector should be RL_NUMSC/2? */ + uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ ((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0); - sim_activate (uptr, rl_swait * abs (newc - curr)); +/* +Real timing: +min 6.5ms, max 15ms for head switch, +max 17ms for 1 track seek w/head switch +55ms avg seek +100ms max seek +*/ + tim = abs (newc - curr); + if (tim == 0) + tim++; + tim *= rl_swait; + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL SEEK: drv %d, dist %d, head sw %d, tim %d\n", + (int32) (uptr - rl_dev.units), + abs (newc - curr), (rlda & RLDA_SK_HD), tim); + uptr->FNC = RLCS_SEEK; + sim_activate (uptr, tim); /* must be > 0 */ + rl_set_done (0); /* ctrlr is ready */ break; - default: /* data transfer */ + case RLCS_GSTA: + if (!(rlda & RLDA_GS)) { /* GS bit must be set */ + rl_set_done (RLCS_ERR | RLCS_INCMP); /* OPI; request error */ + return (SCPE_OK); + } + if (rlda & RLDA_GS_CLR) /* reset errors? */ + uptr->STAT &= ~RLDS_ERR; + /* develop drive state */ + rlmp = uptr->STAT | (uptr->TRK & RLDS_HD); + if (uptr->flags & UNIT_RL02) + rlmp |= RLDS_RL02; + if (uptr->flags & UNIT_WPRT) + rlmp |= RLDS_WLK; + if (uptr->flags & (UNIT_DIS | UNIT_OFFL)) { + rlmp |= RLDS_DSE; + rl_set_done (RLCS_DRE | RLCS_INCMP); + } + rlmp2 = rlmp1 = rlmp; + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL GSTA: rlds=%06o drv=%ld\n", + rlmp, uptr - rl_dev.units); + rl_set_done (0); /* done */ + break; + default: /* data transfer */ + if ((uptr->flags & (UNIT_DIS|UNIT_OFFL)) || (!(uptr->flags & UNIT_ATT))) { + rl_set_done (RLCS_INCMP); + break; + } +/* +EK-0RL11-TD-001, p2-3: "If the CPU software initiates another +operation on a drive that is busy seeking, the controller will +suspend the operation until the seek is completed." + +Check for the condition where there is an outstanding operation but +the program is requesting another operation without waiting for +drive ready. If so, remove the previous queue entry, complete the +operation now, and queue the next operation. +*/ + if (sim_is_active (uptr)) { + sim_cancel (uptr); + rl_svc (uptr); + } + uptr->FNC = GET_FUNC (rlcs); sim_activate (uptr, rl_swait); /* activate unit */ break; } /* end switch func */ break; /* end case RLCS */ - +/* +Contrary to what the RL01/RL02 User Guide (EK-RL012-UG-006, p.4-5) +says, bit 0 can be written and read (as 1) on an RLV12 (verified +2011-01-05). Not sure about the RLV11. +*/ case 1: /* RLBA */ if (access == WRITEB) data = (PA & 1)? (rlba & 0377) | (data << 8): (rlba & ~0377) | data; - rlba = data & RLBA_IMP; + rlba = data & (UNIBUS ? 0177776 : 0177777); + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL wr: RLBA %06o\n", rlba); break; case 2: /* RLDA */ if (access == WRITEB) data = (PA & 1)? (rlda & 0377) | (data << 8): (rlda & ~0377) | data; rlda = data; + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL wr: RLDA %06o\n", rlda); break; case 3: /* RLMP */ if (access == WRITEB) data = (PA & 1)? (rlmp & 0377) | (data << 8): (rlmp & ~0377) | data; rlmp = rlmp1 = rlmp2 = data; + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL wr: RLMP %06o\n", rlmp); break; case 4: /* RLBAE */ - if (UNIBUS) /* not in RL11 */ + if (UNIBUS || (rl_dev.flags & DEV_RLV11)) /* not in RL11/RLV11 */ return SCPE_NXM; if (PA & 1) return SCPE_OK; rlbae = data & RLBAE_IMP; rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL wr: RLBAE %06o\n", rlbae); break; + default: + return (SCPE_NXM); } /* end switch */ return SCPE_OK; } +/* CRC16 as implemented by the DEC 9401 chip */ +static uint32 calcCRC (const int wc, const uint16 *data) +{ + uint32 crc, j, d; + int32 i; + + crc = 0; + for (i = 0; i < wc; i++) { + d = *data++; + /* cribbed from KG11-A */ + for (j = 0; j < 16; j++) { + crc = (crc & ~01) | ((crc & 01) ^ (d & 01)); + crc = (crc & 01) ? (crc >> 1) ^ 0120001 : crc >> 1; + d >>= 1; + } + } + return (crc); +} + +/* +Perform the maintenance function of the RLV1x; this is fully described +on pages 4-14 and 4-15 of EK-RL012-UG-006. Note that the description +of this in EK-RLV12-UG-002 (p.5-3) contains a typo, the constant +for -511 is incorrect. +*/ +static void rlv_maint (void) +{ + int32 i; + uint32 ma; + uint16 w; + + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL maint: RLDA %06o\n", rlda); + /* 1: check internal logic */ + rlda = (rlda & ~0377) | ((rlda + 1) & 0377); + + /* 2: check internal logic */ + rlda = (rlda & ~0377) | ((rlda + 1) & 0377); + + /* 3: check DMA transfers */ + ma = (rlbae << 16) | rlba; /* get mem addr */ + /* xfer 256 words to FIFO */ + if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL maint: RLMP %06o\n", rlmp); + if (rlmp != 0177001) { /* must be exactly -511 */ + rlcs |= RLCS_ERR | RLCS_HDE; /* HNF error */ + return; + } + for (i = 0; i < 256; i++) { + if (Map_ReadW (ma, 2, &rlxb[i])) { /* mem wd */ + rlcs |= RLCS_ERR | RLCS_NXM; /* nxm */ + break; + } + ma += 2; + rlmp++; + } + /* xfer 255 words from FIFO */ + for (i = 0; i < 255; i++) { + if (Map_WriteW (ma, 2, &rlxb[i])) { /* store buffer */ + rlcs |= RLCS_ERR | RLCS_NXM; /* nxm */ + break; + } + ma += 2; + rlmp++; + } + rlda = (rlda & ~0377) | ((rlda + 1) & 0377); + rlbae = (ma >> 16) & RLBAE_IMP; /* upper 6b */ + rlba = ma & RLBA_IMP; /* lower 16b */ + + /* 4: check the CRC of (DAR + 3) */ + w = rlda; + rlxb[0] = calcCRC (1, &w); /* calculate CRC */ + rlda = (rlda & ~0377) | ((rlda + 1) & 0377); + + /* 5: check the CRC of (DAR + 4) */ + w = rlda; + rlxb[1] = calcCRC (1, &w); /* calculate CRC */ + rlda = (rlda & ~0377) | ((rlda + 1) & 0377); + + /* 6: check the CRC of (CRC of DAR + 4) */ + w = rlxb[1]; + rlxb[1] = calcCRC (1, &w); /* calculate CRC */ + rlmp = rlxb[0]; + rlmp1 = rlxb[1]; + rlda = (rlda & ~0377) | ((rlda + 1) & 0377); +} + /* Service unit timeout If seek in progress, complete seek command @@ -446,78 +702,178 @@ return SCPE_OK; t_stat rl_svc (UNIT *uptr) { int32 err, wc, maxwc, t; -int32 i, func, da, awc; +int32 i, da, awc; uint32 ma; uint16 comp; +static const char * const funcname[] = { + "NOP", "WCK", "GSTA", "SEEK", + "RHDR", "WT", "RD", "RNOHDR", "SPECIAL", +}; -func = GET_FUNC (rlcs); /* get function */ -if (func == RLCS_GSTA) { /* get status */ - if (rlda & RLDA_GS_CLR) - uptr->STAT = uptr->STAT & ~RLDS_ERR; - rlmp = uptr->STAT | (uptr->TRK & RLDS_HD) | - ((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT); - if (uptr->flags & UNIT_RL02) - rlmp = rlmp | RLDS_RL02; - if (uptr->flags & UNIT_WPRT) - rlmp = rlmp | RLDS_WLK; - rlmp2 = rlmp1 = rlmp; - rl_set_done (0); /* done */ - return SCPE_OK; +if (DEBUG_PRS (rl_dev)) { + if (uptr->FNC == RLCS_SPECIAL) + fprintf (sim_deb, ">>RL svc: func=SPECIAL(%s) drv=%d\n", + state[uptr->STAT & RLDS_M_STATE], (int32) (uptr - rl_dev.units)); + else + fprintf (sim_deb, ">>RL svc: func=%s drv=%d rlda=%06o\n", + funcname[uptr->FNC], (int32) (uptr - rl_dev.units), rlda); +} + +/* really shouldn't happen... */ +if ((uptr->FNC == RLCS_GSTA) || (uptr->FNC == RLCS_NOP)) { + rl_set_done (0); + return (SCPE_OK); } +/* +This situation occurs when the drive (not controller) state needs +to transition from one state to another. The state bits indicate +the state the drive is currently in. +*/ + +if (uptr->FNC == RLCS_SPECIAL) { + switch (uptr->STAT & RLDS_M_STATE) { +/* +The LOAD state is a little different. We can stay in LOAD until +the user hits the RUN (LOAD) button, at which time we should come +here to transition to the next state and begin the startup process. +*/ + case RLDS_LOAD: + /* load pressed, spinning up */ + if (!(uptr->STAT & RLDS_CVO)) { + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_SPIN; + /* actual time is 45-50 seconds from press to Lock */ + sim_activate (uptr, 200 * rl_swait); + uptr->STAT &= ~RLDS_HDO; + uptr->STAT |= RLDS_BHO; + } + break; +/* +Original RL01 drives would transition to the Brush Cycle, but this +was removed in a later ECO. +*/ + case RLDS_SPIN: /* spun up, load brushes or heads */ + if (uptr->flags & UNIT_BRUSH) { + uptr->STAT &= ~RLDS_BHO; + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_BRUSH; + } else { + uptr->STAT |= RLDS_BHO; + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_HLOAD; + } + sim_activate (uptr, 200 * rl_swait); + break; + case RLDS_BRUSH: + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_HLOAD; + uptr->STAT |= RLDS_BHO; + sim_activate (uptr, 200 * rl_swait); + break; + case RLDS_HLOAD: /* heads loaded, seek to home */ + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_SEEK; + sim_activate (uptr, 200 * rl_swait); + uptr->STAT |= RLDS_BHO | RLDS_HDO; + uptr->TRK = 0; + break; + case RLDS_SEEK: /* home found, lock on */ + /* enter postion mode */ + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_LOCK; + /* sim_activate (uptr, rl_swait); */ + break; + case RLDS_LOCK: /* tracking, nothing to do */ + /* illuminate ready lamp */ + break; +/* +Initiated by depressing the Run (LOAD) switch. +*/ + case RLDS_UNL: /* unload pressed, heads unloaded, spin down */ + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_DOWN; + uptr->STAT &= ~RLDS_HDO; /* retract heads */ + /* actual time is ~30 seconds */ + sim_activate (uptr, 200 * rl_swait); + break; + case RLDS_DOWN: /* OK to open cover */ + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_LOAD; + uptr->STAT |= RLDS_BHO | RLDS_VCK; + break; + default: + ; /* can't happen */ + } + return (SCPE_OK); +} + if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ - rlcs = rlcs & ~RLCS_DRDY; /* clear drive ready */ - uptr->STAT = uptr->STAT | RLDS_SPE; /* spin error */ + uptr->STAT |= RLDS_SPE; /* spin error */ rl_set_done (RLCS_ERR | RLCS_INCMP); /* flag error */ return IORETURN (rl_stopioe, SCPE_UNATT); } -if ((func == RLCS_WRITE) && (uptr->flags & UNIT_WPRT)) { - uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */ +if ((uptr->FNC == RLCS_WRITE) && (uptr->flags & UNIT_WPRT)) { + uptr->STAT |= RLDS_WGE; /* write and locked */ rl_set_done (RLCS_ERR | RLCS_DRE); return SCPE_OK; } -if (func == RLCS_SEEK) { /* seek? */ - rl_set_done (0); /* done */ - return SCPE_OK; +if (uptr->FNC == RLCS_SEEK) { /* seek? */ + /* enter position mode */ + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_LOCK; /* heads locked on cyl */ + return (SCPE_OK); } -if (func == RLCS_RHDR) { /* read header? */ - rlmp = (uptr->TRK & RLDA_TRACK) | GET_SECT (rlda); - rlmp1 = rlmp2 = 0; +if (uptr->FNC == RLCS_RHDR) { /* read header? */ + uint16 hdr[2]; + hdr[0] = rlmp = uptr->TRK & 0177777; + hdr[1] = rlmp1 = 0; + rlmp2 = calcCRC (2, &hdr[0]); /* calculate header CRC */ rl_set_done (0); /* done */ - return SCPE_OK; + /* simulate sequential rotation about the current track */ + uptr->TRK = (uptr->TRK & ~RLDA_M_SECT) | + ((uptr->TRK + 1) & RLDA_M_SECT); + if (GET_SECT (uptr->TRK) >= RL_NUMSC) /* end of track? */ + uptr->TRK &= ~RLDA_M_SECT; /* wrap to 0 */ + return (SCPE_OK); } -if (((func != RLCS_RNOHDR) && ((uptr->TRK & RLDA_CYL) != (rlda & RLDA_CYL))) - || (GET_SECT (rlda) >= RL_NUMSC)) { /* bad cyl or sector? */ - rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ - return SCPE_OK; - } +if (uptr->FNC == RLCS_RNOHDR) { + if (GET_SECT (uptr->TRK) >= RL_NUMSC) { + rl_set_done (RLCS_ERR | RLCS_HDE); /* wrong cylinder? */ + return (SCPE_OK); + } + da = GET_DA (uptr->TRK) * RL_NUMWD; /* get disk addr */ + maxwc = (RL_NUMSC - GET_SECT (uptr->TRK)) * RL_NUMWD; /* max transfer */ +} else { + /* bad cyl or sector? */ + if (((uptr->TRK & RLDA_CYL) != (rlda & RLDA_CYL)) || (GET_SECT (rlda) >= RL_NUMSC)) { + rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ + return (SCPE_OK); + } + da = GET_DA (rlda) * RL_NUMWD; /* get disk addr */ + maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD; /* max transfer */ +} ma = (rlbae << 16) | rlba; /* get mem addr */ -da = GET_DA (rlda) * RL_NUMWD; /* get disk addr */ wc = 0200000 - rlmp; /* get true wc */ -maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD; /* max transfer */ if (wc > maxwc) /* track overrun? */ wc = maxwc; err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); -if ((func >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */ - i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); - err = ferror (uptr->fileref); - for ( ; i < wc; i++) /* fill buffer */ - rlxb[i] = 0; - if (t = Map_WriteW (ma, wc << 1, rlxb)) { /* store buffer */ - rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ - wc = wc - t; /* adjust wc */ - } - } /* end read */ +if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL svc: cyl %d, sect %d, wc %d, maxwc %d, err %d\n", + GET_CYL (rlda), GET_SECT (rlda), wc, maxwc, err); -if ((func == RLCS_WRITE) && (err == 0)) { /* write? */ - if (t = Map_ReadW (ma, wc << 1, rlxb)) { /* fetch buffer */ + if ((uptr->FNC >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */ + i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); + err = ferror (uptr->fileref); + for ( ; i < wc; i++) /* fill buffer */ + rlxb[i] = 0; + if ((t = Map_WriteW (ma, wc << 1, rlxb))) { /* store buffer */ + rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ + wc = wc - t; /* adjust wc */ + } + } /* end read */ + +else +if ((uptr->FNC == RLCS_WRITE) && (err == 0)) { /* write? */ + if ((t = Map_ReadW (ma, wc << 1, rlxb))) { /* fetch buffer */ rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ wc = wc - t; /* adj xfer lnt */ } @@ -530,7 +886,8 @@ if ((func == RLCS_WRITE) && (err == 0)) { /* write? */ } } /* end write */ -if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */ +else +if ((uptr->FNC == RLCS_WCHK) && (err == 0)) { /* write check? */ i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); err = ferror (uptr->fileref); for ( ; i < wc; i++) /* fill buffer */ @@ -546,14 +903,30 @@ if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */ } /* end for */ } /* end wcheck */ +/* Complete Write Check, Write, Read, Read no header */ rlmp = (rlmp + wc) & 0177777; /* final word count */ if (rlmp != 0) /* completed? */ - rlcs = rlcs | RLCS_ERR | RLCS_INCMP; -ma = ma + (wc << 1); /* final byte addr */ + rlcs |= RLCS_ERR | RLCS_INCMP | RLCS_HDE; + +ma += (wc << 1); /* final byte addr */ rlbae = (ma >> 16) & RLBAE_IMP; /* upper 6b */ rlba = ma & RLBA_IMP; /* lower 16b */ rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); -rlda = rlda + ((wc + (RL_NUMWD - 1)) / RL_NUMWD); + +/* +If we ran off the end of the track, return 40 in rlda, but keep +track over a legitimate sector (0)? +*/ +rlda += ((wc + (RL_NUMWD - 1)) / RL_NUMWD); +/* update head pos */ +if (uptr->FNC == RLCS_RNOHDR) + uptr->TRK = (uptr->TRK & ~RLDA_M_SECT) | + ((uptr->TRK + ((wc + (RL_NUMWD - 1)) / RL_NUMWD)) & RLDA_M_SECT); +else + uptr->TRK = rlda; +if (GET_SECT (uptr->TRK) >= RL_NUMSC) + uptr->TRK &= ~RLDA_M_SECT; /* wrap to 0 */ + rl_set_done (0); if (err != 0) { /* error? */ @@ -568,11 +941,10 @@ return SCPE_OK; void rl_set_done (int32 status) { -rlcs = rlcs | status | CSR_DONE; /* set done */ +rlcs |= status | CSR_DONE; /* set done */ if (rlcs & CSR_IE) SET_INT (RL); else CLR_INT (RL); -return; } /* Device reset @@ -591,7 +963,7 @@ CLR_INT (RL); for (i = 0; i < RL_NUMDR; i++) { uptr = rl_dev.units + i; sim_cancel (uptr); - uptr->STAT = 0; + uptr->STAT &= ~RLDS_ERR; } if (rlxb == NULL) rlxb = (uint16 *) calloc (RL_MAXFR, sizeof (uint16)); @@ -611,8 +983,12 @@ uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE; r = attach_unit (uptr, cptr); /* attach unit */ if (r != SCPE_OK) /* error? */ return r; +/* +For compatibility with existing SIMH behavior, set the drive state +as if the load procedure had already executed. +*/ uptr->TRK = 0; /* cylinder 0 */ -uptr->STAT = RLDS_VCK; /* new volume */ +uptr->STAT = RLDS_HDO | RLDS_BHO | RLDS_VCK | RLDS_LOCK; /* new volume */ if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ if (uptr->flags & UNIT_RO) /* if ro, done */ return SCPE_OK; @@ -631,6 +1007,16 @@ else { return SCPE_OK; } +t_stat rl_detach (UNIT *uptr) +{ +t_stat stat; + +sim_cancel (uptr); +stat = detach_unit (uptr); +uptr->STAT = RLDS_BHO | RLDS_LOAD; +return (stat); +} + /* Set size routine */ t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) @@ -648,6 +1034,105 @@ t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc) return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); } +t_stat rl_set_cover (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + /* allowed only if in LOAD state */ + if ((uptr->STAT & RLDS_M_STATE) != RLDS_LOAD) + return (SCPE_NOFNC); + uptr->STAT = (uptr->STAT & ~RLDS_CVO) | val; + return (SCPE_OK); +} + +t_stat rl_show_cover (FILE *st, UNIT *uptr, int val, void *desc) +{ + fprintf (st, "cover %s", (uptr->STAT & RLDS_CVO) ? "open" : "closed"); + return (SCPE_OK); +} + +/* simulate the LOAD button on the drive */ +t_stat rl_set_load (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + if (val == 0) { /* LOAD */ + if (uptr->STAT & RLDS_CVO) /* cover open? */ + return (SCPE_NOFNC); + /* spin error if no cartridge loaded */ + if (!(uptr->flags & UNIT_ATT)) { + uptr->STAT |= RLDS_SPE; + return (SCPE_NOFNC); + } + /* state load? */ + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_LOAD; + } else { /* UNLOAD */ + if ((uptr->STAT & RLDS_M_STATE) != RLDS_LOCK) + return (SCPE_OK); + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_UNL; + } + uptr->FNC = RLCS_SPECIAL; + sim_activate (uptr, 10 * rl_swait); + return (SCPE_OK); +} + +t_stat rl_show_load (FILE *st, UNIT *uptr, int val, void *desc) +{ + fprintf (st, "load %s", + ((uptr->STAT & RLDS_M_STATE) != RLDS_LOAD) ? "set" : "reset"); + return (SCPE_OK); +} + +t_stat rl_show_dstate (FILE *st, UNIT *uptr, int val, void *desc) +{ + int32 cnt; + + fprintf (st, "drive state: %s\n", state[(uptr->STAT & RLDS_M_STATE)]); + fprintf (st, "brushes: %s, heads: %s, cover: %s\n", + (uptr->STAT & RLDS_BHO) ? "home" : "out", + (uptr->STAT & RLDS_HDO) ? "out" : "in", + (uptr->STAT & RLDS_CVO) ? "open" : "closed"); + fprintf (st, "vck:%c, wge:%c, spe:%c\n", + (uptr->STAT & RLDS_VCK) ? '1' : '0', + (uptr->STAT & RLDS_WGE) ? '1' : '0', + (uptr->STAT & RLDS_SPE) ? '1' : '0'); + if (uptr->flags & UNIT_ATT) { + if ((cnt = sim_is_active (uptr)) != 0) + fprintf (st, "FNC: %d, %d\n", uptr->FNC, cnt); + else + fputs ("FNC: none\n", st); + fprintf (st, "TRK: track=%d, cyl=%d, hd=%c, sect=%d\n", + GET_TRACK (uptr->TRK), GET_CYL (uptr->TRK), + (uptr->TRK & RLDA_HD1) ? '1' : '0', + GET_SECT (uptr->TRK)); + } + return (SCPE_OK); +} + +#if defined (VM_PDP11) + +/* Handle SET RL RLV12|RLV11 */ +t_stat rl_set_ctrl (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + if (UNIBUS) + return (SCPE_NOFNC); + if ((val & DEV_RLV11) && (MEMSIZE > UNIMEMSIZE)) + return (SCPE_NOFNC); + rl_dev.flags = (rl_dev.flags & ~(DEV_RLV11|DEV_Q18)) | val; + return (SCPE_OK); +} + +#endif + +/* SHOW RL will display the controller type */ +t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int val, void *desc) +{ + char *s = "RLV12"; + + if (UNIBUS) + s = "RL11"; + else if (rl_dev.flags & DEV_RLV11) + s = "RLV11"; + fputs (s, st); + return (SCPE_OK); +} + /* Device bootstrap */ #if defined (VM_PDP11) @@ -709,7 +1194,7 @@ extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & RLCS_M_DRIVE; -M[BOOT_CSR >> 1] = rl_dib.ba & DMASK; +M[BOOT_CSR >> 1] = rl_dib.ba & 0177777; saved_PC = BOOT_ENTRY; return SCPE_OK; } @@ -722,4 +1207,3 @@ return SCPE_NOFNC; } #endif - diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index e0c54727..c7b8cc70 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -850,14 +850,14 @@ MTAB rq_mod[] = { #if defined (VM_PDP11) { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, 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, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, { 0 } }; diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index bba47ec4..67335d22 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -130,7 +130,7 @@ t_stat rx_wr (int32 data, int32 PA, int32 access); t_stat rx_svc (UNIT *uptr); t_stat rx_reset (DEVICE *dptr); t_stat rx_boot (int32 unitno, DEVICE *dptr); -void rx_done (int32 esr_flags, int32 new_ecode); +void rx_done (int esr_flags, int new_ecode); /* RX11 data structures @@ -179,12 +179,19 @@ REG rx_reg[] = { MTAB rx_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, +#if defined (VM_PDP11) { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", &set_addr_flt, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, +#else + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + NULL, &show_vec, NULL }, +#endif { 0 } }; diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index 5d69ae0f..7310cf80 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -161,7 +161,7 @@ t_stat ry_wr (int32 data, int32 PA, int32 access); t_stat ry_svc (UNIT *uptr); t_stat ry_reset (DEVICE *dptr); t_stat ry_boot (int32 unitno, DEVICE *dptr); -void ry_done (int32 esr_flags, int32 new_ecode); +void ry_done (int esr_flags, int new_ecode); t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ry_attach (UNIT *uptr, char *cptr); @@ -223,13 +223,18 @@ MTAB ry_mod[] = { { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, { (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &ry_set_size }, { (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &ry_set_size }, +#if defined (VM_PDP11) { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, -#if defined (VM_PDP11) { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", &set_addr_flt, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, +#else + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + NULL, &show_vec, NULL }, #endif { 0 } }; diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 2fbf5ed9..b993f349 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -27,6 +27,7 @@ 23-Jan-12 MP Added missing support for Logical EOT detection while positioning. + 17-Aug-11 RMS Added CAPACITY modifier 05-Mar-11 MP Added missing state for proper save/restore 01-Mar-11 MP - Migrated complex physical tape activities to sim_tape - adopted use of asynch I/O interfaces from sim_tape @@ -419,10 +420,10 @@ DIB tq_dib = { }; UNIT tq_unit[] = { - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, 0), INIT_CAP }, + { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) }, + { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) }, + { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) }, + { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) }, { UDATA (&tq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) }, { UDATA (&tq_quesvc, UNIT_IDLE|UNIT_DIS, 0) } }; @@ -499,9 +500,13 @@ MTAB tq_mod[] = { NULL, &tq_show_unitq, NULL }, { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, + { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", + &sim_tape_set_capac, &sim_tape_show_capac, NULL }, #if defined (VM_PDP11) { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL }, #else { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, NULL, &show_addr, NULL }, diff --git a/VAX/vax780_bug_history.txt b/VAX/vax780_bug_history.txt index a8f4aa32..ff6a7e31 100644 --- a/VAX/vax780_bug_history.txt +++ b/VAX/vax780_bug_history.txt @@ -56,6 +56,11 @@ Bugs Found And Fixed During Simulator Debug 53. MTPR SBR/PCBB/SCBB: 11/780 only checks that bits<1:0> == 0. 54. MTPR xLR: 11/780 excludes bits<31:24> from mbz test. 55. MTPR PxBR: 11/780 only checks bits<31,1:0> == 1,00. +56. EMODx: integer overflow case requiring left shift returns wrong result. +57. BPT, XFC: not clearing PSL before taking exception. +58. POLYx: add step require truncation (proved by AXE tests). + + diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index 71140c05..d35eb932 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -1,4 +1,4 @@ -/* vax_syslist.c: VAX device list +/* vax780_syslist.c: VAX 780 device list Copyright (c) 1998-2008, Robert M Supnik diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index af9f1c5c..e38f7efa 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -35,6 +35,8 @@ approach taken in the other BSD derived OSes. Determining a reasonable idle detection pattern does not seem possible for these versions. + 13-Sep-11 RMS Fixed XFC, BPT to clear PSL before exception + (found by Camiel Vanderhoeven) 23-Mar-11 RMS Revised for new idle design (from Mark Pizzolato) 05-Jan-11 MP Added Asynch I/O support 24-Apr-10 RMS Added OLDVMS idle timer option @@ -1585,7 +1587,7 @@ for ( ;; ) { case TSTL: CC_IIZZ_L (op0); /* set cc's */ - if ((cc == CC_Z) && + if ((cc == CC_Z) && /* zero result and */ ((((cpu_idle_mask & VAX_IDLE_ULTOLD) && /* running Old Ultrix or friends? */ (PSL_GETIPL (PSL) == 0x1)) || /* at IPL 1? */ ((cpu_idle_mask & VAX_IDLE_QUAD) && /* running Quasijarus or friends? */ @@ -2553,12 +2555,14 @@ for ( ;; ) { case BPT: SETPC (fault_PC); + PSL = PSL & ~PSL_TP; /* clear */ cc = intexc (SCB_BPT, cc, 0, IE_EXC); GET_CUR; break; case XFC: SETPC (fault_PC); + PSL = PSL & ~PSL_TP; /* clear */ cc = intexc (SCB_XFC, cc, 0, IE_EXC); GET_CUR; break; diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index 8eeac8d9..ccd0ae34 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -1,6 +1,6 @@ /* vax_cpu1.c: VAX complex instructions - Copyright (c) 1998-2011, Robert M Supnik + Copyright (c) 1998-2012, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 15-Mar-12 RMS Fixed potential integer overflow in LDPCTX (from Mark Pizzolato) 25-Nov-11 RMS Added VEC_QBUS test in interrupt handler 23-Mar-11 RMS Revised idle design (from Mark Pizzolato) 28-May-08 RMS Inlined physical memory routines @@ -1137,7 +1138,7 @@ else { SP = KSP; /* new stack */ } } -if (ei == IE_INT) { /* if int, new IPL */ +if (ei > 0) { /* if int, new IPL */ int32 newipl; if (VEC_QBUS && ((vec & VEC_Q) != 0)) /* Qbus and Qbus vector? */ newipl = PSL_IPL17; /* force IPL 17 */ @@ -1274,7 +1275,7 @@ return newpsl & CC_MASK; /* set new cc */ void op_ldpctx (int32 acc) { -int32 newpc, newpsl, pcbpa, t; +uint32 newpc, newpsl, pcbpa, t; if (PSL & PSL_CUR) /* must be kernel */ RSVD_INST_FAULT; diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index 964736c3..608f8662 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-2008, Robert M Supnik + Copyright (c) 1998-2011, Robert 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 Stephen Shirron, Antonio Carlini, and Kevin Peterson in providing specifications for the Qbus VAX's + 05-Nov-11 RMS Added PSL_IPL17 definition 09-May-06 RMS Added system PTE ACV error code 03-May-06 RMS Added EDITPC get/put cc's macros 03-Nov-05 RMS Added 780 stop codes diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index 9a88bb57..222e52f0 100644 --- a/VAX/vax_fpa.c +++ b/VAX/vax_fpa.c @@ -1,6 +1,6 @@ /* vax_fpa.c - VAX f_, d_, g_floating instructions - Copyright (c) 1998-2008, Robert M Supnik + Copyright (c) 1998-2011, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 15-Sep-11 RMS Fixed integer overflow bug in EMODx + Fixed POLYx normalizing before add mask bug + (both from Camiel Vanderhoeven) 28-May-08 RMS Inlined physical memory routines 16-May-06 RMS Fixed bug in 32b floating multiply routine Fixed bug in 64b extended modulus routine @@ -103,7 +106,7 @@ void unpackg (int32 hi, int32 lo, UFP *a); void norm (UFP *a); int32 rpackfd (UFP *a, int32 *rh); int32 rpackg (UFP *a, int32 *rh); -void vax_fadd (UFP *a, UFP *b); +void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo); void vax_fmul (UFP *a, UFP *b, t_bool qd, int32 bias, uint32 mhi, uint32 mlo); void vax_fdiv (UFP *b, UFP *a, int32 prec, int32 bias); void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg); @@ -347,10 +350,11 @@ return rpackg (&a, flo); /* return frac */ /* Unpacked floating point routines */ -void vax_fadd (UFP *a, UFP *b) +void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo) { int32 ediff; UFP t; +t_uint64 mask = (((t_uint64) mhi) << 32) | ((t_uint64) mlo); if (a->frac == 0) { /* s1 = 0? */ *a = *b; @@ -374,6 +378,7 @@ if (a->sign ^ b->sign) { /* eff sub? */ a->frac = a->frac + b->frac; /* add frac */ } else a->frac = a->frac - b->frac; /* sub frac */ + a->frac = a->frac & ~mask; /* mask before norm */ norm (a); /* normalize */ } else { @@ -386,6 +391,7 @@ else { a->frac = UF_NM | (a->frac >> 1); /* shift in carry */ a->exp = a->exp + 1; /* skip norm */ } + a->frac = a->frac & ~mask; /* mask */ } return; } @@ -454,7 +460,11 @@ else if (a->exp <= (bias + 64)) { /* in range [1,64]? */ a->exp = bias; } else { - *intgr = 0; /* out of range */ + if (a->exp < (bias + 96)) /* need left shift? */ + *intgr = (int32) (a->frac << (a->exp - bias - 64)); + else *intgr = 0; /* out of range */ + if (a->sign) + *intgr = -*intgr; a->frac = a->sign = a->exp = 0; /* result 0 */ *flg = CC_V; /* overflow */ } @@ -639,7 +649,7 @@ void unpackg (uint32 hi, uint32 lo, UFP *a); void norm (UFP *a); int32 rpackfd (UFP *a, int32 *rh); int32 rpackg (UFP *a, int32 *rh); -void vax_fadd (UFP *a, UFP *b); +void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo); void vax_fmul (UFP *a, UFP *b, t_bool qd, int32 bias, uint32 mhi, uint32 mlo); void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg); void vax_fdiv (UFP *b, UFP *a, int32 prec, int32 bias); @@ -921,6 +931,8 @@ if (a->sign ^ b->sign) { /* eff sub? */ dp_add (&a->frac, &b->frac); /* "add" frac */ } else dp_sub (&a->frac, &b->frac); /* a >= b */ + a->frac.hi = a->frac.hi & ~mhi; /* mask before norm */ + a->frac.lo = a->frac.lo & ~mlo; norm (a); /* normalize */ } else { @@ -932,6 +944,8 @@ else { a->frac.hi = a->frac.hi | UF_NM_H; /* add norm bit */ a->exp = a->exp + 1; /* skip norm */ } + a->frac.hi = a->frac.hi & ~mhi; /* mask */ + a->frac.lo = a->frac.lo & ~mlo; } return; } @@ -1004,7 +1018,14 @@ else if (a->exp <= (bias + 64)) { /* in range [1,64]? */ a->exp = bias; } else { - *intgr = 0; /* out of range */ + if (a->exp < (bias + 96)) { /* need left shift? */ + ifr = a->frac; + dp_lsh (&ifr, a->exp - bias - 64); + *intgr = ifr.lo; + } + else *intgr = 0; /* out of range */ + if (a->sign) + *intgr = -*intgr; a->frac.hi = a->frac.lo = a->sign = a->exp = 0; /* result 0 */ *flg = CC_V; /* overflow */ } @@ -1379,7 +1400,7 @@ unpackf (opnd[0], &a); /* F format */ unpackf (opnd[1], &b); if (sub) /* sub? -s1 */ a.sign = a.sign ^ FPSIGN; -vax_fadd (&a, &b); /* add fractions */ +vax_fadd (&a, &b, 0, 0); /* add fractions */ return rpackfd (&a, NULL); } @@ -1391,7 +1412,7 @@ unpackd (opnd[0], opnd[1], &a); unpackd (opnd[2], opnd[3], &b); if (sub) /* sub? -s1 */ a.sign = a.sign ^ FPSIGN; -vax_fadd (&a, &b); /* add fractions */ +vax_fadd (&a, &b, 0, 0); /* add fractions */ return rpackfd (&a, rh); } @@ -1403,7 +1424,7 @@ unpackg (opnd[0], opnd[1], &a); unpackg (opnd[2], opnd[3], &b); if (sub) /* sub? -s1 */ a.sign = a.sign ^ FPSIGN; -vax_fadd (&a, &b); /* add fractions */ +vax_fadd (&a, &b, 0, 0); /* add fractions */ return rpackg (&a, rh); /* round and pack */ } @@ -1499,7 +1520,7 @@ for (i = 0; i < deg; i++) { /* loop */ wd = Read (ptr, L_LONG, RD); /* get Cnext */ ptr = ptr + 4; unpackf (wd, &c); /* unpack Cnext */ - vax_fadd (&r, &c); /* r = r + Cnext */ + vax_fadd (&r, &c, 1, LMASK); /* r = r + Cnext */ res = rpackfd (&r, NULL); /* round and pack */ } R[0] = res; @@ -1530,7 +1551,7 @@ for (i = 0; i < deg; i++) { /* loop */ wd1 = Read (ptr + 4, L_LONG, RD); ptr = ptr + 8; unpackd (wd, wd1, &c); /* unpack Cnext */ - vax_fadd (&r, &c); /* r = r + Cnext */ + vax_fadd (&r, &c, 0, 1); /* r = r + Cnext */ res = rpackfd (&r, &resh); /* round and pack */ } R[0] = res; @@ -1564,7 +1585,7 @@ for (i = 0; i < deg; i++) { /* loop */ wd1 = Read (ptr + 4, L_LONG, RD); ptr = ptr + 8; unpackg (wd, wd1, &c); /* unpack Cnext */ - vax_fadd (&r, &c); /* r = r + Cnext */ + vax_fadd (&r, &c, 0, 1); /* r = r + Cnext */ res = rpackg (&r, &resh); /* round and pack */ } R[0] = res; diff --git a/VAX/vax_octa.c b/VAX/vax_octa.c index 5b0448da..b4e0fd3e 100644 --- a/VAX/vax_octa.c +++ b/VAX/vax_octa.c @@ -1,6 +1,6 @@ /* vax_octa.c - VAX octaword and h_floating instructions - Copyright (c) 2004-2008, Robert M Supnik + Copyright (c) 2004-2011, Robert 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 @@ This module simulates the VAX h_floating instruction set. + 15-Sep-11 RMS Fixed integer overflow bug in EMODH + Fixed POLYH normalizing before add mask bug + (both from Camiel Vanderhoeven) 28-May-08 RMS Inlined physical memory routines 10-May-06 RMS Fixed bug in reported VA on faulting cross-page write 03-May-06 RMS Fixed MNEGH to test negated sign, clear C @@ -93,7 +96,7 @@ void h_write_w (int32 spec, int32 va, int32 val, int32 acc); void h_write_l (int32 spec, int32 va, int32 val, int32 acc); void h_write_q (int32 spec, int32 va, int32 vl, int32 vh, int32 acc); void h_write_o (int32 spec, int32 va, int32 *val, int32 acc); -void vax_hadd (UFPH *a, UFPH *b); +void vax_hadd (UFPH *a, UFPH *b, uint32 mlo); void vax_hmul (UFPH *a, UFPH *b, uint32 mlo); void vax_hmod (UFPH *a, int32 *intgr, int32 *flg); void vax_hdiv (UFPH *a, UFPH *b); @@ -581,7 +584,7 @@ h_unpackh (&opnd[0], &a); /* unpack s1, s2 */ h_unpackh (&opnd[4], &b); if (sub) /* sub? -s1 */ a.sign = a.sign ^ FPSIGN; -vax_hadd (&a, &b); /* do add */ +vax_hadd (&a, &b, 0); /* do add */ return h_rpackh (&a, hflt); /* round and pack */ } @@ -643,7 +646,7 @@ for (i = 0; i < deg; i++) { /* loop */ wd[3] = Read (ptr + 12, L_LONG, RD); ptr = ptr + 16; h_unpackh (wd, &c); /* unpack Cnext */ - vax_hadd (&r, &c); /* r = r + Cnext */ + vax_hadd (&r, &c, 1); /* r = r + Cnext */ h_rpackh (&r, res); /* round and pack */ } R[0] = res[0]; /* result */ @@ -678,7 +681,7 @@ return h_rpackh (&a, hflt); /* round and pack frac * /* Floating add */ -void vax_hadd (UFPH *a, UFPH *b) +void vax_hadd (UFPH *a, UFPH *b, uint32 mlo) { int32 ediff; UFPH t; @@ -703,6 +706,7 @@ if (a->sign ^ b->sign) { /* eff sub? */ if (ediff) /* denormalize */ qp_rsh_s (&b->frac, ediff, 1); qp_add (&a->frac, &b->frac); /* "add" frac */ + a->frac.f0 = a->frac.f0 & ~mlo; /* mask before norm */ h_normh (a); /* normalize */ } else { @@ -713,6 +717,7 @@ else { a->frac.f3 = a->frac.f3 | UH_NM_H; /* add norm bit */ a->exp = a->exp + 1; /* incr exp */ } + a->frac.f0 = a->frac.f0 & ~mlo; /* mask */ } return; } @@ -778,7 +783,14 @@ else if (a->exp <= (H_BIAS + 128)) { /* in range? */ a->exp = H_BIAS; } else { - *intgr = 0; /* out of range */ + if (a->exp < (H_BIAS + 160)) { /* left shift needed? */ + ifr = a->frac; + qp_lsh (&ifr, a->exp - H_BIAS - 128); + *intgr = ifr.f0; + } + else *intgr = 0; /* out of range */ + if (a->sign) + *intgr = -*intgr; a->frac.f0 = a->frac.f1 = 0; /* result 0 */ a->frac.f2 = a->frac.f3 = 0; a->sign = a->exp = 0; diff --git a/VAX/vax_syslist.c b/VAX/vax_syslist.c index f2e4eefe..aba7119c 100644 --- a/VAX/vax_syslist.c +++ b/VAX/vax_syslist.c @@ -1,4 +1,4 @@ -/* vax_sys.c: VAX simulator interface +/* vax_syslist.c: VAX device list Copyright (c) 1998-2008, Robert M Supnik diff --git a/Visual Studio Projects/AltairZ80.vcproj b/Visual Studio Projects/AltairZ80.vcproj index b910589a..9125307d 100644 --- a/Visual Studio Projects/AltairZ80.vcproj +++ b/Visual Studio Projects/AltairZ80.vcproj @@ -237,10 +237,6 @@ RelativePath="..\AltairZ80\i86_prim_ops.c" > - - diff --git a/alpha/alpha_500au_syslist.c b/alpha/alpha_500au_syslist.c new file mode 100644 index 00000000..5acdc997 --- /dev/null +++ b/alpha/alpha_500au_syslist.c @@ -0,0 +1,49 @@ +/* alpha_500au_syslist.c: Alpha device list for 500au + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "alpha_defs.h" + +extern DEVICE cpu_dev; +extern DEVICE tlb_dev; +extern DEVICE ev5pal_dev; +extern DEVICE rom_dev; + +/* SCP data structures and interface routines + + sim_name simulator name + sim_devices array of pointers to simulated devices +*/ + +char sim_name[] = "Alpha"; + +DEVICE *sim_devices[] = { + &cpu_dev, + &tlb_dev, + &ev5pal_dev, + &rom_dev, + NULL + }; + diff --git a/alpha/alpha_cpu.c b/alpha/alpha_cpu.c new file mode 100644 index 00000000..7cacf0ea --- /dev/null +++ b/alpha/alpha_cpu.c @@ -0,0 +1,1865 @@ +/* alpha_cpu.c: Alpha CPU simulator + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + Alpha architecturally-defined CPU state: + + PC<63:0> program counter + R[0:31]<63:0> integer registers + F[0:31]<63:0> floating registers + FPCR<63:0> floating point control register + (only left 32b are implemented) + PCC<63:0> hardware cycle counter + trap_summ<6:0> arithmetic trap summary + trap_mask<63:0> arithmetic trap register mask + lock_flag load_locked flag + vax_flag<0> VAX compatibility interrupt flag + FEN<0> floating point enable flag + + The Alpha CPU privileged state is "soft" and varies significantly from + operating system to operating system. Alpha provides an intermediate layer + of software (called PALcode) that implements the privileged state as well + as a library of complex instruction functions. PALcode implementations + are chip specific and system specific, as well as OS specific. + + Alpha memory management is also "soft" and supported a variety of mapping + schemes. VMS and Unix use a three level page table and directly expose + the underlying 64b hardware PTE. NT uses a condensed 32b PTE. + + All Alpha instructions are 32b wide. There are five basic formats: PALcall, + branch, memory reference, integer operate, and floating operate. + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + | opcode | PAL function | PAL + | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | + | opcode | Ra | branch displacement | branch + | | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | + | opcode | Ra | Rb | address displacement | memory + | | | | | reference + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | | | | + | opcode | Ra | Rb |0 0 0|0| function | Rc | integer + | | | | | | | | operate + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + | literal |1| + | | | + +-+-+-+-+-+-+-+-+-+ + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | | | | + | opcode | Ra | Rb | trap|rnd| function | Rc | floating + | | | | | | | | operate + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Memory reference format is also used for some two-operand operates; + the address displacement is the function code. + + This routine is the instruction decode routine for the Alpha. It + is called from the simulator control program to execute instructions + in simulated memory, starting at the simulated PC. It runs until an + enabled exception is encountered. + + General notes: + + 1. Traps and interrupts. Variable trap_summ summarizes the outstanding + trap requests (if any). Variable intr_summ summarizes the outstanding + interrupt requests (if any). + + 2. Interrupt requests are maintained in the int_req array, one word per + interrupt level, one bit per device. + + 3. Adding I/O devices. These modules must be modified: + + alpha_defs.h add device address and interrupt definitions + alpha_sys.c add sim_devices table entry +*/ + +#include "alpha_defs.h" + +#define UNIT_V_CONH (UNIT_V_UF + 0) /* halt to console */ +#define UNIT_V_MSIZE (UNIT_V_UF + 1) +#define UNIT_CONH (1 << UNIT_V_CONH) +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) + +#define HIST_PC 0x2 +#define HIST_MIN 64 +#define HIST_MAX (1 << 18) + +typedef struct { + t_uint64 pc; + uint32 ir; + uint32 filler; + t_uint64 ra; + t_uint64 rb; + } InstHistory; + +#define H_A 0x01 +#define H_B 0x02 +#define H_B_LIT 0x04 +#define H_EA 0x08 +#define H_EA_B 0x10 +#define H_EA_L16 0x20 +#define H_MRF (H_A|H_B|H_EA) +#define H_BRA (H_A|H_EA|H_EA_B) +#define H_IOP (H_A|H_B|H_B_LIT) +#define H_FOP (H_A|H_B) +#define H_PAL (H_A|H_EA|H_EA_L16) +#define H_JMP (H_A|H_B|H_EA|H_EA_L16) + +t_uint64 *M = 0; /* memory */ +t_uint64 R[32]; /* integer reg */ +t_uint64 FR[32]; /* floating reg */ +t_uint64 PC; /* PC, <1:0> MBZ */ +uint32 pc_align = 0; /* PC<1:0> */ +t_uint64 trap_mask = 0; /* trap reg mask */ +uint32 trap_summ = 0; /* trap summary */ +uint32 fpcr = 0; /* fp ctrl reg */ +uint32 pcc_l = 0; /* rpcc high */ +uint32 pcc_h = 0; /* rpcc low */ +uint32 pcc_enb = 0; +uint32 arch_mask = AMASK_BWX | AMASK_PRC; /* arch mask */ +uint32 impl_ver = IMPLV_EV5; /* impl version */ +uint32 lock_flag = 0; /* load lock flag */ +uint32 vax_flag = 0; /* vax intr flag */ +uint32 intr_summ = 0; /* interrupt summary */ +uint32 pal_mode = 1; /* PAL mode */ +uint32 pal_type = PAL_UNDF; /* PAL type */ +uint32 dmapen = 0; /* data mapping enable */ +uint32 fpen = 0; /* flt point enabled */ +uint32 ir = 0; /* instruction register */ +t_uint64 p1 = 0; /* exception parameter */ +uint32 int_req[IPL_HLVL] = { 0 }; /* interrupt requests */ +REG *pcq_r = NULL; /* PC queue reg ptr */ +t_uint64 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +uint32 cpu_astop = 0; +uint32 hst_p = 0; /* history pointer */ +uint32 hst_lnt = 0; /* history length */ +InstHistory *hst = NULL; /* instruction history */ +jmp_buf save_env; + +const t_uint64 byte_mask[8] = { + 0x00000000000000FF, 0x000000000000FF00, + 0x0000000000FF0000, 0x00000000FF000000, + 0x000000FF00000000, 0x0000FF0000000000, + 0x00FF000000000000, 0xFF00000000000000 + }; + +const t_uint64 word_mask[4] = { + 0x000000000000FFFF, 0x00000000FFFF0000, + 0x0000FFFF00000000, 0xFFFF000000000000 + }; + +extern int32 sim_interval; +extern int32 sim_int_char; +extern FILE *sim_deb; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi); +t_uint64 byte_zap (t_uint64 op, uint32 mask); +t_stat cpu_reset (DEVICE *dptr); +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_hist (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc); +t_stat cpu_fprint_one_inst (FILE *st, uint32 ir, t_uint64 pc, t_uint64 ra, t_uint64 rb); + +extern t_uint64 op_ldf (t_uint64 op); +extern t_uint64 op_ldg (t_uint64 op); +extern t_uint64 op_lds (t_uint64 op); +extern t_uint64 op_stf (t_uint64 op); +extern t_uint64 op_stg (t_uint64 op); +extern t_uint64 op_sts (t_uint64 op); +extern t_uint64 vax_sqrt (uint32 ir, t_bool dp); +extern t_uint64 ieee_sqrt (uint32 ir, t_bool dp); +extern void vax_fop (uint32 ir); +extern void ieee_fop (uint32 ir); +extern t_stat pal_19 (uint32 ir); +extern t_stat pal_1b (uint32 ir); +extern t_stat pal_1d (uint32 ir); +extern t_stat pal_1e (uint32 ir); +extern t_stat pal_1f (uint32 ir); +extern t_uint64 trans_c (t_uint64 va); +extern t_stat cpu_show_tlb (FILE *of, UNIT *uptr, int32 val, void *desc); +extern t_stat pal_eval_intr (uint32 flag); +extern t_stat pal_proc_excp (uint32 type); +extern t_stat pal_proc_trap (uint32 type); +extern t_stat pal_proc_intr (uint32 type); +extern t_stat pal_proc_inst (uint32 fnc); +extern uint32 tlb_set_cm (int32 cm); + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit + cpu_reg CPU register list + cpu_mod CPU modifier list +*/ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, INITMEMSIZE) }; + +REG cpu_reg[] = { + { HRDATA (PC, PC, 64), PV_LEFT }, + { HRDATA (PCALG, pc_align, 3) }, + { HRDATA (R0, R[0], 64) }, + { HRDATA (R1, R[1], 64) }, + { HRDATA (R2, R[2], 64) }, + { HRDATA (R3, R[3], 64) }, + { HRDATA (R4, R[4], 64) }, + { HRDATA (R5, R[5], 64) }, + { HRDATA (R6, R[6], 64) }, + { HRDATA (R7, R[7], 64) }, + { HRDATA (R8, R[8], 64) }, + { HRDATA (R9, R[9], 64) }, + { HRDATA (R10, R[10], 64) }, + { HRDATA (R11, R[11], 64) }, + { HRDATA (R12, R[12], 64) }, + { HRDATA (R13, R[13], 64) }, + { HRDATA (R14, R[14], 64) }, + { HRDATA (R15, R[15], 64) }, + { HRDATA (R16, R[16], 64) }, + { HRDATA (R17, R[17], 64) }, + { HRDATA (R18, R[18], 64) }, + { HRDATA (R19, R[19], 64) }, + { HRDATA (R20, R[20], 64) }, + { HRDATA (R21, R[21], 64) }, + { HRDATA (R22, R[22], 64) }, + { HRDATA (R23, R[23], 64) }, + { HRDATA (R24, R[24], 64) }, + { HRDATA (R25, R[25], 64) }, + { HRDATA (R26, R[26], 64) }, + { HRDATA (R27, R[27], 64) }, + { HRDATA (R28, R[28], 64) }, + { HRDATA (R29, R[29], 64) }, + { HRDATA (R30, R[30], 64) }, + { HRDATA (R31, R[31], 64), REG_RO }, + { HRDATA (F0, FR[0], 64) }, + { HRDATA (F1, FR[1], 64) }, + { HRDATA (F2, FR[2], 64) }, + { HRDATA (F3, FR[3], 64) }, + { HRDATA (F4, FR[4], 64) }, + { HRDATA (F5, FR[5], 64) }, + { HRDATA (F6, FR[6], 64) }, + { HRDATA (F7, FR[7], 64) }, + { HRDATA (F8, FR[8], 64) }, + { HRDATA (F9, FR[9], 64) }, + { HRDATA (F10, FR[10], 64) }, + { HRDATA (F11, FR[11], 64) }, + { HRDATA (F12, FR[12], 64) }, + { HRDATA (F13, FR[13], 64) }, + { HRDATA (F14, FR[14], 64) }, + { HRDATA (F15, FR[15], 64) }, + { HRDATA (F16, FR[16], 64) }, + { HRDATA (F17, FR[17], 64) }, + { HRDATA (F18, FR[18], 64) }, + { HRDATA (F19, FR[19], 64) }, + { HRDATA (F20, FR[20], 64) }, + { HRDATA (F21, FR[21], 64) }, + { HRDATA (F22, FR[22], 64) }, + { HRDATA (F23, FR[23], 64) }, + { HRDATA (F24, FR[24], 64) }, + { HRDATA (F25, FR[25], 64) }, + { HRDATA (F26, FR[26], 64) }, + { HRDATA (F27, FR[27], 64) }, + { HRDATA (F28, FR[28], 64) }, + { HRDATA (F29, FR[29], 64) }, + { HRDATA (F30, FR[30], 64) }, + { HRDATA (F31, FR[31], 64), REG_RO }, + { HRDATA (FPCR, fpcr, 32) }, + { FLDATA (FEN, fpen, 0) }, + { HRDATA (TRAPS, trap_summ, 8) }, + { HRDATA (TRAPM, trap_mask, 64) }, + { HRDATA (PCCH, pcc_h, 32) }, + { HRDATA (PCCL, pcc_l, 32) }, + { FLDATA (LOCK, lock_flag, 0) }, + { FLDATA (VAXF, vax_flag, 0) }, + { FLDATA (PALMODE, pal_mode, 0) }, + { HRDATA (PALTYPE, pal_type, 2), REG_HRO }, + { HRDATA (DMAPEN, dmapen, 0) }, + { HRDATA (AMASK, arch_mask, 13), REG_RO }, + { HRDATA (IMPLV, impl_ver, 2), REG_RO }, + { BRDATA (PCQ, pcq, 16, 32, PCQ_SIZE), REG_RO+REG_CIRC }, + { HRDATA (PCQP, pcq_p, 6), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } + }; + +MTAB cpu_mod[] = { + { UNIT_MSIZE, (1u << 25), NULL, "32M", &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|MTAB_SHP, 0, "VIRTUAL", NULL, + NULL, &cpu_show_virt }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "ITLB", NULL, + NULL, &cpu_show_tlb }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 1, "DTLB", NULL, + NULL, &cpu_show_tlb }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", + &cpu_set_hist, &cpu_show_hist }, + { 0 } + }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 16, 48, 8, 16, 64, + &cpu_ex, &cpu_dep, &cpu_reset, + &cpu_boot, NULL, NULL, + NULL, DEV_DYNM|DEV_DEBUG, 0, + NULL, &cpu_set_size, NULL + }; + +t_stat sim_instr (void) +{ +t_stat reason; +int abortval; +t_bool tracing; + +PC = PC | pc_align; /* put PC together */ +abortval = setjmp (save_env); /* set abort hdlr */ +if (abortval != 0) { /* exception? */ + if (abortval < 0) { /* SCP stop? */ + pcc_l = pcc_l & M32; + pcq_r->qptr = pcq_p; /* update pc q ptr */ + pc_align = ((uint32) PC) & 3; /* separate PC<1:0> */ + PC = PC & 0xFFFFFFFFFFFFFFFC; + return -abortval; + } + reason = pal_proc_excp (abortval); /* pal processing */ + } +else reason = 0; +tlb_set_cm (-1); /* resync cm */ +tracing = ((hst_lnt != 0) || DEBUG_PRS (cpu_dev)); + +intr_summ = pal_eval_intr (1); /* eval interrupts */ + +/* Main instruction loop */ + +while (reason == 0) { + + int32 i; + uint32 op, ra, rb, rc, fnc, sc, s32, t32, sgn; + t_int64 s1, s2, sr; + t_uint64 ea, dsp, rbv, res, s64, t64; + + if (cpu_astop) { /* debug stop? */ + cpu_astop = 0; /* clear */ + reason = SCPE_STOP; /* stop simulation */ + break; + } + + if (sim_interval <= 0) { /* chk clock queue */ + if (reason = sim_process_event ()) break; + intr_summ = pal_eval_intr (1); /* eval interrupts */ + } + + if (intr_summ && !pal_mode) { /* interrupt pending? */ + reason = pal_proc_intr (intr_summ); /* pal processing */ + intr_summ = pal_eval_intr (1); /* eval interrupts */ + continue; + } + + if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + sim_interval = sim_interval - 1; /* count instr */ + pcc_l = pcc_l + pcc_enb; + ir = ReadI (PC); /* get instruction */ + op = I_GETOP (ir); /* get opcode */ + ra = I_GETRA (ir); /* get ra */ + rb = I_GETRB (ir); /* get rb */ + + if (tracing) { /* trace or history? */ + if (hst_lnt) { /* history enabled? */ + hst_p = (hst_p + 1); /* next entry */ + if (hst_p >= hst_lnt) hst_p = 0; + hst[hst_p].pc = PC | pc_align | HIST_PC; /* save PC */ + hst[hst_p].ir = ir; /* save ir */ + hst[hst_p].ra = R[ra]; /* save Ra */ + hst[hst_p].rb = R[rb]; /* save Rb */ + } + if (DEBUG_PRS (cpu_dev)) /* trace enabled? */ + cpu_fprint_one_inst (sim_deb, ir, PC | pc_align, R[ra], R[rb]); + } + + PC = (PC + 4) & M64; /* advance PC */ + switch (op) { + +/* Memory reference instructions */ + + case OP_LDA: /* LDA */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ea; + } + break; + + case OP_LDAH: /* LDAH */ + if (ra != 31) { + dsp = I_GETMDSP (ir) << 16; + ea = (R[rb] + SEXT_L_Q (dsp)) & M64; + R[ra] = ea; + } + break; + + case OP_LDBU: /* LDBU */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); /* EV56 or later */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadB (ea); + } + break; + + case OP_LDQ_U: /* LDQ_U */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadQ (ea & ~7); /* ignore ea<2:0> */ + } + break; + + case OP_LDWU: /* LDWU */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); /* EV56 or later */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadW (ea); + } + break; + + case OP_STW: /* STW */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); /* EV56 or later */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteW (ea, R[ra]); + break; + + case OP_STB: /* STB */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); /* EV56 or later */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteB (ea, R[ra]); + break; + + case OP_STQ_U: /* STQ_U */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteQ (ea & ~7, R[ra]); /* ignore ea<2:0> */ + break; + + case OP_LDF: /* LDF */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + FR[ra] = op_ldf (ReadL (ea)); /* swizzle bits */ + } + break; + + case OP_LDG: /* LDG */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + FR[ra] = op_ldg (ReadQ (ea)); /* swizzle bits */ + } + break; + + case OP_LDS: /* LDS */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + FR[ra] = op_lds (ReadL (ea)); /* swizzle bits */ + } + break; + + case OP_LDT: /* LDT */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + FR[ra] = ReadQ (ea); /* no swizzling needed */ + } + break; + + case OP_STF: /* STF */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteL (ea, op_stf (FR[ra])); /* swizzle bits */ + break; + + case OP_STG: /* STG */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteQ (ea, op_stg (FR[ra])); /* swizzle bits */ + break; + + case OP_STS: /* STS */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteL (ea, op_sts (FR[ra])); /* swizzle bits */ + break; + + case OP_STT: /* STT */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteQ (ea, FR[ra]); /* no swizzling needed */ + break; + + case OP_LDL: /* LDL */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + res = ReadL (ea); + R[ra] = SEXT_L_Q (res); + } + break; + + case OP_LDQ: /* LDQ */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadQ (ea); + } + break; + + case OP_LDL_L: /* LDL_L */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + res = ReadL (ea); + R[ra] = SEXT_L_Q (res); + lock_flag = 1; /* set lock flag */ + } + break; + + case OP_LDQ_L: /* LDQ_L */ + if (ra != 31) { + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + R[ra] = ReadQ (ea); + lock_flag = 1; /* set lock flag */ + } + break; + + case OP_STL: /* STL */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteL (ea, R[ra]); + break; + + case OP_STQ: /* STQ */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + WriteQ (ea, R[ra]); + break; + + case OP_STL_C: /* STL_C */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + if (lock_flag) WriteL (ea, R[ra]); /* unlocking? ok */ + else R[ra] = 0; /* write fails */ + lock_flag = 0; /* clear lock */ + break; + + case OP_STQ_C: /* STQ_C */ + dsp = I_GETMDSP (ir); + ea = (R[rb] + SEXT_MDSP (dsp)) & M64; + if (lock_flag) WriteQ (ea, R[ra]); /* unlocking? ok */ + else R[ra] = 0; /* write fails */ + lock_flag = 0; /* clear lock */ + break; + +/* Control instructions */ + + case OP_JMP: /* JMP */ + PCQ_ENTRY; + rbv = R[rb]; /* in case Ra = Rb */ + if (ra != 31) R[ra] = PC; /* save PC */ + PC = rbv; /* jump */ + break; + + case OP_BR: /* BR, BSR */ + case OP_BSR: + PCQ_ENTRY; + if (ra != 31) R[ra] = PC; /* save PC */ + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; /* branch */ + break; + + case OP_FBEQ: /* FBEQ */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if ((FR[ra] & ~FPR_SIGN) == 0) { /* +0 or - 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBLT: /* FBLT */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (FR[ra] > FPR_SIGN) { /* -0 to -n? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBLE: /* FBLE */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if ((FR[ra] & FPR_SIGN) || (FR[ra] == 0)) { /* - or 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBNE: /* FBNE */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if ((FR[ra] & ~FPR_SIGN) != 0) { /* not +0 or -0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBGE: /* FBGE */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (FR[ra] <= FPR_SIGN) { /* +0 to +n? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_FBGT: /* FBGT */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + if (!(FR[ra] & FPR_SIGN) && (FR[ra] != 0)) { /* not - and not 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BLBC: /* BLBC */ + if ((R[ra] & 1) == 0) { /* R<0> == 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BEQ: /* BEQ */ + if (R[ra] == 0) { /* R == 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BLT: /* BLT */ + if (R[ra] & Q_SIGN) { /* R<63> == 1? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BLE: /* BLE */ + if ((R[ra] == 0) || (R[ra] & Q_SIGN)) { /* R == 0 || R<63> == 1? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BLBS: /* BLBS */ + if ((R[ra] & 1) != 0) { /* R<0> == 1? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BNE: /* BNE */ + if (R[ra] != 0) { /* R != 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BGE: /* BGE */ + if (!(R[ra] & Q_SIGN)) { /* R<63> == 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + + case OP_BGT: /* BGT */ + if ((R[ra] != 0) && !(R[ra] & Q_SIGN)) { /* R != 0 && R<63> == 0? */ + PCQ_ENTRY; + dsp = I_GETBDSP (ir); + PC = (PC + (SEXT_BDSP (dsp) << 2)) & M64; + } + break; + +/* Integer arithmetic operates (10) */ + + case OP_IALU: /* integer arith opr */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x00: /* ADDL */ + res = SEXT_L_Q (R[ra] + rbv); + break; + + case 0x02: /* S4ADDL */ + res = SEXT_L_Q ((R[ra] << 2) + rbv); + break; + + case 0x09: /* SUBL */ + res = SEXT_L_Q (R[ra] - rbv); + break; + + case 0x0B: /* S4SUBL */ + res = SEXT_L_Q ((R[ra] << 2) - rbv); + break; + + case 0x0F: /* CMPBGE */ + for (i = 0, res = 0; i < 8; i++) { + if ((R[ra] & byte_mask[i]) >= (rbv & byte_mask[i])) + res = res | ((t_uint64) 1u << i); + } + break; + + case 0x12: /* S8ADDL */ + res = SEXT_L_Q ((R[ra] << 3) + rbv); + break; + + case 0x1B: /* S8SUBL */ + res = SEXT_L_Q ((R[ra] << 3) - rbv); + break; + + case 0x1D: /* CMPULT */ + res = (R[ra] < rbv); + break; + + case 0x20: /* ADDQ */ + res = R[ra] + rbv; + break; + + case 0x22: /* S4ADDQ */ + res = (R[ra] << 2) + rbv; + break; + + case 0x29: /* SUBQ */ + res = R[ra] - rbv; + break; + + case 0x2B: /* S4SUBQ */ + res = (R[ra] << 2) - rbv; + break; + + case 0x2D: /* CMPEQ */ + res = (R[ra] == rbv); + break; + + case 0x32: /* S8ADDQ */ + res = (R[ra] << 3) + rbv; + break; + + case 0x3B: /* S8SUBQ */ + res = (R[ra] << 3) - rbv; + break; + + case 0x3D: /* CMPULE */ + res = (R[ra] <= rbv); + break; + + case 0x40: /* ADDL/V */ + res = SEXT_L_Q (R[ra] + rbv); + if (((~R[ra] ^ rbv) & (R[ra] ^ res)) & L_SIGN) + arith_trap (TRAP_IOV, ir); + break; + + case 0x49: /* SUBL/V */ + res = SEXT_L_Q (R[ra] - rbv); + if (((R[ra] ^ rbv) & (~rbv ^ res)) & L_SIGN) + arith_trap (TRAP_IOV, ir); + break; + + case 0x4D: /* CMPLT */ + sgn = Q_GETSIGN (R[ra]); /* get Ra sign */ + if (sgn ^ Q_GETSIGN (rbv)) res = sgn; /* signs diff? */ + else res = sgn ^ (R[ra] < rbv); + break; + + case 0x60: /* ADDQ/V */ + res = R[ra] + rbv; + if (((~R[ra] ^ rbv) & (R[ra] ^ res)) & Q_SIGN) + arith_trap (TRAP_IOV, ir); + break; + + case 0x69: /* SUBQ/V */ + res = R[ra] - rbv; + if (((R[ra] ^ rbv) & (~rbv ^ res)) & Q_SIGN) + arith_trap (TRAP_IOV, ir); + break; + + case 0x6D: /* CMPLE */ + if (R[ra] == rbv) res = 1; + else { + sgn = Q_GETSIGN (R[ra]); /* get Ra sign */ + if (sgn ^ Q_GETSIGN (rbv)) res = sgn; /* signs diff? */ + else res = sgn ^ (R[ra] < rbv); + } + + break; + default: + res = R[rc]; + break; + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* Integer logical operates (11) */ + + case OP_ILOG: /* integer logic opr */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x00: /* AND */ + res = R[ra] & rbv; + break; + + case 0x08: /* BIC */ + res = R[ra] & ~rbv; + break; + + case 0x14: /* CMOVLBS */ + if ((R[ra] & 1) != 0) res = rbv; + else res = R[rc]; + break; + + case 0x16: /* CMOVLBC */ + if ((R[ra] & 1) == 0) res = rbv; + else res = R[rc]; + break; + + case 0x20: /* BIS */ + res = R[ra] | rbv; + break; + + case 0x24: /* CMOVEQ */ + if (R[ra] == 0) res = rbv; + else res = R[rc]; + break; + + case 0x26: /* CMOVNE */ + if (R[ra] != 0) res = rbv; + else res = R[rc]; + break; + + case 0x28: /* ORNOT */ + res = R[ra] | ~rbv; + break; + + case 0x40: /* XOR */ + res = R[ra] ^ rbv; + break; + + case 0x44: /* CMOVLT */ + if (R[ra] & Q_SIGN) res = rbv; + else res = R[rc]; + break; + + case 0x46: /* CMOVGE */ + if (!(R[ra] & Q_SIGN)) res = rbv; + else res = R[rc]; + break; + + case 0x48: /* EQV */ + res = R[ra] ^ ~rbv; + break; + + case 0x61: /* AMASK */ + res = rbv & ~arch_mask; + break; + + case 0x64: /* CMOVLE */ + if ((R[ra] & Q_SIGN) || (R[ra] == 0)) res = rbv; + else res = R[rc]; + break; + + case 0x66: /* CMOVGT */ + if (!(R[ra] & Q_SIGN) && (R[ra] != 0)) res = rbv; + else res = R[rc]; + break; + + case 0x6C: /* IMPLVER */ + res = impl_ver; + break; + + default: + res = R[rc]; + break; + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* Integer logical shifts (12) */ + + case OP_ISHFT: /* integer shifts */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x02: /* MSKBL */ + sc = ((uint32) rbv) & 7; + res = byte_zap (R[ra], 0x1 << sc); + break; + + case 0x06: /* EXTBL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] >> sc) & M8; + break; + + case 0x0B: /* INSBL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] & M8) << sc; + break; + + case 0x12: /* MSKWL */ + sc = ((uint32) rbv) & 7; + res = byte_zap (R[ra], 0x3 << sc); + break; + + case 0x16: /* EXTWL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] >> sc) & M16; + break; + + case 0x1B: /* INSWL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] & M16) << sc; + break; + + case 0x22: /* MSKLL */ + sc = ((uint32) rbv) & 7; + res = byte_zap (R[ra], 0xF << sc); + break; + + case 0x26: /* EXTLL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] >> sc) & M32; + break; + + case 0x2B: /* INSLL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = (R[ra] & M32) << sc; + break; + + case 0x30: /* ZAP */ + res = byte_zap (R[ra], (uint32) rbv); + break; + + case 0x31: /* ZAPNOT */ + res = byte_zap (R[ra], ~((uint32) rbv)); + break; + + case 0x32: /* MSKQL */ + sc = ((uint32) rbv) & 7; + res = byte_zap (R[ra], 0xFF << sc); + break; + + case 0x34: /* SRL */ + sc = ((uint32) rbv) & 0x3F; + res = R[ra] >> sc; + break; + + case 0x36: /* EXTQL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = R[ra] >> sc; + break; + + case 0x39: /* SLL */ + sc = ((uint32) rbv) & 0x3F; + res = R[ra] << sc; + break; + + case 0x3B: /* INSQL */ + sc = (((uint32) rbv) << 3) & 0x3F; + res = R[ra] << sc; + break; + + case 0x3C: /* SRA */ + sc = ((uint32) rbv) & 0x3F; + res = (R[ra] >> sc); + if (sc && (R[ra] & Q_SIGN)) res = res | + (((t_uint64) M64) << (64 - sc)); + break; + + case 0x52: /* MSKWH */ + sc = 8 - (((uint32) rbv) & 7); + res = byte_zap (R[ra], 0x3 >> sc); + break; + + case 0x57: /* EXTWH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = (R[ra] << sc) & M16; + break; + + case 0x5A: /* INSWH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = (R[ra] & M16) >> sc; + break; + + case 0x62: /* MSKLH */ + sc = 8 - (((uint32) rbv) & 7); + res = byte_zap (R[ra], 0xF >> sc); + break; + + case 0x67: /* EXTLH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = (R[ra] << sc) & M32; + break; + + case 0x6A: /* INSLH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = (R[ra] & M32) >> sc; + break; + + case 0x72: /* MSKQH */ + sc = 8 - (((uint32) rbv) & 7); + res = byte_zap (R[ra], 0xFF >> sc); + break; + + case 0x77: /* EXTQH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = R[ra] << sc; + break; + + case 0x7A: /* INSQH */ + sc = (64 - (((uint32) rbv) << 3)) & 0x3F; + res = R[ra] >> sc; + break; + + default: + res = R[rc]; + break; + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* Integer multiply (13) */ + + case OP_IMUL: /* integer multiply */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x00: /* MULL */ + s1 = SEXT_L_Q (R[ra]); + s2 = SEXT_L_Q (rbv); + sr = s1 * s2; + res = SEXT_L_Q (sr); + break; + + case 0x20: /* MULQ */ + res = uemul64 (R[ra], rbv, NULL); /* low 64b invariant */ + break; /* with sign/unsigned */ + + case 0x30: /* UMULH */ + uemul64 (R[ra], rbv, &res); + break; + + case 0x40: /* MULL/V */ + s1 = SEXT_L_Q (R[ra]); + s2 = SEXT_L_Q (rbv); + sr = s1 * s2; + res = SEXT_L_Q (sr); + if (((sr ^ res) & M64) != 0) /* overflow? */ + arith_trap (TRAP_IOV, ir); + break; + + case 0x60: /* MULQ/V */ + res = uemul64 (R[ra], rbv, &t64); + if (Q_GETSIGN(R[ra])) + t64 = (t64 - rbv) & M64; + if (Q_GETSIGN(rbv)) + t64 = (t64 - R[ra]) & M64; + if (Q_GETSIGN (res)? (t64 != M64): (t64 != 0)) + arith_trap (TRAP_IOV, ir); + break; + + default: + res = R[rc]; + break; + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* FIX optional floating point set (14) */ + + case OP_IFLT: /* int to flt */ + if (!(arch_mask & AMASK_FIX)) ABORT (EXC_RSVI); /* EV56 or later */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + rc = I_GETRC (ir); /* get rc */ + fnc = I_GETFFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x04: /* ITOFS */ + if (ir & (I_FRND|I_FTRP)) ABORT (EXC_RSVI); + t32 = ((uint32) R[ra]) & M32; + res = op_lds (t32); + break; + + case 0x0A: /* SQRTF */ + if (ir & I_F_VAXRSV) ABORT (EXC_RSVI); + res = vax_sqrt (ir, DT_F); + break; + + case 0x0B: /* SQRTS */ + res = ieee_sqrt (ir, DT_S); + break; + + case 0x14: /* ITOFF */ + if (ir & (I_FRND|I_FTRP)) ABORT (EXC_RSVI); + t32 = ((uint32) R[ra]) & M32; + res = op_ldf (SWAP_VAXF (t32)); + break; + + case 0x24: /* ITOFT */ + if (ir & (I_FRND|I_FTRP)) ABORT (EXC_RSVI); + res = R[ra]; + break; + + case 0x2A: /* SQRTG */ + if (ir & I_F_VAXRSV) ABORT (EXC_RSVI); + res = vax_sqrt (ir, DT_G); + break; + + case 0x2B: /* SQRTT */ + res = ieee_sqrt (ir, DT_T); + break; + + default: + ABORT (EXC_RSVI); + } + + if (rc != 31) FR[rc] = res & M64; + break; + +/* VAX and IEEE floating point operates - done externally */ + + case OP_VAX: /* VAX fp opr */ + if (ir & I_F_VAXRSV) ABORT (EXC_RSVI); /* reserved */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + vax_fop (ir); + break; + + case OP_IEEE: /* IEEE fp opr */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + ieee_fop (ir); + break; + +/* Data type independent floating point (17) */ + + case OP_FP: /* other fp */ + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + rc = I_GETRC (ir); /* get rc */ + fnc = I_GETFFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x10: /* CVTLQ */ + res = ((FR[rb] >> 32) & 0xC0000000) | ((FR[rb] >> 29) & 0x3FFFFFFF); + res = SEXT_L_Q (res); + break; + + case 0x20: /* CPYS */ + res = (FR[ra] & FPR_SIGN) | (FR[rb] & ~FPR_SIGN); + break; + + case 0x21: /* CPYSN */ + res = ((FR[ra] & FPR_SIGN) ^ FPR_SIGN) | (FR[rb] & ~FPR_SIGN); + break; + + case 0x22: /* CPYSE */ + res = (FR[ra] & (FPR_SIGN|FPR_EXP)) | (FR[rb] & ~(FPR_SIGN|FPR_EXP)); + break; + + case 0x24: /* MT_FPCR */ + fpcr = ((uint32) (FR[ra] >> 32)) & ~FPCR_RAZ; + res = FR[rc]; + break; + + case 0x25: /* MF_FPCR */ + res = ((t_uint64) fpcr) << 32; + break; + + case 0x2A: /* FCMOVEQ */ + if ((FR[ra] & ~FPR_SIGN) == 0) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2B: /* FCMOVNE */ + if ((FR[ra] & ~FPR_SIGN) != 0) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2C: /* FCMOVLT */ + if (FR[ra] > FPR_SIGN) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2D: /* FCMOVGE */ + if (FR[ra] <= FPR_SIGN) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2E: /* FCMOVLE */ + if (FPR_GETSIGN (FR[ra]) || (FR[ra] == 0)) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x2F: /* FCMOVGT */ + if (!FPR_GETSIGN (FR[ra]) && (FR[ra] != 0)) res = FR[rb]; + else res = FR[rc]; + break; + + case 0x30: /* CVTQL */ + res = ((FR[rb] & 0xC0000000) << 32) | ((FR[rb] & 0x3FFFFFFF) << 29); + if (FPR_GETSIGN (FR[rb])? + (FR[rb] < 0xFFFFFFFF80000000): + (FR[rb] > 0x000000007FFFFFFF)) { + fpcr = fpcr | FPCR_IOV | FPCR_INE | FPCR_SUM; + if (ir & I_FTRP_V) arith_trap (TRAP_IOV, ir); + } + break; + + default: + res = FR[rc]; + break; + } + + if (rc != 31) FR[rc] = res & M64; + break; + +/* Barriers and misc (18) + + Alpha has a weak memory ordering model and an imprecise exception model; + together, they require a wide variety of barrier instructions to guarantee + memory coherency in multiprocessor systems, as well as backward compatible + exception instruction semantics. + + The simulator is uniprocessor only, and has ordered memory accesses and + precise exceptions. Therefore, the barriers are all NOP's. */ + + case OP_MISC: /* misc */ + fnc = I_GETMDSP (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0xC000: /* RPCC */ + pcc_l = pcc_l & M32; + if (ra != 31) R[ra] = (((t_uint64) pcc_h) << 32) | ((t_uint64) pcc_l); + break; + + case 0xE000: /* RC */ + if (ra != 31) R[ra] = vax_flag; + vax_flag = 0; + break; + + case 0xF000: /* RS */ + if (ra != 31) R[ra] = vax_flag; + vax_flag = 1; + break; + + default: + break; + } + + break; + +/* Optional instruction sets (1C) */ + + case OP_FLTI: /* float to int */ + rc = I_GETRC (ir); /* get rc */ + if (ir & I_ILIT) rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = R[rb]; /* no, rbv = R[rb] */ + fnc = I_GETIFNC (ir); /* get function */ + switch (fnc) { /* case on function */ + + case 0x00: /* SEXTB */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); + res = SEXT_B_Q (rbv); + break; + + case 0x01: /* SEXTW */ + if (!(arch_mask & AMASK_BWX)) ABORT (EXC_RSVI); + res = SEXT_W_Q (rbv); + break; + + case 0x30: /* CTPOP */ + if (!(arch_mask & AMASK_CIX)) ABORT (EXC_RSVI); + for (res = 0; rbv != 0; res++) { + rbv = rbv & ~(rbv & NEG_Q (rbv)); + } + break; + + case 0x31: /* PERR */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 64; i = i + 8) { + s32 = (uint32) (R[ra] >> i) & M8; + t32 = (uint32) (rbv >> i) & M8; + res = res + ((t_uint64) (s32 >= t32)? (s32 - t32): (t32 - s32)); + } + break; + + case 0x32: /* CTLZ */ + if (!(arch_mask & AMASK_CIX)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 64; i++) { + if ((rbv >> (63 - i)) & 1) break; + res = res + 1; + } + break; + + case 0x33: /* CTTZ */ + if (!(arch_mask & AMASK_CIX)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 64; i++) { + if ((rbv >> i) & 1) break; + res = res + 1; + } + break; + + case 0x34: /* UNPKBL */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + res = ((rbv & 0xFF00) << 24) | (rbv & 0xFF); + break; + + case 0x35: /* UNPKBW */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + res = ((rbv & 0xFF000000) << 24) | ((rbv & 0xFF0000) << 16) | + ((rbv & 0xFF00) << 8) | (rbv & 0xFF); + break; + + case 0x36: /* PKWB */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + res = ((rbv >> 24) & 0xFF000000) | ((rbv >> 16) & 0xFF0000) | + ((rbv >> 8) & 0xFF00) | (rbv & 0xFF); + break; + + case 0x37: /* PKLB */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + res = ((rbv >> 24) & 0xFF00) | (rbv & 0xFF); + break; + + case 0x38: /* MINSB8 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i++) { + s1 = SEXT_B_Q (R[ra] >> (i << 3)); + s2 = SEXT_B_Q (rbv >> (i << 3)); + res = res | (((s1 <= s2)? R[ra]: rbv) & byte_mask[i]); + } + break; + + case 0x39: /* MINSW4 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i = i++) { + s1 = SEXT_W_Q (R[ra] >> (i << 4)); + s2 = SEXT_W_Q (rbv >> (i << 4)); + res = res | (((s1 <= s2)? R[ra]: rbv) & word_mask[i]); + } + break; + + case 0x3A: /* MINUB8 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i++) { + s64 = R[ra] & byte_mask[i]; + t64 = rbv & byte_mask[i]; + res = res | ((s64 <= t64)? s64: t64); + } + break; + + case 0x3B: /* MINUW4 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i = i++) { + s64 = R[ra] & word_mask[i]; + t64 = rbv & word_mask[i]; + res = res | ((s64 <= t64)? s64: t64); + } + break; + + case 0x3C: /* MAXUB8 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i++) { + s64 = R[ra] & byte_mask[i]; + t64 = rbv & byte_mask[i]; + res = res | ((s64 >= t64)? s64: t64); + } + break; + + case 0x3D: /* MAXUW4 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i = i++) { + s64 = R[ra] & word_mask[i]; + t64 = rbv & word_mask[i]; + res = res | ((s64 >= t64)? s64: t64); + } + break; + + case 0x3E: /* MAXSB8 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i++) { + s1 = SEXT_B_Q (R[ra] >> (i << 3)); + s2 = SEXT_B_Q (rbv >> (i << 3)); + res = res | (((s1 >= s2)? R[ra]: rbv) & byte_mask[i]); + } + break; + + case 0x3F: /* MAXSW4 */ + if (!(arch_mask & AMASK_MVI)) ABORT (EXC_RSVI); + for (i = 0, res = 0; i < 8; i = i++) { + s1 = SEXT_W_Q (R[ra] >> (i << 4)); + s2 = SEXT_W_Q (rbv >> (i << 4)); + res = res | (((s1 >= s2)? R[ra]: rbv) & word_mask[i]); + } + break; + + case 0x70: /* FTOIS */ + if (!(arch_mask & AMASK_FIX)) ABORT (EXC_RSVI); + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + res = op_sts (FR[ra]); + break; + + case 0x78: /* FTOIT */ + if (!(arch_mask & AMASK_FIX)) ABORT (EXC_RSVI); + if (fpen == 0) ABORT (EXC_FPDIS); /* flt point disabled? */ + res = FR[ra]; + break; + + default: + ABORT (EXC_RSVI); + } + + if (rc != 31) R[rc] = res & M64; + break; + +/* PAL hardware functions */ + + case OP_PAL19: + reason = pal_19 (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL1B: + reason = pal_1b (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL1D: + reason = pal_1d (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL1E: + reason = pal_1e (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL1F: + reason = pal_1f (ir); + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + case OP_PAL: /* PAL code */ + fnc = I_GETPAL (ir); /* get function code */ + if ((fnc & 0x40) || (fnc >= 0xC0)) /* out of range? */ + ABORT (EXC_RSVI); + reason = pal_proc_inst (fnc); /* processed externally */ + intr_summ = pal_eval_intr (1); /* eval interrupts */ + break; + + default: + ABORT (EXC_RSVI); + } /* end case */ + if (trap_summ) { /* any traps? */ + reason = pal_proc_trap (trap_summ); /* process trap */ + trap_summ = 0; /* clear trap reg */ + trap_mask = 0; + intr_summ = pal_eval_intr (1); /* eval interrupts */ + } + } /* end while */ +pcc_l = pcc_l & M32; +pcq_r->qptr = pcq_p; /* update pc q ptr */ +pc_align = ((uint32) PC) & 3; /* separate PC<1:0> */ +PC = PC & 0xFFFFFFFFFFFFFFFC; +return reason; +} + +/* Utility routines */ + +/* Byte zap function */ + +t_uint64 byte_zap (t_uint64 op, uint32 m) +{ +int32 i; + +m = m & 0xFF; /* 8 bit mask */ +for (i = 0; m != 0; m = m >> 1, i++) { + if (m & 1) op = op & ~byte_mask[i]; + } +return op; +} + +/* 64b * 64b unsigned multiply */ + +t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi) +{ +t_uint64 ahi, alo, bhi, blo, rhi, rmid1, rmid2, rlo; + +ahi = (a >> 32) & M32; +alo = a & M32; +bhi = (b >> 32) & M32; +blo = b & M32; +rhi = ahi * bhi; +rmid1 = ahi * blo; +rmid2 = alo * bhi; +rlo = alo * blo; +rhi = rhi + ((rmid1 >> 32) & M32) + ((rmid2 >> 32) & M32); +rmid1 = (rmid1 << 32) & M64; +rmid2 = (rmid2 << 32) & M64; +rlo = (rlo + rmid1) & M64; +if (rlo < rmid1) rhi = rhi + 1; +rlo = (rlo + rmid2) & M64; +if (rlo < rmid2) rhi = rhi + 1; +if (hi) *hi = rhi & M64; +return rlo; +} + +/* 64b / 64b unsigned fraction divide */ + +t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky) +{ +t_uint64 quo; +uint32 i; + +quo = 0; /* clear quotient */ +for (i = 0; (i < prec) && dvd; i++) { /* divide loop */ + quo = quo << 1; /* shift quo */ + if (dvd >= dvr) { /* div step ok? */ + dvd = dvd - dvr; /* subtract */ + quo = quo + 1; /* quo bit = 1 */ + } + dvd = dvd << 1; /* shift divd */ + } +quo = quo << (UF_V_NM - i + 1); /* shift quo */ +if (sticky) *sticky = (dvd? 1: 0); /* set sticky bit */ +return quo; /* return quotient */ +} + +/* Set arithmetic trap */ + +void arith_trap (uint32 mask, uint32 ir) +{ +uint32 rc = I_GETRC (ir); + +trap_summ = trap_summ | mask; +if (ir & I_FTRP_S) trap_summ = trap_summ | TRAP_SWC; +if ((mask & TRAP_IOV) == 0) rc = rc + 32; +trap_mask = trap_mask | ((t_uint64) 1u << rc); +return; +} + +/* Reset */ + +t_stat cpu_reset (DEVICE *dptr) +{ +R[31] = 0; +FR[31] = 0; +pal_mode = 1; +dmapen = 0; +fpen = 1; +vax_flag = 0; +lock_flag = 0; +trap_summ = 0; +trap_mask = 0; +if (M == NULL) M = (t_uint64 *) calloc (((uint32) MEMSIZE) >> 3, sizeof (t_uint64)); +if (M == NULL) return SCPE_MEM; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r->qptr = 0; +else return SCPE_IERR; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; +} + +/* Bootstrap */ + +t_stat cpu_boot (int32 unitno, DEVICE *dptr) +{ +return SCPE_ARG; +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if (vptr == NULL) return SCPE_ARG; +if (sw & SWMASK ('V') && dmapen) { + addr = trans_c (addr); + if (addr == M64) return STOP_MME; + } +if (ADDR_IS_MEM (addr)) { + *vptr = ReadPQ (addr); + return SCPE_OK; + } +return SCPE_NXM; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if (sw & SWMASK ('V') && dmapen) { + addr = trans_c (addr); + if (addr == M64) return STOP_MME; + } +if (ADDR_IS_MEM (addr)) { + WritePQ (addr, val); + return SCPE_OK; + } +return SCPE_NXM; +} + +/* Memory allocation */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +t_uint64 mc = 0; +uint32 i, clim; +t_uint64 *nM = NULL; + +for (i = val; i < MEMSIZE; i = i + 8) mc = mc | M[i >> 3]; +if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) + return SCPE_OK; +nM = (t_uint64 *) calloc (val >> 3, sizeof (t_uint64)); +if (nM == NULL) return SCPE_MEM; +clim = (uint32) ((((uint32) val) < MEMSIZE)? val: MEMSIZE); +for (i = 0; i < clim; i = i + 8) nM[i >> 3] = M[i >>3]; +free (M); +M = nM; +MEMSIZE = val; +return SCPE_OK; +} + +/* Show virtual address */ + +t_stat cpu_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +t_stat r; +char *cptr = (char *) desc; +t_uint64 va, pa; + +if (cptr) { + DEVICE *dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + va = get_uint (cptr, 16, M64, &r); + if (r == SCPE_OK) { + pa = trans_c (va); + if (pa == M64) { + fprintf (of, "Translation error\n"); + return SCPE_OK; + } + fputs ("Virtual ", of); + fprint_val (of, va, 16, 64, PV_LEFT); + fputs (" = physical ", of); + fprint_val (of, pa, 16, 64, PV_LEFT); + fputc ('\n', of); + return SCPE_OK; + } + } +fprintf (of, "Invalid argument\n"); +return SCPE_OK; +} + +/* Set history */ + +t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 i, lnt; +t_stat r; + +if (cptr == NULL) { + for (i = 0; i < hst_lnt; i++) hst[i].pc = 0; + hst_p = 0; + return SCPE_OK; + } +lnt = (uint32) get_uint (cptr, 10, HIST_MAX, &r); +if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG; +hst_p = 0; +if (hst_lnt) { + free (hst); + hst_lnt = 0; + hst = NULL; + } +if (lnt) { + hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); + if (hst == NULL) return SCPE_MEM; + hst_lnt = lnt; + } +return SCPE_OK; +} + +/* Print instruction trace */ + +t_stat cpu_fprint_one_inst (FILE *st, uint32 ir, t_uint64 pc, t_uint64 ra, t_uint64 rb) +{ +uint32 op; +t_value sim_val; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); + +static const h_fmt[64] = { + 0, 0, 0, 0, 0, 0, 0, 0, + H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, + H_IOP, H_IOP, H_IOP, H_IOP, H_FOP, H_FOP, H_FOP, H_FOP, + 0, H_PAL, H_JMP, H_PAL, H_FOP, H_PAL, H_PAL, H_PAL, + H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, + H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, H_MRF, + H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, + H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA, H_BRA + }; + +pc = pc & ~HIST_PC; +fprint_val (st, pc, 16, 64, PV_RZRO); +fputc (' ', st); +op = I_GETOP (ir); /* get opcode */ +if (h_fmt[op] & H_A) fprint_val (st, ra, 16, 64, PV_RZRO); +else fputs (" ", st); +fputc (' ', st); +if (h_fmt[op] & H_B) { /* Rb? */ + t_uint64 rbv; + if ((h_fmt[op] & H_B_LIT) && (ir & I_ILIT)) + rbv = I_GETLIT8 (ir); /* literal? rbv = lit */ + else rbv = rb; /* no, rbv = R[rb] */ + fprint_val (st, rbv, 16, 64, PV_RZRO); + } +else fputs (" ", st); +fputc (' ', st); +if (h_fmt[op] & H_EA) { /* ea? */ + t_uint64 ea; + if (h_fmt[op] & H_EA_L16) ea = ir & M16; + else if (h_fmt[op] & H_EA_B) + ea = (pc + (SEXT_BDSP (I_GETBDSP (ir)) << 2)) & M64; + else ea = (rb + SEXT_MDSP (I_GETMDSP (ir))) & M64; + fprint_val (st, ea, 16, 64, PV_RZRO); + } +else fputs (" ", st); +fputc (' ', st); +if (pc & 4) sim_val = ((t_uint64) ir) << 32; +else sim_val = ir; +if ((fprint_sym (st, pc & ~03, &sim_val, &cpu_unit, SWMASK ('M'))) > 0) + fprintf (st, "(undefined) %08X", ir); +fputc ('\n', st); /* end line */ +return SCPE_OK; +} + +/* Show history */ + +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +uint32 k, di, lnt; +char *cptr = (char *) desc; +t_stat r; +InstHistory *h; + +if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */ +if (cptr) { + lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); + if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; + } +else lnt = hst_lnt; +di = hst_p - lnt; /* work forward */ +if (di < 0) di = di + hst_lnt; +fprintf (st, "PC Ra Rb IR\n\n"); +for (k = 0; k < lnt; k++) { /* print specified */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + if (h->pc & HIST_PC) { /* instruction? */ + cpu_fprint_one_inst (st, h->ir, h->pc, h->ra, h->rb); + } /* end if */ + } /* end for */ +return SCPE_OK; +} diff --git a/alpha/alpha_defs.h b/alpha/alpha_defs.h new file mode 100644 index 00000000..6f1ee907 --- /dev/null +++ b/alpha/alpha_defs.h @@ -0,0 +1,457 @@ +/* alpha_defs.h: Alpha architecture definitions file + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + Respectfully dedicated to the great people of the Alpha chip, systems, and + software development projects; and to the memory of Peter Conklin, of the + Alpha Program Office. +*/ + +#ifndef _ALPHA_DEFS_H_ +#define _ALPHA_DEFS_H_ 0 + +#include "sim_defs.h" +#include + +#if defined (__GNUC__) +#define INLINE inline +#else +#define INLINE +#endif + +/* Configuration */ + +#define INITMEMSIZE (1 << 24) /* !!debug!! */ +#define MEMSIZE (cpu_unit.capac) +#define ADDR_IS_MEM(x) ((x) < MEMSIZE) +#define DEV_DIB (1u << (DEV_V_UF + 0)) /* takes a DIB */ + +/* Simulator stops */ + +#define STOP_HALT 1 /* halt */ +#define STOP_IBKPT 2 /* breakpoint */ +#define STOP_NSPAL 3 /* non-supported PAL */ +#define STOP_KSNV 4 /* kernel stk inval */ +#define STOP_INVABO 5 /* invalid abort code */ +#define STOP_MME 6 /* console mem mgt error */ + +/* Bit patterns */ + +#define M8 0xFF +#define M16 0xFFFF +#define M32 0xFFFFFFFF +#define M64 0xFFFFFFFFFFFFFFFF +#define B_SIGN 0x80 +#define W_SIGN 0x8000 +#define L_SIGN 0x80000000 +#define Q_SIGN 0x8000000000000000 +#define Q_GETSIGN(x) (((uint32) ((x) >> 63)) & 1) + +/* Architectural variants */ + +#define AMASK_BWX 0x0001 /* byte/word */ +#define AMASK_FIX 0x0002 /* sqrt/flt-int moves */ +#define AMASK_CIX 0x0004 /* counts */ +#define AMASK_MVI 0x0100 /* multimedia */ +#define AMASK_PRC 0x0200 /* precise exceptions */ +#define AMASK_PFM 0x1000 /* prefetch w modify */ + +#define IMPLV_EV4 0x0 /* EV4 (21064) */ +#define IMPLV_EV5 0x1 /* EV5 (21164) */ +#define IMPLV_EV6 0x2 /* EV6 (21264) */ +#define IMPLV_EV7 0x3 /* EV7 (21364) */ + +/* Instruction formats */ + +#define I_V_OP 26 /* opcode */ +#define I_M_OP 0x3F +#define I_OP (I_M_OP << I_V_OP) +#define I_V_RA 21 /* Ra */ +#define I_M_RA 0x1F +#define I_V_RB 16 /* Rb */ +#define I_M_RB 0x1F +#define I_V_FTRP 13 /* floating trap mode */ +#define I_M_FTRP 0x7 +#define I_FTRP (I_M_FTRP << I_V_FTRP) +#define I_F_VAXRSV 0x4800 /* VAX reserved */ +#define I_FTRP_V 0x2000 /* /V trap */ +#define I_FTRP_U 0x2000 /* /U trap */ +#define I_FTRP_S 0x8000 /* /S trap */ +#define I_FTRP_SUI 0xE000 /* /SUI trap */ +#define I_FTRP_SVI 0xE000 /* /SVI trap */ +#define I_V_FRND 11 /* floating round mode */ +#define I_M_FRND 0x3 +#define I_FRND (I_M_FRND << I_V_FRND) +#define I_FRND_C 0 /* chopped */ +#define I_FRND_M 1 /* to minus inf */ +#define I_FRND_N 2 /* normal */ +#define I_FRND_D 3 /* dynamic */ +#define I_FRND_P 3 /* in FPCR: plus inf */ +#define I_V_FSRC 9 /* floating source */ +#define I_M_FSRC 0x3 +#define I_FSRC (I_M_FSRC << I_V_FSRC) +#define I_FSRC_X 0x0200 /* data type X */ +#define I_V_FFNC 5 /* floating function */ +#define I_M_FFNC 0x3F +#define I_V_LIT8 13 /* integer 8b literal */ +#define I_M_LIT8 0xFF +#define I_V_ILIT 12 /* literal flag */ +#define I_ILIT (1u << I_V_ILIT) +#define I_V_IFNC 5 /* integer function */ +#define I_M_IFNC 0x3F +#define I_V_RC 0 /* Rc */ +#define I_M_RC 0x1F +#define I_V_MDSP 0 /* memory displacement */ +#define I_M_MDSP 0xFFFF +#define I_V_BDSP 0 +#define I_M_BDSP 0x1FFFFF /* branch displacement */ +#define I_V_PALOP 0 +#define I_M_PALOP 0x3FFFFFF /* PAL subopcode */ +#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP) +#define I_GETRA(x) (((x) >> I_V_RA) & I_M_RA) +#define I_GETRB(x) (((x) >> I_V_RB) & I_M_RB) +#define I_GETLIT8(x) (((x) >> I_V_LIT8) & I_M_LIT8) +#define I_GETIFNC(x) (((x) >> I_V_IFNC) & I_M_IFNC) +#define I_GETFRND(x) (((x) >> I_V_FRND) & I_M_FRND) +#define I_GETFFNC(x) (((x) >> I_V_FFNC) & I_M_FFNC) +#define I_GETRC(x) (((x) >> I_V_RC) & I_M_RC) +#define I_GETMDSP(x) (((x) >> I_V_MDSP) & I_M_MDSP) +#define I_GETBDSP(x) (((x) >> I_V_BDSP) & I_M_BDSP) +#define I_GETPAL(x) (((x) >> I_V_PALOP) & I_M_PALOP) + +/* Floating point types */ + +#define DT_F 0 /* type F */ +#define DT_G 1 /* type G */ +#define DT_S 0 /* type S */ +#define DT_T 1 /* type T */ + +/* Floating point memory format (VAX F) */ + +#define F_V_SIGN 15 +#define F_SIGN (1u << F_V_SIGN) +#define F_V_EXP 7 +#define F_M_EXP 0xFF +#define F_BIAS 0x80 +#define F_EXP (F_M_EXP << F_V_EXP) +#define F_V_FRAC 29 +#define F_GETEXP(x) ((uint32) (((x) >> F_V_EXP) & F_M_EXP)) +#define SWAP_VAXF(x) ((((x) >> 16) & 0xFFFF) | (((x) & 0xFFFF) << 16)) + +/* Floating point memory format (VAX G) */ + +#define G_V_SIGN 15 +#define G_SIGN (1u << F_V_SIGN) +#define G_V_EXP 4 +#define G_M_EXP 0x7FF +#define G_BIAS 0x400 +#define G_EXP (G_M_EXP << G_V_EXP) +#define G_GETEXP(x) ((uint32) (((x) >> G_V_EXP) & G_M_EXP)) +#define SWAP_VAXG(x) ((((x) & 0x000000000000FFFF) << 48) | \ + (((x) & 0x00000000FFFF0000) << 16) | \ + (((x) >> 16) & 0x00000000FFFF0000) | \ + (((x) >> 48) & 0x000000000000FFFF)) + +/* Floating memory format (IEEE S) */ + +#define S_V_SIGN 31 +#define S_SIGN (1u << S_V_SIGN) +#define S_V_EXP 23 +#define S_M_EXP 0xFF +#define S_BIAS 0x7F +#define S_NAN 0xFF +#define S_EXP (S_M_EXP << S_V_EXP) +#define S_V_FRAC 29 +#define S_GETEXP(x) ((uint32) (((x) >> S_V_EXP) & S_M_EXP)) + +/* Floating point memory format (IEEE T) */ + +#define T_V_SIGN 63 +#define T_SIGN 0x8000000000000000 +#define T_V_EXP 52 +#define T_M_EXP 0x7FF +#define T_BIAS 0x3FF +#define T_NAN 0x7FF +#define T_EXP 0x7FF0000000000000 +#define T_FRAC 0x000FFFFFFFFFFFFF +#define T_GETEXP(x) ((uint32) (((uint32) ((x) >> T_V_EXP)) & T_M_EXP)) + +/* Floating point register format (all except VAX D) */ + +#define FPR_V_SIGN 63 +#define FPR_SIGN 0x8000000000000000 +#define FPR_V_EXP 52 +#define FPR_M_EXP 0x7FF +#define FPR_NAN 0x7FF +#define FPR_EXP 0x7FF0000000000000 +#define FPR_HB 0x0010000000000000 +#define FPR_FRAC 0x000FFFFFFFFFFFFF +#define FPR_GUARD (UF_V_NM - FPR_V_EXP) +#define FPR_GETSIGN(x) (((uint32) ((x) >> FPR_V_SIGN)) & 1) +#define FPR_GETEXP(x) (((uint32) ((x) >> FPR_V_EXP)) & FPR_M_EXP) +#define FPR_GETFRAC(x) ((x) & FPR_FRAC) + +#define FP_TRUE 0x4000000000000000 /* 0.5/2.0 in reg */ + +/* Floating point register format (VAX D) */ + +#define FDR_V_SIGN 63 +#define FDR_SIGN 0x8000000000000000 +#define FDR_V_EXP 55 +#define FDR_M_EXP 0xFF +#define FDR_EXP 0x7F80000000000000 +#define FDR_HB 0x0080000000000000 +#define FDR_FRAC 0x007FFFFFFFFFFFFF +#define FDR_GUARD (UF_V_NM - FDR_V_EXP) +#define FDR_GETSIGN(x) (((uint32) ((x) >> FDR_V_SIGN)) & 1) +#define FDR_GETEXP(x) (((uint32) ((x) >> FDR_V_EXP)) & FDR_M_EXP) +#define FDR_GETFRAC(x) ((x) & FDR_FRAC) + +#define D_BIAS 0x80 + +/* Unpacked floating point number */ + +typedef struct { + uint32 sign; + int32 exp; + t_uint64 frac; + } UFP; + +#define UF_V_NM 63 +#define UF_NM 0x8000000000000000 /* normalized */ + +/* IEEE control register (left 32b only) */ + +#define FPCR_SUM 0x80000000 /* summary */ +#define FPCR_INED 0x40000000 /* inexact disable */ +#define FPCR_UNFD 0x20000000 /* underflow disable */ +#define FPCR_UNDZ 0x10000000 /* underflow to 0 */ +#define FPCR_V_RMOD 26 /* rounding mode */ +#define FPCR_M_RMOD 0x3 +#define FPCR_IOV 0x02000000 /* integer overflow */ +#define FPCR_INE 0x01000000 /* inexact */ +#define FPCR_UNF 0x00800000 /* underflow */ +#define FPCR_OVF 0x00400000 /* overflow */ +#define FPCR_DZE 0x00200000 /* div by zero */ +#define FPCR_INV 0x00100000 /* invalid operation */ +#define FPCR_OVFD 0x00080000 /* overflow disable */ +#define FPCR_DZED 0x00040000 /* div by zero disable */ +#define FPCR_INVD 0x00020000 /* invalid op disable */ +#define FPCR_DNZ 0x00010000 /* denormal to zero */ +#define FPCR_DNOD 0x00008000 /* denormal disable */ +#define FPCR_RAZ 0x00007FFF /* zero */ +#define FPCR_ERR (FPCR_IOV|FPCR_INE|FPCR_UNF|FPCR_OVF|FPCR_DZE|FPCR_INV) +#define FPCR_GETFRND(x) (((x) >> FPCR_V_RMOD) & FPCR_M_RMOD) + +/* PTE - hardware format */ + +#define PTE_V_PFN 32 /* PFN */ +#define PFN_MASK 0xFFFFFFFF +#define PTE_V_UWE 15 /* write enables */ +#define PTE_V_SWE 14 +#define PTE_V_EWE 13 +#define PTE_V_KWE 12 +#define PTE_V_URE 11 /* read enables */ +#define PTE_V_SRE 10 +#define PTE_V_ERE 9 +#define PTE_V_KRE 8 +#define PTE_V_GH 5 /* granularity hint */ +#define PTE_M_GH 0x3 +#define PTE_GH (PTE_M_GH << PTE_V_GH) +#define PTE_V_ASM 4 /* address space match */ +#define PTE_V_FOE 3 /* fault on execute */ +#define PTE_V_FOW 2 /* fault on write */ +#define PTE_V_FOR 1 /* fault on read */ +#define PTE_V_V 0 /* valid */ +#define PTE_UWE (1u << PTE_V_UWE) +#define PTE_SWE (1u << PTE_V_SWE) +#define PTE_EWE (1u << PTE_V_EWE) +#define PTE_KWE (1u << PTE_V_KWE) +#define PTE_URE (1u << PTE_V_URE) +#define PTE_SRE (1u << PTE_V_SRE) +#define PTE_ERE (1u << PTE_V_ERE) +#define PTE_KRE (1u << PTE_V_KRE) +#define PTE_ASM (1u << PTE_V_ASM) +#define PTE_FOE (1u << PTE_V_FOE) +#define PTE_FOW (1u << PTE_V_FOW) +#define PTE_FOR (1u << PTE_V_FOR) +#define PTE_V (1u << PTE_V_V) +#define PTE_MASK 0xFF7F +#define PTE_GETGH(x) ((((uint32) (x)) >> PTE_V_GH) & PTE_M_GH) +#define VPN_GETLVL1(x) (((x) >> ((2 * VA_N_LVL) - 3)) & (VA_M_LVL << 3)) +#define VPN_GETLVL2(x) (((x) >> (VA_N_LVL - 3)) & (VA_M_LVL << 3)) +#define VPN_GETLVL3(x) (((x) << 3) & (VA_M_LVL << 3)) + +#define ACC_E(m) ((PTE_KRE << (m)) | PTE_FOE | PTE_V) +#define ACC_R(m) ((PTE_KRE << (m)) | PTE_FOR | PTE_V) +#define ACC_W(m) ((PTE_KWE << (m)) | PTE_FOW | PTE_V) +#define ACC_M(m) (((PTE_KRE|PTE_KWE) << (m)) | PTE_FOR | PTE_FOW | PTE_V) + +/* Exceptions */ + +#define ABORT(x) longjmp (save_env, (x)) +#define ABORT1(x,y) { p1 = (x); longjmp (save_env, (y)); } + +#define EXC_RSVI 0x01 /* reserved instruction */ +#define EXC_RSVO 0x02 /* reserved operand */ +#define EXC_ALIGN 0x03 /* operand alignment */ +#define EXC_FPDIS 0x04 /* flt point disabled */ +#define EXC_TBM 0x08 /* TLB miss */ +#define EXC_FOX 0x10 /* fault on r/w/e */ +#define EXC_ACV 0x14 /* access control viol */ +#define EXC_TNV 0x18 /* translation not valid */ +#define EXC_BVA 0x1C /* bad address format */ +#define EXC_E 0x00 /* offset for execute */ +#define EXC_R 0x01 /* offset for read */ +#define EXC_W 0x02 /* offset for write */ + +/* Traps - corresponds to arithmetic trap summary register */ + +#define TRAP_SWC 0x001 /* software completion */ +#define TRAP_INV 0x002 /* invalid operand */ +#define TRAP_DZE 0x004 /* divide by zero */ +#define TRAP_OVF 0x008 /* overflow */ +#define TRAP_UNF 0x010 /* underflow */ +#define TRAP_INE 0x020 /* inexact */ +#define TRAP_IOV 0x040 /* integer overflow */ +#define TRAP_SUMM_RW 0x07F + +/* PALcode */ + +#define SP R[30] /* stack pointer */ +#define MODE_K 0 /* kernel */ +#define MODE_E 1 /* executive (UNIX user) */ +#define MODE_S 2 /* supervisor */ +#define MODE_U 3 /* user */ + +#define PAL_UNDF 0 /* undefined */ +#define PAL_VMS 1 /* VMS */ +#define PAL_UNIX 2 /* UNIX */ +#define PAL_NT 3 /* Windows NT */ + +/* Machine check error summary register */ + +#define MCES_INP 0x01 /* in progress */ +#define MCES_SCRD 0x02 /* sys corr in prog */ +#define MCES_PCRD 0x04 /* proc corr in prog */ +#define MCES_DSCRD 0x08 /* disable system corr */ +#define MCES_DPCRD 0x10 /* disable proc corr */ +#define MCES_W1C (MCES_INP|MCES_SCRD|MCES_PCRD) +#define MCES_DIS (MCES_DSCRD|MCES_DPCRD) + +/* I/O devices */ + +#define L_BYTE 0 /* IO request lengths */ +#define L_WORD 1 +#define L_LONG 2 +#define L_QUAD 3 + +/* Device information block */ + +typedef struct { /* device info block */ + t_uint64 low; /* low addr */ + t_uint64 high; /* high addr */ + t_bool (*read)(t_uint64 pa, t_uint64 *val, uint32 lnt); + t_bool (*write)(t_uint64 pa, t_uint64 val, uint32 lnt); + uint32 ipl; + } DIB; + +/* Interrupt system - 6 levels in EV4 and EV6, 4 in EV5 - software expects 4 */ + +#define IPL_HMAX 0x17 /* highest hwre level */ +#define IPL_HMIN 0x14 /* lowest hwre level */ +#define IPL_HLVL (IPL_HMAX - IPL_HMIN + 1) /* # hardware levels */ +#define IPL_SMAX 0x0F /* highest swre level */ + +/* Macros */ + +#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 - 4) & M64 + +#define SEXT_B_Q(x) (((x) & B_SIGN)? ((x) | ~((t_uint64) M8)): ((x) & M8)) +#define SEXT_W_Q(x) (((x) & W_SIGN)? ((x) | ~((t_uint64) M16)): ((x) & M16)) +#define SEXT_L_Q(x) (((x) & L_SIGN)? ((x) | ~((t_uint64) M32)): ((x) & M32)) +#define NEG_Q(x) ((~(x) + 1) & M64) +#define ABS_Q(x) (((x) & Q_SIGN)? NEG_Q (x): (x)) + +#define SIGN_BDSP 0x100000 +#define SIGN_MDSP 0x008000 +#define SEXT_MDSP(x) (((x) & SIGN_MDSP)? \ + ((x) | ~((t_uint64) I_M_MDSP)): ((x) & I_M_MDSP)) +#define SEXT_BDSP(x) (((x) & SIGN_BDSP)? \ + ((x) | ~((t_uint64) I_M_BDSP)): ((x) & I_M_BDSP)) + +/* Opcodes */ + +enum opcodes { + OP_PAL, OP_OPC01, OP_OPC02, OP_OPC03, + OP_OPC04, OP_OPC05, OP_OPC06, OP_OPC07, + OP_LDA, OP_LDAH, OP_LDBU, OP_LDQ_U, + OP_LDWU, OP_STW, OP_STB, OP_STQ_U, + OP_IALU, OP_ILOG, OP_ISHFT, OP_IMUL, + OP_IFLT, OP_VAX, OP_IEEE, OP_FP, + OP_MISC, OP_PAL19, OP_JMP, OP_PAL1B, + OP_FLTI, OP_PAL1D, OP_PAL1E, OP_PAL1F, + OP_LDF, OP_LDG, OP_LDS, OP_LDT, + OP_STF, OP_STG, OP_STS, OP_STT, + OP_LDL, OP_LDQ, OP_LDL_L, OP_LDQ_L, + OP_STL, OP_STQ, OP_STL_C, OP_STQ_C, + OP_BR, OP_FBEQ, OP_FBLT, OP_FBLE, + OP_BSR, OP_FBNE, OP_FBGE, OP_FBGT, + OP_BLBC, OP_BEQ, OP_BLT, OP_BLE, + OP_BLBS, OP_BNE, OP_BGE, OP_BGT + }; + +/* Function prototypes */ + +uint32 ReadI (t_uint64 va); +t_uint64 ReadB (t_uint64 va); +t_uint64 ReadW (t_uint64 va); +t_uint64 ReadL (t_uint64 va); +t_uint64 ReadQ (t_uint64 va); +t_uint64 ReadAccL (t_uint64 va, uint32 acc); +t_uint64 ReadAccQ (t_uint64 va, uint32 acc); +INLINE t_uint64 ReadPB (t_uint64 pa); +INLINE t_uint64 ReadPW (t_uint64 pa); +INLINE t_uint64 ReadPL (t_uint64 pa); +INLINE t_uint64 ReadPQ (t_uint64 pa); +t_bool ReadIO (t_uint64 pa, t_uint64 *val, uint32 lnt); +void WriteB (t_uint64 va, t_uint64 dat); +void WriteW (t_uint64 va, t_uint64 dat); +void WriteL (t_uint64 va, t_uint64 dat); +void WriteQ (t_uint64 va, t_uint64 dat); +void WriteAccL (t_uint64 va, t_uint64 dat, uint32 acc); +void WriteAccQ (t_uint64 va, t_uint64 dat, uint32 acc); +INLINE void WritePB (t_uint64 pa, t_uint64 dat); +INLINE void WritePW (t_uint64 pa, t_uint64 dat); +INLINE void WritePL (t_uint64 pa, t_uint64 dat); +INLINE void WritePQ (t_uint64 pa, t_uint64 dat); +t_bool WriteIO (t_uint64 pa, t_uint64 val, uint32 lnt); +uint32 mmu_set_cm (uint32 mode); +void mmu_set_icm (uint32 mode); +void mmu_set_dcm (uint32 mode); +void arith_trap (uint32 trap, uint32 ir); + +#endif diff --git a/alpha/alpha_ev5_cons.c b/alpha/alpha_ev5_cons.c new file mode 100644 index 00000000..fb576705 --- /dev/null +++ b/alpha/alpha_ev5_cons.c @@ -0,0 +1,143 @@ +/* alpha_ev5_cons.c - Alpha console support routines for EV5 + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "alpha_defs.h" +#include "alpha_ev5_defs.h" + +t_uint64 srm_ptbr = 1; + +extern uint32 dtlb_spage; +extern uint32 pal_type; +extern uint32 ev5_mcsr; +extern t_uint64 *M; +extern t_uint64 ev5_mvptbr; +extern UNIT cpu_unit; + +/* Local quadword physical read - exceptions or IO space lookups */ + +t_stat l_ReadPQ (t_uint64 pa, t_uint64 *dat) +{ +if (ADDR_IS_MEM (pa)) { + *dat = M[pa >> 3]; + return TRUE; + } +return FALSE; +} + +/* "SRM" 3-level pte lookup + + Inputs: + va = virtual address + *pte = pointer to pte to be returned + Output: + status = 0 for successful fill + EXC_ACV for ACV on intermediate level + EXC_TNV for TNV on intermediate level +*/ + +uint32 cons_find_pte_srm (t_uint64 va, t_uint64 *l3pte) +{ +t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte; +uint32 vpte_vpn; +TLBENT *vpte_p; + +vptea = FMT_MVA_VMS (va); /* try virt lookup */ +vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ +vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ +if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) + l3ptea = PHYS_ADDR (vpte_p->pfn, vptea); +else { + uint32 vpn = VA_GETVPN (va); + if (srm_ptbr & 1) return 1; /* uninitialized? */ + l1ptea = srm_ptbr + VPN_GETLVL1 (vpn); + if (!l_ReadPQ (l1ptea, &l1pte)) return 1; + if ((l1pte & PTE_V) == 0) + return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l2ptea = l2ptea + VPN_GETLVL2 (vpn); + if (!l_ReadPQ (l2ptea, &l2pte)) return 1; + if ((l2pte & PTE_V) == 0) + return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l3ptea = l3ptea + VPN_GETLVL3 (vpn); + } +if (!l_ReadPQ (l3ptea, l3pte)) return 1; +return 0; +} + +/* NT 2-level pte lookup + + Inputs: + va = virtual address + *pte = pointer to pte to be returned + Output: + status = 0 for successful fill + EXC_ACV for ACV on intermediate level + EXC_TNV for TNV on intermediate level +*/ + +uint32 cons_find_pte_nt (t_uint64 va, t_uint64 *l3pte) +{ +t_uint64 vptea, l3ptea; +uint32 vpte_vpn; +TLBENT *vpte_p; + +vptea = FMT_MVA_NT (va); /* try virt lookup */ +vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ +vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ +if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) + l3ptea = PHYS_ADDR (vpte_p->pfn, vptea); +else { + return 1; /* for now */ + } +if (!l_ReadPQ (l3ptea, l3pte)) return 1; +return 0; +} + +/* Translate address for console access */ + +t_uint64 trans_c (t_uint64 va) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +TLBENT *tlbp; +t_uint64 pte64; +uint32 exc, pfn; + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ + return M64; +if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) + return (va & SP43_MASK); /* 43b superpage? */ +if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) + return (va & SP32_MASK); /* 32b superpage? */ +if (tlbp = dtlb_lookup (vpn)) /* try TLB */ + return PHYS_ADDR (tlbp->pfn, va); /* found it */ +if (ev5_mcsr & MCSR_NT) exc = cons_find_pte_nt (va, &pte64); +else exc = cons_find_pte_srm (va, &pte64); +if (exc || ((pte64 & PTE_V) == 0)) return M64; /* check valid */ +pfn = (uint32) (pte64 >> 32) & M32; +return PHYS_ADDR (pfn, va); /* return phys addr */ +} diff --git a/alpha/alpha_ev5_defs.h b/alpha/alpha_ev5_defs.h new file mode 100644 index 00000000..cba29614 --- /dev/null +++ b/alpha/alpha_ev5_defs.h @@ -0,0 +1,428 @@ +/* alpha_ev5_defs.h: Alpha EV5 chip definitions file + + Copyright (c) 2003-2005, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + Respectfully dedicated to the great people of the Alpha chip, systems, and + software development projects; and to the memory of Peter Conklin, of the + Alpha Program Office. +*/ + +#ifndef _ALPHA_EV5_DEFS_H_ +#define _ALPHA_EV5_DEFS_H_ 0 + +/* Address limits */ + +#define VA_SIZE 43 /* VA size */ +#define NTVA_WIDTH 32 /* VA width for NT */ +#define VA_MASK 0x000007FFFFFFFFFF +#define EV5_PA_SIZE 40 /* PA size */ +#define EV5_PA_MASK 0x000000FFFFFFFFFF + +/* Virtual address */ + +#define VA_N_OFF 13 /* offset size */ +#define VA_PAGSIZE (1u << VA_N_OFF) /* page size */ +#define VA_M_OFF ((1u << VA_N_OFF) - 1) /* offset mask */ +#define VA_N_LVL 10 /* width per level */ +#define VA_M_LVL ((1u << VA_N_LVL) - 1) /* level mask */ +#define VA_V_VPN VA_N_OFF /* vpn start */ +#define VA_N_VPN (VA_N_LVL * 3) /* vpn size */ +#define VA_M_VPN ((1u << VA_N_VPN) - 1) /* vpn mask */ +#define VA_WIDTH (VA_N_VPN + VA_N_OFF) /* total VA size */ +#define VA_V_SEXT (VA_WIDTH - 1) /* sext start */ +#define VA_M_SEXT ((1u << (64 - VA_V_SEXT)) - 1) /* sext mask */ +#define VA_GETOFF(x) (((uint32) (x)) & VA_M_OFF) +#define VA_GETVPN(x) (((uint32) ((x) >> VA_V_VPN)) & VA_M_VPN) +#define VA_GETSEXT(x) (((uint32) ((x) >> VA_V_SEXT)) & VA_M_SEXT) +#define PHYS_ADDR(p,v) ((((t_uint64) (p)) < VA_N_OFF) | VA_GETOFF (v)) + +/* 43b and 32b superpages - present in all implementations */ + +#define SPEN_43 0x2 +#define SPEN_32 0x1 +#define SP43_MASK 0x000001FFFFFFFFFF +#define SP32_MASK 0x000000003FFFFFFF +#define VPN_GETSP43(x) ((uint32) (((x) >> (VA_WIDTH - VA_N_OFF - 2)) & 3)) +#define VPN_GETSP32(x) ((uint32) (((x) >> (NTVA_WIDTH - VA_N_OFF - 2)) & 0x1FFF)) + +/* TLBs */ + +#define INV_TAG M32 +#define ITLB_SIZE 48 +#define DTLB_SIZE 64 +#define ITLB_WIDTH 6 +#define DTLB_WIDTH 6 + +#define TLB_CI 0x1 /* clear I */ +#define TLB_CD 0x2 /* clear D */ +#define TLB_CA 0x4 /* clear all */ + +typedef struct { + uint32 tag; /* tag */ + uint8 asn; /* addr space # */ + uint8 idx; /* entry # */ + uint16 gh_mask; /* gh mask */ + uint32 pfn; /* pfn */ + uint32 pte; /* swre/pte */ + } TLBENT; + +/* Register shadow */ + +#define PALSHAD_SIZE 8 +#define PAL_USE_SHADOW \ + ev5_palsave[0] = R[8]; ev5_palsave[1] = R[9]; \ + ev5_palsave[2] = R[10]; ev5_palsave[3] = R[11]; \ + ev5_palsave[4] = R[12]; ev5_palsave[5] = R[13]; \ + ev5_palsave[6] = R[14]; ev5_palsave[7] = R[25]; \ + R[8] = ev5_palshad[0]; R[9] = ev5_palshad[1]; \ + R[10] = ev5_palshad[2]; R[11] = ev5_palshad[3]; \ + R[12] = ev5_palshad[4]; R[13] = ev5_palshad[5]; \ + R[14] = ev5_palshad[6]; R[25] = ev5_palshad[7] +#define PAL_USE_MAIN \ + ev5_palshad[0] = R[8]; ev5_palshad[1] = R[9]; \ + ev5_palshad[2] = R[10]; ev5_palshad[3] = R[11]; \ + ev5_palshad[4] = R[12]; ev5_palshad[5] = R[13]; \ + ev5_palshad[6] = R[14]; ev5_palshad[7] = R[25]; \ + R[8] = ev5_palsave[0]; R[9] = ev5_palsave[1]; \ + R[10] = ev5_palsave[2]; R[11] = ev5_palsave[3]; \ + R[12] = ev5_palsave[4]; R[13] = ev5_palsave[5]; \ + R[14] = ev5_palsave[6]; R[25] = ev5_palsave[7] + +/* PAL instructions */ + +#define HW_MFPR 0x19 +#define HW_LD 0x1B +#define HW_MTPR 0x1D +#define HW_REI 0x1E +#define HW_ST 0x1F + +#define HW_LD_V 0x8000 +#define HW_LD_ALT 0x4000 +#define HW_LD_WCH 0x2000 +#define HW_LD_Q 0x1000 +#define HW_LD_PTE 0x0800 +#define HW_LD_LCK 0x0400 +#define HW_LD_DSP 0x03FF +#define SIGN_HW_LD_DSP 0x0200 +#define HW_LD_GETDSP(x) ((x) & HW_LD_DSP) +#define SEXT_HW_LD_DSP(x) (((x) & SIGN_HW_LD_DSP)? \ + ((x) | ~((t_uint64) HW_LD_DSP)): ((x) & HW_LD_DSP)) + +#define HW_REI_S 0x4000 + +/* PAL entry offsets */ + +#define PALO_RESET 0x0000 +#define PALO_IACV 0x0080 +#define PALO_INTR 0x0100 +#define PALO_ITBM 0x0180 +#define PALO_DTBM 0x0200 +#define PALO_DTBM_D 0x0280 +#define PALO_ALGN 0x0300 +#define PALO_DFLT 0x0380 +#define PALO_MCHK 0x0400 +#define PALO_RSVI 0x0480 +#define PALO_TRAP 0x0500 +#define PALO_FDIS 0x0580 +#define PALO_CALLPR 0x2000 +#define PALO_CALLUNPR 0x3000 + +/* Special (above 1F) and normal interrupt levels */ + +#define IPL_HALT 0x40 +#define IPL_SLI 0x20 +#define IPL_1F 0x1F /* highest level */ +#define IPL_CRD 0x1F /* corrected read data */ +#define IPL_PWRFL 0x1E /* power fail */ +#define IPL_AST 0x02 /* AST interrupt level */ + +/* Internal registers */ + +#define PALTEMP_SIZE 24 + +enum ev5_internal_reg { + ISR = 0x100, ITB_TAG, ITB_PTE, ITB_ASN, + ITB_PTE_TEMP, ITB_IA, ITB_IAP, ITB_IS, + SIRR, ASTRR, ASTEN, EXC_ADDR, + EXC_SUMM, EXC_MASK, PAL_BASE, ICM, + IPLR, INTID, IFAULT_VA_FORM, IVPTBR, + HWINT_CLR = 0x115, SL_XMIT, SL_RCV, + ICSR, IC_FLUSH_CTL, ICPERR_STAT, PMCTR = 0x11C, + PALTEMP = 0x140, + DTB_ASN = 0x200, DTB_CM, DTB_TAG, DTB_PTE, + DTB_PTE_TEMP, MM_STAT, VA, VA_FORM, + MVPTBR, DTB_IAP, DTB_IA, DTB_IS, + ALTMODE, CC, CC_CTL, MCSR, + DC_FLUSH, DC_PERR_STAT = 0x212, DC_TEST_CTL, + DC_TEST_TAG, DC_TEST_TAG_TEMP, DC_MODE, MAF_MODE + }; + +/* Ibox registers */ +/* ISR - instruction summary register - read only */ + +#define ISR_V_AST 0 +#define ISR_V_SIRR 4 +#define ISR_V_ATR 19 +#define ISR_V_IRQ0 20 +#define ISR_V_IRQ1 21 +#define ISR_V_IRQ2 22 +#define ISR_V_IRQ3 23 +#define ISR_V_PFL 30 +#define ISR_V_MCHK 31 +#define ISR_V_CRD 32 +#define ISR_V_SLI 33 +#define ISR_V_HALT 34 + +#define ISR_ATR (((t_uint64) 1u) << ISR_V_ATR) +#define ISR_IRQ0 (((t_uint64) 1u) << ISR_V_IRQ0) +#define ISR_IRQ1 (((t_uint64) 1u) << ISR_V_IRQ1) +#define ISR_IRQ2 (((t_uint64) 1u) << ISR_V_IRQ2) +#define ISR_IRQ3 (((t_uint64) 1u) << ISR_V_IRQ3) +#define ISR_HALT (((t_uint64) 1u) << ISR_V_HALT) + +/* ITB_TAG - ITLB tag - write only - stores VPN (tag) of faulting address */ + +/* ITB_PTE - ITLB pte - read and write in different formats */ + +#define ITBR_PTE_V_ASM 13 +#define ITBR_PTE_ASM (1u << ITBR_PTE_V_ASM) +#define ITBR_PTE_V_KRE 18 +#define ITBR_PTE_GH0 0x00000000 +#define ITBR_PTE_GH1 0x20000000 +#define ITBR_PTE_GH2 0x60000000 +#define ITBR_PTE_GH3 0xE0000000 + +/* ITB_ASN - ITLB ASN - read write */ + +#define ITB_ASN_V_ASN 4 +#define ITB_ASN_M_ASN 0x7F +#define ITB_ASN_WIDTH 7 + +/* ITB_PTE_TEMP - ITLB PTE readout - read only */ + +/* ITB_IA, ITB_IAP, ITB_IS - ITLB invalidates - write only */ + +/* SIRR - software interrupt request register - read/write */ + +#define SIRR_V_SIRR 4 +#define SIRR_M_SIRR 0x7FFF + +/* ASTRR, ASTEN - AST request, enable registers - read/write */ + +#define AST_MASK 0xF /* AST bits */ + +/* EXC_ADDR - read/write */ + +/* EXC_SUMM - read/cleared on write */ + +/* EXC_MASK - read only */ + +/* PAL_BASE - read/write */ + +#define PAL_BASE_RW 0x000000FFFFFFFFC000 + +/* ICM - ITLB current mode - read/write */ + +#define ICM_V_CM 3 +#define ICM_M_CM 0x3 + +/* IPLR - interrupt priority level - read/write */ + +#define IPLR_V_IPL 0 +#define IPLR_M_IPL 0x1F + +/* INTID - interrupt ID - read only */ + +#define INTID_MASK 0x1F + +/* IFAULT_VA_FORM - formated fault VA - read only */ + +/* IVPTBR - virtual page table base - read/write */ + +#define IVPTBR_VMS 0xFFFFFFF800000000 +#define IVPTBR_NT 0xFFFFFFFFC0000000 +#define FMT_IVA_VMS(x) (ev5_ivptbr | (((x) >> (VA_N_OFF - 3)) & 0x1FFFFFFF8)) +#define FMT_IVA_NT(x) (ev5_ivptbr | (((x) >> (VA_N_OFF - 3)) & 0x0003FFFF8)) + +/* HWINT_CLR - hardware interrupt clear - write only */ + +#define HWINT_CLR_W1C 0x00000003C8000000 + +/* SL_XMIT - serial line transmit - write only */ + +/* SL_RCV - real line receive - read only */ + +/* ICSR - Ibox control/status - read/write */ + +#define ICSR_V_PME 8 +#define ICSR_M_PME 0x3 +#define ICSR_V_BSE 17 +#define ICSR_V_MSK0 20 +#define ICSR_V_MSK1 21 +#define ICSR_V_MSK2 22 +#define ICSR_V_MSK3 23 +#define ICSR_V_TMM 24 +#define ICSR_V_TMD 25 +#define ICSR_V_FPE 26 +#define ICSR_V_HWE 27 +#define ICSR_V_SPE 28 +#define ICSR_M_SPE 0x3 +#define ICSR_V_SDE 30 +#define ICSR_V_CRDE 32 +#define ICSR_V_SLE 33 +#define ICSR_V_FMS 34 +#define ICSR_V_FBT 35 +#define ICSR_V_FBD 36 +#define ICSR_V_BIST 38 +#define ICSR_V_TEST 39 + +#define ICSR_NT (((t_uint64) 1u) << ICSR_V_SPE) +#define ICSR_BSE (((t_uint64) 1u) << ICSR_V_BSE) +#define ICSR_MSK0 (((t_uint64) 1u) << ICSR_V_MSK0) +#define ICSR_MSK1 (((t_uint64) 1u) << ICSR_V_MSK1) +#define ICSR_MSK2 (((t_uint64) 1u) << ICSR_V_MSK2) +#define ICSR_MSK3 (((t_uint64) 1u) << ICSR_V_MSK3) +#define ICSR_HWE (((t_uint64) 1u) << ICSR_V_HWE) +#define ICSR_SDE (((t_uint64) 1u) << ICSR_V_SDE) +#define ICSR_CRDE (((t_uint64) 1u) << ICSR_V_CRDE) +#define ICSR_SLE (((t_uint64) 1u) << ICSR_V_SLE) + +#define ICSR_RW 0x0000009F4BF00300 +#define ICSR_MBO 0x0000006000000000 + +/* IC_FLUSH_CTL - Icache flush control - write only */ + +/* ICPERR_STAT - Icache parity status - read/write 1 to clear */ + +#define ICPERR_V_DPE 11 +#define ICPERR_V_TPE 12 +#define ICPERR_V_TMO 13 + +#define ICPERR_DPE (1u << ICPERR_V_DPE) +#define ICPERR_TPE (1u << ICPERR_V_TPE) +#define ICPERR_TMO (1u << ICPERR_V_TMO) + +#define ICPERR_W1C (ICPERR_DPE|ICPERR_TPE|ICPERR_TMO) + +/* Mbox registers */ +/* DTB_ASN - DTLB ASN - write only */ + +#define DTB_ASN_V_ASN 57 +#define DTB_ASN_M_ASN 0x7F +#define DTB_ASN_WIDTH 7 + +/* DTB_CM - DTLB current mode - write only */ + +#define DCM_V_CM 3 +#define DCM_M_CM 0x3 + +/* DTB_TAG - DTLB tag and update - write only */ + +/* DTB_PTE - DTLB PTE - read/write */ + +/* DTB_PTE_TEMP - DTLB PTE read out register - read only */ + +/* MM_STAT - data fault status register - read only */ + +#define MM_STAT_WR 0x00001 +#define MM_STAT_ACV 0x00002 +#define MM_STAT_FOR 0x00004 +#define MM_STAT_FOW 0x00008 +#define MM_STAT_TBM 0x00010 +#define MM_STAT_BVA 0x00020 +#define MM_STAT_V_RA 6 +#define MM_STAT_IMASK 0x1FFC0 + +/* VA - data fault virtual address - read only */ + +/* VA_FORM - data fault formated virtual address - read only */ + +#define FMT_MVA_VMS(x) (ev5_mvptbr | (((x) >> (VA_N_OFF - 3)) & 0x1FFFFFFF8)) +#define FMT_MVA_NT(x) (ev5_mvptbr | (((x) >> (VA_N_OFF - 3)) & 0x0003FFFF8)) + +/* MVPTBR - DTB virtual page table base - write only */ + +#define MVPTBR_MBZ ((t_uint64) 0x3FFFFFFF) + +/* DTB_IAP, DTB_IA, DTB_IS - DTB invalidates - write only */ + +/* ALT_MODE - DTLB current mode - write only */ + +#define ALT_V_CM 3 +#define ALT_M_CM 0x3 + +/* CC - cycle counter - upper half is RW, lower half is RO */ + +/* CC_CTL - cycle counter control - write only */ + +#define CC_CTL_ENB 0x100000000 +#define CC_CTL_MBZ 0xF + +/* MCSR - Mbox control/status register - read/write */ + +#define MCSR_RW 0x11 +#define MCSR_V_SPE 1 +#define MCSR_M_SPE 0x3 +#define MCSR_NT 0x02 + +/* DC_PERR_STAT - data cache parity error status - read/write */ + +#define DC_PERR_W1C 0x3 +#define DC_PERR_ERR 0x1C + +/* DC_MODE - data cache mode - read/write */ + +#define DC_MODE_RW 0xF + +/* MAF_MODE - miss address file mode - read/write */ + +#define MAF_MODE_RW 0xFF + +/* DC_TEST_CTL - data cache test control - read/write */ + +#define DC_TEST_CTL_RW 0x1FFFB + +/* DC_TEST_TAG - data cache test tag - read/write */ + +#define DC_TEST_TAG_RW 0x0000007FFFFFFF04 + +/* Function prototypes (TLB interface) */ + +void tlb_ia (uint32 flags); +void tlb_is (t_uint64 va, uint32 flags); +void itlb_set_asn (uint32 asn); +void itlb_set_cm (uint32 mode); +void itlb_set_spage (uint32 spage); +TLBENT *itlb_lookup (uint32 vpn); +TLBENT *itlb_load (uint32 vpn, t_uint64 pte); +t_uint64 itlb_read (void); +void dtlb_set_asn (uint32 asn); +void dtlb_set_cm (uint32 mode); +void dtlb_set_spage (uint32 spage); +TLBENT *dtlb_lookup (uint32 vpn); +TLBENT *dtlb_load (uint32 vpn, t_uint64 pte); +t_uint64 dtlb_read (void); + +#endif + diff --git a/alpha/alpha_ev5_pal.c b/alpha/alpha_ev5_pal.c new file mode 100644 index 00000000..4910b0ce --- /dev/null +++ b/alpha/alpha_ev5_pal.c @@ -0,0 +1,961 @@ +/* alpha_ev5_pal.c - Alpha EV5 PAL mode simulator + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + EV5 was the second generation Alpha CPU. It was a four-way, in order issue + CPU with onchip primary instruction and data caches, an onchip second level + cache, and support for an offchip third level cache. EV56 was a shrink, with + added support for byte and word operations. PCA56 was a version of EV56 + without the onchip second level cache. PCA57 was a shrink of PCA56. + + EV5 includes the usual five PALcode instructions: + + HW_LD PALcode load + HW_ST PALcode store + HW_MTPR PALcode move to internal processor register + HW_MFPR PALcode move from internal processor register + HW_REI PALcode return + + PALcode instructions can only be issued in PALmode, or in kernel mode + if the appropriate bit is set in ICSR. + + EV5 implements 8 "PAL shadow" registers, which replace R8-R14, R25 in + PALmode without save/restore; and 24 "PAL temporary" registers. + + Internal registers fall into three groups: IBox IPRs, MBox IPRs, and + PAL temporaries. +*/ + +#include "alpha_defs.h" +#include "alpha_ev5_defs.h" + +t_uint64 ev5_palshad[PALSHAD_SIZE] = { 0 }; /* PAL shadow reg */ +t_uint64 ev5_palsave[PALSHAD_SIZE] = { 0 }; /* PAL save main */ +t_uint64 ev5_paltemp[PALTEMP_SIZE] = { 0 }; /* PAL temps */ +t_uint64 ev5_palbase = 0; /* PALcode base */ +t_uint64 ev5_excaddr = 0; /* exception address */ +t_uint64 ev5_isr = 0; /* intr summary */ +t_uint64 ev5_icsr = 0; /* IBox control */ +t_uint64 ev5_itb_pte = 0; /* ITLB pte */ +t_uint64 ev5_itb_pte_temp = 0; /* ITLB readout */ +t_uint64 ev5_ivptbr = 0; /* IBox virt ptbl */ +t_uint64 ev5_iva_form = 0; /* Ibox fmt'd VA */ +t_uint64 ev5_va = 0; /* Mbox VA */ +t_uint64 ev5_mvptbr = 0; /* Mbox virt ptbl */ +t_uint64 ev5_va_form = 0; /* Mbox fmt'd VA */ +t_uint64 ev5_dtb_pte = 0; /* DTLB pte */ +t_uint64 ev5_dtb_pte_temp = 0; /* DTLB readout */ +t_uint64 ev5_dc_test_tag = 0; /* Dcache test tag */ +t_uint64 ev5_dc_test_tag_temp = 0; /* Dcache tag readout */ +uint32 ev5_itb_tag = 0; /* ITLB tag (vpn) */ +uint32 ev5_dtb_tag = 0; /* DTLB tag (vpn) */ +uint32 ev5_icperr = 0; /* Icache par err */ +uint32 ev5_mm_stat = 0; /* MBox fault code */ +uint32 ev5_mcsr = 0; /* MBox control */ +uint32 ev5_alt_mode = 0; /* MBox alt mode */ +uint32 ev5_dc_mode = 0; /* Dcache mode */ +uint32 ev5_dcperr = 0; /* Dcache par err */ +uint32 ev5_dc_test_ctl = 0; /* Dcache test ctrl */ +uint32 ev5_maf_mode = 0; /* MAF mode */ +uint32 ev5_va_lock = 0; /* VA lock flag */ +uint32 ev5_mchk = 0; /* machine check pin */ +uint32 ev5_sli = 0; /* serial line intr */ +uint32 ev5_crd = 0; /* corr read data pin */ +uint32 ev5_pwrfl = 0; /* power fail pin */ +uint32 ev5_ipl = 0; /* ipl */ +uint32 ev5_sirr = 0; /* software int req */ +uint32 ev5_astrr = 0; /* AST requests */ +uint32 ev5_asten = 0; /* AST enables */ +const uint32 ast_map[4] = { 0x1, 0x3, 0x7, 0xF }; + +t_stat ev5_palent (t_uint64 fpc, uint32 off); +t_stat ev5_palent_d (t_uint64 fpc, uint32 off, uint32 sta); +t_stat pal_proc_reset_hwre (DEVICE *dptr); +t_stat pal_proc_intr_ev5 (uint32 lvl); +uint32 pal_eval_intr_ev5 (uint32 flag); + +extern t_uint64 R[32]; +extern t_uint64 PC; +extern t_uint64 trap_mask; +extern t_uint64 p1; +extern uint32 ir; +extern uint32 vax_flag, lock_flag; +extern uint32 fpen; +extern uint32 pcc_h, pcc_l, pcc_enb; +extern uint32 trap_summ; +extern uint32 arch_mask; +extern uint32 pal_mode, pal_type; +extern uint32 int_req[IPL_HLVL]; +extern uint32 itlb_cm, dtlb_cm; +extern uint32 itlb_asn, dtlb_asn; +extern uint32 itlb_spage, dtlb_spage; +extern jmp_buf save_env; +extern uint32 pal_type; +extern t_uint64 pcq[PCQ_SIZE]; /* PC queue */ +extern int32 pcq_p; /* PC queue ptr */ + +extern int32 parse_reg (char *cptr); + +/* EV5PAL data structures + + ev5pal_dev device descriptor + ev5pal_unit unit + ev5pal_reg register list +*/ + +UNIT ev5pal_unit = { UDATA (NULL, 0, 0) }; + +REG ev5pal_reg[] = { + { BRDATA (PALSHAD, ev5_palshad, 16, 64, PALSHAD_SIZE) }, + { BRDATA (PALSAVE, ev5_palsave, 16, 64, PALSHAD_SIZE) }, + { BRDATA (PALTEMP, ev5_paltemp, 16, 64, PALTEMP_SIZE) }, + { HRDATA (PALBASE, ev5_palbase, 64) }, + { HRDATA (EXCADDR, ev5_excaddr, 64) }, + { HRDATA (IPL, ev5_ipl, 5) }, + { HRDATA (SIRR, ev5_sirr, 15) }, + { HRDATA (ASTRR, ev5_astrr, 4) }, + { HRDATA (ASTEN, ev5_asten, 4) }, + { HRDATA (ISR, ev5_isr, 35) }, + { HRDATA (ICSR, ev5_icsr, 40) }, + { HRDATA (ITB_TAG, ev5_itb_tag, 32) }, + { HRDATA (ITB_PTE, ev5_itb_pte, 64) }, + { HRDATA (ITB_PTE_TEMP, ev5_itb_pte_temp, 64) }, + { HRDATA (IVA_FORM, ev5_iva_form, 64) }, + { HRDATA (IVPTBR, ev5_ivptbr, 64) }, + { HRDATA (ICPERR_STAT, ev5_icperr, 14) }, + { HRDATA (VA, ev5_va, 64) }, + { HRDATA (VA_FORM, ev5_va_form, 64) }, + { HRDATA (MVPTBR, ev5_mvptbr, 64) }, + { HRDATA (MM_STAT, ev5_mm_stat, 17) }, + { HRDATA (MCSR, ev5_mcsr, 6) }, + { HRDATA (DTB_TAG, ev5_dtb_tag, 32) }, + { HRDATA (DTB_PTE, ev5_dtb_pte, 64) }, + { HRDATA (DTB_PTE_TEMP, ev5_dtb_pte_temp, 64) }, + { HRDATA (DC_MODE, ev5_dc_mode, 4) }, + { HRDATA (DC_PERR_STAT, ev5_dcperr, 6) }, + { HRDATA (DC_TEST_CTL, ev5_dc_test_ctl, 13) }, + { HRDATA (DC_TEST_TAG, ev5_dc_test_tag, 39) }, + { HRDATA (DC_TEST_TAG_TEMP, ev5_dc_test_tag_temp, 39) }, + { HRDATA (MAF_MODE, ev5_maf_mode, 8) }, + { FLDATA (VA_LOCK, ev5_va_lock, 0) }, + { FLDATA (MCHK, ev5_mchk, 0) }, + { FLDATA (CRD, ev5_crd, 0) }, + { FLDATA (PWRFL, ev5_pwrfl, 0) }, + { FLDATA (SLI, ev5_sli, 0) }, + { NULL } + }; + +DEVICE ev5pal_dev = { + "EV5PAL", &ev5pal_unit, ev5pal_reg, NULL, + 1, 16, 1, 1, 16, 8, + NULL, NULL, &pal_proc_reset_hwre, + NULL, NULL, NULL, + NULL, DEV_DIS + }; + +/* EV5 interrupt dispatch - reached from top of instruction loop - + dispatch to PALcode */ + +t_stat pal_proc_intr (uint32 lvl) +{ +return ev5_palent (PC, PALO_INTR); +} + +/* EV5 trap dispatch - reached from bottom of instruction loop - + trap_mask and trap_summ are set up correctly - dispatch to PALcode */ + +t_stat pal_proc_trap (uint32 summ) +{ +return ev5_palent (PC, PALO_TRAP); +} + +/* EV5 exception dispatch - reached from ABORT handler - + set up any exception-specific registers - dispatch to PALcode */ + +t_stat pal_proc_excp (uint32 abval) +{ +switch (abval) { + + case EXC_RSVI: /* reserved instruction */ + return ev5_palent (PC, PALO_RSVI); + + case EXC_ALIGN: /* unaligned */ + return ev5_palent (PC, PALO_ALGN); + + case EXC_FPDIS: /* fp disabled */ + return ev5_palent (PC, PALO_FDIS); + + case EXC_FOX+EXC_R: /* FOR */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_FOR); + + case EXC_FOX+EXC_W: /* FOW */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_FOR|MM_STAT_WR); + + case EXC_BVA+EXC_E: /* instr bad VA */ + case EXC_ACV+EXC_E: /* instr ACV */ + ev5_itb_tag = VA_GETVPN (PC); /* fault VPN */ + if (ev5_icsr & ICSR_NT) /* formatted addr */ + ev5_iva_form = ev5_ivptbr | FMT_IVA_NT (PC); + else ev5_iva_form = ev5_ivptbr | FMT_IVA_VMS (PC); + return ev5_palent (PC, PALO_IACV); + + case EXC_ACV+EXC_R: /* data read ACV */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_ACV); + + case EXC_ACV+EXC_W: /* data write ACV */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_ACV|MM_STAT_WR); + + case EXC_BVA+EXC_R: /* data read bad addr */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_BVA); + + case EXC_BVA+EXC_W: /* data write bad addr */ + return ev5_palent_d (PC, PALO_DFLT, MM_STAT_BVA|MM_STAT_WR); + + case EXC_TBM + EXC_E: /* TLB miss */ + ev5_itb_tag = VA_GETVPN (PC); /* fault VPN */ + if (ev5_icsr & ICSR_NT) /* formatted addr */ + ev5_iva_form = ev5_ivptbr | FMT_IVA_NT (PC); + else ev5_iva_form = ev5_ivptbr | FMT_IVA_VMS (PC); + return ev5_palent (PC, PALO_ITBM); + + case EXC_TBM + EXC_R: /* data TB miss read */ + if ((I_GETOP (ir) == HW_LD) && (ir & HW_LD_PTE)) + return ev5_palent_d (PC, PALO_DTBM_D, MM_STAT_TBM); + return ev5_palent_d (PC, PALO_DTBM, MM_STAT_TBM); + + case EXC_TBM + EXC_W: /* data TB miss write */ + if ((I_GETOP (ir) == HW_LD) && (ir & HW_LD_PTE)) + return ev5_palent_d (PC, PALO_DTBM_D, MM_STAT_TBM|MM_STAT_WR); + return ev5_palent_d (PC, PALO_DTBM, MM_STAT_TBM|MM_STAT_WR); + + case EXC_RSVO: /* reserved operand */ + case EXC_TNV+EXC_E: /* instr TNV */ + case EXC_TNV+EXC_R: /* data read TNV */ + case EXC_TNV+EXC_W: /* data write TNV */ + case EXC_FOX+EXC_E: /* FOE */ + return SCPE_IERR; /* should never get here */ + + default: + return STOP_INVABO; + } + +return SCPE_OK; +} + +/* EV5 call PAL - reached from instruction decoder - + compute offset from function code - dispatch to PALcode */ + +t_stat pal_proc_inst (uint32 fnc) +{ +uint32 off = (fnc & 0x3F) << 6; + +if (fnc & 0x80) return ev5_palent (PC, PALO_CALLUNPR + off); +if (itlb_cm != MODE_K) ABORT (EXC_RSVI); +return ev5_palent (PC, PALO_CALLPR + off); +} + +/* EV5 evaluate interrupts - returns highest outstanding + interrupt level about target ipl - plus nonmaskable flags + + flag = 1: evaluate for real interrupt capability + flag = 0: evaluate as though IPL = 0, normal mode */ + +uint32 pal_eval_intr (uint32 flag) +{ +uint32 i, req = 0; +uint32 lvl = flag? ev5_ipl: 0; + +if (flag && pal_mode) return 0; +if (ev5_mchk) req = IPL_1F; +else if (ev5_crd && (ICSR & ICSR_CRDE)) req = IPL_CRD; +else if (ev5_pwrfl) req = IPL_PWRFL; +else if (int_req[3] && !(ICSR & ICSR_MSK3)) req = IPL_HMIN + 3; +else if (int_req[2] && !(ICSR & ICSR_MSK2)) req = IPL_HMIN + 2; +else if (int_req[1] && !(ICSR & ICSR_MSK1)) req = IPL_HMIN + 1; +else if (int_req[0] && !(ICSR & ICSR_MSK0)) req = IPL_HMIN + 0; +else if (ev5_sirr) { + for (i = IPL_SMAX; i > 0; i--) { /* check swre int */ + if ((ev5_sirr >> (i - 1)) & 1) { /* req != 0? int */ + req = i; + break; + } + } + } +if ((req < IPL_AST) && (ev5_astrr & ev5_asten & ast_map[itlb_cm])) + req = IPL_AST; +if (req <= lvl) req = 0; +if (ev5_sli && (ICSR & ICSR_SLE)) req = req | IPL_SLI; +if (ev5_isr & ISR_HALT) req = req | IPL_HALT; +return req; +} + +/* EV5 enter PAL, data TLB miss/memory management flows - + set Mbox registers - dispatch to PALcode */ + +t_stat ev5_palent_d (t_uint64 fpc, uint32 off, uint32 sta) +{ +if (!ev5_va_lock) { /* not locked? */ + ev5_mm_stat = sta | /* merge IR<31:21> */ + ((ir >> (I_V_RA - MM_STAT_V_RA)) & MM_STAT_IMASK); + ev5_va = p1; /* fault address */ + if (ev5_mcsr & MCSR_NT) /* formatted VA */ + ev5_va_form = ev5_mvptbr | FMT_MVA_NT (p1); + else ev5_va_form = ev5_mvptbr | FMT_MVA_VMS (p1); + ev5_va_lock = 1; /* lock registers */ + } +return ev5_palent (fpc, off); +} + +/* EV5 enter PAL */ + +t_stat ev5_palent (t_uint64 fpc, uint32 off) +{ +ev5_excaddr = fpc | pal_mode; /* save exc addr */ +PCQ_ENTRY; /* save PC */ +PC = ev5_palbase + off; /* new PC */ +if (!pal_mode && (ev5_icsr & ICSR_SDE)) { /* entering PALmode? */ + PAL_USE_SHADOW; /* swap in shadows */ + } +pal_mode = 1; /* in PAL mode */ +return SCPE_OK; +} + +/* PAL instructions */ + +/* 1B: HW_LD */ + +t_stat pal_1b (uint32 ir) +{ +t_uint64 dsp, ea, res; +uint32 ra, rb, acc, mode; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +ra = I_GETRA (ir); /* get ra */ +rb = I_GETRB (ir); /* get rb */ +dsp = HW_LD_GETDSP (ir); /* get displacement */ +ea = (R[rb] + (SEXT_HW_LD_DSP (dsp))) & M64; /* eff address */ +if (ir & HW_LD_V) { /* virtual? */ + mode = (ir & HW_LD_ALT)? ev5_alt_mode: dtlb_cm; /* access mode */ + acc = (ir & HW_LD_WCH)? ACC_W (mode): ACC_R (mode); + if (ir & HW_LD_Q) res = ReadAccQ (ea, acc); /* quad? */ + else { /* long, sext */ + res = ReadAccL (ea, acc); + res = SEXT_L_Q (res); + } + } +else if (ir & HW_LD_Q) R[ra] = ReadPQ (ea); /* physical, quad? */ +else { + res = ReadPL (ea); /* long, sext */ + res = SEXT_L_Q (res); + } +if (ir & HW_LD_LCK) lock_flag = 1; /* lock? set flag */ +if (ra != 31) R[ra] = res; /* if not R31, store */ +return SCPE_OK; +} + +/* 1F: HW_ST */ + +t_stat pal_1f (uint32 ir) +{ +t_uint64 dsp, ea; +uint32 ra, rb, acc, mode; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +ra = I_GETRA (ir); /* get ra */ +rb = I_GETRB (ir); /* get rb */ +dsp = HW_LD_GETDSP (ir); /* get displacement */ +ea = (R[rb] + (SEXT_HW_LD_DSP (dsp))) & M64; /* eff address */ +if ((ir & HW_LD_LCK) && !lock_flag) R[ra] = 0; /* lock fail? */ +else { + if (ir & HW_LD_V) { /* virtual? */ + mode = (ir & HW_LD_ALT)? ev5_alt_mode: dtlb_cm; /* access mode */ + acc = ACC_W (mode); + if (ir & HW_LD_Q) WriteAccQ (ea, R[ra], acc); /* quad? */ + else WriteAccL (ea, R[ra], acc); /* long */ + } + else if (ir & HW_LD_Q) WritePQ (ea, R[ra]); /* physical, quad? */ + else WritePL (ea, R[ra]); /* long */ + if (ir & HW_LD_LCK) lock_flag = 0; /* unlock? clr flag */ + } +return SCPE_OK; +} + +/* 1E: HW_REI */ + +t_stat pal_1e (uint32 ir) +{ +uint32 new_pal = ((uint32) ev5_excaddr) & 1; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +PCQ_ENTRY; +PC = ev5_excaddr; +if (pal_mode && !new_pal && (ev5_icsr & ICSR_SDE)) { /* leaving PAL mode? */ + PAL_USE_MAIN; /* swap out shadows */ + } +pal_mode = new_pal; +return SCPE_OK; +} + +/* PAL move from processor registers */ + +t_stat pal_19 (uint32 ir) +{ +t_uint64 res; +uint32 fnc, ra; +static const uint32 itbr_map_gh[4] = { + ITBR_PTE_GH0, ITBR_PTE_GH1, ITBR_PTE_GH2, ITBR_PTE_GH3 }; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +fnc = I_GETMDSP (ir); +ra = I_GETRA (ir); +switch (fnc) { + + case ISR: /* intr summary */ + res = ev5_isr | ((ev5_astrr & ev5_asten) << ISR_V_AST) | + ((ev5_sirr & SIRR_M_SIRR) << ISR_V_SIRR) | + (int_req[0] && !(ev5_icsr & ICSR_MSK0)? ISR_IRQ0: 0) | + (int_req[1] && !(ev5_icsr & ICSR_MSK1)? ISR_IRQ1: 0) | + (int_req[2] && !(ev5_icsr & ICSR_MSK2)? ISR_IRQ2: 0) | + (int_req[3] && !(ev5_icsr & ICSR_MSK3)? ISR_IRQ3: 0); + if (ev5_astrr & ev5_asten & ast_map[itlb_cm]) res = res | ISR_ATR; + break; + + case ITB_PTE: + res = itlb_read (); + ev5_itb_pte_temp = (res & PFN_MASK) | + ((res & PTE_ASM)? ITBR_PTE_ASM: 0) | + ((res & (PTE_KRE|PTE_ERE|PTE_SRE|PTE_URE)) << + (ITBR_PTE_V_KRE - PTE_V_KRE)) | + itbr_map_gh[PTE_GETGH (res)]; + res = 0; + break; + + case ITB_ASN: + res = (itlb_asn & ITB_ASN_M_ASN) << ITB_ASN_V_ASN; + break; + + case ITB_PTE_TEMP: + res = ev5_itb_pte_temp; + break; + + case SIRR: + res = (ev5_sirr & SIRR_M_SIRR) << SIRR_V_SIRR; + break; + + case ASTRR: + res = ev5_astrr & AST_MASK; + break; + + case ASTEN: + res = ev5_asten & AST_MASK; + break; + + case EXC_ADDR: + res = ev5_excaddr; + break; + + case EXC_SUMM: + res = trap_summ & TRAP_SUMM_RW; + break; + + case EXC_MASK: + res = trap_mask; + break; + + case PAL_BASE: + res = ev5_palbase & PAL_BASE_RW; + break; + + case ICM: + res = (itlb_cm & ICM_M_CM) << ICM_V_CM; + break; + + case IPLR: + res = (ev5_ipl & IPLR_M_IPL) << IPLR_V_IPL; + break; + + case INTID: + res = pal_eval_intr (0) & INTID_MASK; + break; + + case IFAULT_VA_FORM: + res = ev5_iva_form; + break; + + case IVPTBR: + res = ev5_ivptbr; + break; + + case ICSR: + res = (ev5_icsr & ICSR_RW) | ICSR_MBO | + ((itlb_spage & ICSR_M_SPE) << ICSR_V_SPE) | + ((fpen & 1) << ICSR_V_FPE) | + ((arch_mask & AMASK_BWX)? ICSR_BSE: 0); + break; + + case PALTEMP+0x00: case PALTEMP+0x01: case PALTEMP+0x02: case PALTEMP+0x03: + case PALTEMP+0x04: case PALTEMP+0x05: case PALTEMP+0x06: case PALTEMP+0x07: + case PALTEMP+0x08: case PALTEMP+0x09: case PALTEMP+0x0A: case PALTEMP+0x0B: + case PALTEMP+0x0C: case PALTEMP+0x0D: case PALTEMP+0x0E: case PALTEMP+0x0F: + case PALTEMP+0x10: case PALTEMP+0x11: case PALTEMP+0x12: case PALTEMP+0x13: + case PALTEMP+0x14: case PALTEMP+0x15: case PALTEMP+0x16: case PALTEMP+0x17: + res = ev5_paltemp[fnc - PALTEMP]; + break; + + case DTB_PTE: + ev5_dtb_pte_temp = dtlb_read (); + res = 0; + break; + + case DTB_PTE_TEMP: + res = ev5_dtb_pte_temp; + break; + + case MM_STAT: + res = ev5_mm_stat; + break; + + case VA: + res = ev5_va; + ev5_va_lock = 0; + break; + + case VA_FORM: + res = ev5_va_form; + break; + + case DC_PERR_STAT: + res = ev5_dcperr; + break; + + case MCSR: + res = (ev5_mcsr & MCSR_RW) | ((dtlb_spage & MCSR_M_SPE) << MCSR_V_SPE); + break; + + case DC_MODE: + res = ev5_dc_mode & DC_MODE_RW; + break; + + case MAF_MODE: + res = ev5_maf_mode & MAF_MODE_RW; + break; + + case CC: + res = (((t_uint64) pcc_h) << 32) | ((t_uint64) pcc_l); + break; + + case DC_TEST_CTL: + res = ev5_dc_test_ctl & DC_TEST_CTL_RW; + break; + + case DC_TEST_TAG: + // to be determined + res = 0; + break; + + case DC_TEST_TAG_TEMP: + res = ev5_dc_test_tag_temp & DC_TEST_TAG_RW; + break; + + default: + res = 0; + break; + } + +if (ra != 31) R[ra] = res & M64; +return SCPE_OK; +} + +/* PAL move to processor registers */ + +t_stat pal_1d (uint32 ir) +{ +uint32 fnc = I_GETMDSP (ir); +uint32 ra = I_GETRA (ir); +t_uint64 val = R[ra]; + +if (!pal_mode && (!(itlb_cm == MODE_K) || /* pal mode, or kernel */ + !(ev5_icsr & ICSR_HWE))) ABORT (EXC_RSVI); /* and enabled? */ +switch (fnc) { + + case ITB_TAG: + ev5_itb_tag = VA_GETVPN (val); + break; + + case ITB_PTE: + ev5_itb_pte = (val | PTE_V) & (PFN_MASK | ((t_uint64) (PTE_ASM | PTE_GH | + PTE_KRE | PTE_ERE | PTE_SRE | PTE_URE))); + itlb_load (ev5_itb_tag, ev5_itb_pte); + break; + + case ITB_ASN: + itlb_set_asn ((((uint32) val) >> ITB_ASN_V_ASN) & ITB_ASN_M_ASN); + break; + + case ITB_IA: + tlb_ia (TLB_CI | TLB_CA); + break; + + case ITB_IAP: + tlb_ia (TLB_CI); + break; + + case ITB_IS: + tlb_is (val, TLB_CI); + break; + + case SIRR: + ev5_sirr = (((uint32) val) >> SIRR_V_SIRR) & SIRR_M_SIRR; + break; + + case ASTRR: + ev5_astrr = ((uint32) val) & AST_MASK; + break; + + case ASTEN: + ev5_asten = ((uint32) val) & AST_MASK; + break; + + case EXC_ADDR: + ev5_excaddr = val; + break; + + case EXC_SUMM: + trap_summ = 0; + trap_mask = 0; + break; + + case PAL_BASE: + ev5_palbase = val & PAL_BASE_RW; + break; + + case ICM: + itlb_set_cm ((((uint32) val) >> ICM_V_CM) & ICM_M_CM); + break; + + case IPLR: + ev5_ipl = (((uint32) val) >> IPLR_V_IPL) & IPLR_M_IPL; + break; + + case IVPTBR: + if (ev5_icsr & ICSR_NT) ev5_ivptbr = val & IVPTBR_NT; + else ev5_ivptbr = val & IVPTBR_VMS; + break; + + case HWINT_CLR: + ev5_isr = ev5_isr & ~(val & HWINT_CLR_W1C); + break; + + case ICSR: + if (pal_mode && ((val ^ ev5_icsr) & ICSR_SDE)) { + if (val & ICSR_SDE) { PAL_USE_SHADOW; } + else { PAL_USE_MAIN; } + } + ev5_icsr = val & ICSR_RW; + itlb_set_spage ((((uint32) val) >> ICSR_V_SPE) & ICSR_M_SPE); + fpen = (((uint32) val) >> ICSR_V_FPE) & 1; + if (val & ICSR_BSE) arch_mask = arch_mask | AMASK_BWX; + else arch_mask = arch_mask & ~AMASK_BWX; + break; + + case ICPERR_STAT: + ev5_icperr = ev5_icperr & ~(((uint32) val) & ICPERR_W1C); + break; + + case PALTEMP+0x00: case PALTEMP+0x01: case PALTEMP+0x02: case PALTEMP+0x03: + case PALTEMP+0x04: case PALTEMP+0x05: case PALTEMP+0x06: case PALTEMP+0x07: + case PALTEMP+0x08: case PALTEMP+0x09: case PALTEMP+0x0A: case PALTEMP+0x0B: + case PALTEMP+0x0C: case PALTEMP+0x0D: case PALTEMP+0x0E: case PALTEMP+0x0F: + case PALTEMP+0x10: case PALTEMP+0x11: case PALTEMP+0x12: case PALTEMP+0x13: + case PALTEMP+0x14: case PALTEMP+0x15: case PALTEMP+0x16: case PALTEMP+0x17: + ev5_paltemp[fnc - PALTEMP] = val; + break; + + case DTB_ASN: + dtlb_set_asn (((uint32) (val >> DTB_ASN_V_ASN)) & DTB_ASN_M_ASN); + break; + + case DTB_CM: + dtlb_set_cm (((uint32) (val >> ICM_V_CM)) & ICM_M_CM); + break; + + case DTB_TAG: + ev5_dtb_tag = VA_GETVPN (val); + val = (val | PTE_V) & (PFN_MASK | ((t_uint64) (PTE_MASK & ~PTE_FOE))); + dtlb_load (ev5_dtb_tag, val); + break; + + case DTB_PTE: + ev5_dtb_pte = val; + break; + + case MVPTBR: + ev5_mvptbr = val & ~MVPTBR_MBZ; + break; + + case DC_PERR_STAT: + ev5_dcperr = ev5_dcperr & ~(((uint32) val) & DC_PERR_W1C); + if ((ev5_dcperr & DC_PERR_W1C) == 0) ev5_dcperr = 0; + break; + + case DTB_IA: + tlb_ia (TLB_CD | TLB_CA); + break; + + case DTB_IAP: + tlb_ia (TLB_CD); + break; + + case DTB_IS: + tlb_is (val, TLB_CD); + break; + + case MCSR: + ev5_mcsr = ((uint32) val) & MCSR_RW; + dtlb_set_spage ((((uint32) val) >> MCSR_V_SPE) & MCSR_M_SPE); + if (ev5_mcsr & MCSR_NT) pal_type = PAL_NT; + break; + + case DC_MODE: + ev5_dc_mode = ((uint32) val) & DC_MODE_RW; + break; + + case MAF_MODE: + ev5_maf_mode = ((uint32) val) & MAF_MODE_RW; + break; + + case CC: + pcc_h = (uint32) ((val >> 32) & M32); + break; + + case CC_CTL: + pcc_l = ((uint32) val) & (M32 & ~CC_CTL_MBZ); + if (val & CC_CTL_ENB) pcc_enb = 1; + else pcc_enb = 0; + break; + + case DC_TEST_CTL: + ev5_dc_test_ctl = ((uint32) val) & DC_TEST_CTL_RW; + break; + + case DC_TEST_TAG: + ev5_dc_test_tag = val & DC_TEST_TAG_RW; + break; + + default: + break; + } + +return SCPE_OK; +} + +/* EV5 PALcode reset */ + +t_stat pal_proc_reset_hwre (DEVICE *dptr) +{ +ev5_palbase = 0; +ev5_mchk = 0; +ev5_pwrfl = 0; +ev5_crd = 0; +ev5_sli = 0; +itlb_set_cm (MODE_K); +itlb_set_asn (0); +itlb_set_spage (0); +dtlb_set_cm (MODE_K); +dtlb_set_asn (0); +dtlb_set_spage (0); +return SCPE_OK; +} + +/* EV5 PAL instruction print and parse routines */ + +static const char *pal_inam[] = { + "HW_MFPR", "HW_LD", "HW_MTPR", "HW_REI", "HW_ST", NULL + }; + +static const uint32 pal_ival[] = { + 0x64000000, 0x6C000000, 0x74000000, 0x7BFF8000, 0x7C000000 + }; + +struct pal_opt { + uint32 mask; /* bit mask */ + char let; /* matching letter */ + }; + +static struct pal_opt ld_st_opt[] = { + { HW_LD_V, 'V' }, + { HW_LD_ALT, 'A' }, + { HW_LD_WCH, 'W' }, + { HW_LD_Q, 'Q' }, + { HW_LD_PTE, 'P' }, + { HW_LD_LCK, 'L' }, + { 0 } + }; + +static struct pal_opt rei_opt[] = { + { HW_REI_S, 'S' }, + { 0 } + }; + +/* Print options for hardware PAL instruction */ + +void fprint_opt_ev5 (FILE *of, uint32 inst, struct pal_opt opt[]) +{ +uint32 i; + +for (i = 0; opt[i].mask != 0; i++) { + if (inst & opt[i].mask) { + fprintf (of, "/%c", opt[i].let); + inst = inst & ~opt[i].mask; + } + } +return; +} + +/* Parse options for hardware PAL instruction */ + +char *parse_opt_ev5 (char *cptr, uint32 *val, struct pal_opt opt[]) +{ +uint32 i; +char *tptr, gbuf[CBUFSIZE]; + +if (*(cptr - 1) != '/') return cptr; +cptr = get_glyph (cptr - 1, tptr = gbuf, 0); +while (*tptr == '/') { + tptr++; + for (i = 0; opt[i].mask != 0; i++) { + if (*tptr == opt[i].let) { + *val = *val | opt[i].mask; + break; + } + } + if (opt[i].mask == 0) return NULL; + tptr++; + } +if (*tptr != 0) return NULL; +return cptr; +} + +/* Print PAL hardware opcode symbolically */ + +t_stat fprint_pal_hwre (FILE *of, uint32 inst) +{ +uint32 op, ra, rb; + +op = I_GETOP (inst); +ra = I_GETRA (inst); +rb = I_GETRB (inst); +switch (op) { + + case OP_PAL19: /* HW_MFPR */ + case OP_PAL1D: /* HW_MTPR */ + fputs ((op == OP_PAL19)? "HW_MFPR": "HW_MTPR", of); + fprintf (of, " R%d,%X", ra, inst & M16); + break; + + case OP_PAL1B: /* HW_LD */ + case OP_PAL1F: /* HW_ST */ + fputs ((op == OP_PAL1B)? "HW_LD": "HW_ST", of); + fprint_opt_ev5 (of, inst, ld_st_opt); + fprintf (of, " R%d,%X", ra, inst & HW_LD_DSP); + if (rb != 31) fprintf (of, "(R%d)", rb); + break; + + case OP_PAL1E: /* HW_REI */ + fputs ("HW_REI", of); + fprint_opt_ev5 (of, inst, rei_opt); + break; + + default: + return SCPE_ARG; + } + +return -3; +} + +/* Parse PAL hardware opcode symbolically */ + +t_stat parse_pal_hwre (char *cptr, t_value *inst) +{ +uint32 i, d, val = 0; +int32 reg; +char *tptr, gbuf[CBUFSIZE]; +t_stat r; + +cptr = get_glyph (cptr, gbuf, '/'); +for (i = 0; pal_inam[i] != NULL; i++) { + if (strcmp (gbuf, pal_inam[i]) == 0) val = pal_ival[i]; + } +if (val == 0) return SCPE_ARG; +switch (I_GETOP (val)) { + + case OP_PAL19: /* HW_MFPR */ + case OP_PAL1D: /* HW_MTPR */ + if (*(cptr - 1) == '/') return SCPE_ARG; + cptr = get_glyph (cptr, gbuf, ','); /* get reg */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + val = val | (reg << I_V_RA) | (reg << I_V_RB); + cptr = get_glyph (cptr, gbuf, 0); /* get ipr */ + d = (uint32) get_uint (gbuf, 16, M16, &r); + if (r != SCPE_OK) return r; + val = val | d; + break; + + case OP_PAL1B: /* HW_LD */ + case OP_PAL1F: /* HW_ST */ + cptr = parse_opt_ev5 (cptr, &val, ld_st_opt); + if (cptr == NULL) return SCPE_ARG; + cptr = get_glyph (cptr, gbuf, ','); /* get reg */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + val = val | (reg << I_V_RA); + cptr = get_glyph (cptr, gbuf, 0); + d = (uint32) strtotv (gbuf, &tptr, 16); + if ((gbuf == tptr) || (d > HW_LD_DSP)) return SCPE_ARG; + val = val | d; + if (*tptr == '(') { + tptr = get_glyph (tptr + 1, gbuf, ')'); + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + val = val | (reg << I_V_RB); + } + else val = val | (31 << I_V_RB); + break; + + case OP_PAL1E: /* HW_REI */ + cptr = parse_opt_ev5 (cptr, &val, rei_opt); + if (cptr == NULL) return SCPE_ARG; + break; + + default: + return SCPE_ARG; + } + +*inst = val; +if (*cptr != 0) return SCPE_ARG; +return -3; +} + diff --git a/alpha/alpha_ev5_tlb.c b/alpha/alpha_ev5_tlb.c new file mode 100644 index 00000000..9cfded4a --- /dev/null +++ b/alpha/alpha_ev5_tlb.c @@ -0,0 +1,566 @@ +/* alpha_ev5_tlb.c - Alpha EV5 TLB simulator + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + EV5 was the second generation Alpha CPU. It was a four-way, in order issue + CPU with onchip primary instruction and data caches, an onchip second level + cache, and support for an offchip third level cache. EV56 was a shrink, with + added support for byte and word operations. EV56PC was a version of EV56 + without the onchip second level cache. + + This module contains the routines for + + itlb_lookup lookup vpn in instruction TLB + itlb_load load pte into instruction TLB + itlb_read read pte from instruction TLB using NLU pointer + itlb_set_asn set iasn + itlb_set_cm set icm + itlb_set_spage set ispage + dtlb_lookup lookup vpn in data TLB + dtlb_load load pte into data TLB + dtlb_read read pte from data TLB using NLU pointer + dtlb_set_asn set dasn + dtlb_set_cm set dcm + dtlb_set_spage set dspage + tlb_ia TLB invalidate all + tlb_is TLB invalidate single + tlb_set_cm TLB set current mode +*/ + +#include "alpha_defs.h" +#include "alpha_ev5_defs.h" + +#define ITLB_SORT qsort (itlb, ITLB_SIZE, sizeof (TLBENT), &tlb_comp); +#define DTLB_SORT qsort (dtlb, DTLB_SIZE, sizeof (TLBENT), &tlb_comp); +#define TLB_ESIZE (sizeof (TLBENT)/sizeof (uint32)) +#define MM_RW(x) (((x) & PTE_FOW)? EXC_W: EXC_R) + +uint32 itlb_cm = 0; /* current modes */ +uint32 itlb_spage = 0; /* superpage enables */ +uint32 itlb_asn = 0; +uint32 itlb_nlu = 0; +TLBENT i_mini_tlb; +TLBENT itlb[ITLB_SIZE]; +uint32 dtlb_cm = 0; +uint32 dtlb_spage = 0; +uint32 dtlb_asn = 0; +uint32 dtlb_nlu = 0; +TLBENT d_mini_tlb; +TLBENT dtlb[DTLB_SIZE]; + +uint32 cm_eacc = ACC_E (MODE_K); /* precomputed */ +uint32 cm_racc = ACC_R (MODE_K); /* access checks */ +uint32 cm_wacc = ACC_W (MODE_K); +uint32 cm_macc = ACC_M (MODE_K); + +extern t_uint64 p1; +extern jmp_buf save_env; + +uint32 mm_exc (uint32 macc); +void tlb_inval (TLBENT *tlbp); +t_stat itlb_reset (void); +t_stat dtlb_reset (void); +int tlb_comp (const void *e1, const void *e2); +t_stat tlb_reset (DEVICE *dptr); + +/* TLB data structures + + tlb_dev pager device descriptor + tlb_unit pager units + tlb_reg pager register list +*/ + +UNIT tlb_unit = { UDATA (NULL, 0, 0) }; + +REG tlb_reg[] = { + { HRDATA (ICM, itlb_cm, 2) }, + { HRDATA (ISPAGE, itlb_spage, 2), REG_HRO }, + { HRDATA (IASN, itlb_asn, ITB_ASN_WIDTH) }, + { HRDATA (INLU, itlb_nlu, ITLB_WIDTH) }, + { BRDATA (IMINI, &i_mini_tlb, 16, 32, TLB_ESIZE) }, + { BRDATA (ITLB, itlb, 16, 32, ITLB_SIZE*TLB_ESIZE) }, + { HRDATA (DCM, dtlb_cm, 2) }, + { HRDATA (DSPAGE, dtlb_spage, 2), REG_HRO }, + { HRDATA (DASN, dtlb_asn, DTB_ASN_WIDTH) }, + { HRDATA (DNLU, dtlb_nlu, DTLB_WIDTH) }, + { BRDATA (DMINI, &d_mini_tlb, 16, 32, TLB_ESIZE) }, + { BRDATA (DTLB, dtlb, 16, 32, DTLB_SIZE*TLB_ESIZE) }, + { NULL } + }; + +DEVICE tlb_dev = { + "TLB", &tlb_unit, tlb_reg, NULL, + 1, 0, 0, 1, 0, 0, + NULL, NULL, &tlb_reset, + NULL, NULL, NULL + }; + +/* Translate address, instruction, data, and console + + Inputs: + va = virtual address + acc = (VAX only) access mode + Outputs: + pa = translation buffer index +*/ + +t_uint64 trans_i (t_uint64 va) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +TLBENT *tlbp; + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ + ABORT1 (va, EXC_BVA + EXC_E); +if ((itlb_spage & SPEN_43) && VPN_GETSP43 (vpn) == 2) { /* 43b superpage? */ + if (itlb_cm != MODE_K) ABORT1 (va, EXC_ACV + EXC_E); + return (va & SP43_MASK); + } +if ((itlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) { + if (itlb_cm != MODE_K) ABORT1 (va, EXC_ACV + EXC_E); + return (va & SP32_MASK); /* 32b superpage? */ + } +if (!(tlbp = itlb_lookup (vpn))) /* lookup vpn; miss? */ + ABORT1 (va, EXC_TBM + EXC_E); /* abort reference */ +if (cm_eacc & ~tlbp->pte) /* check access */ + ABORT1 (va, mm_exc (cm_eacc & ~tlbp->pte) | EXC_E); +return PHYS_ADDR (tlbp->pfn, va); /* return phys addr */ +} + +t_uint64 trans_d (t_uint64 va, uint32 acc) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +TLBENT *tlbp; + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ + ABORT1 (va, EXC_BVA + MM_RW (acc)); +if ((dtlb_spage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) { + if (dtlb_cm != MODE_K) ABORT1 (va, EXC_ACV + MM_RW (acc)); + return (va & SP43_MASK); /* 43b superpage? */ + } +if ((dtlb_spage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) { + if (dtlb_cm != MODE_K) ABORT1 (va, EXC_ACV + MM_RW (acc)); + return (va & SP32_MASK); /* 32b superpage? */ + } +if (!(tlbp = dtlb_lookup (vpn))) /* lookup vpn; miss? */ + ABORT1 (va, EXC_TBM + MM_RW (acc)); /* abort reference */ +if (acc & ~tlbp->pte) /* check access */ + ABORT1 (va, mm_exc (acc & ~tlbp->pte) | MM_RW (acc)); +return PHYS_ADDR (tlbp->pfn, va); /* return phys addr */ +} + +/* Generate a memory management error code, based on the access check bits not + set in PTE + + - If the access check bits, without FOx and V, fail, then ACV + - If FOx set, then FOx + - Otherwise, TNV */ + +uint32 mm_exc (uint32 not_set) +{ +uint32 tacc; + +tacc = not_set & ~(PTE_FOR | PTE_FOW | PTE_FOE | PTE_V); +if (tacc) return EXC_ACV; +tacc = not_set & (PTE_FOR | PTE_FOW | PTE_FOE); +if (tacc) return EXC_FOX; +return EXC_TNV; +} + +/* TLB invalidate single */ + +void tlb_is (t_uint64 va, uint32 flags) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +TLBENT *itlbp, *dtlbp; + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) return; +if ((flags & TLB_CI) && (itlbp = itlb_lookup (vpn))) { + tlb_inval (itlbp); + tlb_inval (&i_mini_tlb); + ITLB_SORT; + } +if ((flags & TLB_CD) && (dtlbp = dtlb_lookup (vpn))) { + tlb_inval (dtlbp); + tlb_inval (&d_mini_tlb); + DTLB_SORT; + } +return; +} + +/* TLB invalidate all */ + +void tlb_ia (uint32 flags) +{ +uint32 i; + +if (flags & TLB_CA) { + if (flags & TLB_CI) itlb_reset (); + if (flags & TLB_CD) dtlb_reset (); + return; + } +if (flags & TLB_CI) { + for (i = 0; i < ITLB_SIZE; i++) { + if (!(itlb[i].pte & PTE_ASM)) tlb_inval (&itlb[i]); + } + tlb_inval (&i_mini_tlb); + ITLB_SORT; + } +if (flags & TLB_CD) { + for (i = 0; i < DTLB_SIZE; i++) { + if (!(dtlb[i].pte & PTE_ASM)) tlb_inval (&dtlb[i]); + } + tlb_inval (&d_mini_tlb); + DTLB_SORT; + } +return; +} + +/* TLB lookup */ + +TLBENT *itlb_lookup (uint32 vpn) +{ +int32 p, hi, lo; + +if (vpn == i_mini_tlb.tag) return &i_mini_tlb; +lo = 0; /* initial bounds */ +hi = ITLB_SIZE - 1; +do { + p = (lo + hi) >> 1; /* probe */ + if ((itlb_asn == itlb[p].asn) && + (((vpn ^ itlb[p].tag) & + ~((uint32) itlb[p].gh_mask)) == 0)) { /* match to TLB? */ + i_mini_tlb.tag = vpn; + i_mini_tlb.pte = itlb[p].pte; + i_mini_tlb.pfn = itlb[p].pfn; + itlb_nlu = itlb[p].idx + 1; + if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0; + return &i_mini_tlb; + } + if ((itlb_asn < itlb[p].asn) || + ((itlb_asn == itlb[p].asn) && (vpn < itlb[p].tag))) + hi = p - 1; /* go down? p is upper */ + else lo = p + 1; /* go up? p is lower */ + } +while (lo <= hi); +return NULL; +} + +TLBENT *dtlb_lookup (uint32 vpn) +{ +int32 p, hi, lo; + +if (vpn == d_mini_tlb.tag) return &d_mini_tlb; +lo = 0; /* initial bounds */ +hi = DTLB_SIZE - 1; +do { + p = (lo + hi) >> 1; /* probe */ + if ((dtlb_asn == dtlb[p].asn) && + (((vpn ^ dtlb[p].tag) & + ~((uint32) dtlb[p].gh_mask)) == 0)) { /* match to TLB? */ + d_mini_tlb.tag = vpn; + d_mini_tlb.pte = dtlb[p].pte; + d_mini_tlb.pfn = dtlb[p].pfn; + dtlb_nlu = dtlb[p].idx + 1; + if (dtlb_nlu >= DTLB_SIZE) dtlb_nlu = 0; + return &d_mini_tlb; + } + if ((dtlb_asn < dtlb[p].asn) || + ((dtlb_asn == dtlb[p].asn) && (vpn < dtlb[p].tag))) + hi = p - 1; /* go down? p is upper */ + else lo = p + 1; /* go up? p is lower */ + } +while (lo <= hi); +return NULL; +} + +/* Load TLB entry at NLU pointer, advance NLU pointer */ + +TLBENT *itlb_load (uint32 vpn, t_uint64 l3pte) +{ +uint32 i, gh; + +for (i = 0; i < ITLB_SIZE; i++) { + if (itlb[i].idx == itlb_nlu) { + TLBENT *tlbp = itlb + i; + itlb_nlu = itlb_nlu + 1; + if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0; + tlbp->tag = vpn; + tlbp->pte = (uint32) (l3pte & PTE_MASK) ^ (PTE_FOR|PTE_FOR|PTE_FOE); + tlbp->pfn = ((uint32) (l3pte >> PTE_V_PFN)) & PFN_MASK; + tlbp->asn = itlb_asn; + gh = PTE_GETGH (tlbp->pte); + tlbp->gh_mask = (1u << (3 * gh)) - 1; + tlb_inval (&i_mini_tlb); + ITLB_SORT; + return tlbp; + } + } +fprintf (stderr, "%%ITLB entry not found, itlb_nlu = %d\n", itlb_nlu); +ABORT (-SCPE_IERR); +return NULL; +} + +TLBENT *dtlb_load (uint32 vpn, t_uint64 l3pte) +{ +uint32 i, gh; + +for (i = 0; i < DTLB_SIZE; i++) { + if (dtlb[i].idx == dtlb_nlu) { + TLBENT *tlbp = dtlb + i; + dtlb_nlu = dtlb_nlu + 1; + if (dtlb_nlu >= ITLB_SIZE) dtlb_nlu = 0; + tlbp->tag = vpn; + tlbp->pte = (uint32) (l3pte & PTE_MASK) ^ (PTE_FOR|PTE_FOR|PTE_FOE); + tlbp->pfn = ((uint32) (l3pte >> PTE_V_PFN)) & PFN_MASK; + tlbp->asn = dtlb_asn; + gh = PTE_GETGH (tlbp->pte); + tlbp->gh_mask = (1u << (3 * gh)) - 1; + tlb_inval (&d_mini_tlb); + DTLB_SORT; + return tlbp; + } + } +fprintf (stderr, "%%DTLB entry not found, dtlb_nlu = %d\n", dtlb_nlu); +ABORT (-SCPE_IERR); +return NULL; +} + +/* Read TLB entry at NLU pointer, advance NLU pointer */ + +t_uint64 itlb_read (void) +{ +uint8 i; + +for (i = 0; i < ITLB_SIZE; i++) { + if (itlb[i].idx == itlb_nlu) { + TLBENT *tlbp = itlb + i; + itlb_nlu = itlb_nlu + 1; + if (itlb_nlu >= ITLB_SIZE) itlb_nlu = 0; + return (((t_uint64) tlbp->pfn) << PTE_V_PFN) | + ((tlbp->pte ^ (PTE_FOR|PTE_FOR|PTE_FOE)) & PTE_MASK); + } + } +fprintf (stderr, "%%ITLB entry not found, itlb_nlu = %d\n", itlb_nlu); +ABORT (-SCPE_IERR); +return 0; +} + +t_uint64 dtlb_read (void) +{ +uint8 i; + +for (i = 0; i < DTLB_SIZE; i++) { + if (dtlb[i].idx == dtlb_nlu) { + TLBENT *tlbp = dtlb + i; + dtlb_nlu = dtlb_nlu + 1; + if (dtlb_nlu >= DTLB_SIZE) dtlb_nlu = 0; + return (((t_uint64) tlbp->pfn) << PTE_V_PFN) | + ((tlbp->pte ^ (PTE_FOR|PTE_FOR|PTE_FOE)) & PTE_MASK); + } + } +fprintf (stderr, "%%DTLB entry not found, dtlb_nlu = %d\n", dtlb_nlu); +ABORT (-SCPE_IERR); +return 0; +} + +/* Set ASN - rewrite TLB globals with correct ASN */ + +void itlb_set_asn (uint32 asn) +{ +int32 i; + +itlb_asn = asn; +for (i = 0; i < ITLB_SIZE; i++) { + if (itlb[i].pte & PTE_ASM) itlb[i].asn = asn; + } +tlb_inval (&i_mini_tlb); +ITLB_SORT; +return; +} + +void dtlb_set_asn (uint32 asn) +{ +int32 i; + +dtlb_asn = asn; +for (i = 0; i < DTLB_SIZE; i++) { + if (dtlb[i].pte & PTE_ASM) dtlb[i].asn = asn; + } +tlb_inval (&d_mini_tlb); +DTLB_SORT; +return; +} + +/* Set superpage */ + +void itlb_set_spage (uint32 spage) +{ +itlb_spage = spage; +return; +} + +void dtlb_set_spage (uint32 spage) +{ +dtlb_spage = spage; +return; +} + +/* Set current mode */ + +void itlb_set_cm (uint32 mode) +{ +itlb_cm = mode; +cm_eacc = ACC_E (mode); +return; +} + +void dtlb_set_cm (uint32 mode) +{ +dtlb_cm = mode; +cm_racc = ACC_R (mode); +cm_wacc = ACC_W (mode); +return; +} + +uint32 tlb_set_cm (int32 cm) +{ +if (cm >= 0) { + itlb_set_cm (cm); + dtlb_set_cm (cm); + return cm; + } +itlb_set_cm (itlb_cm); +dtlb_set_cm (dtlb_cm); +return dtlb_cm; +} + +/* Invalidate TLB entry */ + +void tlb_inval (TLBENT *tlbp) +{ +tlbp->tag = INV_TAG; +tlbp->pte = 0; +tlbp->pfn = 0; +tlbp->asn = tlbp->idx; +tlbp->gh_mask = 0; +return; +} + +/* Compare routine for qsort */ + +int tlb_comp (const void *e1, const void *e2) +{ +TLBENT *t1 = (TLBENT *) e1; +TLBENT *t2 = (TLBENT *) e2; + +if (t1->asn > t2->asn) return +1; +if (t1->asn < t2->asn) return -1; +if (t1->tag > t2->tag) return +1; +if (t1->tag < t2->tag) return -1; +return 0; +} + +/* ITLB reset */ + +t_stat itlb_reset (void) +{ +int32 i; + +itlb_nlu = 0; +for (i = 0; i < ITLB_SIZE; i++) { + itlb[i].tag = INV_TAG; + itlb[i].pte = 0; + itlb[i].pfn = 0; + itlb[i].asn = i; + itlb[i].gh_mask = 0; + itlb[i].idx = i; + } +tlb_inval (&i_mini_tlb); +return SCPE_OK; +} +/* DTLB reset */ + +t_stat dtlb_reset (void) +{ +int32 i; + +dtlb_nlu = 0; +for (i = 0; i < DTLB_SIZE; i++) { + dtlb[i].tag = INV_TAG; + dtlb[i].pte = 0; + dtlb[i].pfn = 0; + dtlb[i].asn = i; + dtlb[i].gh_mask = 0; + dtlb[i].idx = i; + } +tlb_inval (&d_mini_tlb); +return SCPE_OK; +} + +/* SimH reset */ + +t_stat tlb_reset (DEVICE *dptr) +{ +itlb_reset (); +dtlb_reset (); +return SCPE_OK; +} + +/* Show TLB entry or entries */ + +t_stat cpu_show_tlb (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +t_addr lo, hi; +uint32 lnt; +TLBENT *tlbp; +DEVICE *dptr; +char *cptr = (char *) desc; + +lnt = (val)? DTLB_SIZE: ITLB_SIZE; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +if (cptr) { + cptr = get_range (dptr, cptr, &lo, &hi, 10, lnt, 0); + if ((cptr == NULL) || (*cptr != 0)) return SCPE_ARG; + } +else { + lo = 0; + hi = lnt - 1; + } +tlbp = (val)? dtlb + lo: itlb + lo; + +do { + fprintf (of, "TLB %02d\tTAG=%02X/%08X, ", (uint32) lo, tlbp->asn, tlbp->tag); + fprintf (of, "MASK=%X, INDX=%d, ", tlbp->gh_mask, tlbp->idx); + fprintf (of, "PTE=%04X, PFN=%08X\n", tlbp->pte, tlbp->pfn); + tlbp++; + lo++; + } while (lo <= hi); + +return SCPE_OK; +} + diff --git a/alpha/alpha_fpi.c b/alpha/alpha_fpi.c new file mode 100644 index 00000000..62c7b459 --- /dev/null +++ b/alpha/alpha_fpi.c @@ -0,0 +1,776 @@ +/* alpha_fpi.c - Alpha IEEE floating point simulator + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This module contains the instruction simulators for + + - single precision floating point, S + - double precision floating point, T + + Portions of this module (specifically, the convert floating to integer + routine and the square root routine) are a derivative work from SoftFloat, + written by John Hauser. SoftFloat includes the following license terms: + + Written by John R. Hauser. This work was made possible in part by the + International Computer Science Institute, located at Suite 600, 1947 Center + Street, Berkeley, California 94704. Funding was partially provided by the + National Science Foundation under grant MIP-9311980. The original version + of this code was written as part of a project to build a fixed-point vector + processor in collaboration with the University of California at Berkeley, + overseen by Profs. Nelson Morgan and John Wawrzynek. More information + is available through the Web page 'http://www.cs.berkeley.edu/~jhauser/ + arithmetic/SoftFloat.html'. + + THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has + been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES + RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS + AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, + COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE + EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE + INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR + OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + + Derivative works are acceptable, even for commercial purposes, so long as + (1) the source code for the derivative work includes prominent notice that + the work is derivative, and (2) the source code includes prominent notice with + these four paragraphs for those parts of this code that are retained. +*/ + +#include "alpha_defs.h" + +#define UFT_ZERO 0 /* unpacked: zero */ +#define UFT_FIN 1 /* finite */ +#define UFT_DENORM 2 /* denormal */ +#define UFT_INF 3 /* infinity */ +#define UFT_NAN 4 /* not a number */ + +#define Q_FINITE(x) ((x) <= UFT_FIN) /* finite */ +#define Q_SUI(x) (((x) & I_FTRP) == I_FTRP_SVI) + +/* Register format constants */ + +#define QNAN 0x0008000000000000 /* quiet NaN flag */ +#define CQNAN 0xFFF8000000000000 /* canonical quiet NaN */ +#define FPZERO 0x0000000000000000 /* plus zero (fp) */ +#define FMZERO 0x8000000000000000 /* minus zero (fp) */ +#define FPINF 0x7FF0000000000000 /* plus infinity (fp) */ +#define FMINF 0xFFF0000000000000 /* minus infinity (fp) */ +#define FPMAX 0x7FEFFFFFFFFFFFFF /* plus MAX (fp) */ +#define FMMAX 0xFFEFFFFFFFFFFFFF /* minus MAX (fp) */ +#define IPMAX 0x7FFFFFFFFFFFFFFF /* plus MAX (int) */ +#define IMMAX 0x8000000000000000 /* minus MAX (int) */ + +/* Unpacked rounding constants */ + +#define UF_SRND 0x0000008000000000 /* S normal round */ +#define UF_SINF 0x000000FFFFFFFFFF /* S infinity round */ +#define UF_TRND 0x0000000000000400 /* T normal round */ +#define UF_TINF 0x00000000000007FF /* T infinity round */ + +extern t_uint64 FR[32]; +extern uint32 fpcr; +extern jmp_buf save_env; + +t_bool ieee_unpack (t_uint64 op, UFP *r, uint32 ir); +void ieee_norm (UFP *r); +t_uint64 ieee_rpack (UFP *r, uint32 ir, uint32 dp); +void ieee_trap (uint32 trap, uint32 instenb, uint32 fpcrdsb, uint32 ir); +int32 ieee_fcmp (t_uint64 a, t_uint64 b, uint32 ir, uint32 signal_nan); +t_uint64 ieee_cvtst (t_uint64 op, uint32 ir); +t_uint64 ieee_cvtts (t_uint64 op, uint32 ir); +t_uint64 ieee_cvtif (t_uint64 val, uint32 ir, uint32 dp); +t_uint64 ieee_cvtfi (t_uint64 op, uint32 ir); +t_uint64 ieee_fadd (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp, t_bool sub); +t_uint64 ieee_fmul (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp); +t_uint64 ieee_fdiv (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp); +uint32 estimateSqrt32 (uint32 exp, uint32 a); +t_uint64 estimateDiv128 (t_uint64 hi, t_uint64 lo, t_uint64 dvr); + +extern t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi); +extern t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky); +t_uint64 fsqrt64 (t_uint64 frac, int32 exp); + +/* IEEE S load */ + +t_uint64 op_lds (t_uint64 op) +{ +uint32 exp = S_GETEXP (op); /* get exponent */ + +if (exp == S_NAN) exp = FPR_NAN; /* inf or NaN? */ +else if (exp != 0) exp = exp + T_BIAS - S_BIAS; /* zero or denorm? */ +return (((t_uint64) (op & S_SIGN))? FPR_SIGN: 0) | /* reg format */ + (((t_uint64) exp) << FPR_V_EXP) | + (((t_uint64) (op & ~(S_SIGN|S_EXP))) << S_V_FRAC); +} + +/* IEEE S store */ + +t_uint64 op_sts (t_uint64 op) +{ +uint32 sign = FPR_GETSIGN (op)? S_SIGN: 0; +uint32 frac = ((uint32) (op >> S_V_FRAC)) & M32; +uint32 exp = FPR_GETEXP (op); + +if (exp == FPR_NAN) exp = S_NAN; /* inf or NaN? */ +else if (exp != 0) exp = exp + S_BIAS - T_BIAS; /* non-zero? */ +exp = (exp & S_M_EXP) << S_V_EXP; +return (t_uint64) (sign | exp | (frac & ~(S_SIGN|S_EXP))); +} + +/* IEEE floating operate */ + +void ieee_fop (uint32 ir) +{ +UFP a, b; +uint32 ftpa, ftpb, fnc, ra, rb, rc; +t_uint64 res; + +fnc = I_GETFFNC (ir); /* get function */ +ra = I_GETRA (ir); /* get registers */ +rb = I_GETRB (ir); +rc = I_GETRC (ir); +switch (fnc) { /* case on func */ + + case 0x00: /* ADDS */ + res = ieee_fadd (FR[ra], FR[rb], ir, DT_S, 0); + break; + + case 0x01: /* SUBS */ + res = ieee_fadd (FR[ra], FR[rb], ir, DT_S, 1); + break; + + case 0x02: /* MULS */ + res = ieee_fmul (FR[ra], FR[rb], ir, DT_S); + break; + + case 0x03: /* DIVS */ + res = ieee_fdiv (FR[ra], FR[rb], ir, DT_S); + break; + + case 0x20: /* ADDT */ + res = ieee_fadd (FR[ra], FR[rb], ir, DT_T, 0); + break; + + case 0x21: /* SUBT */ + res = ieee_fadd (FR[ra], FR[rb], ir, DT_T, 1); + break; + + case 0x22: /* MULT */ + res = ieee_fmul (FR[ra], FR[rb], ir, DT_T); + break; + + case 0x23: /* DIVT */ + res = ieee_fdiv (FR[ra], FR[rb], ir, DT_T); + break; + + case 0x24: /* CMPTUN */ + ftpa = ieee_unpack (FR[ra], &a, ir); /* unpack */ + ftpb = ieee_unpack (FR[rb], &b, ir); + if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) /* if NaN, T */ + res = FP_TRUE; + else res = 0; + break; + + case 0x25: /* CMPTEQ */ + if (ieee_fcmp (FR[ra], FR[rb], ir, 0) == 0) res = FP_TRUE; + else res = 0; + break; + + case 0x26: /* CMPTLT */ + if (ieee_fcmp (FR[ra], FR[rb], ir, 1) < 0) res = FP_TRUE; + else res = 0; + break; + + case 0x27: /* CMPTLE */ + if (ieee_fcmp (FR[ra], FR[rb], ir, 1) <= 0) res = FP_TRUE; + else res = 0; + break; + + case 0x2C: /* CVTST, CVTTS */ + if (ir & 0x2000) res = ieee_cvtst (FR[rb], ir); /* CVTST */ + else res = ieee_cvtts (FR[rb], ir); /* CVTTS */ + break; + + case 0x2F: /* CVTTQ */ + res = ieee_cvtfi (FR[rb], ir); + break; + + case 0x3C: /* CVTQS */ + res = ieee_cvtif (FR[rb], ir, DT_S); + break; + + case 0x3E: /* CVTQT */ + res = ieee_cvtif (FR[rb], ir, DT_T); + break; + + default: + if ((ir & I_FSRC) == I_FSRC_X) ABORT (EXC_RSVI); + res = FR[rc]; + break; + } + +if (rc != 31) FR[rc] = res & M64; +return; +} + +/* IEEE S to T convert - LDS doesn't handle denorms correctly */ + +t_uint64 ieee_cvtst (t_uint64 op, uint32 ir) +{ +UFP b; +uint32 ftpb; + +ftpb = ieee_unpack (op, &b, ir); /* unpack; norm dnorm */ +if (ftpb == UFT_DENORM) { /* denormal? */ + b.exp = b.exp + T_BIAS - S_BIAS; /* change 0 exp to T */ + return ieee_rpack (&b, ir, DT_T); /* round, pack */ + } +else return op; /* identity */ +} + +/* IEEE T to S convert */ + +t_uint64 ieee_cvtts (t_uint64 op, uint32 ir) +{ +UFP b; +uint32 ftpb; + +ftpb = ieee_unpack (op, &b, ir); /* unpack */ +if (Q_FINITE (ftpb)) return ieee_rpack (&b, ir, DT_S); /* finite? round, pack */ +if (ftpb == UFT_NAN) return (op | QNAN); /* nan? cvt to quiet */ +if (ftpb == UFT_INF) return op; /* inf? unchanged */ +return 0; /* denorm? 0 */ +} + +/* IEEE floating compare + + - Take care of NaNs + - Force -0 to +0 + - Then normal compare will work (even on inf and denorms) */ + +int32 ieee_fcmp (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 trap_nan) +{ +UFP a, b; +uint32 ftpa, ftpb; + +ftpa = ieee_unpack (s1, &a, ir); +ftpb = ieee_unpack (s2, &b, ir); +if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) { /* NaN involved? */ + if (trap_nan) ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); + return +1; /* force failure */ + } +if (ftpa == UFT_ZERO) a.sign = 0; /* only +0 allowed */ +if (ftpb == UFT_ZERO) b.sign = 0; +if (a.sign != b.sign) return (a.sign? -1: +1); /* unequal signs? */ +if (a.exp != b.exp) return ((a.sign ^ (a.exp < b.exp))? -1: +1); +if (a.frac != b.frac) return ((a.sign ^ (a.frac < b.frac))? -1: +1); +return 0; +} + +/* IEEE integer to floating convert */ + +t_uint64 ieee_cvtif (t_uint64 val, uint32 ir, uint32 dp) +{ +UFP a; + +if (val == 0) return 0; /* 0? return +0 */ +if (val & FPR_SIGN) { /* < 0? */ + a.sign = 1; /* set sign */ + val = NEG_Q (val); /* |val| */ + } +else a.sign = 0; +a.exp = 63 + T_BIAS; /* set exp */ +a.frac = val; /* set frac */ +ieee_norm (&a); /* normalize */ +return ieee_rpack (&a, ir, dp); /* round and pack */ +} + +/* IEEE floating to integer convert - rounding code from SoftFloat + The Alpha architecture specifies return of the low order bits of + the true result, whereas the IEEE standard specifies the return + of the maximum plus or minus value */ + +t_uint64 ieee_cvtfi (t_uint64 op, uint32 ir) +{ +UFP a; +t_uint64 sticky; +uint32 rndm, ftpa, ovf; +int32 ubexp; + +ftpa = ieee_unpack (op, &a, ir); /* unpack */ +if (!Q_FINITE (ftpa)) { /* inf, NaN, dnorm? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv operation */ + return 0; + } +if (ftpa == UFT_ZERO) return 0; /* zero? */ +ovf = 0; /* assume no ovflo */ +ubexp = a.exp - T_BIAS; /* unbiased exp */ +if (ubexp < 0) { /* < 1? */ + if (ubexp == -1) sticky = a.frac; /* [.5,1)? */ + else sticky = 1; /* (0,.5) */ + a.frac = 0; + } +else if (ubexp < UF_V_NM) { /* in range? */ + sticky = (a.frac << (64 - (UF_V_NM - ubexp))) & M64; + a.frac = a.frac >> (UF_V_NM - ubexp); /* result */ + } +else if (ubexp == UF_V_NM) sticky = 0; /* at limit of range? */ +else { + if ((ubexp - UF_V_NM) > 63) a.frac = 0; /* out of range */ + else a.frac = (a.frac << (ubexp - UF_V_NM)) & M64; + ovf = 1; /* overflow */ + sticky = 0; /* no rounding */ + } +rndm = I_GETFRND (ir); /* get round mode */ +if (((rndm == I_FRND_N) && (sticky & Q_SIGN)) || /* nearest? */ + ((rndm == I_FRND_P) && !a.sign && sticky) || /* +inf and +? */ + ((rndm == I_FRND_M) && a.sign && sticky)) { /* -inf and -? */ + a.frac = (a.frac + 1) & M64; + if (a.frac == 0) ovf = 1; /* overflow? */ + if ((rndm == I_FRND_N) && (sticky == Q_SIGN)) /* round nearest hack */ + a.frac = a.frac & ~1; + } +if (a.frac > (a.sign? IMMAX: IPMAX)) ovf = 1; /* overflow? */ +if (ovf) ieee_trap (TRAP_IOV, ir & I_FTRP_V, 0, 0); /* overflow trap */ +if (ovf || sticky) /* ovflo or round? */ + ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); +return (a.sign? NEG_Q (a.frac): a.frac); +} + +/* IEEE floating add + + - Take care of NaNs and infinites + - Test for zero (fast exit) + - Sticky logic for floating add + > If result normalized, sticky in right place + > If result carries out, renormalize, retain sticky + - Sticky logic for floating subtract + > If shift < guard, no sticky bits; 64b result is exact + If shift <= 1, result may require extensive normalization, + but there are no sticky bits to worry about + > If shift >= guard, there is a sticky bit, + but normalization is at most 1 place, sticky bit is retained + for rounding purposes (but not in low order bit) */ + +t_uint64 ieee_fadd (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp, t_bool sub) +{ +UFP a, b, t; +uint32 ftpa, ftpb; +uint32 sticky, rndm; +int32 ediff; + +ftpa = ieee_unpack (s1, &a, ir); /* unpack operands */ +ftpb = ieee_unpack (s2, &b, ir); +if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */ +if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */ +if (sub) b.sign = b.sign ^ 1; /* sign of B */ +if (ftpb == UFT_INF) { /* B = inf? */ + if ((ftpa == UFT_INF) && (a.sign ^ b.sign)) { /* eff sub of inf? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */ + return CQNAN; /* canonical NaN */ + } + return (sub? (s2 ^ FPR_SIGN): s2); /* return B */ + } +if (ftpa == UFT_INF) return s1; /* A = inf? ret A */ +rndm = I_GETFRND (ir); /* inst round mode */ +if (rndm == I_FRND_D) rndm = FPCR_GETFRND (fpcr); /* dynamic? use FPCR */ +if (ftpa == UFT_ZERO) { /* A = 0? */ + if (ftpb != UFT_ZERO) a = b; /* B != 0? result is B */ + else if (a.sign != b.sign) /* both 0, subtract? */ + a.sign = (rndm == I_FRND_M); /* +0 unless RM */ + } +else if (ftpb != UFT_ZERO) { /* s2 != 0? */ + if ((a.exp < b.exp) || /* s1 < s2? swap */ + ((a.exp == b.exp) && (a.frac < b.frac))) { + t = a; + a = b; + b = t; + } + ediff = a.exp - b.exp; /* exp diff */ + if (ediff > 63) b.frac = 1; /* >63? retain sticky */ + else if (ediff) { /* [1,63]? shift */ + sticky = ((b.frac << (64 - ediff)) & M64)? 1: 0; /* lost bits */ + b.frac = ((b.frac >> ediff) & M64) | sticky; + } + if (a.sign ^ b.sign) { /* eff sub? */ + a.frac = (a.frac - b.frac) & M64; /* subtract fractions */ + if (a.frac == 0) { /* result 0? */ + a.exp = 0; + a.sign = (rndm == I_FRND_M); /* +0 unless RM */ + } + else ieee_norm (&a); /* normalize */ + } + else { /* eff add */ + a.frac = (a.frac + b.frac) & M64; /* add frac */ + if (a.frac < b.frac) { /* chk for carry */ + a.frac = UF_NM | (a.frac >> 1) | /* shift in carry */ + (a.frac & 1); /* retain sticky */ + a.exp = a.exp + 1; /* skip norm */ + } + } + } /* end else if */ +return ieee_rpack (&a, ir, dp); /* round and pack */ +} + +/* IEEE floating multiply + + - Take care of NaNs and infinites + - Test for zero operands (fast exit) + - 64b x 64b fraction multiply, yielding 128b result + - Normalize (at most 1 bit) + - Insert "sticky" bit in low order fraction, for rounding + + Because IEEE fractions have a range of [1,2), the result can have a range + of [1,4). Results in the range of [1,2) appear to be denormalized by one + place, when in fact they are correct. Results in the range of [2,4) appear + to be in correct, when in fact they are 2X larger. This problem is taken + care of in the result exponent calculation. */ + +t_uint64 ieee_fmul (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp) +{ +UFP a, b; +uint32 ftpa, ftpb; +t_uint64 resl; + +ftpa = ieee_unpack (s1, &a, ir); /* unpack operands */ +ftpb = ieee_unpack (s2, &b, ir); +if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */ +if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */ +a.sign = a.sign ^ b.sign; /* sign of result */ +if ((ftpa == UFT_ZERO) || (ftpb == UFT_ZERO)) { /* zero operand? */ + if ((ftpa == UFT_INF) || (ftpb == UFT_INF)) { /* 0 * inf? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */ + return CQNAN; /* canonical NaN */ + } + return (a.sign? FMZERO: FPZERO); /* return signed 0 */ + } +if (ftpb == UFT_INF) return (a.sign? FMINF: FPINF); /* B = inf? */ +if (ftpa == UFT_INF) return (a.sign? FMINF: FPINF); /* A = inf? */ +a.exp = a.exp + b.exp + 1 - T_BIAS; /* add exponents */ +resl = uemul64 (a.frac, b.frac, &a.frac); /* multiply fracs */ +ieee_norm (&a); /* normalize */ +a.frac = a.frac | (resl? 1: 0); /* sticky bit */ +return ieee_rpack (&a, ir, dp); /* round and pack */ +} + +/* Floating divide + + - Take care of NaNs and infinites + - Check for zero cases + - Divide fractions (55b to develop a rounding bit) + - Set sticky bit if remainder non-zero + + Because IEEE fractions have a range of [1,2), the result can have a range + of (.5,2). Results in the range of [1,2) are correct. Results in the + range of (.5,1) need to be normalized by one place. */ + +t_uint64 ieee_fdiv (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp) +{ +UFP a, b; +uint32 ftpa, ftpb, sticky; + +ftpa = ieee_unpack (s1, &a, ir); +ftpb = ieee_unpack (s2, &b, ir); +if (ftpb == UFT_NAN) return s2 | QNAN; /* B = NaN? quiet B */ +if (ftpa == UFT_NAN) return s1 | QNAN; /* A = NaN? quiet A */ +a.sign = a.sign ^ b.sign; /* sign of result */ +if (ftpb == UFT_INF) { /* B = inf? */ + if (ftpa == UFT_INF) { /* inf/inf? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */ + return CQNAN; /* canonical NaN */ + } + return (a.sign? FMZERO: FPZERO); /* !inf/inf, ret 0 */ + } +if (ftpa == UFT_INF) /* A = inf? */ + return (a.sign? FMINF: FPINF); /* return inf */ +if (ftpb == UFT_ZERO) { /* B = 0? */ + if (ftpa == UFT_ZERO) { /* 0/0? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* inv op trap */ + return CQNAN; /* canonical NaN */ + } + ieee_trap (TRAP_DZE, 1, FPCR_DZED, ir); /* div by 0 trap */ + return (a.sign? FMINF: FPINF); /* return inf */ + } +if (ftpa == UFT_ZERO) return (a.sign? FMZERO: FPZERO); /* A = 0? */ +a.exp = a.exp - b.exp + T_BIAS; /* unbiased exp */ +a.frac = a.frac >> 1; /* allow 1 bit left */ +b.frac = b.frac >> 1; +a.frac = ufdiv64 (a.frac, b.frac, 55, &sticky); /* divide */ +ieee_norm (&a); /* normalize */ +a.frac = a.frac | sticky; /* insert sticky */ +return ieee_rpack (&a, ir, dp); /* round and pack */ +} + +/* IEEE floating square root + + - Take care of NaNs, +infinite, zero + - Check for negative operand + - Compute result exponent + - Compute sqrt of fraction */ + +t_uint64 ieee_sqrt (uint32 ir, uint32 dp) +{ +t_uint64 op; +uint32 ftpb; +UFP b; + +op = FR[I_GETRB (ir)]; /* get F[rb] */ +ftpb = ieee_unpack (op, &b, ir); /* unpack */ +if (ftpb == UFT_NAN) return op | QNAN; /* NaN? */ +if ((ftpb == UFT_ZERO) || /* zero? */ + ((ftpb == UFT_INF) && !b.sign)) return op; /* +infinity? */ +if (b.sign) { /* minus? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */ + return CQNAN; + } +b.exp = ((b.exp - T_BIAS) >> 1) + T_BIAS - 1; /* result exponent */ +b.frac = fsqrt64 (b.frac, b.exp); /* result fraction */ +return ieee_rpack (&b, ir, dp); /* round and pack */ +} + +/* Support routines */ + +t_bool ieee_unpack (t_uint64 op, UFP *r, uint32 ir) +{ +r->sign = FPR_GETSIGN (op); /* get sign */ +r->exp = FPR_GETEXP (op); /* get exponent */ +r->frac = FPR_GETFRAC (op); /* get fraction */ +if (r->exp == 0) { /* exponent = 0? */ + if (r->frac == 0) return UFT_ZERO; /* frac = 0? then true 0 */ + if (fpcr & FPCR_DNZ) { /* denorms to 0? */ + r->frac = 0; /* clear fraction */ + return UFT_ZERO; + } + r->frac = r->frac << FPR_GUARD; /* guard fraction */ + ieee_norm (r); /* normalize dnorm */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */ + return UFT_DENORM; + } +if (r->exp == FPR_NAN) { /* exponent = max? */ + if (r->frac == 0) return UFT_INF; /* frac = 0? then inf */ + if (!(r->frac & QNAN)) /* signaling NaN? */ + ieee_trap (TRAP_INV, 1, FPCR_INVD, ir); /* signal inv op */ + return UFT_NAN; + } +r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */ +return UFT_FIN; /* finite */ +} + +/* Normalize - input must be zero, finite, or denorm */ + +void ieee_norm (UFP *r) +{ +int32 i; +static t_uint64 normmask[5] = { + 0xc000000000000000, 0xf000000000000000, 0xff00000000000000, + 0xffff000000000000, 0xffffffff00000000 + }; +static int32 normtab[6] = { 1, 2, 4, 8, 16, 32 }; + +r->frac = r->frac & M64; +if (r->frac == 0) { /* if fraction = 0 */ + r->sign = 0; + r->exp = 0; /* result is 0 */ + return; + } +while ((r->frac & UF_NM) == 0) { /* normalized? */ + for (i = 0; i < 5; i++) { /* find first 1 */ + if (r->frac & normmask[i]) break; + } + r->frac = r->frac << normtab[i]; /* shift frac */ + r->exp = r->exp - normtab[i]; /* decr exp */ + } +return; +} + +/* Round and pack + + Much of the treachery of the IEEE standard is buried here + - Rounding modes (chopped, +infinity, nearest, -infinity) + - Inexact (set if there are any rounding bits, regardless of rounding) + - Overflow (result is infinite if rounded, max if not) + - Underflow (no denorms!) + + Underflow handling is particularly complicated + - Result is always 0 + - UNF and INE are always set in FPCR + - If /U is set, + o If /S is clear, trap + o If /S is set, UNFD is set, but UNFZ is clear, ignore UNFD and + trap, because the hardware cannot produce denormals + o If /S is set, UNFD is set, and UNFZ is set, do not trap + - If /SUI is set, and INED is clear, trap */ + +t_uint64 ieee_rpack (UFP *r, uint32 ir, uint32 dp) +{ +static const t_uint64 stdrnd[2] = { UF_SRND, UF_TRND }; +static const t_uint64 infrnd[2] = { UF_SINF, UF_TINF }; +static const int32 expmax[2] = { T_BIAS - S_BIAS + S_M_EXP - 1, T_M_EXP - 1 }; +static const int32 expmin[2] = { T_BIAS - S_BIAS, 0 }; +t_uint64 rndadd, rndbits, res; +uint32 rndm; + +if (r->frac == 0) /* result 0? */ + return ((t_uint64) r->sign << FPR_V_SIGN); +rndm = I_GETFRND (ir); /* inst round mode */ +if (rndm == I_FRND_D) rndm = FPCR_GETFRND (fpcr); /* dynamic? use FPCR */ +rndbits = r->frac & infrnd[dp]; /* isolate round bits */ +if (rndm == I_FRND_N) rndadd = stdrnd[dp]; /* round to nearest? */ +else if (((rndm == I_FRND_P) && !r->sign) || /* round to inf and */ + ((rndm == I_FRND_M) && r->sign)) /* right sign? */ + rndadd = infrnd[dp]; +else rndadd = 0; +r->frac = (r->frac + rndadd) & M64; /* round */ +if ((r->frac & UF_NM) == 0) { /* carry out? */ + r->frac = (r->frac >> 1) | UF_NM; /* renormalize */ + r->exp = r->exp + 1; + } +if (rndbits) /* inexact? */ + ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */ +if (r->exp > expmax[dp]) { /* ovflo? */ + ieee_trap (TRAP_OVF, 1, FPCR_OVFD, ir); /* set overflow trap */ + ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */ + if (rndadd) /* did we round? */ + return (r->sign? FMINF: FPINF); /* return infinity */ + return (r->sign? FMMAX: FPMAX); /* no, return max */ + } +if (r->exp <= expmin[dp]) { /* underflow? */ + ieee_trap (TRAP_UNF, ir & I_FTRP_U, /* set underflow trap */ + (fpcr & FPCR_UNDZ)? FPCR_UNFD: 0, ir); /* (dsbl only if UNFZ set) */ + ieee_trap (TRAP_INE, Q_SUI (ir), FPCR_INED, ir); /* set inexact */ + return 0; /* underflow to +0 */ + } +res = (((t_uint64) r->sign) << FPR_V_SIGN) | /* form result */ + (((t_uint64) r->exp) << FPR_V_EXP) | + ((r->frac >> FPR_GUARD) & FPR_FRAC); +if ((rndm == I_FRND_N) && (rndbits == stdrnd[dp])) /* nearest and halfway? */ + res = res & ~1; /* clear lo bit */ +return res; +} + +/* IEEE arithmetic trap - only one can be set at a time! */ + +void ieee_trap (uint32 trap, uint32 instenb, uint32 fpcrdsb, uint32 ir) +{ +fpcr = fpcr | (trap << 19); /* FPCR to trap summ offset */ +if ((instenb == 0) || /* not enabled in inst? ignore */ + ((ir & I_FTRP_S) && (fpcr & fpcrdsb))) return; /* /S and disabled? ignore */ +arith_trap (trap, ir); /* set Alpha trap */ +return; +} + +/* Fraction square root routine - code from SoftFloat */ + +t_uint64 fsqrt64 (t_uint64 asig, int32 exp) +{ +t_uint64 zsig, remh, reml, t; +uint32 sticky = 0; + +zsig = estimateSqrt32 (exp, (uint32) (asig >> 32)); + +/* Calculate the final answer in two steps. First, do one iteration of + Newton's approximation. The divide-by-2 is accomplished by clever + positioning of the operands. Then, check the bits just below the + (double precision) rounding bit to see if they are close to zero + (that is, the rounding bits are close to midpoint). If so, make + sure that the result^2 is the input operand */ + +asig = asig >> ((exp & 1)? 3: 2); /* leave 2b guard */ +zsig = estimateDiv128 (asig, 0, zsig << 32) + (zsig << 30 ); +if ((zsig & 0x1FF) <= 5) { /* close to even? */ + reml = uemul64 (zsig, zsig, &remh); /* result^2 */ + remh = asig - remh - (reml? 1:0); /* arg - result^2 */ + reml = NEG_Q (reml); + while (Q_GETSIGN (remh) != 0) { /* if arg < result^2 */ + zsig = zsig - 1; /* decr result */ + t = (zsig << 1) | 1; /* incr result^2 */ + reml = reml + t; /* and retest */ + remh = remh + (zsig >> 63) + ((reml < t)? 1: 0); + } + if ((remh | reml) != 0 ) sticky = 1; /* not exact? */ + } +return zsig; +} + +/* Estimate 32b SQRT + + Calculate an approximation to the square root of the 32-bit significand given + by 'a'. Considered as an integer, 'a' must be at least 2^31. If bit 0 of + 'exp' (the least significant bit) is 1, the integer returned approximates + 2^31*sqrt('a'/2^31), where 'a' is considered an integer. If bit 0 of 'exp' + is 0, the integer returned approximates 2^31*sqrt('a'/2^30). In either + case, the approximation returned lies strictly within +/-2 of the exact + value. */ + +uint32 estimateSqrt32 (uint32 exp, uint32 a) +{ +uint32 index, z; +static const uint32 sqrtOdd[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; +static const uint32 sqrtEven[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + +index = (a >> 27) & 0xF; /* bits<30:27> */ +if (exp & 1) { /* odd exp? */ + z = 0x4000 + (a >> 17) - sqrtOdd[index]; /* initial guess */ + z = ((a / z) << 14) + (z << 15); /* Newton iteration */ + a = a >> 1; + } +else { + z = 0x8000 + (a >> 17) - sqrtEven[index]; /* initial guess */ + z = (a / z) + z; /* Newton iteration */ + z = (z >= 0x20000) ? 0xFFFF8000: (z << 15); + if (z <= a) z = (a >> 1) | 0x80000000; + } +return (uint32) ((((((t_uint64) a) << 31) / ((t_uint64) z)) + (z >> 1)) & M32); +} + +/* Estimate 128b unsigned divide */ + +t_uint64 estimateDiv128 (t_uint64 a0, t_uint64 a1, t_uint64 b) +{ +t_uint64 b0, b1; +t_uint64 rem0, rem1, term0, term1; +t_uint64 z; + +if (b <= a0) return 0xFFFFFFFFFFFFFFFF; +b0 = b >> 32; +z = ((b0 << 32) <= a0)? 0xFFFFFFFF00000000: ((a0 / b0) << 32); +term1 = uemul64 (b, z, &term0); +rem0 = a0 - term0 - (a1 < term1); +rem1 = a1 - term1; +while (Q_GETSIGN (rem0)) { + z = z - ((t_uint64) 0x100000000); + b1 = b << 32; + rem1 = b1 + rem1; + rem0 = b0 + rem0 + (rem1 < b1); + } +rem0 = (rem0 << 32) | (rem1 >> 32); +z |= (((b0 << 32) <= rem0)? 0xFFFFFFFF : (rem0 / b0)); +return z; +} diff --git a/alpha/alpha_fpv.c b/alpha/alpha_fpv.c new file mode 100644 index 00000000..67fca723 --- /dev/null +++ b/alpha/alpha_fpv.c @@ -0,0 +1,457 @@ +/* alpha_fpv.c - Alpha VAX floating point simulator + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This module contains the instruction simulators for + + - single precision floating point, F + - double precision floating point, G +*/ + +#include "alpha_defs.h" + +#define IPMAX 0x7FFFFFFFFFFFFFFF /* plus MAX (int) */ +#define IMMAX 0x8000000000000000 /* minus MAX (int) */ + +/* Unpacked rounding constants */ + +#define UF_FRND 0x0000008000000000 /* F round */ +#define UF_DRND 0x0000000000000080 /* D round */ +#define UF_GRND 0x0000000000000400 /* G round */ + +extern t_uint64 FR[32]; +extern jmp_buf save_env; + +t_bool vax_unpack (t_uint64 op, UFP *a, uint32 ir); +t_bool vax_unpack_d (t_uint64 op, UFP *a, uint32 ir); +void vax_norm (UFP *a); +t_uint64 vax_rpack (UFP *a, uint32 ir, uint32 dp); +t_uint64 vax_rpack_d (UFP *a, uint32 ir); +int32 vax_fcmp (t_uint64 a, t_uint64 b, uint32 ir); +t_uint64 vax_cvtif (t_uint64 val, uint32 ir, uint32 dp); +t_uint64 vax_cvtfi (t_uint64 op, uint32 ir); +t_uint64 vax_fadd (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp, t_bool sub); +t_uint64 vax_fmul (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp); +t_uint64 vax_fdiv (t_uint64 a, t_uint64 b, uint32 ir, uint32 dp); + +extern t_uint64 uemul64 (t_uint64 a, t_uint64 b, t_uint64 *hi); +extern t_uint64 ufdiv64 (t_uint64 dvd, t_uint64 dvr, uint32 prec, uint32 *sticky); +extern t_uint64 fsqrt64 (t_uint64 frac, int32 exp); + +/* VAX floating point loads and stores */ + +t_uint64 op_ldf (t_uint64 op) +{ +uint32 exp = F_GETEXP (op); + +if (exp != 0) exp = exp + G_BIAS - F_BIAS; /* zero? */ +return (((t_uint64) (op & F_SIGN))? FPR_SIGN: 0) | /* finite non-zero */ + (((t_uint64) exp) << FPR_V_EXP) | + (((t_uint64) SWAP_VAXF (op & ~(F_SIGN|F_EXP))) << F_V_FRAC); +} + +t_uint64 op_ldg (t_uint64 op) +{ +return SWAP_VAXG (op); /* swizzle bits */ +} + +t_uint64 op_stf (t_uint64 op) +{ +uint32 sign = FPR_GETSIGN (op)? F_SIGN: 0; +uint32 frac = (uint32) (op >> F_V_FRAC); +uint32 exp = FPR_GETEXP (op); + +if (exp != 0) exp = exp + F_BIAS - G_BIAS; /* zero? */ +exp = (exp & F_M_EXP) << F_V_EXP; +return (t_uint64) (sign | exp | (SWAP_VAXF (frac) & ~(F_SIGN|F_EXP))); +} + +t_uint64 op_stg (t_uint64 op) +{ +return SWAP_VAXG (op); /* swizzle bits */ +} + +/* VAX floating point operate */ + +void vax_fop (uint32 ir) +{ +UFP b; +t_uint64 res; +uint32 fnc, ra, rb, rc; + +fnc = I_GETFFNC (ir); /* get function */ +ra = I_GETRA (ir); /* get registers */ +rb = I_GETRB (ir); +rc = I_GETRC (ir); +switch (fnc) { /* case on func */ + + case 0x00: /* ADDF */ + res = vax_fadd (FR[ra], FR[rb], ir, DT_F, 0); + break; + + case 0x01: /* SUBF */ + res = vax_fadd (FR[ra], FR[rb], ir, DT_F, 1); + break; + + case 0x02: /* MULF */ + res = vax_fmul (FR[ra], FR[rb], ir, DT_F); + break; + + case 0x03: /* DIVF */ + res = vax_fdiv (FR[ra], FR[rb], ir, DT_F); + break; + + case 0x20: /* ADDG */ + res = vax_fadd (FR[ra], FR[rb], ir, DT_G, 0); + break; + + case 0x21: /* SUBG */ + res = vax_fadd (FR[ra], FR[rb], ir, DT_G, 1); + break; + + case 0x22: /* MULG */ + res = vax_fmul (FR[ra], FR[rb], ir, DT_G); + break; + + case 0x23: /* DIVG */ + res = vax_fdiv (FR[ra], FR[rb], ir, DT_G); + break; + + case 0x25: /* CMPGEQ */ + if (vax_fcmp (FR[ra], FR[rb], ir) == 0) res = FP_TRUE; + else res = 0; + break; + + case 0x26: /* CMPGLT */ + if (vax_fcmp (FR[ra], FR[rb], ir) < 0) res = FP_TRUE; + else res = 0; + break; + + case 0x27: /* CMPGLE */ + if (vax_fcmp (FR[ra], FR[rb], ir) <= 0) res = FP_TRUE; + else res = 0; + break; + + case 0x1E: /* CVTDG */ + if (vax_unpack_d (FR[rb], &b, ir)) res = 0; + else res = vax_rpack (&b, ir, DT_G); + break; + + case 0x2C: /* CVTGF */ + if (vax_unpack (FR[rb], &b, ir)) res = 0; + else res = vax_rpack (&b, ir, DT_F); + break; + + case 0x2D: /* CVTGD */ + if (vax_unpack (FR[rb], &b, ir)) res = 0; + else res = vax_rpack_d (&b, ir); + break; + + case 0x2F: /* CVTGQ */ + res = vax_cvtfi (FR[rb], ir); + break; + + case 0x3C: /* CVTQF */ + res = vax_cvtif (FR[rb], ir, DT_F); + break; + + case 0x3E: /* CVTQG */ + res = vax_cvtif (FR[rb], ir, DT_G); + break; + + default: + res = FR[rc]; + break; + } + +if (rc != 31) FR[rc] = res & M64; +return; +} + +/* VAX floating compare */ + +int32 vax_fcmp (t_uint64 s1, t_uint64 s2, uint32 ir) +{ +UFP a, b; + +if (vax_unpack (s1, &a, ir)) return +1; /* unpack, rsv? */ +if (vax_unpack (s2, &b, ir)) return +1; /* unpack, rsv? */ +if (s1 == s2) return 0; /* equal? */ +if (a.sign != b.sign) return (a.sign? -1: +1); /* opp signs? */ +return (((s1 < s2) ^ a.sign)? -1: +1); /* like signs */ +} + +/* VAX integer to floating convert */ + +t_uint64 vax_cvtif (t_uint64 val, uint32 ir, uint32 dp) +{ +UFP a; + +if (val == 0) return 0; /* 0? return +0 */ +if (val < 0) { /* < 0? */ + a.sign = 1; /* set sign */ + val = NEG_Q (val); /* |val| */ + } +else a.sign = 0; +a.exp = 64 + G_BIAS; /* set exp */ +a.frac = val; /* set frac */ +vax_norm (&a); /* normalize */ +return vax_rpack (&a, ir, dp); /* round and pack */ +} + +/* VAX floating to integer convert - note that rounding cannot cause a + carry unless the fraction has been shifted right at least FP_GUARD + places; in which case a carry out is impossible */ + +t_uint64 vax_cvtfi (t_uint64 op, uint32 ir) +{ +UFP a; +uint32 rndm = I_GETFRND (ir); +int32 ubexp; + +if (vax_unpack (op, &a, ir)) return 0; /* unpack, rsv? */ +ubexp = a.exp - G_BIAS; /* unbiased exp */ +if (ubexp < 0) return 0; /* zero or too small? */ +if (ubexp <= UF_V_NM) { /* in range? */ + a.frac = a.frac >> (UF_V_NM - ubexp); /* leave rnd bit */ + if (rndm) a.frac = a.frac + 1; /* not chopped, round */ + a.frac = a.frac >> 1; /* now justified */ + if ((a.frac > (a.sign? IMMAX: IPMAX)) && /* out of range? */ + (ir & I_FTRP_V)) /* trap enabled? */ + arith_trap (TRAP_IOV, ir); /* set overflow */ + } +else { + if (ubexp > (UF_V_NM + 64)) a.frac = 0; /* out of range */ + else a.frac = (a.frac << (ubexp - UF_V_NM - 1)) & M64; /* no rnd bit */ + if (ir & I_FTRP_V) /* trap enabled? */ + arith_trap (TRAP_IOV, ir); /* set overflow */ + } +return (a.sign? NEG_Q (a.frac): a.frac); +} + +/* VAX floating add */ + +t_uint64 vax_fadd (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp, t_bool sub) +{ +UFP a, b, t; +uint32 sticky; +int32 ediff; + +if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */ +if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */ +if (sub) b.sign = b.sign ^ 1; /* sub? invert b sign */ +if (a.exp == 0) a = b; /* s1 = 0? */ +else if (b.exp) { /* s2 != 0? */ + if ((a.exp < b.exp) || /* |s1| < |s2|? swap */ + ((a.exp == b.exp) && (a.frac < b.frac))) { + t = a; + a = b; + b = t; + } + ediff = a.exp - b.exp; /* exp diff */ + if (a.sign ^ b.sign) { /* eff sub? */ + if (ediff > 63) b.frac = 1; /* >63? retain sticky */ + else if (ediff) { /* [1,63]? shift */ + sticky = ((b.frac << (64 - ediff)) & M64)? 1: 0; /* lost bits */ + b.frac = (b.frac >> ediff) | sticky; + } + a.frac = (a.frac - b.frac) & M64; /* subtract fractions */ + vax_norm (&a); /* normalize */ + } + else { /* eff add */ + if (ediff > 63) b.frac = 0; /* >63? b disappears */ + else if (ediff) b.frac = b.frac >> ediff; /* denormalize */ + a.frac = (a.frac + b.frac) & M64; /* add frac */ + if (a.frac < b.frac) { /* chk for carry */ + a.frac = UF_NM | (a.frac >> 1); /* shift in carry */ + a.exp = a.exp + 1; /* skip norm */ + } + } + } /* end else if */ +return vax_rpack (&a, ir, dp); /* round and pack */ +} + +/* VAX floating multiply */ + +t_uint64 vax_fmul (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp) +{ +UFP a, b; + +if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */ +if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */ +if ((a.exp == 0) || (b.exp == 0)) return 0; /* zero argument? */ +a.sign = a.sign ^ b.sign; /* sign of result */ +a.exp = a.exp + b.exp - G_BIAS; /* add exponents */ +uemul64 (a.frac, b.frac, &a.frac); /* mpy fractions */ +vax_norm (&a); /* normalize */ +return vax_rpack (&a, ir, dp); /* round and pack */ +} + +/* VAX floating divide + Needs to develop at least one rounding bit. Since the first + divide step can fail, develop 2 more bits than the precision of + the fraction. */ + +t_uint64 vax_fdiv (t_uint64 s1, t_uint64 s2, uint32 ir, uint32 dp) +{ +UFP a, b; + +if (vax_unpack (s1, &a, ir)) return 0; /* unpack, rsv? */ +if (vax_unpack (s2, &b, ir)) return 0; /* unpack, rsv? */ +if (b.exp == 0) { /* divr = 0? */ + arith_trap (TRAP_DZE, ir); /* dze trap */ + return 0; + } +if (a.exp == 0) return 0; /* divd = 0? */ +a.sign = a.sign ^ b.sign; /* result sign */ +a.exp = a.exp - b.exp + G_BIAS + 1; /* unbiased exp */ +a.frac = a.frac >> 1; /* allow 1 bit left */ +b.frac = b.frac >> 1; +a.frac = ufdiv64 (a.frac, b.frac, 55, NULL); /* divide */ +vax_norm (&a); /* normalize */ +return vax_rpack (&a, ir, dp); /* round and pack */ +} + +/* VAX floating square root */ + +t_uint64 vax_sqrt (uint32 ir, uint32 dp) +{ +t_uint64 op; +UFP b; + +op = FR[I_GETRB (ir)]; /* get F[rb] */ +if (vax_unpack (op, &b, ir)) return 0; /* unpack, rsv? */ +if (b.exp == 0) return 0; /* zero? */ +if (b.sign) { /* minus? */ + arith_trap (TRAP_INV, ir); /* invalid operand */ + return 0; + } +b.exp = ((b.exp + 1 - G_BIAS) >> 1) + G_BIAS; /* result exponent */ +b.frac = fsqrt64 (b.frac, b.exp); /* result fraction */ +return vax_rpack (&b, ir, dp); /* round and pack */ +} + +/* Support routines */ + +t_bool vax_unpack (t_uint64 op, UFP *r, uint32 ir) +{ +r->sign = FPR_GETSIGN (op); /* get sign */ +r->exp = FPR_GETEXP (op); /* get exponent */ +r->frac = FPR_GETFRAC (op); /* get fraction */ +if (r->exp == 0) { /* exp = 0? */ + if (op != 0) arith_trap (TRAP_INV, ir); /* rsvd op? */ + r->frac = r->sign = 0; + return TRUE; + } +r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */ +return FALSE; +} + +t_bool vax_unpack_d (t_uint64 op, UFP *r, uint32 ir) +{ +r->sign = FDR_GETSIGN (op); /* get sign */ +r->exp = FDR_GETEXP (op); /* get exponent */ +r->frac = FDR_GETFRAC (op); /* get fraction */ +if (r->exp == 0) { /* exp = 0? */ + if (op != 0) arith_trap (TRAP_INV, ir); /* rsvd op? */ + r->frac = r->sign = 0; + return TRUE; + } +r->exp = r->exp + G_BIAS - D_BIAS; /* change to G bias */ +r->frac = (r->frac | FDR_HB) << FDR_GUARD; /* ins hidden bit, guard */ +return FALSE; +} + +/* VAX normalize */ + +void vax_norm (UFP *r) +{ +int32 i; +static t_uint64 normmask[5] = { + 0xc000000000000000, 0xf000000000000000, 0xff00000000000000, + 0xffff000000000000, 0xffffffff00000000 + }; +static int32 normtab[6] = { 1, 2, 4, 8, 16, 32 }; + +r->frac = r->frac & M64; +if (r->frac == 0) { /* if fraction = 0 */ + r->sign = r->exp = 0; /* result is 0 */ + return; + } +while ((r->frac & UF_NM) == 0) { /* normalized? */ + for (i = 0; i < 5; i++) { /* find first 1 */ + if (r->frac & normmask[i]) break; + } + r->frac = r->frac << normtab[i]; /* shift frac */ + r->exp = r->exp - normtab[i]; /* decr exp */ + } +return; +} + +/* VAX round and pack */ + +t_uint64 vax_rpack (UFP *r, uint32 ir, uint32 dp) +{ +uint32 rndm = I_GETFRND (ir); +static const t_uint64 roundbit[2] = { UF_FRND, UF_GRND }; +static const int32 expmax[2] = { G_BIAS - F_BIAS + F_M_EXP, G_M_EXP }; +static const int32 expmin[2] = { G_BIAS - F_BIAS, 0 }; + +if (r->frac == 0) return 0; /* result 0? */ +if (rndm) { /* round? */ + r->frac = (r->frac + roundbit[dp]) & M64; /* add round bit */ + if ((r->frac & UF_NM) == 0) { /* carry out? */ + r->frac = (r->frac >> 1) | UF_NM; /* renormalize */ + r->exp = r->exp + 1; + } + } +if (r->exp > expmax[dp]) { /* ovflo? */ + arith_trap (TRAP_OVF, ir); /* set trap */ + r->exp = expmax[dp]; /* return max */ + } +if (r->exp <= expmin[dp]) { /* underflow? */ + if (ir & I_FTRP_V) arith_trap (TRAP_UNF, ir); /* enabled? set trap */ + return 0; /* underflow to 0 */ + } +return (((t_uint64) r->sign) << FPR_V_SIGN) | + (((t_uint64) r->exp) << FPR_V_EXP) | + ((r->frac >> FPR_GUARD) & FPR_FRAC); +} + +t_uint64 vax_rpack_d (UFP *r, uint32 ir) +{ +if (r->frac == 0) return 0; /* result 0? */ +r->exp = r->exp + D_BIAS - G_BIAS; /* rebias */ +if (r->exp > FDR_M_EXP) { /* ovflo? */ + arith_trap (TRAP_OVF, ir); /* set trap */ + r->exp = FDR_M_EXP; /* return max */ + } +if (r->exp <= 0) { /* underflow? */ + if (ir & I_FTRP_V) arith_trap (TRAP_UNF, ir); /* enabled? set trap */ + return 0; /* underflow to 0 */ + } +return (((t_uint64) r->sign) << FDR_V_SIGN) | + (((t_uint64) r->exp) << FDR_V_EXP) | + ((r->frac >> FDR_GUARD) & FDR_FRAC); +} diff --git a/alpha/alpha_io.c b/alpha/alpha_io.c new file mode 100644 index 00000000..aa021d41 --- /dev/null +++ b/alpha/alpha_io.c @@ -0,0 +1,214 @@ +/* alpha_io.c: Alpha I/O and miscellaneous devices + + Copyright (c) 2006, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + rom boot ROM +*/ + +#include "alpha_defs.h" +#include "alpha_sys_defs.h" + +t_uint64 *rom = NULL; /* boot ROM */ + +extern DEVICE *sim_devices[]; + +t_bool rom_rd (t_uint64 pa, t_uint64 *val, uint32 lnt); +t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt); +t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw); +t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw); +t_stat rom_reset (DEVICE *dptr); + +/* ROM data structures + + rom_dev ROM device descriptor + rom_unit ROM units + rom_reg ROM register list +*/ + +DIB rom_dib = { + ROMBASE, ROMBASE + ROMSIZE, &rom_rd, &rom_wr, 0 + }; + +UNIT rom_unit = { + UDATA (NULL, UNIT_FIX+UNIT_BINK, ROMSIZE) + }; + +REG rom_reg[] = { + { NULL } + }; + +DEVICE rom_dev = { + "ROM", &rom_unit, rom_reg, NULL, + 1, 16, 24, 8, 16, 64, + &rom_ex, &rom_dep, &rom_reset, + NULL, NULL, NULL, + &rom_dib, DEV_DIB + }; + +/* ReadIO - read IO space + + Inputs: + pa = physical address + *dat = pointer to data + lnt = length (BWLQ) + Output: + TRUE if read succeeds, else FALSE +*/ + +t_bool ReadIO (t_uint64 pa, t_uint64 *dat, uint32 lnt) +{ +DEVICE *dptr; +uint32 i; + +for (i = 0; sim_devices[i] != NULL; i++) { + dptr = sim_devices[i]; + if (dptr->flags & DEV_DIB) { + DIB *dibp = (DIB *) dptr->ctxt; + if ((pa >= dibp->low) && (pa < dibp->high)) + return dibp->read (pa, dat, lnt); + } + } +return FALSE; +} + +/* WriteIO - write register space + + Inputs: + ctx = CPU context + pa = physical address + val = data to write, right justified in 64b quadword + lnt = length (BWLQ) + Output: + TRUE if write succeeds, else FALSE +*/ + +t_bool WriteIO (t_uint64 pa, t_uint64 dat, uint32 lnt) +{ +DEVICE *dptr; +uint32 i; + +for (i = 0; sim_devices[i] != NULL; i++) { + dptr = sim_devices[i]; + if (dptr->flags & DEV_DIB) { + DIB *dibp = (DIB *) dptr->ctxt; + if ((pa >= dibp->low) && (pa < dibp->high)) + return dibp->write (pa, dat, lnt); + } + } +return FALSE; +} + +/* Boot ROM read */ + +t_bool rom_rd (t_uint64 pa, t_uint64 *val, uint32 lnt) +{ +uint32 sc, rg = ((uint32) ((pa - ROMBASE) & (ROMSIZE - 1))) >> 3; + +switch (lnt) { + + case L_BYTE: + sc = (((uint32) pa) & 7) * 8; + *val = (rom[rg] >> sc) & M8; + break; + + case L_WORD: + sc = (((uint32) pa) & 6) * 8; + *val = (rom[rg] >> sc) & M16; + break; + + case L_LONG: + if (pa & 4) *val = (rom[rg] >> 32) & M32; + else *val = rom[rg] & M32; + break; + + case L_QUAD: + *val = rom[rg]; + break; + } + +return TRUE; +} + +/* Boot ROM write */ + +t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt) +{ +uint32 sc, rg = ((uint32) ((pa - ROMBASE) & (ROMSIZE - 1))) >> 3; + +switch (lnt) { + + case L_BYTE: + sc = (((uint32) pa) & 7) * 8; + rom[rg] = (rom[rg] & ~(((t_uint64) M8) << sc)) | (((t_uint64) (val & M8)) << sc); + break; + + case L_WORD: + sc = (((uint32) pa) & 6) * 8; + rom[rg] = (rom[rg] & ~(((t_uint64) M16) << sc)) | (((t_uint64) (val & M16)) << sc); + break; + + case L_LONG: + if (pa & 4) rom[rg] = ((t_uint64) (rom[rg] & M32)) | (((t_uint64) (val & M32)) << 32); + else rom[rg] = (rom[rg] & ~((t_uint64) M32)) | ((t_uint64) val & M32); + break; + + case L_QUAD: + rom[rg] = val; + break; + } + +return TRUE; +} + +/* ROM examine */ + +t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw) +{ +uint32 addr = (uint32) exta; + +if (vptr == NULL) return SCPE_ARG; +if (addr >= ROMSIZE) return SCPE_NXM; +*vptr = rom[addr >> 3]; +return SCPE_OK; +} + +/* ROM deposit */ + +t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw) +{ +uint32 addr = (uint32) exta; + +if (addr >= ROMSIZE) return SCPE_NXM; +rom[addr >> 3] = val; +return SCPE_OK; +} + +/* ROM reset */ + +t_stat rom_reset (DEVICE *dptr) +{ +if (rom == NULL) rom = (t_uint64 *) calloc (ROMSIZE >> 3, sizeof (t_uint64)); +if (rom == NULL) return SCPE_MEM; +return SCPE_OK; +} diff --git a/alpha/alpha_mmu.c b/alpha/alpha_mmu.c new file mode 100644 index 00000000..8d000b09 --- /dev/null +++ b/alpha/alpha_mmu.c @@ -0,0 +1,308 @@ +/* alpha_mmu.c - Alpha memory management simulator + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This module contains the routines for + + ReadB,W,L,Q - read aligned virtual + ReadAccL,Q - read aligned virtual, special access check + ReadPB,W,L,Q - read aligned physical + WriteB,W,L,Q - write aligned virtual + WriteAccL,Q - write aligned virtual, special access check + WritePB,W,L,Q - write aligned physical + + The TLB is organized for optimum lookups and is broken up into three fields: + + tag VA<42:13> for an 8KB page system + pte PTE<31:0>, <31:16> are zero; FOE, FOR, FOW stored inverted + pfn PFN<31:0> left shifted by page size + + The inversion of FOE, FOR, FOW means that all checked bits must be one + for a reference to proceed. + + All Alpha implementations provide support for a 43b superpage for Unix, + and a 32b superpage for NT: + + 43b superpage 0xFFFFFC0000000000:0xFFFFFDFFFFFFFFFF + 32b superpage 0xFFFFFFFF80000000:0xFFFFFFFFBFFFFFFF +*/ + +#include "alpha_defs.h" + +extern t_uint64 trans_i (t_uint64 va); +extern t_uint64 trans_d (t_uint64 va, uint32 acc); + +extern t_uint64 *M; +extern t_uint64 p1; +extern uint32 pal_mode, dmapen; +extern uint32 cm_eacc, cm_racc, cm_wacc; +extern jmp_buf save_env; +extern UNIT cpu_unit; + +/* Read virtual aligned + + Inputs: + va = virtual address + Output: + returned data, right justified +*/ + +t_uint64 ReadB (t_uint64 va) +{ +t_uint64 pa; + +if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */ +else pa = va; +return ReadPB (pa); +} + +t_uint64 ReadW (t_uint64 va) +{ +t_uint64 pa; + +if (va & 1) ABORT1 (va, EXC_ALIGN); /* must be W aligned */ +if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */ +else pa = va; +return ReadPW (pa); +} + +t_uint64 ReadL (t_uint64 va) +{ +t_uint64 pa; + +if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */ +if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */ +else pa = va; +return ReadPL (pa); +} + +t_uint64 ReadQ (t_uint64 va) +{ +t_uint64 pa; + +if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */ +if (dmapen) pa = trans_d (va, cm_racc); /* mapping on? */ +else pa = va; +return ReadPQ (pa); +} + +/* Read with generalized access controls - used by PALcode */ + +t_uint64 ReadAccL (t_uint64 va, uint32 acc) +{ +t_uint64 pa; + +if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */ +if (dmapen) pa = trans_d (va, acc); /* mapping on? */ +else pa = va; +return ReadPL (pa); +} + +t_uint64 ReadAccQ (t_uint64 va, uint32 acc) +{ +t_uint64 pa; + +if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */ +if (dmapen) pa = trans_d (va, acc); /* mapping on? */ +else pa = va; +return ReadPQ (pa); +} + +/* Read instruction */ + +uint32 ReadI (t_uint64 va) +{ +t_uint64 pa; + +if (!pal_mode) pa = trans_i (va); /* mapping on? */ +else pa = va; +return (uint32) ReadPL (pa); +} + +/* Write virtual aligned + + Inputs: + va = virtual address + val = data to be written, right justified in 32b or 64b + Output: + none +*/ + +void WriteB (t_uint64 va, t_uint64 dat) +{ +t_uint64 pa; + +if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */ +else pa = va; +WritePB (pa, dat); +return; +} + +void WriteW (t_uint64 va, t_uint64 dat) +{ +t_uint64 pa; + +if (va & 1) ABORT1 (va, EXC_ALIGN); /* must be W aligned */ +if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */ +else pa = va; +WritePW (pa, dat); +return; +} + +void WriteL (t_uint64 va, t_uint64 dat) +{ +t_uint64 pa; + +if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */ +if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */ +else pa = va; +WritePL (pa, dat); +return; +} + +void WriteQ (t_uint64 va, t_uint64 dat) +{ +t_uint64 pa; + +if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */ +if (dmapen) pa = trans_d (va, cm_wacc); /* mapping on? */ +else pa = va; +WritePQ (pa, dat); +return; +} + +/* Write with generalized access controls - used by PALcode */ + +void WriteAccL (t_uint64 va, t_uint64 dat, uint32 acc) +{ +t_uint64 pa; + +if (va & 3) ABORT1 (va, EXC_ALIGN); /* must be L aligned */ +if (dmapen) pa = trans_d (va, acc); /* mapping on? */ +else pa = va; +WritePL (pa, dat); +return; +} + +void WriteAccQ (t_uint64 va, t_uint64 dat, uint32 acc) +{ +t_uint64 pa; + +if (va & 7) ABORT1 (va, EXC_ALIGN); /* must be Q aligned */ +if (dmapen) pa = trans_d (va, acc); /* mapping on? */ +else pa = va; +WritePQ (pa, dat); +return; +} + +/* Read and write physical aligned - access point to I/O */ + +INLINE t_uint64 ReadPB (t_uint64 pa) +{ +t_uint64 val; + +if (ADDR_IS_MEM (pa)) { + uint32 bo = ((uint32) pa) & 07; + return (((M[pa >> 3] >> (bo << 3))) & M8); + } +if (ReadIO (pa, &val, L_BYTE)) return val; +return 0; +} + +INLINE t_uint64 ReadPW (t_uint64 pa) +{ +t_uint64 val; + +if (ADDR_IS_MEM (pa)) { + uint32 bo = ((uint32) pa) & 06; + return (((M[pa >> 3] >> (bo << 3))) & M16); + } +if (ReadIO (pa, &val, L_WORD)) return val; +return 0; +} + +INLINE t_uint64 ReadPL (t_uint64 pa) +{ +t_uint64 val; + +if (ADDR_IS_MEM (pa)) { + if (pa & 4) return (((M[pa >> 3] >> 32)) & M32); + return ((M[pa >> 3]) & M32); + } +if (ReadIO (pa, &val, L_LONG)) return val; +return 0; +} + +INLINE t_uint64 ReadPQ (t_uint64 pa) +{ +t_uint64 val; + +if (ADDR_IS_MEM (pa)) return M[pa >> 3]; +if (ReadIO (pa, &val, L_QUAD)) return val; +return 0; +} + +INLINE void WritePB (t_uint64 pa, t_uint64 dat) +{ +dat = dat & M8; +if (ADDR_IS_MEM (pa)) { + uint32 bo = ((uint32) pa) & 07; + M[pa >> 3] = (M[pa >> 3] & ~(((t_uint64) M8) << (bo << 3))) | + (dat << (bo << 3)); + } +else WriteIO (pa, dat, L_BYTE); +return; +} + +INLINE void WritePW (t_uint64 pa, t_uint64 dat) +{ +dat = dat & M16; +if (ADDR_IS_MEM (pa)) { + uint32 bo = ((uint32) pa) & 07; + M[pa >> 3] = (M[pa >> 3] & ~(((t_uint64) M16) << (bo << 3))) | + (dat << (bo << 3)); + } +else WriteIO (pa, dat, L_WORD); +return; +} + +INLINE void WritePL (t_uint64 pa, t_uint64 dat) +{ +dat = dat & M32; +if (ADDR_IS_MEM (pa)) { + if (pa & 4) M[pa >> 3] = (M[pa >> 3] & M32) | + (dat << 32); + else M[pa >> 3] = (M[pa >> 3] & ~((t_uint64) M32)) | dat; + } +else WriteIO (pa, dat, L_LONG); +return; +} + +INLINE void WritePQ (t_uint64 pa, t_uint64 dat) +{ +if (ADDR_IS_MEM (pa)) M[pa >> 3] = dat; +else WriteIO (pa, dat, L_QUAD); +return; +} + diff --git a/alpha/alpha_sys.c b/alpha/alpha_sys.c new file mode 100644 index 00000000..630f9df5 --- /dev/null +++ b/alpha/alpha_sys.c @@ -0,0 +1,814 @@ +/* alpha_sys.c: Alpha simulator interface + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "alpha_defs.h" +#include + +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern int32 sim_switches; +extern uint32 pal_type; + +t_stat fprint_sym_m (FILE *of, t_addr addr, uint32 inst); +t_stat parse_sym_m (char *cptr, t_addr addr, t_value *inst); +int32 parse_reg (char *cptr); + +extern t_stat fprint_pal_hwre (FILE *of, uint32 inst); +extern t_stat parse_pal_hwre (char *cptr, t_value *inst); +extern t_bool rom_wr (t_uint64 pa, t_uint64 val, uint32 lnt); + +/* SCP data structures and interface routines + + sim_PC pointer to saved PC register descriptor + sim_emax number of words for examine + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 1; + +const char *sim_stop_messages[] = { + "Unknown error", + "HALT instruction", + "Breakpoint", + "Unsupported PAL variation", + "Kernel stack not valid", + "Unknown abort code", + "Memory management error" + }; + +/* Binary loader + + The binary loader handles absolute system images, that is, system + images linked /SYSTEM. These are simply a byte stream, with no + origin or relocation information. + + -r load ROM + -o specify origin +*/ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +t_stat r; +int32 i; +t_uint64 origin; + +if (flag) return SCPE_ARG; /* dump? */ +origin = 0; /* memory */ +if (sim_switches & SWMASK ('O')) { /* origin? */ + origin = get_uint (cptr, 16, 0xFFFFFFFF, &r); + if (r != SCPE_OK) return SCPE_ARG; + } + +while ((i = getc (fileref)) != EOF) { /* read byte stream */ + if (sim_switches & SWMASK ('R')) { /* ROM? */ + if (!rom_wr (origin, i, L_BYTE)) + return SCPE_NXM; + } + else if (ADDR_IS_MEM (origin)) /* valid memory? */ + WritePB (origin, i); + else return SCPE_NXM; + origin = origin + 1; + } +return SCPE_OK; +} + +/* Opcode mnemonics table */ + +#define CL_NO 0 /* no operand */ +#define CL_BR 1 /* branch */ +#define CL_MR 2 /* memory reference */ +#define CL_IO 3 /* integer opr */ +#define CL_FO 4 /* floating opr */ +#define CL_MO 5 /* memory opr */ +#define CL_JP 6 /* jump */ +#define CL_HW 7 /* hardware */ +#define CL_M_PAL 0x00F0 +#define CL_V_PAL 4 +#define CL_VMS (1u << (PAL_VMS + CL_V_PAL)) +#define CL_UNIX (1u << (PAL_UNIX + CL_V_PAL)) +#define CL_NT (1u << (PAL_NT + CL_V_PAL)) +#define FL_RA 0x0100 +#define FL_RB 0x0200 +#define FL_RC 0x0400 +#define FL_RBI 0x0800 +#define FL_MDP 0x1000 +#define FL_BDP 0x2000 +#define FL_JDP 0x4000 +#define FL_LIT 0x8000 +#define CL_CLASS 0x000F +#define PAL_MASK(x) (1u << (pal_type + CL_V_PAL)) + +#define C_NO CL_NO +#define C_PCM CL_NO | CL_VMS | CL_UNIX | CL_NT +#define C_PVM CL_NO | CL_VMS +#define C_PUN CL_NO | CL_UNIX +#define C_PNT CL_NO | CL_NT +#define C_BR CL_BR | FL_RA | FL_BDP +#define C_MR CL_MR | FL_RA | FL_RB | FL_RBI | FL_MDP +#define C_FE CL_MO | FL_RB | FL_RBI +#define C_RV CL_MO | FL_RA +#define C_MO CL_MO | FL_RA | FL_RB +#define C_IO CL_IO | FL_RA | FL_RB | FL_RC | FL_LIT +#define C_IAC CL_IO | FL_RA | FL_RC +#define C_IBC CL_IO | FL_RB | FL_RC | FL_LIT +#define C_FO CL_FO | FL_RA | FL_RB | FL_RC +#define C_FAC CL_FO | FL_RA | FL_RC +#define C_FBC CL_FO | FL_RB | FL_RC +#define C_JP CL_JP | FL_RA | FL_RB | FL_RBI | FL_JDP +#define C_HW CL_HW + +uint32 masks[8] = { + 0xFFFFFFFF, 0xFC000000, + 0xFC000000, 0xFC000FE0, + 0xFC00FFE0, 0xFC00FFFF, + 0xFC00C000, 0xFC000000 + }; + +const char *opcode[] = { + "HALT", "DRAINA", "CFLUSH", "LDQP", /* VMS PALcode */ + "STQP", "SWPCTX", "MFPR_ASN", "MTPR_ASTEN", + "MTPR_ASTSR", "CSERVE", "SWPPAL", "MFPR_FEN", + "MTPR_FEN", "MTPR_IPIR", "MFPR_IPL", "MTPR_IPL", + "MFPR_MCES", "MTPR_MCES", "MFPR_PCBB", "MFPR_PRBR", + "MTPR_PRBR", "MFPR_PTBR", "MFPR_SCBB", "MTPR_SCBB", + "MTPR_SIRR", "MFPR_SISR", "MFPR_TBCHK", "MTPR_TBIA", + "MTPR_TBIAP", "MTPR_TBIS", "MFPR_ESP", "MTPR_ESP", + "MFPR_SSP", "MTPR_SSP", "MFPR_USP", "MTPR_USP", + "MTPR_TBISD", "MTPR_TBISI", "MFPR_ASTEN", "MFPR_ASTSR", + "MFPR_VTBR", "MTPR_VTBR", "MTPR_PERFMON", "MTPR_DATFX", + "MFPR_VIRBND", "MTPR_VIRBND", "MFPR_SYSPTBR", "MTPR_SYSPTBR", + "WTINT", "MFPR_WHAMI", + "BPT", "BUGCHK", "CHME", "CHMK", + "CHMS", "CHMU", "IMB", "INSQHIL", + "INSQTIL", "INSQHIQ", "INSQTIQ", "INSQUEL", + "INSQUEQ", "INSQUEL/D", "INSQUEQ/D", "PROBER", + "PROBEW", "RD_PS", "REI", "REMQHIL", + "REMQTIL", "REMQHIQ", "REMQTIQ", "REMQUEL", + "REMQUEQ", "REMQUEL/D", "REMQUEQ/D", "SWASTEN", + "WR_PS_SW", "RSCC", "RD_UNQ", "WR_UNQ", + "AMOVRR", "AMOVRM", "INSQHILR", "INSQTILR", + "INSQHIQR", "INSQTIQR", "REMQHILR", "REMQTILR", + "REMQHIQR", "REMQTIQR", "GENTRAP", "CLRFEN", + "RDMCES", "WRMCES", "WRVIRBND", "WRSYSPTBR", /* UNIX PALcode */ + "WRFEN", "WRVPTPTR", "WRASN", + "SWPCTX", "WRVAL", "RDVAL", "TBI", + "WRENT", "SWPIPL", "RDPS", "WRKGP", + "WRUSP", "WRPERFMON", "RDUSP", + "WHAMI", "RETSYS", "RTI", + "URTI", "RDUNIQUE", "WRUNIQUE", + "LDA", "LDAH", "LDBU", "LDQ_U", + "LDWU", "STW", "STB", "STQ_U", + "ADDL", "S4ADDL", "SUBL", "S4SUBL", + "CMPBGE", "S8ADDL", "S8SUBL", "CMPULT", + "ADDQ", "S4ADDQ", "SUBQ", "S4SUBQ", + "CMPEQ", "S8ADDQ", "S8SUBQ", "CMPULE", + "ADDL/V", "SUBL/V", "CMPLT", + "ADDQ/V", "SUBQ/V", "CMPLE", + "AND", "BIC", "CMOVLBS", "CMOVLBC", + "BIS", "CMOVEQ", "CMOVNE", "ORNOT", + "XOR", "CMOVLT", "CMOVGE", "EQV", + "CMOVLE", "CMOVGT", + "MSKBL", "EXTBL", "INSBL", + "MSKWL", "EXTWL", "INSWL", + "MSKLL", "EXTLL", "INSLL", + "ZAP", "ZAPNOT", "MSKQL", "SRL", + "EXTQL", "SLL", "INSQL", "SRA", + "MSKWQ", "EXTWQ", "INSWQ", + "MSKLQ", "EXTLQ", "INSLQ", + "MSKQH", "EXTQH", "INSQH", + "MULL", "MULQ", "UMULH", + "MULL/V", "MULLQ/V", + "ITOFS", "ITOFF", "ITOFT", + "SQRTF/C", "SQRTF", "SQRTF/UC", "SQRTF/U", + "SQRTF/SC", "SQRTF/S", "SQRTF/SUC", "SQRTF/SU", + "SQRTG/C", "SQRTG", "SQRTG/UC", "SQRTG/U", + "SQRTG/SC", "SQRTG/S", "SQRTG/SUC", "SQRTG/SU", + "SQRTS/C", "SQRTS/M", "SQRTS", "SQRTS/D", + "SQRTS/UC", "SQRTS/UM", "SQRTS/U", "SQRTS/UD", + "SQRTS/SUC", "SQRTS/SUM", "SQRTS/SU", "SQRTS/SUD", + "SQRTS/SUIC", "SQRTS/SUIM", "SQRTS/SUI", "SQRTS/SUID", + "SQRTT/C", "SQRTT/M", "SQRTT", "SQRTT/D", + "SQRTT/UC", "SQRTT/UM", "SQRTT/U", "SQRTT/UD", + "SQRTT/SUC", "SQRTT/SUM", "SQRTT/SU", "SQRTT/SUD", + "SQRTT/SUIC", "SQRTT/SUIM", "SQRTT/SUI", "SQRTT/SUID", + "ADDF/C", "ADDF", "ADDF/UC", "ADDF/U", + "ADDF/SC", "ADDF/S", "ADDF/SUC", "ADDF/SU", + "SUBF/C", "SUBF", "SUBF/UC", "SUBF/U", + "SUBF/SC", "SUBF/S", "SUBF/SUC", "SUBF/SU", + "MULF/C", "MULF", "MULF/UC", "MULF/U", + "MULF/SC", "MULF/S", "MULF/SUC", "MULF/SU", + "DIVF/C", "DIVF", "DIVF/UC", "DIVF/U", + "DIVF/SC", "DIVF/S", "DIVF/SUC", "DIVF/SU", + "ADDG/C", "ADDG", "ADDG/UC", "ADDG/U", + "ADDG/SC", "ADDG/S", "ADDG/SUC", "ADDG/SU", + "SUBG/C", "SUBG", "SUBG/UC", "SUBG/U", + "SUBG/SC", "SUBG/S", "SUBG/SUC", "SUBG/SU", + "MULG/C", "MULG", "MULG/UC", "MULG/U", + "MULG/SC", "MULG/S", "MULG/SUC", "MULG/SU", + "DIVG/C", "DIVG", "DIVG/UC", "DIVG/U", + "DIVG/SC", "DIVG/S", "DIVG/SUC", "DIVG/SU", + "CVTDG/C", "CVTDG", "CVTDG/UC", "CVTDG/U", + "CVTDG/SC", "CVTDG/S", "CVTDG/SUC", "CVTDG/SU", + "CVTGF/C", "CVTGF", "CVTGF/UC", "CVTGF/U", + "CVTGF/SC", "CVTGF/S", "CVTGF/SUC", "CVTGF/SU", + "CVTGD/C", "CVTGD", "CVTGD/UC", "CVTGD/U", + "CVTGD/SC", "CVTGD/S", "CVTGD/SUC", "CVTGD/SU", + "CVTGQ/C", "CVTGQ", "CVTGQ/VC", "CVTGQ/V", + "CVTGQ/SC", "CVTGQ/S", "CVTGQ/SVC", "CVTGQ/SV", + "CVTQF/C", "CVTQF", "CVTQG/C", "CVTQG", + "CMPGEQ/C", "CMPGEQ/SC", "CMPGLT/C", "CMPGLT/SC", + "CMPGLE/C", "CMPGLE/SC", + "ADDS/C", "ADDS/M", "ADDS", "ADDS/D", + "ADDS/UC", "ADDS/UM", "ADDS/U", "ADDS/UD", + "ADDS/SUC", "ADDS/SUM", "ADDS/SU", "ADDS/SUD", + "ADDS/SUIC", "ADDS/SUIM", "ADDS/SUI", "ADDS/SUID", + "SUBS/C", "SUBS/M", "SUBS", "SUBS/D", + "SUBS/UC", "SUBS/UM", "SUBS/U", "SUBS/UD", + "SUBS/SUC", "SUBS/SUM", "SUBS/SU", "SUBS/SUD", + "SUBS/SUIC", "SUBS/SUIM", "SUBS/SUI", "SUBS/SUID", + "MULS/C", "MULS/M", "MULS", "MULS/D", + "MULS/UC", "MULS/UM", "MULS/U", "MULS/UD", + "MULS/SUC", "MULS/SUM", "MULS/SU", "MULS/SUD", + "MULS/SUIC", "MULS/SUIM", "MULS/SUI", "MULS/SUID", + "DIVS/C", "DIVS/M", "DIVS", "DIVS/D", + "DIVS/UC", "DIVS/UM", "DIVS/U", "DIVS/UD", + "DIVS/SUC", "DIVS/SUM", "DIVS/SU", "DIVS/SUD", + "DIVS/SUIC", "DIVS/SUIM", "DIVS/SUI", "DIVS/SUID", + "ADDT/C", "ADDT/M", "ADDT", "ADDT/D", + "ADDT/UC", "ADDT/UM", "ADDT/U", "ADDT/UD", + "ADDT/SUC", "ADDT/SUM", "ADDT/SU", "ADDT/SUD", + "ADDT/SUIC", "ADDT/SUIM", "ADDT/SUI", "ADDT/SUID", + "SUBT/C", "SUBT/M", "SUBT", "SUBT/D", + "SUBT/UC", "SUBT/UM", "SUBT/U", "SUBT/UD", + "SUBT/SUC", "SUBT/SUM", "SUBT/SU", "SUBT/SUD", + "SUBT/SUIC", "SUBT/SUIM", "SUBT/SUI", "SUBT/SUID", + "MULT/C", "MULT/M", "MULT", "MULT/D", + "MULT/UC", "MULT/UM", "MULT/U", "MULT/UD", + "MULT/SUC", "MULT/SUM", "MULT/SU", "MULT/SUD", + "MULT/SUIC", "MULT/SUIM", "MULT/SUI", "MULT/SUID", + "DIVT/C", "DIVT/M", "DIVT", "DIVT/D", + "DIVT/UC", "DIVT/UM", "DIVT/U", "DIVT/UD", + "DIVT/SUC", "DIVT/SUM", "DIVT/SU", "DIVT/SUD", + "DIVT/SUIC", "DIVT/SUIM", "DIVT/SUI", "DIVT/SUID", + "CVTTS/C", "CVTTS/M", "CVTTS", "CVTTS/D", + "CVTTS/UC", "CVTTS/UM", "CVTTS/U", "CVTTS/UD", + "CVTTS/SUC", "CVTTS/SUM", "CVTTS/SU", "CVTTS/SUD", + "CVTTS/SUIC", "CVTTS/SUIM", "CVTTS/SUI", "CVTTS/SUID", + "CVTTQ/C", "CVTTQ/M", "CVTTQ", "CVTTQ/D", + "CVTTQ/VC", "CVTTQ/VM", "CVTTQ/V", "CVTTQ/VD", + "CVTTQ/SVC", "CVTTQ/SVM", "CVTTQ/SV", "CVTTQ/SVD", + "CVTTQ/SVIC", "CVTTQ/SVIM", "CVTTQ/SVI", "CVTTQ/SVID", + "CVTQS/C", "CVTQS/M", "CVTQS", "CVTQS/D", + "CVTQS/SUIC", "CVTQS/SUIM", "CVTQS/SUI", "CVTQS/SUID", + "CVTQT/C", "CVTQT/M", "CVTQT", "CVTQT/D", + "CVTQT/SUIC", "CVTQT/SUIM", "CVTQT/SUI", "CVTQT/SUID", + "CMPTUN/C", "CMPTUN/S", "CMPTEQ/C", "CMPTEQ/S", + "CMPTLT/C", "CMPTLT/S", "CMPTLE/C", "CMPTLE/S", + "CVTLQ", "CPYS", "CPYSN", "CPYSE", + "MT_FPCR", "MF_FPCR", + "FCMOVEQ", "FCMOVNE", "FCMOVLT", + "FCMOVGE", "FCMOVLE", "FCMOVGT", + "CVTQL", "CVTQL/V", "CVTQL/SV", + "TRAPB", "EXCB", "MB", "WMB", + "FETCH", "FETCH_M", "RPCC", + "RC", "RS", + "JMP", "JSR", "RET", "JSR_COROUTINE", + "SEXTB", "SEXTW", + "CTPOP", "PERR", "CTLZ", "CTTZ", + "UNPKBW", "UNPKBL", "PKWB", "PKLB", + "MINSB8", "MINSW4", "MINUB8", "MINUW4", + "MAXSB8", "MAXSW4", "MAXUB8", "MAXUW4", + "FTOIT", "FTOIS", + "LDF", "LDG", "LDS", "LDT", + "STS", "STG", "STS", "STT", + "LDL", "LDQ", "LDL_L", "LDQ_L", + "STL", "STQ", "STL_L", "STQ_L", + "BR", "FBEQ", "FBLT", "FBLE", + "BSR", "FBNE", "BFGE", "FBGT", + "BLBC", "BEQ", "BLT", "BLE", + "BLBS", "BNE", "BGE", "BGT", + NULL + }; + +const uint32 opval[] = { + 0x00000000, C_PCM, 0x00000001, C_PCM, 0x00000002, C_PCM, 0x00000003, C_PVM, + 0x00000004, C_PVM, 0x00000005, C_PVM, 0x00000006, C_PVM, 0x00000007, C_PVM, + 0x00000008, C_PVM, 0x00000009, C_PCM, 0x0000000A, C_PCM, 0x0000000B, C_PVM, + 0x0000000C, C_PVM, 0x0000000D, C_PVM, 0x0000000E, C_PVM, 0x0000000F, C_PVM, + 0x00000010, C_PVM, 0x00000011, C_PVM, 0x00000012, C_PVM, 0x00000013, C_PVM, + 0x00000014, C_PVM, 0x00000015, C_PVM, 0x00000016, C_PVM, 0x00000017, C_PVM, + 0x00000018, C_PVM, 0x00000019, C_PVM, 0x0000001A, C_PVM, 0x0000001B, C_PVM, + 0x0000001C, C_PVM, 0x0000001D, C_PVM, 0x0000001E, C_PVM, 0x0000001F, C_PVM, + 0x00000020, C_PVM, 0x00000021, C_PVM, 0x00000022, C_PVM, 0x00000023, C_PVM, + 0x00000024, C_PVM, 0x00000025, C_PVM, 0x00000026, C_PVM, 0x00000027, C_PVM, + 0x00000029, C_PVM, 0x0000002A, C_PVM, 0x0000002B, C_PVM, 0x0000002E, C_PVM, + 0x00000030, C_PVM, 0x00000031, C_PVM, 0x00000032, C_PVM, 0x00000033, C_PVM, + 0x0000003E, C_PCM, 0x0000003F, C_PVM, + 0x00000080, C_PCM, 0x00000081, C_PCM, 0x00000082, C_PVM, 0x00000083, C_PVM, + 0x00000084, C_PVM, 0x00000085, C_PVM, 0x00000086, C_PCM, 0x00000087, C_PVM, + 0x00000088, C_PVM, 0x00000089, C_PVM, 0x0000008A, C_PVM, 0x0000008B, C_PVM, + 0x0000008C, C_PVM, 0x0000008D, C_PVM, 0x0000008E, C_PVM, 0x0000008F, C_PVM, + 0x00000090, C_PVM, 0x00000091, C_PVM, 0x00000092, C_PVM, 0x00000093, C_PVM, + 0x00000094, C_PVM, 0x00000095, C_PVM, 0x00000096, C_PVM, 0x00000097, C_PVM, + 0x00000098, C_PVM, 0x00000099, C_PVM, 0x0000009A, C_PVM, 0x0000009B, C_PVM, + 0x0000009C, C_PVM, 0x0000009D, C_PVM, 0x0000009E, C_PVM, 0x0000009F, C_PVM, + 0x000000A0, C_PVM, 0x000000A1, C_PVM, 0x000000A2, C_PVM, 0x000000A3, C_PVM, + 0x000000A4, C_PVM, 0x000000A5, C_PVM, 0x000000A6, C_PVM, 0x000000A7, C_PVM, + 0x000000A8, C_PVM, 0x000000A9, C_PVM, 0x000000AA, C_PCM, 0x000000AE, C_PCM, + 0x00000010, C_PUN, 0x00000011, C_PUN, 0x00000013, C_PUN, 0x00000014, C_PUN, + 0x0000002B, C_PUN, 0x0000002D, C_PUN, 0x0000002E, C_PUN, + 0x00000030, C_PUN, 0x00000031, C_PUN, 0x00000032, C_PUN, 0x00000033, C_PUN, + 0x00000034, C_PUN, 0x00000035, C_PUN, 0x00000036, C_PUN, 0x00000037, C_PUN, + 0x00000038, C_PUN, 0x00000039, C_PUN, 0x0000003A, C_PUN, + 0x0000003C, C_PUN, 0x0000003D, C_PUN, 0x0000003F, C_PUN, + 0x00000092, C_PUN, 0x0000009E, C_PUN, 0x0000009F, C_PUN, + 0x20000000, C_MR, 0x24000000, C_MR, 0x28000000, C_MR, 0x2C000000, C_MR, + 0x30000000, C_MR, 0x34000000, C_MR, 0x38000000, C_MR, 0x3C000000, C_MR, + 0x40000000, C_IO, 0x40000040, C_IO, 0x40000120, C_IO, 0x40000160, C_IO, + 0x400001C0, C_IO, 0x40000240, C_IO, 0x40000360, C_IO, 0x400003A0, C_IO, + 0x40000400, C_IO, 0x40000440, C_IO, 0x40000520, C_IO, 0x40000560, C_IO, + 0x400005A0, C_IO, 0x40000640, C_IO, 0x40000760, C_IO, 0x400007A0, C_IO, + 0x40000800, C_IO, 0x40000920, C_IO, 0x400009A0, C_IO, + 0x40000C00, C_IO, 0x40000D20, C_IO, 0x40000DA0, C_IO, + 0x44000000, C_IO, 0x44000100, C_IO, 0x44000280, C_IO, 0x440002C0, C_IO, + 0x44000400, C_IO, 0x44000480, C_IO, 0x440004C0, C_IO, 0x44000500, C_IO, + 0x44000800, C_IO, 0x44000880, C_IO, 0x440008C0, C_IO, 0x44000900, C_IO, + 0x44000C80, C_IO, 0x44000CC0, C_IO, + 0x48000040, C_IO, 0x480000C0, C_IO, 0x48000160, C_IO, + 0x48000240, C_IO, 0x480002C0, C_IO, 0x48000360, C_IO, + 0x48000440, C_IO, 0x480004C0, C_IO, 0x48000560, C_IO, + 0x48000600, C_IO, 0x48000620, C_IO, 0x48000640, C_IO, 0x48000680, C_IO, + 0x480006C0, C_IO, 0x48000720, C_IO, 0x48000760, C_IO, 0x48000780, C_IO, + 0x48000A40, C_IO, 0x48000AE0, C_IO, 0x48000B40, C_IO, + 0x48000C40, C_IO, 0x48000CE0, C_IO, 0x48000D40, C_IO, + 0x48000E40, C_IO, 0x48000EE0, C_IO, 0x48000F40, C_IO, + 0x4C000000, C_IO, 0x4C000400, C_IO, 0x4C000600, C_IO, + 0x4C000800, C_IO, 0x4C000C00, C_IO, + 0x501F0080, C_FAC, 0x501F0280, C_FAC, 0x501F0480, C_FAC, + 0x53E00140, C_FBC, 0x53E01140, C_FBC, 0x53E02140, C_FBC, 0x53E03140, C_FBC, + 0x53E08140, C_FBC, 0x53E09140, C_FBC, 0x53E0A140, C_FBC, 0x53E0B140, C_FBC, + 0x53E00540, C_FBC, 0x53E01540, C_FBC, 0x53E02540, C_FBC, 0x53E03540, C_FBC, + 0x53E08540, C_FBC, 0x53E09540, C_FBC, 0x53E0A540, C_FBC, 0x53E0B540, C_FBC, + 0x53E00160, C_FBC, 0x53E00960, C_FBC, 0x53E01160, C_FBC, 0x53E01960, C_FBC, + 0x53E02160, C_FBC, 0x53E02960, C_FBC, 0x53E03160, C_FBC, 0x53E03960, C_FBC, + 0x53E0A160, C_FBC, 0x53E0A960, C_FBC, 0x53E0B160, C_FBC, 0x53E0B960, C_FBC, + 0x53E0E160, C_FBC, 0x53E0E960, C_FBC, 0x53E0F160, C_FBC, 0x53E0F960, C_FBC, + 0x53E00560, C_FBC, 0x53E00D60, C_FBC, 0x53E01560, C_FBC, 0x53E01D60, C_FBC, + 0x53E02560, C_FBC, 0x53E02D60, C_FBC, 0x53E03560, C_FBC, 0x53E03D60, C_FBC, + 0x53E0A560, C_FBC, 0x53E0AD60, C_FBC, 0x53E0B560, C_FBC, 0x53E0BD60, C_FBC, + 0x53E0E560, C_FBC, 0x53E0ED60, C_FBC, 0x53E0F560, C_FBC, 0x53E0FD60, C_FBC, + 0x54000000, C_FO, 0x54001000, C_FO, 0x54002000, C_FO, 0x54003000, C_FO, + 0x54008000, C_FO, 0x54009000, C_FO, 0x5400A000, C_FO, 0x5400B000, C_FO, + 0x54000020, C_FO, 0x54001020, C_FO, 0x54002020, C_FO, 0x54003020, C_FO, + 0x54008020, C_FO, 0x54009020, C_FO, 0x5400A020, C_FO, 0x5400B020, C_FO, + 0x54000040, C_FO, 0x54001040, C_FO, 0x54002040, C_FO, 0x54003040, C_FO, + 0x54008040, C_FO, 0x54009040, C_FO, 0x5400A040, C_FO, 0x5400B040, C_FO, + 0x54000060, C_FO, 0x54001060, C_FO, 0x54002060, C_FO, 0x54003060, C_FO, + 0x54008060, C_FO, 0x54009060, C_FO, 0x5400A060, C_FO, 0x5400B060, C_FO, + 0x54000400, C_FO, 0x54001400, C_FO, 0x54002400, C_FO, 0x54003400, C_FO, + 0x54008400, C_FO, 0x54009400, C_FO, 0x5400A400, C_FO, 0x5400B400, C_FO, + 0x54000420, C_FO, 0x54001420, C_FO, 0x54002420, C_FO, 0x54003420, C_FO, + 0x54008420, C_FO, 0x54009420, C_FO, 0x5400A420, C_FO, 0x5400B420, C_FO, + 0x54000440, C_FO, 0x54001440, C_FO, 0x54002440, C_FO, 0x54003440, C_FO, + 0x54008440, C_FO, 0x54009440, C_FO, 0x5400A440, C_FO, 0x5400B440, C_FO, + 0x54000460, C_FO, 0x54001460, C_FO, 0x54002460, C_FO, 0x54003460, C_FO, + 0x54008460, C_FO, 0x54009460, C_FO, 0x5400A460, C_FO, 0x5400B460, C_FO, + 0x57E003C0, C_FBC, 0x57E013C0, C_FBC, 0x57E023C0, C_FBC, 0x57E033C0, C_FBC, + 0x57E083C0, C_FBC, 0x57E093C0, C_FBC, 0x57E0A3C0, C_FBC, 0x57E0B3C0, C_FBC, + 0x57E00580, C_FBC, 0x57E01580, C_FBC, 0x57E02580, C_FBC, 0x57E03580, C_FBC, + 0x57E08580, C_FBC, 0x57E09580, C_FBC, 0x57E0A580, C_FBC, 0x57E0B580, C_FBC, + 0x57E005A0, C_FBC, 0x57E015A0, C_FBC, 0x57E025A0, C_FBC, 0x57E035A0, C_FBC, + 0x57E085A0, C_FBC, 0x57E095A0, C_FBC, 0x57E0A5A0, C_FBC, 0x57E0B5A0, C_FBC, + 0x57E005E0, C_FBC, 0x57E015E0, C_FBC, 0x57E025E0, C_FBC, 0x57E035E0, C_FBC, + 0x57E085E0, C_FBC, 0x57E095E0, C_FBC, 0x57E0A5E0, C_FBC, 0x57E0B5E0, C_FBC, + 0x57E00780, C_FBC, 0x57E01780, C_FBC, 0x57E007C0, C_FBC, 0x57E017C0, C_FBC, + 0x540014A0, C_FO, 0x540094A0, C_FO, 0x540014C0, C_FO, 0x540094C0, C_FO, + 0x540014E0, C_FO, 0x540094E0, C_FO, + 0x58000000, C_FO, 0x58000800, C_FO, 0x58001000, C_FO, 0x58001800, C_FO, + 0x58002000, C_FO, 0x58002800, C_FO, 0x58003000, C_FO, 0x58003800, C_FO, + 0x5800A000, C_FO, 0x5800A800, C_FO, 0x5800B000, C_FO, 0x5800B800, C_FO, + 0x5800E000, C_FO, 0x5800E800, C_FO, 0x5800F000, C_FO, 0x5800F800, C_FO, + 0x58000020, C_FO, 0x58000820, C_FO, 0x58001020, C_FO, 0x58001820, C_FO, + 0x58002020, C_FO, 0x58002820, C_FO, 0x58003020, C_FO, 0x58003820, C_FO, + 0x5800A020, C_FO, 0x5800A820, C_FO, 0x5800B020, C_FO, 0x5800B820, C_FO, + 0x5800E020, C_FO, 0x5800E820, C_FO, 0x5800F020, C_FO, 0x5800F820, C_FO, + 0x58000040, C_FO, 0x58000840, C_FO, 0x58001040, C_FO, 0x58001840, C_FO, + 0x58002040, C_FO, 0x58002840, C_FO, 0x58003040, C_FO, 0x58003840, C_FO, + 0x5800A040, C_FO, 0x5800A840, C_FO, 0x5800B040, C_FO, 0x5800B840, C_FO, + 0x5800E040, C_FO, 0x5800E840, C_FO, 0x5800F040, C_FO, 0x5800F840, C_FO, + 0x58000060, C_FO, 0x58000860, C_FO, 0x58001060, C_FO, 0x58001860, C_FO, + 0x58002060, C_FO, 0x58002860, C_FO, 0x58003060, C_FO, 0x58003860, C_FO, + 0x5800A060, C_FO, 0x5800A860, C_FO, 0x5800B060, C_FO, 0x5800B860, C_FO, + 0x5800E060, C_FO, 0x5800E860, C_FO, 0x5800F060, C_FO, 0x5800F860, C_FO, + 0x58000400, C_FO, 0x58000C00, C_FO, 0x58001400, C_FO, 0x58001C00, C_FO, + 0x58002400, C_FO, 0x58002C00, C_FO, 0x58003400, C_FO, 0x58003C00, C_FO, + 0x5800A400, C_FO, 0x5800AC00, C_FO, 0x5800B400, C_FO, 0x5800BC00, C_FO, + 0x5800E400, C_FO, 0x5800EC00, C_FO, 0x5800F400, C_FO, 0x5800FC00, C_FO, + 0x58000420, C_FO, 0x58000C20, C_FO, 0x58001420, C_FO, 0x58001C20, C_FO, + 0x58002420, C_FO, 0x58002C20, C_FO, 0x58003420, C_FO, 0x58003C20, C_FO, + 0x5800A420, C_FO, 0x5800AC20, C_FO, 0x5800B420, C_FO, 0x5800BC20, C_FO, + 0x5800E420, C_FO, 0x5800EC20, C_FO, 0x5800F420, C_FO, 0x5800FC20, C_FO, + 0x58000440, C_FO, 0x58000C40, C_FO, 0x58001440, C_FO, 0x58001C40, C_FO, + 0x58002440, C_FO, 0x58002C40, C_FO, 0x58003440, C_FO, 0x58003C40, C_FO, + 0x5800A440, C_FO, 0x5800AC40, C_FO, 0x5800B440, C_FO, 0x5800BC40, C_FO, + 0x5800E440, C_FO, 0x5800EC40, C_FO, 0x5800F440, C_FO, 0x5800FC40, C_FO, + 0x58000460, C_FO, 0x58000C60, C_FO, 0x58001460, C_FO, 0x58001C60, C_FO, + 0x58002460, C_FO, 0x58002C60, C_FO, 0x58003460, C_FO, 0x58003C60, C_FO, + 0x5800A460, C_FO, 0x5800AC60, C_FO, 0x5800B460, C_FO, 0x5800BC60, C_FO, + 0x5800E460, C_FO, 0x5800EC60, C_FO, 0x5800F460, C_FO, 0x5800FC60, C_FO, + 0x5BE00580, C_FBC, 0x5BE00D80, C_FBC, 0x5BE01580, C_FBC, 0x5BE01D80, C_FBC, + 0x5BE02580, C_FBC, 0x5BE02D80, C_FBC, 0x5BE03580, C_FBC, 0x5BE03D80, C_FBC, + 0x5BE0A580, C_FBC, 0x5BE0AD80, C_FBC, 0x5BE0B580, C_FBC, 0x5BE0BD80, C_FBC, + 0x5BE0E580, C_FBC, 0x5BE0ED80, C_FBC, 0x5BE0F580, C_FBC, 0x5BE0FD80, C_FBC, + 0x5BE005E0, C_FBC, 0x5BE00DE0, C_FBC, 0x5BE015E0, C_FBC, 0x5BE01DE0, C_FBC, + 0x5BE025E0, C_FBC, 0x5BE02DE0, C_FBC, 0x5BE035E0, C_FBC, 0x5BE03DE0, C_FBC, + 0x5BE0A5E0, C_FBC, 0x5BE0ADE0, C_FBC, 0x5BE0B5E0, C_FBC, 0x5BE0BDE0, C_FBC, + 0x5BE0E5E0, C_FBC, 0x5BE0EDE0, C_FBC, 0x5BE0F5E0, C_FBC, 0x5BE0FDE0, C_FBC, + 0x5BE00780, C_FBC, 0x5BE00F80, C_FBC, 0x5BE01780, C_FBC, 0x5BE01F80, C_FBC, + 0x5BE0E780, C_FBC, 0x5BE0EF80, C_FBC, 0x5BE0F780, C_FBC, 0x5BE0FF80, C_FBC, + 0x5BE007C0, C_FBC, 0x5BE00FC0, C_FBC, 0x5BE017C0, C_FBC, 0x5BE01FC0, C_FBC, + 0x5BE0E7C0, C_FBC, 0x5BE0EFC0, C_FBC, 0x5BE0F7C0, C_FBC, 0x5BE0FFC0, C_FBC, + 0x58001480, C_FO, 0x58009480, C_FO, 0x580014A0, C_FO, 0x580094A0, C_FO, + 0x580014C0, C_FO, 0x580094C0, C_FO, 0x580014E0, C_FO, 0x580094E0, C_FO, + 0x5FE00200, C_IBC, 0x5C000400, C_IO, 0x5C000420, C_IO, 0x5C000440, C_IO, + 0x5C000480, C_IO, 0x5C0004A0, C_IO, + 0x5C000540, C_IO, 0x5C000560, C_IO, 0x5C000580, C_IO, + 0x5C0005A0, C_IO, 0x5C0005C0, C_IO, 0x5C0005E0, C_IO, + 0x5FE00060, C_IBC, 0x5FE00260, C_IBC, 0x5FE00A60, C_IBC, + 0x60000000, C_NO, 0x60000400, C_NO, 0x60004000, C_NO, 0x60004400, C_NO, + 0x60008000, C_FE, 0x6000A000, C_FE, 0x6000C000, C_NO, + 0x6000E000, C_RV, 0x6000F000, C_RV, + 0x68000000, C_JP, 0x68004000, C_JP, 0x68008000, C_JP, 0x6800C000, C_JP, + 0x73E00000, C_IBC, 0x73E00020, C_IBC, + 0x73E00600, C_IBC, 0x70000620, C_IO, 0x73E00640, C_IBC, 0x73E00660, C_IBC, + 0x73E00680, C_IBC, 0x73E006A0, C_IBC, 0x73E006C0, C_IBC, 0x73E006E0, C_IBC, + 0x70000700, C_IO, 0x70000720, C_IO, 0x70000740, C_IO, 0x70000780, C_IO, + 0x70000780, C_IO, 0x700007A0, C_IO, 0x700007C0, C_IO, 0x700007E0, C_IO, + 0x701F0E00, C_IAC, 0x701F0F00, C_IAC, + 0x80000000, C_MR, 0x84000000, C_MR, 0x88000000, C_MR, 0x8C000000, C_MR, + 0x90000000, C_MR, 0x94000000, C_MR, 0x98000000, C_MR, 0x9C000000, C_MR, + 0xA0000000, C_MR, 0xA4000000, C_MR, 0xA8000000, C_MR, 0xAC000000, C_MR, + 0xB0000000, C_MR, 0xB4000000, C_MR, 0xB8000000, C_MR, 0xBC000000, C_MR, + 0xC0000000, C_BR, 0xC4000000, C_BR, 0xC8000000, C_BR, 0xCC000000, C_BR, + 0xD0000000, C_BR, 0xD4000000, C_BR, 0xD8000000, C_BR, 0xDC000000, C_BR, + 0xE0000000, C_BR, 0xE4000000, C_BR, 0xE8000000, C_BR, 0xEC000000, C_BR, + 0xF0000000, C_BR, 0xF4000000, C_BR, 0xF8000000, C_BR, 0xFC000000, C_BR, + M32, 0 + }; + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current PC + *val = values to decode + *uptr = pointer to unit + sw = switches + Outputs: + return = if >= 0, error code + if < 0, number of extra bytes retired +*/ + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ +uint32 c, sc, rdx; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ +else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */ +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) return SCPE_IERR; +if (sw & SWMASK ('D')) rdx = 10; /* get radix */ +else if (sw & SWMASK ('O')) rdx = 8; +else if (sw & SWMASK ('H')) rdx = 16; +else rdx = dptr->dradix; + +if (sw & SWMASK ('A')) { /* ASCII? */ + sc = (uint32) (addr & 0x7) * 8; /* shift count */ + c = (uint32) (val[0] >> sc) & 0x7F; + fprintf (of, (c < 0x20)? "<%02X>": "%c", c); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + sc = (uint32) (addr & 0x7) * 8; /* shift count */ + c = (uint32) (val[0] >> sc) & M8; + fprintf (of, "%02X", c); + return 0; + } +if (sw & SWMASK ('W')) { /* word? */ + sc = (uint32) (addr & 0x6) * 8; /* shift count */ + c = (uint32) (val[0] >> sc) & M16; + fprintf (of, "%04X", c); + return -1; + } +if (sw & SWMASK ('L')) { /* long? */ + if (addr & 4) c = (uint32) (val[0] >> 32) & M32; + else c = (uint32) val[0] & M32; + fprintf (of, "%08X", c); + return -3; + } +if (sw & SWMASK ('C')) { /* char format? */ + for (sc = 0; sc < 64; sc = sc + 8) { /* print string */ + c = (uint32) (val[0] >> sc) & 0x7F; + fprintf (of, (c < 0x20)? "<%02X>": "%c", c); + } + return -7; /* return # chars */ + } +if (sw & SWMASK ('M')) { /* inst format? */ + if (addr & 4) c = (uint32) (val[0] >> 32) & M32; + else c = (uint32) val[0] & M32; + r = fprint_sym_m (of, addr, c); /* decode inst */ + if (r <= 0) return r; + } + +fprint_val (of, val[0], rdx, 64, PV_RZRO); +return -7; +} + +/* Symbolic decode for -m + + Inputs: + of = output stream + addr = current PC + inst = instruction to decode + Outputs: + return = if >= 0, error code + if < 0, number of extra bytes retired (-3) +*/ + +t_stat fprint_sym_m (FILE *of, t_addr addr, uint32 inst) +{ +uint32 i, j, k, fl, ra, rb, rc, md, bd, jd, lit8, any; +t_stat r; + +if ((r = fprint_pal_hwre (of, inst)) < 0) return r; /* PAL instruction? */ +for (i = 0; opval[i] != M32; i = i + 2) { /* loop thru ops */ + fl = opval[i + 1]; /* flags */ + j = fl & CL_CLASS; /* get class */ + k = i >> 1; + if (((opval[i] & masks[j]) == (inst & masks[j])) && /* match? */ + ((j != CL_NO) || (fl & PAL_MASK (pal_type)))) { + ra = I_GETRA (inst); /* all fields */ + rb = I_GETRB (inst); + rc = I_GETRC (inst); + lit8 = I_GETLIT8 (inst); + md = I_GETMDSP (inst); + bd = I_GETBDSP (inst); + jd = inst & 0x3FFF; + any = 0; + fprintf (of, "%s", opcode[k]); /* opcode */ + if (fl & FL_RA) /* ra? */ + any = fprintf (of, " R%d", ra); + if (fl & FL_BDP) { /* branch? */ + addr = (addr + (SEXT_BDSP (bd) << 2) + 4) & M64; + any = fprintf (of, (any? ",": " ")); + fprint_val (of, addr, 16, 64, PV_LEFT); + } + else if (fl & FL_MDP) { /* mem ref? */ + if ((fl & FL_RBI) && (rb != 31)) + any = fprintf (of, (any? ",%X(R%d)": " %X(R%d)"), md, rb); + else any = fprintf (of, (any? ",%X": " %X"), md); + } + else if (fl & FL_RB) { /* rb? */ + if (fl & FL_RBI) + any = fprintf (of, (any? ",(R%d)": " (R%d)"), rb); + else if ((fl & FL_LIT) && (inst & I_ILIT)) + any = fprintf (of, (any? ",#%X": " #%X"), lit8); + else any = fprintf (of, (any? ",R%d": " R%d"), rb); + } + if ((fl & FL_JDP) && jd) /* jmp? */ + any = fprintf (of, (any? ",%X": " %X"), jd); + else if (fl & FL_RC) /* rc? */ + any = fprintf (of, (any? ",R%d": " R%d"), rc); + return -3; + } /* end if */ + } /* end for */ +return SCPE_ARG; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = > 0 error code + <= 0 -number of extra words +*/ + +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ +t_value num; +uint32 i, sc, rdx; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ +else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */ +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) return SCPE_IERR; +if (sw & SWMASK ('D')) rdx = 10; /* get radix */ +else if (sw & SWMASK ('O')) rdx = 8; +else if (sw & SWMASK ('H')) rdx = 16; +else rdx = dptr->dradix; + +if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + sc = (uint32) (addr & 0x7) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M8) << sc)) | + (((t_uint64) cptr[0]) << sc); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + num = get_uint (cptr, rdx, M8, &r); /* get byte */ + if (r != SCPE_OK) return SCPE_ARG; + sc = (uint32) (addr & 0x7) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M8) << sc)) | + (num << sc); + return 0; + } +if (sw & SWMASK ('W')) { /* word? */ + num = get_uint (cptr, rdx, M16, &r); /* get word */ + if (r != SCPE_OK) return SCPE_ARG; + sc = (uint32) (addr & 0x6) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M16) << sc)) | + (num << sc); + return -1; + } +if (sw & SWMASK ('L')) { /* longword? */ + num = get_uint (cptr, rdx, M32, &r); /* get longword */ + if (r != SCPE_OK) return SCPE_ARG; + sc = (uint32) (addr & 0x4) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M32) << sc)) | + (num << sc); + return -3; + } +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + for (i = 0; i < 8; i++) { + if (cptr[i] == 0) break; + sc = i * 8; + val[0] = (val[0] & ~(((t_uint64) M8) << sc)) | + (((t_uint64) cptr[i]) << sc); + } + return -7; + } + +if ((addr & 3) == 0) { /* aligned only */ + r = parse_sym_m (cptr, addr, &num); /* try to parse inst */ + if (r <= 0) { /* ok? */ + sc = (uint32) (addr & 0x4) * 8; /* shift count */ + val[0] = (val[0] & ~(((t_uint64) M32) << sc)) | + (num << sc); + return -3; + } + } + +val[0] = get_uint (cptr, rdx, M64, &r); /* get number */ +if (r != SCPE_OK) return r; +return -7; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *val = pointer to output values + Outputs: + status = > 0 error code + <= 0 -number of extra words +*/ + +t_stat parse_sym_m (char *cptr, t_addr addr, t_value *inst) +{ +t_uint64 bra, df, db; +uint32 i, k, lit8, fl; +int32 reg; +t_stat r; +char *tptr, gbuf[CBUFSIZE]; + +if ((r = parse_pal_hwre (cptr, inst)) < 0) return r; /* PAL hardware? */ +cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ +for (i = 0; opcode[i] != NULL; i++) { /* loop thru opcodes */ + if (strcmp (opcode[i], gbuf) == 0) { /* string match? */ + k = i << 1; /* index to opval */ + fl = opval[k + 1]; /* get flags */ + if (((fl & CL_CLASS) != CL_NO) || /* not PAL or */ + (fl & PAL_MASK (pal_type))) break; /* PAL type match? */ + } + } +if (opcode[i] == NULL) return SCPE_ARG; +*inst = opval[k]; /* save base op */ + +if (fl & FL_RA) { /* need Ra? */ + cptr = get_glyph (cptr, gbuf, ','); /* get reg */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RA); + } +if (fl & FL_BDP) { /* need branch disp? */ + cptr = get_glyph (cptr, gbuf, 0); + bra = get_uint (gbuf, 16, M64, &r); + if ((r != SCPE_OK) || (bra & 3)) return SCPE_ARG; + df = ((bra - (addr + 4)) >> 2) & I_M_BDSP; + db = ((addr + 4 - bra) >> 2) & I_M_BDSP; + if (bra == ((addr + 4 + (SEXT_BDSP (df) << 2)) & M64)) + *inst = *inst | (uint32) df; + else if (bra == ((addr + 4 + (SEXT_BDSP (db) << 2)) & M64)) + *inst = *inst | (uint32) db; + else return SCPE_ARG; + } +else if (fl & FL_MDP) { /* need mem disp? */ + cptr = get_glyph (cptr, gbuf, 0); + df = strtotv (gbuf, &tptr, 16); + if ((gbuf == tptr) || (df > I_M_MDSP)) return SCPE_ARG; + *inst = *inst | (uint32) df; + if (*tptr == '(') { + tptr = get_glyph (tptr + 1, gbuf, ')'); + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RB); + } + else *inst = *inst | (31 << I_V_RB); + if (*tptr != 0) return SCPE_ARG; + } +else if (fl & FL_RBI) { /* indexed? */ + cptr = get_glyph (cptr, gbuf, ','); + if (gbuf[0] != '(') return SCPE_ARG; + tptr = get_glyph (gbuf + 1, gbuf, ')'); + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RB); + if (*tptr != 0) return SCPE_ARG; + } +else if (fl & FL_RB) { + cptr = get_glyph (cptr, gbuf, ','); /* get reg/lit */ + if ((gbuf[0] == '#') && (fl & FL_LIT)) { /* literal? */ + lit8 = (uint32) get_uint (gbuf + 1, 16, I_M_LIT8, &r); + if (r != SCPE_OK) return r; + *inst = *inst | I_ILIT | (lit8 << I_V_LIT8); + } + else { /* rb */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RB); + } + } +if (fl & FL_JDP) { /* jmp? */ + cptr = get_glyph (cptr, gbuf, 0); /* get disp */ + df = get_uint (gbuf, 16, 0x3FFF, &r); + if (r != SCPE_OK) return r; + *inst = *inst | df; + } +else if (fl & FL_RC) { /* rc? */ + cptr = get_glyph (cptr, gbuf, ','); /* get reg */ + if ((reg = parse_reg (gbuf)) < 0) return SCPE_ARG; + *inst = *inst | (reg << I_V_RC); + } + +if (*cptr != 0) return SCPE_ARG; /* any leftovers? */ +return -3; +} + +/* Parse a register */ + +int32 parse_reg (char *cptr) +{ +t_stat r; +int32 reg; + +if ((*cptr == 'R') || (*cptr == 'r') || + (*cptr == 'F') || (*cptr == 'f')) cptr++; +reg = (int32) get_uint (cptr, 10, 31, &r); +if (r != SCPE_OK) return -1; +return reg; +} + diff --git a/alpha/alpha_sys_defs.h b/alpha/alpha_sys_defs.h new file mode 100644 index 00000000..7af5a908 --- /dev/null +++ b/alpha/alpha_sys_defs.h @@ -0,0 +1,43 @@ +/* alpha_system_defs.h: Alpha system definitions file + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + Respectfully dedicated to the great people of the Alpha chip, systems, and + software development projects; and to the memory of Peter Conklin, of the + Alpha Program Office. + + This is a STUB! +*/ + +#ifndef _ALPHA_SYS_DEFS_H_ +#define _ALPHA_SYS_DEFS_H_ 0 + +#define PA_SIZE 36 /* PA size */ +#define PA_MASK 0x0000000FFFFFFFFF + +#define ROMBASE 0x000000FFFC000000 +#define ROMSIZE 0x0000000004000000 + +#endif + diff --git a/alpha/old_pal/alpha_pal_defs.h b/alpha/old_pal/alpha_pal_defs.h new file mode 100644 index 00000000..6471e36b --- /dev/null +++ b/alpha/old_pal/alpha_pal_defs.h @@ -0,0 +1,208 @@ +/* alpha_pal_defs.h: Alpha architecture PAL definitions file + + Copyright (c) 2003-2006, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + Respectfully dedicated to the great people of the Alpha chip, systems, and + software development projects; and to the memory of Peter Conklin, of the + Alpha Program Office. +*/ + +#ifndef _ALPHA_PAL_DEFS_H_ +#define _ALPHA_PAL_DEFS_H_ 0 + +/* VA - NT software format */ + +#define NTVA_N_PDE (VA_N_OFF - 2) /* PDE width */ +#define NTVA_M_PDE ((1u << NTVA_N_PDE) - 1) /* PDE mask */ +#define NTVA_N_PTD (32 - VA_N_OFF - NTVA_N_PDE) /* PTD width */ +#define NTVA_M_PTD ((1u << NTVA_N_PTD) - 1) /* PTD mask */ +#define NTVA_M_VPN (M32 >> VA_N_OFF) /* 32b VPN mask */ +#define NTVPN_N_SEXT (VA_WIDTH - 32 + 1) /* VPN sext size */ +#define NTVPN_V_SEXT (VA_N_VPN - NTVPN_N_SEXT) /* VPN sext start */ +#define NTVPN_M_SEXT ((1u << NTVPN_N_SEXT) - 1) /* VPN sext mask */ +#define NTVPN_GETSEXT(x) (((x) >> NTVPN_V_SEXT) & NTVPN_M_SEXT) + +/* PTE - NT software format */ + +#define NT_VPTB 0xFFFFFFFFC0000000 /* virt page tbl base */ +#define NTP_V_PFN 9 /* PFN */ +#define NTP_M_PFN 0x7FFFFF +#define NTP_PFN (NTP_M_PFN << NTP_V_PFN) +#define NTP_V_GH 5 +#define NTP_M_GH 0x3 +#define NTP_V_GBL 4 /* global = ASM */ +#define NTP_V_DIRTY 2 /* dirty = !FOW */ +#define NTP_V_OWNER 1 /* owner */ +#define NTP_V_V 0 /* valid */ +#define NTP_GBL (1u << NTP_V_GBL) +#define NTP_DIRTY (1u << NTP_V_DIRTY) +#define NTP_OWNER (1u << NTP_V_OWNER) +#define NTP_V (1u << NTP_V_V) +#define NT_VPNPTD(x) (((x) >> (NTVA_N_PDE - 2)) & (NTVA_M_PTD << 2)) +#define NT_VPNPDE(x) (((x) << 2) & (NTVA_M_PDE << 2)) + +/* VMS PALcode */ + +#define PSV_V_SPA 56 /* VMS PS: stack align */ +#define PSV_M_SPA 0x3F +#define PSV_V_IPL 8 /* interrupt priority */ +#define PSV_M_IPL 0x1F +#define PSV_V_VMM 7 /* virt machine monitor */ +#define PSV_V_CM 3 /* current mode */ +#define PSV_M_CM 0x3 +#define PSV_V_IP 2 /* intr in progress */ +#define PSV_V_SW 0 /* software */ +#define PSV_M_SW 0x3 +#define PSV_VMM (1u << PSV_V_VMM) +#define PSV_IP (1u << PSV_V_IP) +#define PSV_MASK (PSV_VMM | PSV_IP | PSV_M_SW) +#define PSV_MBZ 0xC0FFFFFFFFFFE0E4 /* must be zero */ + +#define PCBV_FLAGS 56 /* PCB flags word */ + +#define SISR_MASK 0xFFFE /* SISR bits */ + +#define IPL_SMAX 0x0F /* highest swre level */ + +#define SCB_FDIS 0x010 /* SCB offsets */ +#define SCB_ACV 0x080 +#define SCB_TNV 0x090 +#define SCB_FOR 0x0A0 +#define SCB_FOW 0x0B0 +#define SCB_FOE 0x0C0 +#define SCB_ARITH 0x200 +#define SCB_KAST 0x240 +#define SCB_EAST 0x250 +#define SCB_SAST 0x260 +#define SCB_UAST 0x270 +#define SCB_ALIGN 0x280 +#define SCB_BPT 0x400 +#define SCB_BUG 0x410 +#define SCB_RSVI 0x420 +#define SCB_RSVO 0x430 +#define SCB_GENTRAP 0x440 +#define SCB_CHMK 0x480 +#define SCB_CHME 0x490 +#define SCB_CHMS 0x4A0 +#define SCB_CHMU 0x4B0 +#define SCB_SISR0 0x500 +#define SCB_CLOCK 0x600 +#define SCB_IPIR 0x610 +#define SCB_SCRD 0x620 +#define SCB_PCRD 0x630 +#define SCB_POWER 0x640 +#define SCB_PERFM 0x650 +#define SCB_SMCHK 0x660 +#define SCB_PMCHK 0x670 +#define SCB_PASVR 0x6F0 +#define SCB_IO 0x800 + +#define VMS_L_STKF (8 * 8) /* stack frame length */ +#define VMS_MME_E 0x0000000000000001 /* mem mgt error flags */ +#define VMS_MME_R 0x0000000000000000 +#define VMS_MME_W 0x8000000000000000 + +/* VAX compatible data length definitions (for ReadUna, WriteUna) */ + +#define L_BYTE 1 +#define L_WORD 2 +#define L_LONG 4 +#define L_QUAD 8 + +/* Unix PALcode */ + +#define PSU_V_CM 3 /* Unix PS: curr mode */ +#define PSU_M_CM 0x1 +#define PSU_CM (PSU_M_CM << PSU_V_CM) +#define PSU_V_IPL 0 /* IPL */ +#define PSU_M_IPL 0x7 +#define PSU_IPL (PSU_M_IPL << PSU_V_IPL) + +#define PCBU_FLAGS 40 /* PCB flags word */ + +#define UNIX_L_STKF (6 * 8) /* kernel stack frame */ +#define UNIX_IF_BPT 0 /* entIF a0 values */ +#define UNIX_IF_BUG 1 +#define UNIX_IF_GEN 2 +#define UNIX_IF_FDIS 3 +#define UNIX_IF_RSVI 4 +#define UNIX_INT_IPIR 0 /* entInt a0 values */ +#define UNIX_INT_CLK 1 +#define UNIX_INT_MCRD 2 +#define UNIX_INT_IO 3 +#define UNIX_INT_PERF 4 +#define UNIX_MMCSR_TNV 0 /* entMM a1 values */ +#define UNIX_MMCSR_ACV 1 +#define UNIX_MMCSR_FOR 2 +#define UNIX_MMCSR_FOW 3 +#define UNIX_MMCSR_FOE 4 +#define UNIX_MME_E M64 /* entMM a2 values */ +#define UNIX_MME_R 0 +#define UNIX_MME_W 1 + +enum vms_pal_opcodes { + OP_HALT, OP_DRAINA, OP_CFLUSH, OP_LDQP, + OP_STQP, OP_SWPCTX, MF_ASN, MT_ASTEN, + MT_ASTSR, OP_CSERVE, OP_SWPPAL, MF_FEN, + MT_FEN, MT_IPIR, MF_IPL, MT_IPL, + MF_MCES, MT_MCES, MF_PCBB, MF_PRBR, + MT_PRBR, MF_PTBR, MF_SCBB, MT_SCBB, + MT_SIRR, MF_SISR, MF_TBCHK, MT_TBIA, + MT_TBIAP, MT_TBIS, MF_ESP, MT_ESP, + MF_SSP, MT_SSP, MF_USP, MT_USP, + MT_TBISD, MT_TBISI, MF_ASTEN, MF_ASTSR, + MF_VTBR = 0x29, MT_VTBR,MT_PERFMON, MT_DATFX = 0x2E, + MF_VIRBND = 0x30, MT_VIRBND, MF_SYSPTBR, MT_SYSPTBR, + OP_WTINT = 0x3E, MF_WHAMI = 0x3F, + OP_BPT = 0x80, OP_BUGCHK, OP_CHME, OP_CHMK, + OP_CHMS, OP_CHMU, OP_IMB, OP_INSQHIL, + OP_INSQTIL, OP_INSQHIQ, OP_INSQTIQ, OP_INSQUEL, + OP_INSQUEQ, OP_INSQUELD,OP_INSQUEQD,OP_PROBER, + OP_PROBEW, OP_RD_PS, OP_REI, OP_REMQHIL, + OP_REMQTIL, OP_REMQHIQ, OP_REMQTIQ, OP_REMQUEL, + OP_REMQUEQ, OP_REMQUELD,OP_REMQUEQD,OP_SWASTEN, + OP_WR_PS_SW,OP_RSCC, OP_RD_UNQ, OP_WR_UNQ, + OP_AMOVRR, OP_AMOVRM, OP_INSQHILR,OP_INSQTILR, + OP_INSQHIQR,OP_INSQTIQR,OP_REMQHILR,OP_REMQTILR, + OP_REMQHIQR,OP_REMQTIQR,OP_GENTRAP, + OP_CLRFEN = 0xAE + }; + +enum unix_pal_opcodes { + OP_halt, OP_draina, OP_cflush, + OP_cserve = 0x9, OP_swppal, + OP_rdmces = 0x10, OP_wrmces, + OP_wrvirbnd = 0x13, OP_wrsysptbr = 0x14, + OP_wrfen = 0x2B, OP_wrvptptr = 0x2D, OP_wrasn, + OP_swpctx = 0x30, OP_wrval, OP_rdval, OP_tbi, + OP_wrent, OP_swpipl, OP_rdps, OP_wrkgp, + OP_wrusp, OP_wrperfmon, OP_rdusp, + OP_whami = 0x3C, OP_retsys, OP_wtint, OP_rti, + OP_bpt = 0x80, OP_bugchk, OP_syscall = 0x83, + OP_imb = 0x86, + OP_urti = 0x92, OP_rdunique = 0x9E, OP_wrunique, + OP_gentrap = 0xAA, OP_clrfen = 0xAE + }; + +#endif diff --git a/alpha/old_pal/alpha_pal_unix.c b/alpha/old_pal/alpha_pal_unix.c new file mode 100644 index 00000000..73fa8011 --- /dev/null +++ b/alpha/old_pal/alpha_pal_unix.c @@ -0,0 +1,702 @@ +/* alpha_pal_unix.c - Alpha Unix PAL code simulator + + Copyright (c) 2003-2005, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This module contains the PALcode implementation for Alpha Unix, except for + the console, which is always done in hardware mode. + + Alpha Unix/Linux requires the following privileged state: + + ps<3:0> processor status + cm<0> current mode - in base + ipl<2:0> interrupt level - in base + ksp<63:0> kernel stack pointer + kgp<63:0> kernel global pointer + usp<63:0> user stack pointer + pcbb<63:0> process control block base + ptptr<63:0> page table base + vptptr<63:0> virtual page table base + virbnd<63:0> virtual address boundary + sysptbr<63:0> system page table base register + sysval<63:0> processor base (sysvalue) + unique<63:0> thread-unique value + entArith<63:0> entry vector, arithmetic trap + entIF<63:0> entry vector, instruction + entInt<63:0> entry vector, interrupt + entSys<63:0> entry vector, system call + entMM<63:0> entry vector, memory management fault + entUna<63:0> entry vector, unaligned + + Unix maps kernel/user to the hardware's kernel/executive. It maps the + 8 IPL's to the hardware IPL's as follows: + + 0 0 + 1 1 + 2 2 + 3 IPL_HMIN + 4 IPL_HMIN+1 + 5 IPL_HMIN+2 + 6 IPL_HMIN+3 + 7 IPL_1F +*/ + +#include "alpha_defs.h" + +#define GET_PSU (((unix_cm & PSU_M_CM) << PSU_V_CM) | \ + ((unix_ipl & PSU_M_IPL) << PSU_V_IPL)) + +// kludge for debugging... +#define io_get_vec(x) 0 + +#define ksp unix_stkp[MODE_K] +#define usp unix_stkp[MODE_E] +#define entInt unix_entVec[0] +#define entArith unix_entVec[1] +#define entMM unix_entVec[2] +#define entIF unix_entVec[3] +#define entUna unix_entVec[4] +#define entSys unix_entVec[5] +#define v0 R[0] +#define a0 R[16] +#define a1 R[17] +#define a2 R[18] +#define a3 R[19] +#define at R[28] +#define gp R[29] + +t_uint64 unix_ptptr = 0; /* page table base */ +t_uint64 unix_vptptr = 0; /* virt page table base */ +t_uint64 unix_virbnd = M64; /* virtual boundary */ +t_uint64 unix_sysptbr = 0; /* system page table base */ +t_uint64 unix_hwpcb = 0; /* hardware PCB */ +t_uint64 unix_unique = 0; /* thread unique */ +t_uint64 unix_sysval = 0; /* processor unique */ +t_uint64 unix_mces = 0; /* machine check err summ */ +t_uint64 unix_stkp[2] = { 0 }; +t_uint64 unix_entVec[6] = { 0 }; +t_uint64 unix_kgp = 0; +uint32 unix_ipl = 0; +uint32 unix_cm = 0; + +static const uint32 map_ipl[8] = { + 0, 1, 2, IPL_HMIN, IPL_HMIN + 1, IPL_HMIN + 2, IPL_HMIN + 3, IPL_1F + }; + +extern t_uint64 R[32]; +extern t_uint64 PC, trap_mask; +extern t_uint64 p1; +extern uint32 vax_flag, lock_flag; +extern uint32 fpen; +extern uint32 ir, pcc_h, pcc_l, pcc_enb; +extern uint32 cm_racc, cm_wacc; +extern uint32 mmu_ispage, mmu_dspage; +extern jmp_buf save_env; +extern uint32 int_req[IPL_HLVL]; + +t_stat unix_syscall (void); +t_stat unix_retsys (void); +t_stat unix_rti (void); +void unix_urti (void); +void unix_swpctx (void); +t_stat unix_intexc (t_uint64 vec, t_uint64 arg); +t_stat unix_mm_intexc (t_uint64 par1, t_uint64 par2); +t_stat pal_proc_reset_unix (DEVICE *dptr); +uint32 pal_find_pte_unix (uint32 vpn, t_uint64 *l3pte); + +extern t_stat (*pal_eval_intr) (uint32 ipl); +extern t_stat (*pal_proc_excp) (uint32 type); +extern t_stat (*pal_proc_trap) (uint32 type); +extern t_stat (*pal_proc_intr) (uint32 type); +extern t_stat (*pal_proc_inst) (uint32 fnc); +extern uint32 (*pal_find_pte) (uint32 vpn, t_uint64 *pte); +extern uint32 Test (t_uint64 va, uint32 acc, t_uint64 *pa); + +/* UNIXPAL data structures + + unixpal_dev device descriptor + unixpal_unit unit + unixpal_reg register list +*/ + +UNIT unixpal_unit = { UDATA (NULL, 0, 0) }; + +REG unixpal_reg[] = { + { HRDATA (KSP, ksp, 64) }, + { HRDATA (USP, usp, 64) }, + { HRDATA (ENTARITH, entArith, 64) }, + { HRDATA (ENTIF, entIF, 64) }, + { HRDATA (ENTINT, entInt, 64) }, + { HRDATA (ENTMM, entMM, 64) }, + { HRDATA (ENTSYS, entSys, 64) }, + { HRDATA (ENTUNA, entUna, 64) }, + { HRDATA (KGP, unix_kgp, 64) }, + { HRDATA (PTPTR, unix_ptptr, 64) }, + { HRDATA (VPTPTR, unix_vptptr, 64) }, + { HRDATA (VIRBND, unix_virbnd, 64) }, + { HRDATA (SYSPTBR, unix_sysptbr, 64) }, + { HRDATA (UNIQUE, unix_unique, 64) }, + { HRDATA (SYSVAL, unix_sysval, 64) }, + { HRDATA (HWPCB, unix_hwpcb, 64) }, + { HRDATA (MCES, unix_mces, 64) }, + { HRDATA (IPL, unix_ipl, 3) }, + { HRDATA (CM, unix_cm, 0) }, + { NULL } + }; + +DEVICE unixpal_dev = { + "UNIXPAL", &unixpal_unit, unixpal_reg, NULL, + 1, 16, 1, 1, 16, 8, + NULL, NULL, &pal_proc_reset_unix, + NULL, NULL, NULL, + NULL, DEV_DIS + }; + +/* Unix interrupt evaluator - returns IPL of highest priority interrupt */ + +uint32 pal_eval_intr_unix (uint32 lvl) +{ +uint32 i; +uint32 mipl = map_ipl[lvl & PSU_M_IPL]; + +for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */ + if (i <= mipl) return 0; /* at ipl? no int */ + if (int_req[i - IPL_HMIN]) return i; /* req != 0? int */ + } +return 0; +} + +/* Unix interrupt dispatch - reached from top of execute loop */ + +t_stat pal_proc_intr_unix (uint32 lvl) +{ +t_stat r; + +if (lvl > IPL_HMAX) return SCPE_IERR; /* above max? */ +else if (lvl >= IPL_HMIN) a1 = io_get_vec (lvl); /* hwre? get vector */ +else return SCPE_IERR; /* bug */ +r = unix_intexc (entInt, UNIX_INT_IO); /* do interrupt */ +if (a1 == SCB_CLOCK) a0 = UNIX_INT_CLK; +if (a1 == SCB_IPIR) a0 = UNIX_INT_IPIR; +unix_ipl = lvl; +return r; +} + +/* Unix trap dispatch - reached synchronously from bottom of execute loop */ + +t_stat pal_proc_trap_unix (uint32 tsum) +{ +t_stat r; + +r = unix_intexc (entArith, tsum); /* arithmetic trap */ +a1 = trap_mask; /* set parameter */ +return r; +} + +/* Unix exception dispatch - reached from the ABORT handler */ + +t_stat pal_proc_excp_unix (uint32 abval) +{ +t_stat r; + +switch (abval) { + + case EXC_RSVI: /* reserved instruction */ + return unix_intexc (entIF, UNIX_IF_RSVI); /* trap */ + + case EXC_RSVO: /* reserved operand */ + return unix_intexc (entIF, UNIX_IF_RSVI); /* trap */ + + case EXC_ALIGN: /* unaligned */ + PC = (PC - 4) & M64; /* back up PC */ + r = unix_intexc (entUna, PC); /* fault */ + a1 = I_GETOP (ir); /* get opcode */ + a2 = I_GETRA (ir); /* get ra */ + return r; + + case EXC_FPDIS: /* fp disabled */ + PC = (PC - 4) & M64; /* backup PC */ + return unix_intexc (entIF, UNIX_IF_FDIS); /* fault */ + + case EXC_FOX+EXC_E: /* FOE */ + tlb_is (p1, TLB_CI); + return unix_mm_intexc (UNIX_MMCSR_FOE, UNIX_MME_E); + + case EXC_FOX+EXC_R: /* FOR */ + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_FOR, UNIX_MME_R); + + case EXC_FOX+EXC_W: /* FOW */ + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_FOW, UNIX_MME_W); + + case EXC_BVA+EXC_E: + case EXC_ACV+EXC_E: /* instr ACV */ + return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_E); + + case EXC_BVA+EXC_R: + case EXC_ACV+EXC_R: /* data read ACV */ + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_R); + + case EXC_BVA+EXC_W: + case EXC_ACV+EXC_W: /* data write ACV */ + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_ACV, UNIX_MME_W); + + case EXC_TNV+EXC_E: /* instr TNV */ + tlb_is (p1, TLB_CI); + return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_E); + + case EXC_TNV+EXC_R: /* data read TNV */ + tlb_is (p1, TLB_CD); + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_R); + + case EXC_TNV+EXC_W: /* data write TNV */ + tlb_is (p1, TLB_CD); + PC = (PC - 4) & M64; /* back up PC */ + return unix_mm_intexc (UNIX_MMCSR_TNV, UNIX_MME_W); + + case EXC_TBM + EXC_E: /* TLB miss */ + case EXC_TBM + EXC_R: + case EXC_TBM + EXC_W: + return SCPE_IERR; /* should not occur */ + + default: + return STOP_INVABO; + } +return SCPE_OK; +} + +/* PALcode instruction dispatcher - function code verified in CPU */ + +t_stat pal_proc_inst_unix (uint32 fnc) +{ +uint32 arg32 = (uint32) a0; + +if ((fnc < 0x40) && (unix_cm != MODE_K)) ABORT (EXC_RSVI); +switch (fnc) { + + case OP_halt: + return STOP_HALT; + + case OP_cflush: + case OP_draina: + break; + + case OP_cserve: + //tbd + break; + + case OP_swppal: + v0 = 0; + break; + + case OP_rdmces: + v0 = unix_mces; + break; + + case OP_wrmces: + unix_mces = (unix_mces | (arg32 & MCES_DIS)) & ~(arg32 & MCES_W1C); + break; + + case OP_wrvirbnd: + unix_virbnd = a0; + break; + + case OP_wrsysptbr: + unix_sysptbr = a0; + break; + + case OP_wrfen: + fpen = arg32 & 1; + arg32 = ReadPL (unix_hwpcb + PCBU_FLAGS); + arg32 = (arg32 & ~1) | fpen; + WritePL (unix_hwpcb + PCBU_FLAGS, arg32); + break; + + case OP_wrvptptr: + unix_vptptr = a0; + break; + + case OP_wrasn: + itlb_set_asn (arg32 & M16); + dtlb_set_asn (arg32 & M16); + WritePL (unix_hwpcb + 28, arg32 & M16); + break; + + case OP_swpctx: + unix_swpctx (); + break; + + case OP_wrval: + unix_sysval = a0; + break; + + case OP_rdval: + v0 = unix_sysval; + break; + + case OP_tbi: + switch (a0 + 2) { + case 0: /* -2 = tbia */ + tlb_ia (TLB_CI | TLB_CD | TLB_CA); + break; + case 1: /* -1 = tbiap */ + tlb_ia (TLB_CI | TLB_CD); + break; + case 3: /* +1 = tbis */ + tlb_is (a1, TLB_CI | TLB_CD); + break; + case 4: /* +2 = tbisd */ + tlb_is (a1, TLB_CD); + break; + case 5: /* +3 = tbisi */ + tlb_is (a1, TLB_CI); + break; + default: + break; + } + break; + + case OP_wrent: + if (a0 <= 5) unix_entVec[arg32] = a0; + break; + + case OP_swpipl: + v0 = unix_ipl; + unix_ipl = arg32 & PSU_M_IPL; + break; + + case OP_rdps: + v0 = GET_PSU; + break; + + case OP_wrkgp: + unix_kgp = a0; + break; + + case OP_wrusp: + usp = a0; + break; + + case OP_wrperfmon: + // tbd + break; + + case OP_rdusp: + v0 = usp; + break; + + case OP_whami: + v0 = 0; + break; + + case OP_retsys: + unix_retsys (); + break; + + case OP_wtint: + v0 = 0; + break; + + case OP_rti: + unix_rti (); + break; + +/* Non-privileged */ + + case OP_bpt: + return unix_intexc (entIF, UNIX_IF_BPT); + + case OP_bugchk: + return unix_intexc (entIF, UNIX_IF_BUG); + + case OP_syscall: + if (unix_cm == MODE_K) { + //tbd + } + return unix_syscall (); + + case OP_imb: + break; + + case OP_urti: + if (unix_cm == MODE_K) { + //tbd + } + unix_urti (); + break; + + case OP_rdunique: + v0 = unix_unique; + break; + + case OP_wrunique: + unix_unique = a0; + break; + + case OP_gentrap: + return unix_intexc (entIF, UNIX_IF_GEN); + + case OP_clrfen: + fpen = 0; + arg32 = ReadPL (unix_hwpcb + PCBU_FLAGS); + arg32 = arg32 & ~1; + WritePL (unix_hwpcb + PCBU_FLAGS, arg32); + break; + + default: + ABORT (EXC_RSVI); + } + +return SCPE_OK; +} + +/* Swap privileged context */ + +void unix_swpctx (void) +{ +t_uint64 val; +uint32 tmp1; + +WritePQ (unix_hwpcb + 0, SP); /* save stack ptrs */ +WritePQ (unix_hwpcb + 8, usp); +tmp1 = (pcc_h + pcc_l) & M32; /* elapsed time */ +WritePL (unix_hwpcb + 24, tmp1); /* save PCC */ +WritePQ (unix_hwpcb + 32, unix_unique); /* save unique */ +v0 = unix_hwpcb; /* return curr PCBB */ +unix_hwpcb = a0; /* new PCBB */ +SP = ksp = ReadPQ (unix_hwpcb + 0); /* read stack ptrs */ +usp = ReadPQ (unix_hwpcb + 8); +val = ReadPQ (unix_hwpcb + 16) << VA_N_OFF; /* read new PTBR */ +if (val != unix_ptptr) tlb_ia (TLB_CI | TLB_CD); /* ptbr change? zap TLB */ +unix_ptptr = val; +tmp1 = ReadPL (unix_hwpcb + 24); /* restore PCC */ +pcc_h = (tmp1 - pcc_l) & M32; +tmp1 = ReadPL (unix_hwpcb + 28) & M16; /* read ASN */ +itlb_set_asn (tmp1); +dtlb_set_asn (tmp1); +unix_unique = ReadPQ (unix_hwpcb + 32); /* read unique */ +fpen = ReadPL (unix_hwpcb + PCBU_FLAGS) & 1; /* read FEN */ +return; +} + +/* Unix interrupt or exception - always to kernel mode + + Inputs: + vec = entry vector + arg = argument for a0 + Outputs: + reason = possible processor halt +*/ + +t_stat unix_intexc (t_uint64 vec, t_uint64 arg) +{ +t_uint64 sav_ps = GET_PSU; /* old PS */ + +if ((unix_cm & PSU_M_CM) != MODE_K) { /* not kernel? */ + usp = SP; /* save SP */ + SP = ksp; /* load new SP */ + unix_cm = mmu_set_cm (MODE_K); /* PS = 0 */ + unix_ipl = 0; + } +SP = (SP - UNIX_L_STKF) & M64; /* decr stack */ +if (Test (SP, cm_wacc, NULL)) return STOP_KSNV; /* validate writes */ +if (Test (SP + UNIX_L_STKF - 8, cm_wacc, NULL) < 0) return STOP_KSNV; +WriteQ (SP, sav_ps); /* save PS, PC, gp */ +WriteQ (SP + 8, PC); +WriteQ (SP + 16, gp); +WriteQ (SP + 24, a0); /* save a0-a2 */ +WriteQ (SP + 32, a1); +WriteQ (SP + 40, a2); +PC = vec; /* new PC */ +gp = unix_kgp; /* kernel GP */ +a0 = arg; /* argument */ +return SCPE_OK; +} + +/* Memory management fault */ + +t_stat unix_mm_intexc (t_uint64 par1, t_uint64 par2) +{ +t_stat r; + +r = unix_intexc (entMM, p1); /* do exception */ +a1 = par1; /* set arguments */ +a2 = par2; +tlb_is (p1, TLB_CI | TLB_CD); /* zap TLB entry */ +return r; +} + +/* System call - always user to kernel, abbreviated stack frame, no arguments */ + +t_stat unix_syscall (void) +{ +t_uint64 sav_ps = GET_PSU; /* save PS */ + +usp = SP; /* save user SP */ +SP = ksp; /* load kernel SP */ +unix_cm = mmu_set_cm (MODE_K); /* PS = 0 */ +unix_ipl = 0; +SP = (SP - UNIX_L_STKF) & M64; /* decr stack */ +if (Test (SP, cm_wacc, NULL)) return STOP_KSNV; /* validate writes */ +if (Test (SP + UNIX_L_STKF - 8, cm_wacc, NULL)) return STOP_KSNV; +WriteQ (SP, sav_ps); /* save PS, PC, gp */ +WriteQ (SP + 8, PC); +WriteQ (SP + 16, gp); +PC = entSys; /* new PC */ +gp = unix_kgp; /* kernel GP */ +return SCPE_OK; +} + +/* Return from trap or interrupt - always from kernel */ + +t_stat unix_rti (void) +{ +t_uint64 tpc; +uint32 tps, newm; + +if (Test (SP, cm_racc, NULL)) return STOP_KSNV; /* validate reads */ +if (Test (SP + UNIX_L_STKF - 8, cm_racc, NULL)) return STOP_KSNV; +tps = (uint32) ReadQ (SP); /* read PS, PC */ +tpc = ReadQ (SP + 8); +gp = ReadQ (SP + 16); /* restore gp, a0-a2 */ +a0 = ReadQ (SP + 24); +a1 = ReadQ (SP + 32); +a2 = ReadQ (SP + 40); +SP = (SP + UNIX_L_STKF); /* incr stack */ +newm = (tps >> PSU_V_CM) & PSU_M_CM; +unix_cm = mmu_set_cm (newm); /* new current mode */ +if (newm) { /* to user? */ + ksp = SP; /* save kernel stack */ + SP = usp; /* load user stack */ + unix_ipl = 0; /* ipl = 0 */ + } +else unix_ipl = (tps >> PSU_V_IPL) & PSU_V_IPL; /* restore ipl */ +PC = tpc; /* restore PC */ +vax_flag = 0; /* clear VAX, lock flags */ +lock_flag = 0; +return SCPE_OK; +} + +/* Return from system call - always from kernel to user */ + +t_stat unix_retsys (void) +{ +t_uint64 tpc; + +if (Test (SP + 8, cm_racc, NULL)) return STOP_KSNV; /* validate reads */ +if (Test (SP + 16, cm_racc, NULL)) return STOP_KSNV; +tpc = ReadQ (SP + 8); /* read PC */ +gp = ReadQ (SP + 16); /* restore GP */ +ksp = (SP + UNIX_L_STKF); /* update kernel stack */ +SP = usp; /* restore user stack */ +unix_cm = mmu_set_cm (MODE_E); /* PS = 8 */ +unix_ipl = 0; +PC = tpc; /* restore PC */ +vax_flag = 0; /* clear VAX, lock flags */ +lock_flag = 0; +return SCPE_OK; +} + +/* Return from user mode trap - always from user to user */ + +void unix_urti (void) +{ +t_uint64 tsp, tpc; +uint32 tps; + +if (SP & 0x3F) ABORT (EXC_RSVO); /* not aligned? */ +tps = ReadL (SP + 16); /* read PS */ +if (!(tps & PSU_CM) || (tps & PSU_IPL)) ABORT (EXC_RSVO); +at = ReadQ (SP + 0); /* restore at */ +tsp = ReadQ (SP + 8); /* read SP, PC */ +tpc = ReadQ (SP + 24); +gp = ReadQ (SP + 32); /* restore gp, a0-a2 */ +a0 = ReadQ (SP + 40); +a1 = ReadQ (SP + 48); +a2 = ReadQ (SP + 56); +SP = tsp; /* restore SP */ +PC = tpc; /* restore PC */ +vax_flag = 0; /* clear VAX, lock flags */ +lock_flag = 0; +return; +} + +/* Unix 3-level PTE lookup + + Inputs: + vpn = virtual page number (30b, sext) + *pte = pointer to pte to be returned + Output: + status = 0 for successful fill + EXC_ACV for ACV on intermediate level + EXC_TNV for TNV on intermediate level +*/ + +uint32 pal_find_pte_unix (uint32 vpn, t_uint64 *l3pte) +{ +t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte; +uint32 vpte_vpn; +TLBENT *vpte_p; + +vptea = unix_vptptr | (((t_uint64) (vpn & VA_M_VPN)) << 3); /* try virtual lookup */ +vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ +vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ +if (vpte_p && ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) + l3ptea = vpte_p->pfn | VA_GETOFF (vptea); +else { + l1ptea = unix_ptptr + VPN_GETLVL1 (vpn); + l1pte = ReadPQ (l1ptea); + if ((l1pte & PTE_V) == 0) + return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l2ptea = l2ptea + VPN_GETLVL2 (vpn); + l2pte = ReadPQ (l2ptea); + if ((l2pte & PTE_V) == 0) + return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l3ptea = l3ptea + VPN_GETLVL3 (vpn); + } +*l3pte = ReadPQ (l3ptea); +return 0; +} + +/* Unix PALcode reset */ + +t_stat pal_proc_reset_unix (DEVICE *dptr) +{ +mmu_ispage = mmu_dspage = SPEN_43; +unix_ipl = PSU_M_IPL; +unix_cm = mmu_set_cm (MODE_K); +pcc_enb = 1; +pal_eval_intr = &pal_eval_intr_unix; +pal_proc_intr = &pal_proc_intr_unix; +pal_proc_trap = &pal_proc_trap_unix; +pal_proc_excp = &pal_proc_excp_unix; +pal_proc_inst = &pal_proc_inst_unix; +pal_find_pte = &pal_find_pte_unix; +return SCPE_OK; +} diff --git a/alpha/old_pal/alpha_pal_vms.c b/alpha/old_pal/alpha_pal_vms.c new file mode 100644 index 00000000..df0612da --- /dev/null +++ b/alpha/old_pal/alpha_pal_vms.c @@ -0,0 +1,1780 @@ +/* alpha_pal_vms.c - Alpha VMS PAL code simulator + + Copyright (c) 2003-2005, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This module contains the PALcode implementation for Alpha VMS, except for + the console, which is always done in hardware mode. + + Alpha VMS requires a complex privileged state, modelled after the VAX: + + PS<12:0> processor status + IPL<4:0> interrupt level - in base + VMM<0> virtual machine mode + CM<1:0> current mode - in base + IP<0> interrupt in progress + SW<1:0> software controlled + KSP<63:0> kernel stack pointer + ESP<63:0> executive stack pointer + SSP<63:0> supervisor stack pointer + USP<63:0> user stack pointer + SSC<63:0> system cycle counter + PCBB<63:0> process control block base + SCBB<63:0> system control block base + PTBR<63:0> page table base + VTBR<63:0> virtual page table base + VIRBND<63:0> virtual address boundary + SYSPTBR<63:0> system page table base register + PRBR<63:0> processor base register + THREAD<63:0> thread-unique value + SIRR<15:1> software interrupt requests + ASTEN<3:0> AST enables + ASTRQ<3:0> AST requests + FEN<0> floating enable + DATFX<0> data alignment trap enable + + Note that some of this state exists in the hardware implementations and + so is declared in the base CPU. +*/ + +#include "alpha_defs.h" + +/* Alignment table */ + +#define ALG_W 1 /* word inst */ +#define ALG_L 2 /* long inst */ +#define ALG_Q 3 /* quad inst */ +#define ALG_ST 0x10 /* store */ +#define ALG_INV -1 /* invalid inst */ +#define ALG_ERR 0 /* internal error */ +#define ALG_GETLNT(x) ((x) & 3) + +#define GET_PSV ((vms_ipl << PSV_V_IPL) | (vms_cm << PSV_V_CM) | \ + (vms_ps & PSV_MASK)) +#define AST_TST(l) (((l) < IPL_AST) && (vms_asten & vms_astsr & ast_map[vms_cm])) +#define MOST_PRIV(m1,m2) (((m1) < (m2))? (m1): (m2)) + +#define ksp vms_stkp[MODE_K] +#define esp vms_stkp[MODE_E] +#define ssp vms_stkp[MODE_S] +#define usp vms_stkp[MODE_U] + +// kludge for debugging... +#define io_get_vec(x) 0 + +t_uint64 vms_ptbr = 0; /* page table base */ +t_uint64 vms_vtbr = 0; /* virt page table base */ +t_uint64 vms_virbnd = M64; /* virtual boundary */ +t_uint64 vms_sysptbr = 0; /* system page table base */ +t_uint64 vms_hwpcb = 0; /* hardware PCB */ +t_uint64 vms_thread = 0; /* thread unique */ +t_uint64 vms_prbr = 0; /* processor unique */ +t_uint64 vms_stkp[4]; /* stack pointers */ +t_uint64 vms_scbb = 0; /* SCB base */ +t_uint64 vms_scc = 0; /* system cycle ctr */ +t_uint64 vms_mces = 0; /* machine check err summ */ +uint32 vms_ipl = 0; /* hardware IPL */ +uint32 vms_cm = 0; /* inst current mode */ +uint32 vms_sisr = 0; /* software int req */ +uint32 vms_asten = 0; /* AST enables */ +uint32 vms_astsr = 0; /* AST requests */ +uint32 vms_last_pcc = 0; /* last pcc_l */ +uint32 vms_datfx = 0; /* data alignment */ +uint32 vms_ps = 0; /* static PS */ + +const uint32 ast_map[4] = { 0x1, 0x3, 0x7, 0xF }; +const uint32 ast_pri[16] = { + 0, MODE_K, MODE_E, MODE_K, MODE_S, MODE_K, MODE_E, MODE_K, + MODE_U, MODE_K, MODE_E, MODE_K, MODE_S, MODE_K, MODE_E, MODE_K + }; +static const uint32 lnt_map[4] = { L_BYTE, L_WORD, L_LONG, L_QUAD }; +static const int8 alg_map[64] = { + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_W, ALG_W|ALG_ST, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_L, ALG_Q, ALG_L, ALG_Q, + ALG_L|ALG_ST, ALG_Q|ALG_ST, ALG_L|ALG_ST, ALG_Q|ALG_ST, + ALG_L, ALG_Q, ALG_INV, ALG_INV, + ALG_L|ALG_ST, ALG_Q|ALG_ST, ALG_INV, ALG_INV, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR, + ALG_ERR, ALG_ERR, ALG_ERR, ALG_ERR + }; + +extern t_uint64 R[32]; +extern t_uint64 PC, trap_mask; +extern t_uint64 p1; +extern uint32 vax_flag, lock_flag; +extern uint32 fpen; +extern uint32 ir, pcc_h, pcc_l, pcc_enb; +extern uint32 cm_racc, cm_wacc, cm_macc; +extern uint32 mmu_ispage, mmu_dspage; +extern jmp_buf save_env; +extern uint32 int_req[IPL_HLVL]; + +t_int64 vms_insqhil (void); +t_int64 vms_insqtil (void); +t_int64 vms_insqhiq (void); +t_int64 vms_insqtiq (void); +t_int64 vms_insquel (uint32 defer); +t_int64 vms_insqueq (uint32 defer); +t_int64 vms_remqhil (void); +t_int64 vms_remqtil (void); +t_int64 vms_remqhiq (void); +t_int64 vms_remqtiq (void); +t_int64 vms_remquel (uint32 defer); +t_int64 vms_remqueq (uint32 defer); +t_int64 vms_insqhilr (void); +t_int64 vms_insqtilr (void); +t_int64 vms_insqhiqr (void); +t_int64 vms_insqtiqr (void); +t_int64 vms_remqhilr (void); +t_int64 vms_remqtilr (void); +t_int64 vms_remqhiqr (void); +t_int64 vms_remqtiqr (void); +uint32 vms_probe (uint32 acc); +uint32 vms_amovrr (void); +uint32 vms_amovrm (void); +t_stat vms_rei (void); +void vms_swpctx (void); +t_stat vms_intexc (uint32 vec, uint32 newmode, uint32 newipl); +t_stat vms_mm_intexc (uint32 vec, t_uint64 par2); +t_stat pal_proc_reset_vms (DEVICE *dptr); +t_uint64 ReadUna (t_uint64 va, uint32 lnt, uint32 acc); +void WriteUna (t_uint64 va, t_uint64 val, uint32 lnt, uint32 acc); +uint32 tlb_check (t_uint64 va); +uint32 Test (t_uint64 va, uint32 acc, t_uint64 *pa); + +extern t_stat (*pal_eval_intr) (uint32 ipl); +extern t_stat (*pal_proc_excp) (uint32 type); +extern t_stat (*pal_proc_trap) (uint32 type); +extern t_stat (*pal_proc_intr) (uint32 type); +extern t_stat (*pal_proc_inst) (uint32 fnc); +extern uint32 (*pal_find_pte) (uint32 vpn, t_uint64 *pte); + +/* VMSPAL data structures + + vmspal_dev device descriptor + vmspal_unit unit + vmspal_reg register list +*/ + +UNIT vmspal_unit = { UDATA (NULL, 0, 0) }; + +REG vmspal_reg[] = { + { HRDATA (KSP, ksp, 64) }, + { HRDATA (ESP, esp, 64) }, + { HRDATA (SSP, ssp, 64) }, + { HRDATA (USP, usp, 64) }, + { HRDATA (PTBR, vms_ptbr, 64) }, + { HRDATA (VTBR, vms_vtbr, 64) }, + { HRDATA (VIRBND, vms_virbnd, 64) }, + { HRDATA (SYSPTBR, vms_sysptbr, 64) }, + { HRDATA (THREAD, vms_thread, 64) }, + { HRDATA (PRBR, vms_prbr, 64) }, + { HRDATA (HWPCB, vms_hwpcb, 64) }, + { HRDATA (SCBB, vms_scbb, 64) }, + { HRDATA (SCC, vms_scc, 64) }, + { HRDATA (LASTPCC, vms_last_pcc, 32), REG_HRO }, + { HRDATA (MCES, vms_mces, 64) }, + { HRDATA (PS, vms_ps, 13) }, + { HRDATA (IPL, vms_ipl, 5) }, + { HRDATA (CM, vms_cm, 2) }, + { HRDATA (SISR, vms_sisr, 16) }, + { HRDATA (ASTEN, vms_asten, 4) }, + { HRDATA (ASTSR, vms_astsr, 4) }, + { FLDATA (DATFX, vms_datfx, 0) }, + { NULL } + }; + +DEVICE vmspal_dev = { + "VMSPAL", &vmspal_unit, vmspal_reg, NULL, + 1, 16, 1, 1, 16, 8, + NULL, NULL, &pal_proc_reset_vms, + NULL, NULL, NULL, + NULL, 0 + }; + +/* VMS interrupt evaluator - returns IPL of highest priority interrupt */ + +uint32 pal_eval_intr_vms (uint32 lvl) +{ +uint32 i; +static const int32 sw_int_mask[32] = { + 0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, /* 0 - 3 */ + 0xFFE0, 0xFFC0, 0xFF80, 0xFF00, /* 4 - 7 */ + 0xFE00, 0xFC00, 0xF800, 0xF000, /* 8 - B */ + 0xE000, 0xC000, 0x8000, 0x0000, /* C - F */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 10+ */ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }; + +vms_scc = vms_scc + ((pcc_l - vms_last_pcc) & M32); /* update scc */ +vms_last_pcc = pcc_l; +for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */ + if (i <= lvl) return 0; /* at ipl? no int */ + if (int_req[i - IPL_HMIN]) return i; /* req != 0? int */ + } +if (vms_sisr & sw_int_mask[lvl]) { /* swre interrupt? */ + for (i = IPL_SMAX; i > lvl; i--) { /* check swre int */ + if ((vms_sisr >> i) & 1) /* req != 0? int */ + return (AST_TST (i)? IPL_AST: i); /* check for AST */ + } + } +return (AST_TST (lvl)? IPL_AST: 0); /* no swre, check AST */ +} + +/* VMS interrupt dispatch - reached from top of execute loop */ + +t_stat pal_proc_intr_vms (uint32 lvl) +{ +uint32 vec; +t_stat r; + +if (lvl > IPL_HMAX) return SCPE_IERR; /* above max? */ +else if (lvl >= IPL_HMIN) vec = io_get_vec (lvl); /* hwre? get vector */ +else if (lvl > IPL_SMAX) return SCPE_IERR; /* above swre max? */ +else if (lvl > 0) { /* swre int? */ + if ((lvl == IPL_AST) && (vms_asten & vms_astsr & ast_map[vms_cm])) { + uint32 astm = ast_pri[vms_astsr & 0xF]; /* get AST priority */ + vms_astsr = vms_astsr & ~(1u << astm); /* clear hi pri */ + vec = SCB_KAST + (astm << 4); + } + else { /* swre int */ + vms_sisr = vms_sisr & ~(1u << lvl); + vec = SCB_SISR0 + (lvl << 4); + } + } +else return SCPE_IERR; /* bug */ +if (vec == 0) vec = SCB_PASVR; /* passive release? */ +r = vms_intexc (vec, MODE_K, lvl); /* do interrupt */ +vms_ps = vms_ps | PSV_IP; /* set int in prog */ +return r; +} + +/* VMS trap dispatch - reached synchronously from bottom of execute loop */ + +t_stat pal_proc_trap_vms (uint32 tsum) +{ +t_stat r; + +r = vms_intexc (SCB_ARITH, MODE_K, vms_ipl); /* arithmetic trap */ +R[4] = trap_mask; /* set parameters */ +R[5] = tsum; +return r; +} + +/* VMS exception dispatch - reached from the ABORT handler */ + +t_stat pal_proc_excp_vms (uint32 abval) +{ +uint32 op, ra, lntc; +int8 fl; +t_stat r; + +switch (abval) { + + case EXC_RSVI: /* reserved instr */ + return vms_intexc (SCB_RSVI, MODE_K, vms_ipl); /* trap */ + + case EXC_RSVO: /* reserved operand */ + return vms_intexc (SCB_RSVO, MODE_K, vms_ipl); /* trap */ + + case EXC_ALIGN: /* unaligned */ + op = I_GETOP (ir); /* get opcode */ + ra = I_GETRA (ir); /* get RA */ + fl = alg_map[op]; /* get alignment map */ + if (fl == ALG_ERR) return SCPE_IERR; /* impossible? */ + if (fl == ALG_INV) return (SCB_RSVI, MODE_K, vms_ipl); /* conditional? */ + lntc = ALG_GETLNT (fl); /* get length code */ + if (fl & ALG_ST) /* store? */ + WriteUna (p1, R[ra], lnt_map[lntc], cm_wacc); + else if (ra != 31) + R[ra] = ReadUna (p1, lnt_map[lntc], cm_racc); + if (vms_datfx) break; /* trap? */ + r = vms_intexc (SCB_ALIGN, MODE_K, vms_ipl); /* do trap */ + R[4] = p1; /* R4 = va */ + R[5] = (fl & ALG_ST)? 1: 0; /* R5 = load/store */ + return r; + + case EXC_FPDIS: /* fp disabled */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_intexc (SCB_FDIS, MODE_K, vms_ipl); /* fault */ + + case EXC_FOX+EXC_E: /* FOE */ + tlb_is (p1, TLB_CI); + return vms_mm_intexc (SCB_FOE, VMS_MME_E); + + case EXC_FOX+EXC_R: /* FOR */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_FOR, VMS_MME_R); + + case EXC_FOX+EXC_W: /* FOW */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_FOW, VMS_MME_W); + + case EXC_BVA+EXC_E: + case EXC_ACV+EXC_E: /* instr ACV */ + return vms_mm_intexc (SCB_ACV, VMS_MME_E); + + case EXC_BVA+EXC_R: + case EXC_ACV+EXC_R: /* data read ACV */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_ACV, VMS_MME_R); + + case EXC_BVA+EXC_W: + case EXC_ACV+EXC_W: /* data write ACV */ + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_ACV, VMS_MME_W); + + case EXC_TNV+EXC_E: /* instr TNV */ + tlb_is (p1, TLB_CI); + return vms_mm_intexc (SCB_TNV, VMS_MME_E); + + case EXC_TNV+EXC_R: /* data read TNV */ + tlb_is (p1, TLB_CD); + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_TNV, VMS_MME_R); + + case EXC_TNV+EXC_W: /* data write TNV */ + tlb_is (p1, TLB_CD); + PC = (PC - 4) & M64; /* back up PC */ + return vms_mm_intexc (SCB_TNV, VMS_MME_W); + + case EXC_TBM + EXC_E: /* TLB miss */ + case EXC_TBM + EXC_R: + case EXC_TBM + EXC_W: + return SCPE_IERR; /* should not occur */ + + default: + return STOP_INVABO; + } + +return SCPE_OK; +} + +/* PALcode instruction dispatcher - function code verified in CPU */ + +t_stat pal_proc_inst_vms (uint32 fnc) +{ +t_uint64 val; +uint32 arg32 = (uint32) R[16]; + +if ((fnc < 0x40) && (vms_cm != MODE_K)) ABORT (EXC_RSVI); +switch (fnc) { + + case OP_HALT: + return STOP_HALT; + + case OP_CFLUSH: + case OP_DRAINA: + break; + + case OP_LDQP: + R[0] = ReadPQ (R[16]); + break; + + case OP_STQP: + WritePQ (R[16], R[17]); + break; + + case OP_SWPCTX: + vms_swpctx (); + break; + + case MF_ASN: + R[0] = itlb_read_asn (); + break; + + case MT_ASTEN: + R[0] = vms_asten & AST_MASK; + vms_asten = ((vms_asten & arg32) | (arg32 >> 4)) & AST_MASK; + break; + + case MT_ASTSR: + R[0] = vms_astsr & AST_MASK; + vms_astsr = ((vms_astsr & arg32) | (arg32 >> 4)) & AST_MASK; + break; + + case OP_CSERVE: + // tbd + break; + + case OP_SWPPAL: + R[0] = 0; + break; + + case MF_FEN: + R[0] = fpen & 1; + break; + + case MT_FEN: + fpen = arg32 & 1; + arg32 = ReadPL (vms_hwpcb + PCBV_FLAGS); + arg32 = (arg32 & ~1) | fpen; + WritePL (vms_hwpcb + PCBV_FLAGS, arg32); + break; + + case MT_IPIR: + //tbd + break; + + case MF_IPL: + R[0] = vms_ipl & PSV_M_IPL; + break; + + case MT_IPL: + R[0] = vms_ipl & PSV_M_IPL; + vms_ipl = arg32 & PSV_M_IPL; + break; + + case MF_MCES: + R[0] = vms_mces; + break; + + case MT_MCES: + vms_mces = (vms_mces | (arg32 & MCES_DIS)) & ~(arg32 & MCES_W1C); + break; + + case MF_PCBB: + R[0] = vms_hwpcb; + break; + + case MF_PRBR: + R[0] = vms_prbr; + break; + + case MT_PRBR: + vms_prbr = R[16]; + break; + + case MF_PTBR: + R[0] = (vms_ptbr >> VA_N_OFF); /* PFN only */ + break; + + case MF_SCBB: + R[0] = vms_scbb; + break; + + case MT_SCBB: + vms_scbb = R[16]; + break; + + case MF_SISR: + R[0] = vms_sisr & SISR_MASK; + break; + + case MT_SIRR: + vms_sisr = (vms_sisr | (1u << (arg32 & 0xF))) & SISR_MASK; + break; + + case MF_TBCHK: + if (tlb_check (R[16])) R[0] = Q_SIGN + 1; + else R[0] = Q_SIGN; + break; + + case MT_TBIA: + tlb_ia (TLB_CI | TLB_CD | TLB_CA); + break; + + case MT_TBIAP: + tlb_ia (TLB_CI | TLB_CD); + break; + + case MT_TBIS: + tlb_is (R[16], TLB_CI | TLB_CD | TLB_CA); + break; + + case MF_ESP: + R[0] = esp; + break; + + case MT_ESP: + esp = R[16]; + break; + + case MF_SSP: + R[0] = ssp; + break; + + case MT_SSP: + ssp = R[16]; + break; + + case MF_USP: + R[0] = usp; + break; + + case MT_USP: + usp = R[16]; + break; + + case MT_TBISI: + tlb_is (R[16], TLB_CI | TLB_CA); + break; + + case MT_TBISD: + tlb_is (R[16], TLB_CD | TLB_CA); + break; + + case MF_ASTEN: + R[0] = vms_asten & AST_MASK; + break; + + case MF_ASTSR: + R[0] = vms_astsr & AST_MASK; + break; + + case MF_VTBR: + R[0] = vms_vtbr; + break; + + case MT_VTBR: + vms_vtbr = R[16]; + break; + + case MT_PERFMON: + // tbd + break; + + case MT_DATFX: + vms_datfx = arg32 & 1; + val = ReadPQ (vms_hwpcb + PCBV_FLAGS); + val = (val & ~0x8000000000000000) | (((t_uint64) vms_datfx) << 63); + WritePQ (vms_hwpcb + PCBV_FLAGS, val); + break; + + case MF_VIRBND: + R[0] = vms_virbnd; + break; + + case MT_VIRBND: + vms_virbnd = R[16]; + break; + + case MF_SYSPTBR: + R[0] = vms_sysptbr; + break; + + case MT_SYSPTBR: + vms_sysptbr = R[16]; + break; + + case OP_WTINT: + R[0] = 0; + break; + + case MF_WHAMI: + R[0] = 0; + break; + +/* Non-privileged */ + + case OP_BPT: + return vms_intexc (SCB_BPT, MODE_K, vms_ipl); + + case OP_BUGCHK: + return vms_intexc (SCB_BUG, MODE_K, vms_ipl); + + case OP_CHME: + return vms_intexc (SCB_CHME, MOST_PRIV (MODE_E, vms_cm), vms_ipl); + + case OP_CHMK: + return vms_intexc (SCB_CHMK, MODE_K, vms_ipl); + + case OP_CHMS: + return vms_intexc (SCB_CHMS, MOST_PRIV (MODE_S, vms_cm), vms_ipl); + + case OP_CHMU: + return vms_intexc (SCB_CHMU, vms_cm, vms_ipl); + break; + + case OP_IMB: + break; + + case OP_INSQHIL: + R[0] = vms_insqhil (); + break; + + case OP_INSQTIL: + R[0] = vms_insqtil (); + break; + + case OP_INSQHIQ: + R[0] = vms_insqhiq (); + break; + + case OP_INSQTIQ: + R[0] = vms_insqtiq (); + break; + + case OP_INSQUEL: + R[0] = vms_insquel (0); + break; + + case OP_INSQUEQ: + R[0] = vms_insqueq (0); + break; + + case OP_INSQUELD: + R[0] = vms_insquel (1); + break; + + case OP_INSQUEQD: + R[0] = vms_insqueq (1); + break; + + case OP_PROBER: + R[0] = vms_probe (PTE_KRE); + break; + + case OP_PROBEW: + R[0] = vms_probe (PTE_KRE|PTE_KWE); + break; + + case OP_RD_PS: + R[0] = GET_PSV; + break; + + case OP_REI: + return vms_rei (); + + case OP_REMQHIL: + R[0] = vms_insqhil (); + break; + + case OP_REMQTIL: + R[0] = vms_remqtil (); + break; + + case OP_REMQHIQ: + R[0] = vms_remqhiq (); + break; + + case OP_REMQTIQ: + R[0] = vms_remqtiq (); + break; + + case OP_REMQUEL: + R[0] = vms_remquel (0); + break; + + case OP_REMQUEQ: + R[0] = vms_remqueq (0); + break; + + case OP_REMQUELD: + R[0] = vms_remquel (1); + break; + + case OP_REMQUEQD: + R[0] = vms_remqueq (1); + break; + + case OP_SWASTEN: + R[0] = (vms_asten >> vms_cm) & 1; + vms_asten = (vms_asten & ~(1u << vms_cm)) | ((arg32 & 1) << vms_cm); + break; + + case OP_WR_PS_SW: + vms_ps = (vms_ps & ~PSV_M_SW) | (arg32 & PSV_M_SW); + break; + + case OP_RSCC: + vms_scc = vms_scc + ((pcc_l - vms_last_pcc) & M32); /* update scc */ + vms_last_pcc = pcc_l; + R[0] = vms_scc; + break; + + case OP_RD_UNQ: + R[0] = vms_thread; + break; + + case OP_WR_UNQ: + vms_thread = R[16]; + break; + + case OP_AMOVRR: + R[18] = vms_amovrr (); + break; + + case OP_AMOVRM: + R[18] = vms_amovrm (); + break; + + case OP_INSQHILR: + R[0] = vms_insqhilr (); + break; + + case OP_INSQTILR: + R[0] = vms_insqtilr (); + break; + + case OP_INSQHIQR: + R[0] = vms_insqhiqr (); + break; + + case OP_INSQTIQR: + R[0] = vms_insqtiqr (); + break; + + case OP_REMQHILR: + R[0] = vms_insqhilr (); + break; + + case OP_REMQTILR: + R[0] = vms_remqtilr (); + break; + + case OP_REMQHIQR: + R[0] = vms_remqhiqr (); + break; + + case OP_REMQTIQR: + R[0] = vms_remqtiqr (); + break; + + case OP_GENTRAP: + return vms_intexc (SCB_GENTRAP, MODE_K, vms_ipl); + + case OP_CLRFEN: + fpen = 0; + arg32 = ReadPL (vms_hwpcb + PCBV_FLAGS); + arg32 = arg32 & ~1; + WritePL (vms_hwpcb + PCBV_FLAGS, arg32); + break; + + default: + ABORT (EXC_RSVI); + } + +return SCPE_OK; +} + +/* Interlocked insert instructions + + R[16] = entry + R[17] = header + + Pictorially: + + BEFORE AFTER INSQHI AFTER INSQTI + + H: A-H H: D-H W H: A-H W for interlock + H+4/8: C-H H+4/8: C-H H+4/8: D-H W + + A: B-A A: B-A A: B-A + A+4/8: H-A A+4/8: D-A W A+4/8: H-A + + B: C-B B: C-B B: C-B + B+4/8: A-B B+4/8: A-B B+4/8: A-B + + C: H-C C: H-C C: D-C W + C+4/8: B-C C+4/8: B-C C+4/8: B-C + + D: --- D: A-D W D: H-D W + D+4/8: --- D+4/8: H-D W D+4/8: C-D W + + Note that the queue header, the entry to be inserted, and all + the intermediate entries that are "touched" in any way must be + QUAD(OCTA)WORD aligned. In addition, the header and the entry + must not be equal. + + Note that the offset arithmetic (+4, +8) cannot overflow 64b, + because the entries are quad or octa aligned. +*/ + +t_int64 vms_insqhil (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, a; + +if ((h == d) || ((h | d) & 07) || /* h, d quad align? */ + ((SEXT_L_Q (h) & M64) != h) || + ((SEXT_L_Q (d) & M64) != d)) ABORT (EXC_RSVO); +ReadAccQ (d, cm_wacc); /* wchk (d) */ +ar = ReadQ (h); /* a <- (h) */ +if (ar & 06) ABORT (EXC_RSVO); /* a quad align? */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* get interlock */ +a = (SEXT_L_Q (ar + h)) & M64; /* abs addr of a */ +if (Test (a, cm_wacc, NULL)) WriteQ (h, ar); /* wtst a, rls if err */ +WriteL (a + 4, (uint32) (d - a)); /* (a+4) <- d-a, flt ok */ +WriteL (d, (uint32) (a - d)); /* (d) <- a-d */ +WriteL (d + 4, (uint32) (h - d)); /* (d+4) <- h-d */ +WriteL (h, (uint32) (d - h)); /* (h) <- d-h, rls int */ +return ((ar & M32) == 0)? 0: +1; /* ret 0 if q was empty */ +} + +t_int64 vms_insqhilr (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, a; + +ar = ReadQ (h); /* a <- (h) */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* get interlock */ +a = (SEXT_L_Q (ar + h)) & M64; /* abs addr of a */ +WriteL (a + 4, (uint32) (d - a)); /* (a+4) <- d-a, flt ok */ +WriteL (d, (uint32) (a - d)); /* (d) <- a-d */ +WriteL (d + 4, (uint32) (h - d)); /* (d+4) <- h-d */ +WriteL (h, (uint32) (d - h)); /* (h) <- d-h, rls int */ +return ((ar & M32) == 0)? 0: +1; /* ret 0 if q was empty */ +} + +t_int64 vms_insqhiq (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, a; + +if ((h == d) || ((h | d) & 0xF)) ABORT (EXC_RSVO); /* h, d octa align? */ +ReadAccQ (d, cm_wacc); /* wchk (d) */ +ar = ReadQ (h); /* a <- (h) */ +if (ar & 0xE) ABORT (EXC_RSVO); /* a octa align? */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* get interlock */ +a = (ar + h) & M64; /* abs addr of a */ +if (Test (a, cm_wacc, NULL)) WriteQ (h, ar); /* wtst a, rls if err */ +WriteQ (a + 8, (d - a) & M64); /* (a+8) <- d-a, flt ok */ +WriteQ (d, (a - d) & M64); /* (d) <- a-d */ +WriteQ (d + 8, (h - d) & M64); /* (d+8) <- h-d */ +WriteQ (h, (d - h) & M64); /* (h) <- d-h, rls int */ +return (ar == 0)? 0: +1; /* ret 0 if q was empty */ +} + +t_int64 vms_insqhiqr (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, a; + +ar = ReadQ (h); /* a <- (h) */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* get interlock */ +a = (ar + h) & M64; /* abs addr of a */ +WriteQ (a + 8, (d - a) & M64); /* (a+8) <- d-a, flt ok */ +WriteQ (d, (a - d) & M64); /* (d) <- a-d */ +WriteQ (d + 8, (h - d) & M64); /* (d+8) <- h-d */ +WriteQ (h, (d - h) & M64); /* (h) <- d-h, rls int */ +return (ar == 0)? 0: +1; /* ret 0 if q was empty */ +} + +t_int64 vms_insqtil (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, c; + +if ((h == d) || ((h | d) & 07) || /* h, d quad align? */ + ((SEXT_L_Q (h) & M64) != h) || + ((SEXT_L_Q (d) & M64) != d)) ABORT (EXC_RSVO); +ReadAccQ (d, cm_wacc); /* wchk (d) */ +ar = ReadQ (h); /* a <- (h) */ +if ((ar & M32) == 0) return vms_insqhil (); /* if empty, ins hd */ +if (ar & 06) ABORT (EXC_RSVO); /* a quad align? */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ar >> 32; /* c <- (h+4) */ +c = (SEXT_L_Q (c + h)) & M64; /* abs addr of c */ +if (c & 07) { /* c quad aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (c, cm_wacc, NULL)) WriteQ (h, ar); /* wtst c, rls if err */ +WriteL (c, (uint32) (d - c)); /* (c) <- d-c, flt ok */ +WriteL (d, (uint32) (h - d)); /* (d) <- h-d */ +WriteL (d + 4, (uint32) (c - d)); /* (d+4) <- c-d */ +WriteL (h + 4, (uint32) (d - h)); /* (h+4) <- d-h */ +WriteL (h, (uint32) ar); /* release interlock */ +return 0; /* q was not empty */ +} + +t_int64 vms_insqtilr (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, c; + +ar = ReadQ (h); /* a <- (h) */ +if ((ar & M32) == 0) return vms_insqhilr (); /* if empty, ins hd */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ar >> 32; /* c <- (h+4) */ +c = (SEXT_L_Q (c + h)) & M64; /* abs addr of c */ +WriteL (c, (uint32) (d - c)); /* (c) <- d-c */ +WriteL (d, (uint32) (h - d)); /* (d) <- h-d */ +WriteL (d + 4, (uint32) (c - d)); /* (d+4) <- c-d */ +WriteL (h + 4, (uint32) (d - h)); /* (h+4) <- d-h */ +WriteL (h, (uint32) ar); /* release interlock */ +return 0; /* q was not empty */ +} + +t_int64 vms_insqtiq (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, c; + +if ((h == d) || ((h | d) & 0xF)) ABORT (EXC_RSVO); /* h, d octa align? */ +ReadAccQ (d, cm_wacc); /* wchk ent */ +ar = ReadQ (h); /* a <- (h) */ +if (ar == 0) return vms_insqhiq (); /* if empty, ins hd */ +if (ar & 0xE) ABORT (EXC_RSVO); /* a octa align? */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ReadQ (h + 8); /* c <- (h+8) */ +c = (c + h) & M64; /* abs addr of C */ +if (c & 0xF) { /* c octa aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (c, cm_wacc, NULL)) WriteQ (h, ar); /* wtst c, rls if err */ +WriteQ (c, (d - c) & M64); /* (c) <- d-c, flt ok */ +WriteQ (d, (h - d) & M64); /* (d) <- h-d */ +WriteQ (d + 8, (c - d) & M64); /* (d+8) <- c-d */ +WriteQ (h + 8, (d - h) & M64); /* (h+8) <- d-h */ +WriteQ (h, ar); /* release interlock */ +return 0; /* q was not empty */ +} + +t_int64 vms_insqtiqr (void) +{ +t_uint64 h = R[16]; +t_uint64 d = R[17]; +t_uint64 ar, c; + +ar = ReadQ (h); /* a <- (h) */ +if (ar == 0) return vms_insqhiqr (); /* if empty, ins hd */ +if (ar & 01) return -1; /* busy, ret -1 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ReadQ (h + 8); /* c <- (h+8) */ +c = (c + h) & M64; /* abs addr of C */ +WriteQ (c, (d - c) & M64); /* (c) <- d-c */ +WriteQ (d, (h - d) & M64); /* (d) <- h-d */ +WriteQ (d + 8, (c - d) & M64); /* (d+8) <- c-d */ +WriteQ (h + 8, (d - h) & M64); /* (h+8) <- d-h */ +WriteQ (h, ar); /* release interlock */ +return 0; /* q was not empty */ +} + +/* Interlocked remove instructions + + R[16] = header (hdr.aq) + R[1] ] = receives destination address + + Pictorially: + + BEFORE AFTER REMQHI AFTER REMQTI + + H: A-H H: B-H W H: A-H W for interlock + H+4/8: C-H H+4/8: C-H H+4/8: B-H W + + A: B-A A: B-A R A: B-A + A+4/8: H-A A+4/8: H-A A+4/8: H-A + + B: C-B B: C-B B: H-B W + B+4/8: A-B B+4/8: H-B W B+4/8: A-B + + C: H-C C: H-C C: H-C + C+4/8: B-C C+4/8: B-C C+4/8: B-C R + + Note that the queue header and all the entries that are + "touched" in any way must be QUAD(OCTA)WORD aligned. +*/ + +t_int64 vms_remqhil (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, a, b; + +if ((h & 07) || ((SEXT_L_Q (h) & M64) != h)) /* h quad aligned? */ + ABORT (EXC_RSVO); +ar = ReadQ (h); /* ar <- (h) */ +if (ar & 06) ABORT (EXC_RSVO); /* a quad aligned? */ +if (ar & 01) return -1; /* busy, ret -1 */ +if ((ar & M32) == 0) return 0; /* queue empty? */ +WriteQ (h, ar | 1); /* acquire interlock */ +a = (SEXT_L_Q (ar + h)) & M64; /* abs addr of a */ +if (Test (a, cm_racc, NULL)) WriteQ (h, ar); /* rtst a, rls if err */ +b = ReadL (a); /* b <- (a), flt ok */ +b = (SEXT_L_Q (b + a)) & M64; /* abs addr of b */ +if (b & 07) { /* b quad aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (b, cm_wacc, NULL)) WriteQ (h, ar); /* wtst b, rls if err */ +WriteL (b + 4, (uint32) (h - b)); /* (b+4) <- h-b, flt ok */ +WriteL (h, (uint32) (b - h)); /* (h) <- b-h, rls int */ +R[1] = a; /* address of entry */ +return ((b & M32) == (h & M32))? +2: +1; /* if b = h, q empty */ +} + +t_int64 vms_remqhilr (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, a, b; + +ar = ReadQ (h); /* ar <- (h) */ +if (ar & 01) return -1; /* busy, ret -1 */ +if ((ar & M32) == 0) return 0; /* queue empty? */ +WriteQ (h, ar | 1); /* acquire interlock */ +a = (SEXT_L_Q (ar + h)) & M64; /* abs addr of a */ +b = ReadL (a); /* b <- (a), flt ok */ +b = (SEXT_L_Q (b + a)) & M64; /* abs addr of b */ +WriteL (b + 4, (uint32) (h - b)); /* (b+4) <- h-b, flt ok */ +WriteL (h, (uint32) (b - h)); /* (h) <- b-h, rls int */ +R[1] = a; /* address of entry */ +return ((b & M32) == (h & M32))? +2: +1; /* if b = h, q empty */ +} + +t_int64 vms_remqhiq (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, a, b; + +if (h & 0xF) ABORT (EXC_RSVO); /* h octa aligned? */ +ar = ReadQ (h); /* ar <- (h) */ +if (ar & 0xE) ABORT (EXC_RSVO); /* a octa aligned? */ +if (ar & 01) return -1; /* busy, ret -1 */ +if (ar == 0) return 0; /* queue empty? */ +WriteQ (h, ar | 1); /* acquire interlock */ +a = (ar + h) & M64; /* abs addr of a */ +if (Test (a, cm_racc, NULL)) WriteQ (h, ar); /* rtst a, rls if err */ +b = ReadQ (a); /* b <- (a), flt ok */ +b = (b + a) & M64; /* abs addr of b */ +if (b & 0xF) { /* b octa aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (b, cm_wacc, NULL)) WriteQ (h, ar); /* wtst b, rls if err */ +WriteQ (b + 8, (h - b) & M64); /* (b+8) <- h-b, flt ok */ +WriteQ (h, (b - h) & M64); /* (h) <- b-h, rls int */ +R[1] = a; /* address of entry */ +return (b == h)? +2: +1; /* if b = h, q empty */ +} + +t_int64 vms_remqhiqr (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, a, b; + +ar = ReadQ (h); /* ar <- (h) */ +if (ar & 01) return -1; /* busy, ret -1 */ +if (ar == 0) return 0; /* queue empty? */ +WriteQ (h, ar | 1); /* acquire interlock */ +a = (ar + h) & M64; /* abs addr of a */ +b = ReadQ (a); /* b <- (a) */ +b = (b + a) & M64; /* abs addr of b */ +WriteQ (b + 8, (h - b) & M64); /* (b+8) <- h-b, flt ok */ +WriteQ (h, (b - h) & M64); /* (h) <- b-h, rls int */ +R[1] = a; /* address of entry */ +return (b == h)? +2: +1; /* if b = h, q empty */ +} + +t_int64 vms_remqtil (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, b, c; + +if ((h & 07) || ((SEXT_L_Q (h) & M64) != h)) /* h quad aligned? */ + ABORT (EXC_RSVO); +ar = ReadQ (h); /* a <- (h) */ +if (ar & 06) ABORT (EXC_RSVO); /* a quad aligned? */ +if (ar & 01) return -1; /* busy, return - 1*/ +if ((ar & M32) == 0) return 0; /* empty, return 0 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ar >> 32; /* c <- (h+4) */ +if (c & 07) { /* c quad aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if ((ar & M32) == (c & M32)) { /* single entry? */ + WriteQ (h, ar); /* release interlock */ + return vms_remqhil (); /* treat as remqhil */ + } +c = (SEXT_L_Q (c + h)) & M64; /* abs addr of c */ +if (Test (c + 4, cm_racc, NULL)) WriteQ (h, ar); /* rtst c+4, rls if err */ +b = ReadL (c + 4); /* b <- (c+4), flt ok */ +b = (SEXT_L_Q (b + c)) & M64; /* abs addr of b */ +if (b & 07) { /* b quad aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (b, cm_wacc, NULL)) WriteQ (h, ar); /* wtst b, rls if err */ +WriteL (b, (uint32) (h - b)); /* (b) <- h-b, flt ok */ +WriteL (h + 4, (uint32) (b - h)); /* (h+4) <- b-h */ +WriteL (h, (uint32) ar); /* release interlock */ +R[1] = c; /* store result */ +return +1; /* q can't be empty */ +} + +t_int64 vms_remqtilr (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, b, c; + +ar = ReadQ (h); /* a <- (h) */ +if (ar & 01) return -1; /* busy, return - 1*/ +if ((ar & M32) == 0) return 0; /* emtpy, return 0 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ar >> 32; /* c <- (h+4) */ +if ((ar & M32) == (c & M32)) { /* single entry? */ + WriteQ (h, ar); /* release interlock */ + return vms_remqhilr (); /* treat as remqhil */ + } +c = (SEXT_L_Q (c + h)) & M64; /* abs addr of c */ +b = ReadL (c + 4); /* b <- (c+4) */ +b = (SEXT_L_Q (b) + c) & M64; /* abs addr of b */ +WriteL (b, (uint32) (h - b)); /* (b) <- h-b */ +WriteL (h + 4, (uint32) (b - h)); /* (h+4) <- b-h */ +WriteL (h, (uint32) ar); /* release interlock */ +R[1] = c; /* store result */ +return +1; /* q can't be empty */ +} + +t_int64 vms_remqtiq (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, b, c; + +if (h & 0xF) ABORT (EXC_RSVO); /* h octa aligned? */ +ar = ReadQ (h); /* a <- (h) */ +if (ar & 0xE) ABORT (EXC_RSVO); /* a quad aligned? */ +if (ar & 01) return -1; /* busy, return - 1*/ +if (ar == 0) return 0; /* emtpy, return 0 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ReadQ (h + 8); /* c <- (h+8) */ +if (c & 0xF) { /* c octa aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (ar == c) { /* single entry? */ + WriteQ (h, ar); /* release interlock */ + return vms_remqhiq (); /* treat as remqhil */ + } +c = (c + h) & M64; /* abs addr of c */ +if (Test (c + 8, cm_racc, NULL)) WriteQ (h, ar); /* rtst c+8, rls if err */ +b = ReadQ (c + 8); /* b <- (c+8), flt ok */ +b = (b + c) & M64; /* abs addr of b */ +if (b & 0xF) { /* b octa aligned? */ + WriteQ (h, ar); /* release interlock */ + ABORT (EXC_RSVO); /* fault */ + } +if (Test (b, cm_wacc, NULL)) WriteQ (h, ar); /* wtst b, rls if err */ +WriteQ (b, (h - b) & M64); /* (b) <- h-b, flt ok */ +WriteQ (h + 8, (b - h) & M64); /* (h+8) <- b-h */ +WriteQ (h, ar); /* release interlock */ +R[1] = c; /* store result */ +return +1; /* q can't be empty */ +} + +t_int64 vms_remqtiqr (void) +{ +t_uint64 h = R[16]; +t_uint64 ar, b, c; + +ar = ReadQ (h); /* a <- (h) */ +if (ar & 01) return -1; /* busy, return - 1*/ +if (ar == 0) return 0; /* emtpy, return 0 */ +WriteQ (h, ar | 1); /* acquire interlock */ +c = ReadQ (h + 8); /* c <- (h+8) */ +if (ar == c) { /* single entry? */ + WriteQ (h, ar); /* release interlock */ + return vms_remqhiq (); /* treat as remqhil */ + } +c = (c + h) & M64; /* abs addr of c */ +b = ReadQ (c + 8); /* b <- (c+8) */ +b = (b + c) & M64; /* abs addr of b */ +WriteQ (b, (h - b) & M64); /* (b) <- h-b */ +WriteQ (h + 8, (b - h) & M64); /* (h+8) <- b-h */ +WriteQ (h, ar); /* release interlock */ +R[1] = c; /* store result */ +return +1; /* q can't be empty */ +} + +/* INSQUE + + R[16] = predecessor address + R[17] = entry address + + All writes must be checked before any writes are done. + + Pictorially: + + BEFORE AFTER + + P: S P: E W + P+4/8: (n/a) P+4/8: (n/a) + + E: --- E: S W + E+4/8: --- E+4/8: P W + + S: (n/a) S: (n/a) + S+4/8: P S+4/8: E W + + For longword queues, operands can be misaligned. + Quadword queues must be octaword aligned, and the + address addition cannot overflow 64b. + Note that WriteUna masks data to its proper length. +*/ + +t_int64 vms_insquel (uint32 defer) +{ +t_uint64 p = SEXT_L_Q (R[16]) & M64; +t_uint64 e = SEXT_L_Q (R[17]) & M64; +t_uint64 s; + +if (defer) { /* defer? */ + p = ReadUna (p, L_LONG, cm_racc); /* get address */ + p = SEXT_L_Q (p) & M64; /* make 64b */ + } +s = ReadUna (p, L_LONG, cm_macc); /* s <- (p), wchk */ +s = SEXT_L_Q (s) & M64; /* make 64b */ +ReadUna ((s + 4) & M64, L_LONG, cm_wacc); /* wchk s+4 */ +ReadUna ((e + 4) & M64, L_LONG, cm_wacc); /* wchk e+4 */ +WriteUna (e, s, L_LONG, cm_wacc); /* (e) <- s, last unchecked */ +WriteUna ((e + 4) & M64, p, L_LONG, cm_wacc); /* (e+4) <- p */ +WriteUna ((s + 4) & M64, e, L_LONG, cm_wacc); /* (s+4) <- ent */ +WriteUna (p, e, L_LONG, cm_wacc); /* (p) <- e */ +return (((s & M32) == (p & M32))? +1: 0); /* return status */ +} + +t_int64 vms_insqueq (uint32 defer) +{ +t_uint64 p = R[16]; +t_uint64 e = R[17]; +t_uint64 s; + +if (defer) { /* defer? */ + if (p & 07) ABORT (EXC_RSVO); + p = ReadQ (p); + } +if ((e | p) & 0xF) ABORT (EXC_RSVO); /* p, e octa aligned? */ +s = ReadAccQ (p, cm_macc); /* s <- (p), wchk */ +if (s & 0xF) ABORT (EXC_RSVO); /* s octa aligned? */ +ReadAccQ (s + 8, cm_wacc); /* wchk s+8 */ +ReadAccQ (e + 8, cm_wacc); /* wchk e+8 */ +WriteQ (e, s); /* (e) <- s */ +WriteQ (e + 8, p); /* (e+8) <- p */ +WriteQ (s + 8, e); /* (s+8) <- ent */ +WriteQ (p, e); /* (p) <- e */ +return ((s == p)? +1: 0); /* return status */ +} + +/* REMQUE + + R[16] = entry address + + All writes must be checked before any writes are done. + + Pictorially: + + BEFORE AFTER + + P: E P: S W + P+4/8: (n/a) P+4/8: (n/a) + + E: S W E: S + E+4/8: P W E+4/8: P + + S: (n/a) S: (n/a) + S+4/8: E W S+4/8: P + +*/ + +t_int64 vms_remquel (uint32 defer) +{ +t_uint64 e = SEXT_L_Q (R[16]) & M64; +t_uint64 s, p; + +if (defer) { /* defer? */ + e = ReadUna (e, L_LONG, cm_racc); /* get address */ + e = SEXT_L_Q (e) & M64; /* make 64b */ + } +s = ReadUna (e, L_LONG, cm_racc); /* s <- (e) */ +p = ReadUna ((e + 4) & M64, L_LONG, cm_racc); /* p <- (e+4) */ +s = SEXT_L_Q (s) & M64; +p = SEXT_L_Q (p) & M64; +if (e == p) return -1; /* queue empty? */ +ReadUna ((s + 4) & M64, L_LONG, cm_wacc); /* wchk (s+4) */ +WriteUna (p, s, L_LONG, cm_wacc); /* (p) <- s */ +WriteUna ((s + 4) & M64, p, L_LONG, cm_wacc); /* (s+4) <- p */ +return ((s == p)? 0: +1); +} + +t_int64 vms_remqueq (uint32 defer) +{ +t_uint64 e = R[16]; +t_uint64 s, p; + +if (defer) { /* defer? */ + if (e & 07) ABORT (EXC_RSVO); + e = ReadQ (e); + } +if (e & 0xF) ABORT (EXC_RSVO); /* e octa aligned? */ +s = ReadQ (e); /* s <- (e) */ +p = ReadQ (e + 8); /* p <- (e+8) */ +if ((s | p) & 0xF) ABORT (EXC_RSVO); /* s, p octa aligned? */ +if (e == p) return -1; /* queue empty? */ +ReadAccQ (s + 8, cm_wacc); /* wchk (s+8) */ +WriteQ (p, s); /* (p) <- s */ +WriteQ (s + 8, p); /* (s+8) <- p */ +return ((s == p)? 0: +1); +} + +/* Probe */ + +uint32 vms_probe (uint32 acc) +{ +uint32 pm = ((uint32) R[18]) & 3; + +if (pm <= vms_cm) pm = vms_cm; /* least privileged */ +acc = (acc << pm) | PTE_V; /* access test - no FOR/W */ +if (Test (R[16], acc, NULL)) return 0; /* test start */ +if (Test ((R[16] + R[17]) & M64, acc, NULL)) return 0; /* test end */ +return 1; +} + +/* VMS TIE support instructions */ + +uint32 vms_amovrr (void) +{ +uint32 lnt1 = ((uint32) R[18]) & 3; +uint32 lnt2 = ((uint32) R[21]) & 3; + +if (vax_flag == 0) return 0; /* stop if !vax_flag */ +vax_flag = 0; /* clear vax_flag */ +ReadUna (R[17], lnt_map[lnt1], cm_wacc); /* verify writes */ +ReadUna (R[20], lnt_map[lnt2], cm_wacc); +WriteUna (R[17], R[16], lnt_map[lnt1], cm_wacc); /* do both writes */ +WriteUna (R[20], R[21], lnt_map[lnt2], cm_wacc); /* WriteUna masks data */ +return 1; +} + +uint32 vms_amovrm (void) +{ +t_uint64 va, va1; +uint32 lnt1 = ((uint32) R[18]) & 3; +uint32 lnt2 = ((uint32) R[21]) & 0x3F; +uint32 i, dat; + +if (vax_flag == 0) return 0; /* stop if !vax_flag */ +vax_flag = 0; /* clear vax_flag */ +if (lnt2 && ((R[19] | R[20]) & 3)) ABORT (EXC_RSVO); /* lw aligned? */ +ReadUna (R[17], lnt_map[lnt1], cm_wacc); /* verify first write */ +if (lnt2) { /* if second length */ + va = (R[19] + (lnt2 << 2) - 4) & M64; + va1 = (R[20] + (lnt2 << 2) - 4) & M64; + ReadL (R[19]); /* verify source */ + ReadL (va); + ReadAccL (R[20], cm_wacc); /* verify destination */ + ReadAccL (va1, cm_wacc); + } +WriteUna (R[17], R[16], lnt_map[lnt1], cm_wacc); /* do first write */ +for (i = 0, va = R[19], va1 = R[20]; i < lnt2; i++) { /* move data */ + dat = ReadL (va); + WriteL (va1, dat); + va = (va + 4) & M64; + va1 = (va1 + 4) & M64; + } +return 1; +} + +/* Swap privileged context */ + +void vms_swpctx (void) +{ +t_uint64 val; +uint32 tmp; + +if (R[16] & 0x7F) ABORT (EXC_RSVO); /* must be 128B aligned */ +WritePQ (vms_hwpcb + 0, SP); /* save stack ptrs */ +WritePQ (vms_hwpcb + 8, esp); +WritePQ (vms_hwpcb + 16, ssp); +WritePQ (vms_hwpcb + 24, usp); +WritePQ (vms_hwpcb + 48, (vms_astsr << 4) | vms_asten); /* save AST */ +WritePQ (vms_hwpcb + 64, (pcc_h + pcc_l) & M32); /* save PCC */ +WritePQ (vms_hwpcb + 72, vms_thread); /* save UNIQUE */ +vms_hwpcb = R[16]; /* new PCB */ +SP = ksp = ReadPQ (vms_hwpcb + 0); /* read stack ptrs */ +esp = ReadPQ (vms_hwpcb + 8); +ssp = ReadPQ (vms_hwpcb + 16); +usp = ReadPQ (vms_hwpcb + 24); +val = ReadPQ (vms_hwpcb + 32) << VA_N_OFF; /* read PTBR */ +if (val != vms_ptbr) tlb_ia (TLB_CI | TLB_CD); /* if changed, zap TLB */ +vms_ptbr = val; +tmp = ReadPL (vms_hwpcb + 40) & M16; /* read ASN */ +itlb_set_asn (tmp); +dtlb_set_asn (tmp); +tmp = ReadPL (vms_hwpcb + 48); /* read AST */ +vms_astsr = (tmp >> 4) & AST_MASK; /* separate ASTSR, ASTEN */ +vms_asten = tmp & AST_MASK; +val = ReadPQ (vms_hwpcb + PCBV_FLAGS); /* read flags */ +fpen = ((uint32) val) & 1; /* set FEN */ +vms_datfx = ((uint32) (val >> 63)) & 1; /* set DATFX */ +tmp = ReadL (vms_hwpcb + 64); +pcc_h = (tmp - pcc_l) & M32; +vms_thread = ReadPQ (vms_hwpcb + 72); /* read UNIQUE */ +return; +} + +/* VMS interrupt or exception + + Inputs: + vec = SCB vector + newmode = new mode (usually kernel) + newipl = new IPL + Outputs: + reason = possible processor halt +*/ + +t_stat vms_intexc (uint32 vec, uint32 newmode, uint32 newipl) +{ +t_uint64 pa = (vms_scbb + vec) & ~0xF; /* vector */ +t_uint64 sav_ps = GET_PSV; /* old PS */ +uint32 wacc = ACC_W (newmode); +uint32 exc; + +vms_stkp[vms_cm] = SP; /* save SP */ +SP = vms_stkp[newmode]; /* load new SP */ +sav_ps = sav_ps | ((SP & PSV_M_SPA) << PSV_V_SPA); /* save SP align */ +SP = SP & ~PSV_M_SPA; /* align SP */ +SP = (SP - VMS_L_STKF) & M64; +if (exc = Test (SP, wacc, NULL)) { /* check writes */ + if (newmode == MODE_K) return STOP_KSNV; /* error? stop if kernel */ + ABORT1 (SP, exc + EXC_W); /* else, force fault */ + } +if (exc = Test (SP + VMS_L_STKF - 8, wacc, NULL)) { + if (newmode == MODE_K) return STOP_KSNV; + ABORT1 (SP + VMS_L_STKF - 8, exc + EXC_W); + } +vms_cm = mmu_set_cm (newmode); /* switch mode */ +WriteQ (SP, R[2]); /* save R2-R7 */ +WriteQ (SP + 8, R[3]); +WriteQ (SP + 16, R[4]); +WriteQ (SP + 24, R[5]); +WriteQ (SP + 32, R[6]); +WriteQ (SP + 40, R[7]); +WriteQ (SP + 48, PC); /* save PC */ +WriteQ (SP + 56, sav_ps); /* save PS */ +PC = R[2] = ReadPQ (pa); /* set new PC */ +R[3] = ReadPQ (pa + 8); /* set argument */ +vms_ipl = newipl; /* change IPL */ +vms_ps = vms_ps & ~PSV_M_SW; +return SCPE_OK; +} + +/* Memory management fault */ + +t_stat vms_mm_intexc (uint32 vec, t_uint64 par2) +{ +t_stat r; + +r = vms_intexc (vec, MODE_K, vms_ipl); /* take exception */ +R[4] = p1; /* R[4] = va */ +R[5] = par2; /* R[5] = MME */ +tlb_is (p1, TLB_CI | TLB_CD); /* zap TLB entry */ +return r; +} + +/* Return from exception of interrupt */ + +t_stat vms_rei (void) +{ +t_uint64 t1, t2, t3, t4, t5, t6, t7, t8; +uint32 newmode; + +if (SP & PSV_M_SPA) ABORT (EXC_RSVO); /* check alignment */ +if (vms_cm == MODE_K) { /* in kernel mode? */ + if (Test (SP, cm_racc, NULL)) return STOP_KSNV; /* must be accessible */ + if (Test (SP + VMS_L_STKF - 8, cm_racc, NULL)) return STOP_KSNV; + } +t1 = ReadQ (SP); /* pop stack */ +t2 = ReadQ (SP + 8); +t3 = ReadQ (SP + 16); +t4 = ReadQ (SP + 24); +t5 = ReadQ (SP + 32); +t6 = ReadQ (SP + 40); +t7 = ReadQ (SP + 48); +t8 = ReadQ (SP + 56); +newmode = (((uint32) t8) >> PSV_V_CM) && PSV_M_CM; /* get new mode */ +if ((vms_cm != MODE_K) && /* not kernel? check new PS */ + ((newmode < vms_cm) || (t8 & PSV_MBZ))) ABORT (EXC_RSVO); +SP = (SP + VMS_L_STKF) | ((t8 >> PSV_V_SPA) & PSV_M_SPA); +vms_stkp[vms_cm] = SP; /* save SP */ +SP = vms_stkp[newmode]; /* load new SP */ +R[2] = t1; /* restore R2-R7 */ +R[3] = t2; +R[4] = t3; +R[5] = t4; +R[6] = t5; +R[7] = t6; +PC = t7 & ~3; /* restore PC */ +vms_ps = ((uint32) t8) & PSV_MASK; /* restore PS */ +vms_cm = mmu_set_cm (newmode); /* switch modes */ +vms_ipl = (((uint32) t8) >> PSV_V_IPL) & PSV_M_IPL; /* new IPL */ +vax_flag = 0; /* clear vax, lock flags */ +lock_flag = 0; +return SCPE_OK; +} + +/* Unaligned read virtual - for VMS PALcode only + + Inputs: + va = virtual address + lnt = length code (BWLQ) + acc = access code (includes FOR, FOW) + Output: + returned data, right justified +*/ + +t_uint64 ReadUna (t_uint64 va, uint32 lnt, uint32 acc) +{ +t_uint64 pa, pa1, wl, wh; +uint32 exc, bo, sc; + +if (exc = Test (va, acc, &pa)) /* test, translate */ + ABORT1 (va, exc + EXC_R); +if ((pa & (lnt - 1)) == 0) { /* aligned? */ + if (lnt == L_QUAD) return ReadPQ (pa); /* quad? */ + if (lnt == L_LONG) return ReadPL (pa); /* long? */ + if (lnt == L_WORD) return ReadPW (pa); /* word? */ + return ReadPB (pa); /* byte */ + } +if ((VA_GETOFF (va) + lnt) > VA_PAGSIZE) { /* cross page? */ + if (exc = Test (va + 8, acc, &pa1)) /* test, translate */ + ABORT1 (va + 8, exc + EXC_R); + } +else pa1 = (pa + 8) & PA_MASK; /* not cross page */ +bo = ((uint32) pa) & 7; /* byte in qw */ +sc = bo << 3; /* shift count */ +wl = ReadPQ (pa); /* get low qw */ +if (lnt == L_QUAD) { /* qw unaligned? */ + wh = ReadPQ (pa1); /* get high qw */ + return ((((wl >> sc) & (((t_uint64) M64) >> sc)) | + (wh << (64 - sc))) & M64); /* extract data */ + } +if (lnt == L_LONG) { /* lw unaligned? */ + if (bo <= 4) return ((wl >> sc) & M32); /* all in one qw? */ + wh = ReadPQ (pa1); /* get high qw */ + return ((((wl >> sc) & (M32 >> (sc - 32))) | + (wh << (64 - sc))) & M32); + } +if (bo < 7) return ((wl >> sc) & M16); /* wd, all in one qw? */ +wh = ReadPQ (pa1); /* get hi qw, extract */ +return (((wl >> 56) & 0xFF) | ((wh & 0xFF) << 8)); +} + +/* Unaligned write virtual - for VMS PALcode only + + Inputs: + va = virtual address + val = data to be written, right justified in 64b + lnt = length code (BWLQ) + acc = access code (includes FOW) + Output: + none +*/ + +void WriteUna (t_uint64 va, t_uint64 val, uint32 lnt, uint32 acc) +{ +t_uint64 pa, pa1, wl, wh, mask; +uint32 exc, bo, sc; + +if (exc = Test (va, acc, &pa)) /* test, translate */ + ABORT1 (va, exc + EXC_W); +if ((pa & (lnt - 1)) == 0) { /* aligned? */ + if (lnt == L_QUAD) WritePQ (pa, val); /* quad? */ + else if (lnt == L_LONG) WritePL (pa, (uint32) val); /* long? */ + else if (lnt == L_WORD) WritePW (pa, (uint32) val); /* word? */ + else WritePB (pa, (uint32) val); /* byte */ + return; + } +if ((VA_GETOFF (va) + lnt) > VA_PAGSIZE) { /* cross page? */ + if (exc = Test (va + 8, acc, &pa1)) /* test, translate */ + ABORT1 (va + 8, exc + EXC_W); + } +else pa1 = (pa + 8) & PA_MASK; /* not cross page */ +bo = ((uint32) pa) & 7; /* byte in qw */ +sc = bo << 3; /* shift count */ +wl = ReadPQ (pa); /* get low qw */ +if (lnt == L_QUAD) { /* qw unaligned? */ + val = val & M64; /* mask data */ + mask = ((t_uint64) M64) << sc; /* low qw mask */ + wl = (wl & ~mask) | ((val << sc) & mask); /* insert low */ + wh = ReadPQ (pa1); /* hi qw */ + mask = ((t_uint64) M64) >> (64 - sc); /* hi qw mask */ + wh = (wh & ~mask) | ((val >> (64 - sc)) & mask); + WritePQ (pa, wl); /* write low */ + WritePQ (pa, wh); /* write high */ + } +else if (lnt == L_LONG) { /* lw unaligned? */ + val = val & M32; + mask = ((t_uint64) M32) << sc; /* low qw mask */ + wl = (wl & ~mask) | (val << sc); /* insert low */ + WritePQ (pa, wl); /* write low */ + if (bo >= 4) { /* 2nd qw? */ + wh = ReadPQ (pa1); /* read hi qw */ + mask = ((t_uint64) M32) >> (sc - 32); /* hi qw mask */ + wh = (wh & ~mask) | (val >> (sc - 32)); /* insert high */ + WritePQ (pa1, wh); /* write hi */ + } + } +else { + val = val & M16; /* mask data */ + mask = ((t_uint64) M16) << sc; /* word, low qw mask */ + wl = (wl & ~mask) | ((val & M16) << sc); /* insert low */ + WritePQ (pa, wl); /* write low */ + if (bo >= 7) { /* 2nd qw? */ + wh = ReadPQ (pa1); /* read hi */ + mask = 0xFF; /* hi qw mask */ + wh = (wh & ~mask) | (val >> 8); /* insert high */ + WritePQ (pa1, wh); /* write hi */ + } + } +return; +} + +/* Test the accessibility of an address (VMS and UNIX PALcode only) + + - In VMS, superpage is always 0 + - In Unix, current mode is always kernel + - Hence, superpages are always accessible */ + +uint32 Test (t_uint64 va, uint32 acc, t_uint64 *pa) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); +t_uint64 pte; +uint32 exc; +TLBENT *tlbp; + +if (!dmapen) { /* mapping off? */ + if (pa) *pa = va & PA_MASK; /* pa = va */ + return 0; + } +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) /* invalid virt addr? */ + return EXC_BVA; +if ((mmu_dspage & SPEN_43) && (VPN_GETSP43 (vpn) == 2)) { + if (pa) *pa = va & SP43_MASK; /* 43b superpage? */ + return 0; + } +if ((mmu_dspage & SPEN_32) && (VPN_GETSP32 (vpn) == 0x1FFE)) { + if (pa) *pa = va & SP32_MASK; /* 32b superpage? */ + return 0; + } +if (!(tlbp = dtlb_lookup (vpn))) { /* lookup vpn; miss? */ + if (exc = pal_find_pte (vpn, &pte)) return exc; /* fetch pte; error? */ + tlbp = dtlb_load (vpn, pte); /* load new entry */ + } +if (acc & ~tlbp->pte) return mm_exc (acc & ~tlbp->pte); /* check access */ +if (pa) *pa = PHYS_ADDR (tlbp->pfn, va); /* return phys addr */ +return 0; /* ok */ +} + +/* TLB check - VMS PALcode only */ + +uint32 tlb_check (t_uint64 va) +{ +uint32 va_sext = VA_GETSEXT (va); +uint32 vpn = VA_GETVPN (va); + +if ((va_sext != 0) && (va_sext != VA_M_SEXT)) return 0; +if (itlb_lookup (vpn)) return 1; +if (dtlb_lookup (vpn)) return 1; +return 0; +} + +/* VMS 3-level PTE lookup + + Inputs: + vpn = virtual page number (30b, sext) + *pte = pointer to pte to be returned + Output: + status = 0 for successful fill + EXC_ACV for ACV on intermediate level + EXC_TNV for TNV on intermediate level +*/ + +uint32 pal_find_pte_vms (uint32 vpn, t_uint64 *l3pte) +{ +t_uint64 vptea, l1ptea, l2ptea, l3ptea, l1pte, l2pte; +uint32 vpte_vpn; +TLBENT *vpte_p; + +vptea = vms_vtbr | (((t_uint64) (vpn & VA_M_VPN)) << 3);/* try virtual lookup */ +vpte_vpn = VA_GETVPN (vptea); /* get vpte vpn */ +vpte_p = dtlb_lookup (vpte_vpn); /* get vpte tlb ptr */ +if ((vpte_p->tag == vpte_vpn) && /* TLB hit? */ + ((vpte_p->pte & (PTE_KRE|PTE_V)) == (PTE_KRE|PTE_V))) + l3ptea = vpte_p->pfn | VA_GETOFF (vptea); +else { + l1ptea = vms_ptbr + VPN_GETLVL1 (vpn); + l1pte = ReadPQ (l1ptea); + if ((l1pte & PTE_V) == 0) + return ((l1pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l2ptea = (l1pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l2ptea = l2ptea + VPN_GETLVL2 (vpn); + l2pte = ReadPQ (l2ptea); + if ((l2pte & PTE_V) == 0) + return ((l2pte & PTE_KRE)? EXC_TNV: EXC_ACV); + l3ptea = (l2pte & PFN_MASK) >> (PTE_V_PFN - VA_N_OFF); + l3ptea = l3ptea + VPN_GETLVL3 (vpn); + } +*l3pte = ReadPQ (l3ptea); +return 0; +} + +/* VMS PALcode reset */ + +t_stat pal_proc_reset_vms (DEVICE *dptr) +{ +mmu_ispage = mmu_dspage = 0; +vms_cm = mmu_set_cm (MODE_K); +vms_ipl = IPL_1F; +vms_ps = 0; +vms_datfx = 0; +vms_scbb = 0; +vms_prbr = 0; +vms_scc = 0; +vms_last_pcc = pcc_l; +pcc_enb = 1; +pal_eval_intr = &pal_eval_intr_vms; +pal_proc_intr = &pal_proc_intr_vms; +pal_proc_trap = &pal_proc_trap_vms; +pal_proc_excp = &pal_proc_excp_vms; +pal_proc_inst = &pal_proc_inst_vms; +pal_find_pte = &pal_find_pte_vms; +return SCPE_OK; +} diff --git a/doc/gri_doc.doc b/doc/gri_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..a9832a60d8a87131fa3bfb575f993098e05ee989 GIT binary patch literal 54784 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 Q^S~wXmX^N$B5L6O14C*!?f?J) literal 0 HcmV?d00001 diff --git a/doc/h316_doc.doc b/doc/h316_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..d39be690023696281c624470963b5966139da1c4 GIT binary patch literal 82432 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 literal 0 HcmV?d00001 diff --git a/doc/hp2100_doc.doc b/doc/hp2100_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..987acf0319adb6a4f6ae7fc7066b166db9c6a543 GIT binary patch literal 166400 zcmeFa31H+|UGG~xgD?dY!z#Go{WE}Oq|-?youqqadajkNyO^YtNz&ajz=)Nk(kVJg zg{q{N;o^$#>UF&;;C2_^eb@D==)(*80C%6LS4MF`6!n77tB812RQ7qF@9!-C|G!d| zPWMc+Jm{HU>RFJfu@A>;NwlK%2j3WdvjE>jNK3#)wU-$6c~N4oyo3WX0)|8w~A)qMYkq)>PU zpPm0g|L=Ti=NtE3?b5&S8PbJMm8*YqK7S}Le1`tIRBjypm@og1aXFgF7xITsl~0m5 zKcSq?ay35P{&mh*$k*#L^e2?3cKqJwr2TsCv%q93diTF76xR9dET>x=4)WXCq)-rQ zg#JCYSSY-TdE5TZUwqN_vEMq>*^endE-&=?4pPUBPjhO1s605BEH*ZGH)=c0R&u6Y zJ6|si9qXU1wfct!%jHt3G%+`S|3dZTsioxf+){O7s#IE9uP1BGjg97|#@6{{rMZ2j z)i}StlWaA28Y}grw!OX4sJD}yX0k)d#p>*-q}|+Yt<(=E%Z;sC>&oGzwzZn9Hdl5x z>svduoknx(j#6okQh2>ViL3Qwdv|%G(O$2wCXKD6eEj&ZwdZhhsnyuosc$9ASCWP1 za=o>a%qEMw+gptbrHR;*zLndvc{&r8=IgD^M!QYDNu!;t*IRXpJKw5p?bKHfCu^;G zJ!!5bE9g3d9a$9AQ@3$RJ&Q+IA&7E0F zNU=~ky>x#vH=R^Y-=Ex5Jw16inYwR&VQO(PnOjJzv-306DSoS-o|ri^Sv`F+87CjB zE19XzR+lJrX)aNPzNqRH`KFWEsfCGClw29F&QzD~Kb%Zgmrkq9X$q|*^OXgb=b4$x zLNb45VSa9Lis~mR_H_01^a8a^%}$+OI+9Q=KPFRW`Iao6s?5wJ3v=UB3rku^XXZ~= z?@7j|Xh~&!X37;!Cnjbp)!Dg&M&j^@l)@!e zlo6%c>P5&;qpfAgGHFsk>r$g#7bb7Fnw!lX9x1e4+h8$~E2c`c(#h6#tDS`r7F1l% z+pPv=24Yv+g$T474;rb2KC!eqnn)*~Sb7>mJdwPlncPLd>7(Roaj%ZA7IF70W{-$I6v~ z^3bv4L*vP8eY4rRlFYXl*Oi?f%^7wD99IFu6finCHckN}W5--MBb8)wwvtSM1uZxj z6rH9~{@8djIWa$xdC{YSqppJTplUc;JX>ouYRen-WU_uyysrZJIlm>Y)~kynxdIq7 zpK}rFUGGupXg1GCks*LrZEk{w)qy!*b+7uyeBQDeJVJep#__RA|KQ+IGP%3GQNNrl z)X&2K>aC;-|7)$)=ttlD(!%YAjLFd0(PPPc4dR+C@t4%K)q1N(OONGivpICNjqG3B ze5mc%@sVt8^SfIs>pdzv?kgK|UDJGz43{U8@!hpGSo&(RRNttxkkqSe-7GIdxz*flgF~B}yIYMFTdeJD#p9KU>g_%1 z@C&JID{17&h>&+=7_#o$pQ3EiH#5H&J1{zy%s|gVy2DRk5JpE?E{&BI5=d)h7rvZM ztmK7crrF$HuB}`Ux^JC)k9%r4r+AApinkjaFCTcLS#!Lc_HbmA~YZ}%+JjAD$lRH3x}_v&=7V*QdHGNL?MoNTlWZvy@7F}Hqg4jJZ*Ib3VG@(`lOA`bQ4}CK$I8hh&8@e==V4gL0W*#rN1bsQySHn^FXhlKBT%E_ z3VYghuiABQXxGxEW-@f_*zo?P`$artC^PCg5Q}lTahXv+1?B8g(Sj;k2o(*DjSUX) zhXJ5TTF#^8LAXsEFC{;PBXFmxcu*GiBNx zV>>dypHcn{4eF1o(H!-t$S?0 zMsId0jNTlSknVUS=uwMb*r671V7QE+v0p8Vs%0_MVn{l6e9Y!0U}^an)Ow$W_9$X% z|3UObVi?vlTwJ`ex!goO(_C$D)UKGOS>4*+?I8}0c#<&8+I>dpiA&N_Hzh`)*?~?$ z0Y_g$Og%MkvRcv()_^0W4xzEctAS#%y|R5|y~Jl@^QDN>?dC>3eqXJxwd0qyMl(LQ z>KEfPn(>ABWe1re{Q~80rQbF$`!CeE(otjhu1dnQ6&$`;!SRa~9KWgHl~O5DX9w1| zC8G``{Bw^lUD@8H5&9wfub93q@AKLZK{ltJL+&*VUhkJGxfs&IqZ_odS86qL-?xMN zzb^0pdT9UG!~4HJy8r8u{a=sn|9Whn*9>s)L0Q}0uhXktvWB@>efd7ct_q!cP19<7 zpO*+C`@G%Q-Y@UQ_6~U?wrp-+-lwQdrR~+k&Hbv`+*P@;n(fBgJ|(qxR##c-y{l?p zQC+dL)kf|7k)6vsr4Dt|3_kuh7OA&SLcgFmYmM`0q_VMjGo%be)G7sR3k|+4(xe>q zHs;IuGsU7)Or?1`oo07iN_u(po^vww7)iWBo0JS$pd;C_E~!RQ74wA+5A98c=6m&I z(u|Y7q4Ml~waU(nre@K^y;V;?jSifhP39Jjjhsa--ZY&-*4O%FY^<`6wo9|~3=B#| zMiqAhCL@Pb@e&&Kpz5!bm9UG-z1nEW!soNqRwUS(CC2ICC8^#jfe#6-rjD=f);9XF zz?%Fn!(284+No<4x@EHJwAfbAVol#OE!LDB(_gnue-%q8wM>64%`f?W9i#{;rI{kO zrIeOXBV8k;b1ny+b0?#7?rF)$P$~1iBz@3|Fl{mxQOjy8D|u})7Fj|Gw7jMz1}&G> z;RW-cyrUmtYQmoG^hja3*AU%odkry`>+)>`4Uqz!hDd!&me&-(p7lxf%hiY8=BgY< zj@yxDw=B)>e9-K`ulp>4SJ}dp=LUh*98|Uvik0bAUb~_-|95ppdk*Mj95 z9YkSRGlgMY3PaZdQY}HR-K3hHuqr*Fvsa|fDhEnanl$WjqJP&a>b<1?l5aFpw?uD0 zqRj4Qknpw6_B5gyM03ktLYkIHt=vxf-aofZj1#$i^+FnQB6J@x=Tw-}RFxJon96PF zpQ_wo@P*QRb=nX!t3!kLL5H?1rbDkuhjuQClvS<6otEo3s^CKM0vRomXQ;iqEpq0B z?$q1S#K4Bd2wO57a;Ls2o;D=bfR%jO`B^HCaLPQ=zld*&QpYQc)rr#N++u&VS}hrw zmzAKZKW7EwE~_YgsZ`xcYOBtt;_TgNbKQE}*uc$&>q_1`uM!*`K0b=R!PGX}Xm6OR zF(}pV#4A(};&R~OaN`!HZS3nCZMjTj`%YQ+CMFj%jFJ_@d2J)XNcQqw((E+1g)OPG zr-FxXb6cZ^k!EFAJ{j@p+7?+5uf6#mr`4|ahiP0Fm*(bQT0OnEB$r;hzEfJL%L*v- z2E0C(S5{LeFSyaMtdmn`L(bVIUc4Q653U5*+I^VmJqv4vGTVtfeRLMaMmtw`A+P5H zhl{B++}O_BB*dvn3O6ba zk9p~-oDz*Nw)IuU-TEEeX}p&AD_NwS8pfw3viZNHmB2!ir<+Ci8Tb~@Q?ELpSvOCG ze46zn*HFV?w8Y@&JW@KaxnELP(%g2=HRrs9K&&?%xCd_YakbG5mSlP zGF@w9YQz17XE2v{ysErSoUU~<%AGe$b?kM!R78#=$yuh4#Z}D=$Ra3SbOIjTFhOs? zWXVh-@+0%H_A8lzm^DYrz}ZG?2N}!zRR$0Pa~V6l{1G|Rfd~2UOEp1FY~7+9^)0zV zAa&~^d!Ua+0<4&S#QZ-Q!PeI3hAkeOtLjO58Rsg~lH_Eoxx1~|(mdp6Cp(mjHcpEx z4SX++HD)4PhQ`V|WbqDKbv9C9C8Wa9W7-Ykx10nQ@wW^H91!elOTd6*mNRCzZasJ^npfMb0*PrCA8`6xayKE}qzOaw0vj>t>Khkk+n z;IRa$wZbW}i9>-#Ld#S%Kk#L((b}|-gRlrLHJra2j=o*nSyA|eh@W+>zqWy7WV6A7 z+XdtFs$srN%~qr$OsFHc8j$|rgG?tr9SN;Sn2OEya@%Mv%elR~vYr_(Tx=;Bw+61% zL}R+ra^nVWp*!!X$fVq9B4Vm1HNs%s@Np#;RMCa|c%~M~r3fiBUI@21wUoS~fBKcC zW!>e5?`~pHJdLu!-^9X(zqh>&ZCGnCl*|Tsl~wdi)DM(2BB&p-FGk!8r%YyFjJg+2 zf6TlX9JCi+V~j6s+063F@O3t$8s?Ksg(OowlbA3gfnvH_66v4)sz?vXY(Fy}bkM%G zyyA#6t}(aAnk|oNwmeh4^Gv0A#8GfNpH_51vFIp<=fw$>mxUIKcS$F!i!LoFZMf?d z{f@+r*o)@pR$eUZ^qfnv)l7P(F;Weo=~aTgr+{859IFt==v9JCK@mOEIDR3v(W?xX zLe1!v#&IMure0;Z6qM034K@TOwv#nwiCSi8U1AlN=VV=zJBHSaqlLwFn(!JiJ__x@ z`$EdV0zD7x)#aFs65Vt6l<-S+JhCFkEs-ATweA_fEXzW<2hU_28MdC|!LAZ3g5ieq*(OxC-A|^u5Q&D^SuNN^DuJi7x^dhDjaig%eEWL=S%wE^MN?G!pJR&|~ z(l4?U^SMxqT_+7*0>{*2v71+I*u9X??^>|M<@6TPcil} zYk#Ng?{uj&Te~b&C~CGC8x6Ik^9+`MK9yNv<6k`Ko40X6^n)#Bc8#)#d3}_m`zAT5`l9$=E@slxki}&f~1ylB_}q zDF#)Ht1hI?^VZcnlSW4Yre0dKsUl-@nY_4<#yRKEQmE$a3UDUs6N9435+;S*lHSDk z!cSoJ=B`u_sScM3Xl>Iv1WI3;NgKqAxe`+gwv`pF*9^V=0L66WI>r2|1^Z$dXUm?p zYoGi}1gtt`!Q?-u{Hu3yO=c9kkxt{4@XMAsny%Rq#P&)vOHpcN8MbS7V61< zz^Gbqr%(4#_^7WvjW>U%%{Ti5PHg6+qpUZw9BH;#)PYR(PvU{OMNmV7*1KxK@G`QdRG^ z7q|vMONhI~Y`5x1BK6kz5mFF*^c;#B64s9SfnRZVm7!aHTp>oeag&up(-Dmt8Iz{b z*A`m2uQX>a^V*}WByao`UvD+BA*0Ffwek_0rA}!bLKDGbqV>&!xf3SY$qWGjygNdiFyl=*r4E zWlYk7uxiql`rQGUg$ZtKU=??39gBu5Ks1O}VNq;}>ZnOWszn&{s`YV-~X$X75SYn-(aWYb$1`?lAwv}JhHlS9f+pFK>nzy#C7^!Cj{HQ~gGlp6-$cjkfNU|seElSZiJYkj*`4GO| z;Zf5F*xW~P1%l>L!cUG3d+?@+;t-9RlHm*Zfs8+9WTj*o?r>pS&H^(m_SYFF`wdA5 zLgc(!w3Pr8TiNbiia?<;ei`Ooi`}Jb(8!8k)_w)sXOovy}ZR&O1Y1MEWvNsJb z3}M`0q-?P}p_S%1DgXnL+yQYmkBo>0EDO}Zvg_-1t1dgIslA%E`ekaqHCu>QT6Ap6 zeMzDgdTZYx}m?|NI@v;PCL^XwvsW z{ENfGDQhxvKwGfo$sgBP{8wKN?2 z(|CH}v>)M!jZPRnVtq>FZN6dNV&7~4kQuMut7_$*q+GrudEw$XD%8=VhpVxF78WZH zuLKg|3WBIfd#Rs;S!lCY6**aLjjdrTMNWz=JIsRf*HL9HZR|$Eev7T-e=?i~Eu_2u33Chs-2khQ$r#aoR7a@55JJ68Qv`mA25E z+ppHZ(swP!+ek4ntScy?pCME6W0w3G1<^Y?__ItlMUq( zB^+j?2z5BAV!*SYOc|1oU7{kaS;SLBs8pOw ze`ou8YmH+Q{2Mk%r|;77c2Y^2=B1NU(^JH|`ohzMh_0Zkt7W39h*(Q9T4et|Xt!{{vMGXqBI&7baG;Fi$jMU!lImckWLmVC+%Sq# zkA!$^h|E=fc26pJ2(j8yNOB2hEAuZNyo0TL4}_Mm`HVuo!{rAuGG2T! zJaotC@BQodm&ZoVb@kq3a>( zND;vbRxU!Yp?D;}MzxLjWxJc(hr`fpN`;gRgT25D8<5d95j5j-oKeuBB8gZFQC(<6ef!#Uc9S3a!2{--Cmq>0=pNp5H^;Z%^it&8vCN+ zxyM~JcE1IhB6KT0r;kA3<3smwn87UgI7lpdQGvN^MAx=G)+?JRElI^EDXTOKDIJ(f ztR(k-GQ3w2esf$V`?z~unijXG^O;JTTN@m&L1%`+AUflX53V~qR|tv~Z=ofzGnTmo zf~#Y+69e~Mh^eD@+rZTz^;U-;3O~gfU8idK-xX`BkYfK{a%w0h-v($8Bb64jc-P1s z!*`n)WMQ8cEu>Cq#EC*CSU4{MM3q&n?#jDrFNFMz&Jw?+e%XNCh~tQu zF|w*|nu=$m#y_(RbYf{n7zcxOUG#ktWpospD7YEPRV2y0OX;Vh-_zq3>a$N8zgvOg zj2IKFWFgFvtP*u-F9=pj3lCi)q|m*M=AgZ4JX4w#May)ketElQyGq#hJIn6UG^4fL zBJ_-wk0RGB2z(@VKxoKr7f3~BPkj5^%R z6tg%rQ_ht$)}=X0lrLy37F41GG6-tJ1QIH0FSy+@EjcS@lHSEqYhC!siO!>B(5(X- zPBRZDeQ{83m-WM2jgvk<47W1_=SIWOr`2j*8LRR0Yf73oxaGN=+Ogim=F?nT>#U8b z)>%ZcvS6)9#UWw9xv_2?7hCVy@rDMos31cWgF;x za&4sx=|xht2WDI8aeDMC>a?68_Ue%AeMEMJ!|1d3FG&$ZWZ}pmjSF_Bt%2sM#NVBIKW=rL2niX3;JQ-(t9joT{ALWO`isSqZKn_jX?L;gm$JJu{5;8m8C-JV(>bSMl~ zV^F!hf!s!37k#$9ffdkfxjRkcp1Z8RT$xze= zv@C2VL8M=~!104JWOx2%b?S%$BN?d&Ek?Ag`t29J+N1&~7IU>a6`V@>E;vuAUN4@S zJD1!=S$A`&*jWxs^EjeKA)B~MpdB>!x>R)4o+uAuQ+3N%{h*{=domReLY^uA#9f%4 zB=XyiptKfJ#Y#>L5AI(%?~U?p)i33%jdmw*iMRa+=xqILGO!&9433l;*H*Z(jtCMN z$~B$|cdhKEQ8>%loz`WuRpr_uT+68g{jI2AsP><=HkliOx~l}Fu|VQGW3%%NGHyK zA7#cQDnKeSbB<*?646?z3Qag)Vd1(p=2a=NBUfLXWJ7-;w=Dl2`(1GVWU&~sxt?Xy zxV-`-3EpR)#1!x_5QeiHY+{lXTpSAKUU{P~)GBs4v`lnZE_0vIuMVN9ZwyR5bOPCc zVfQ9fUnxj6X%k~s4n>@)MAC$9$3fASY6*fgz%3A5+o>U?ECq{H3){6Z5BP0V)a1#O z%R@?x#cjAoL#_w#LsLJXVy}b7MpB0@ndYY=x3V%hQ;?xqADZ3 zEqg})szRe_z287e>*vkR;iX=ugU8+lLsZ@yl|jn+xpPwsbJHl%7Iwpq?2VE+o(`A+|ou|f?VfJ`pp)*WE6L1IFXqg?J7%A;9{dj&y(AzmDs!bZPAw< zN@F7BT1XwaB4{{>Wr~jz!5H4nd79IliYb{yQ;2Tlo2MSB>};>*PWMQ z%%gCipz*Fu)LyXa!2qRPC@xS&eTS}!jl-U&vvfVKa^5Ma{5ghs7L~eng#P9?w~~k= zB+Sqjm&&(-B-do4+$h#DAq!qGFA!1+d+W4uRhG1iHQQiJ!LGp&1>>b@9PsvTi&!t& znkw05S=;)$fF(>k>05(~{;GGP{7&Qi&ayEcXV4yz^?zZo6wwr$ehyHNAgO~srd zd@%9tbeuNoaQZeb1&zwMb(F4IV55r>A*^!OHuA6SZkW9^JIV|VUUk$bg%g`#qi&0I zXEt8b7A91tOTq}{X!43?2n@9`G_#4uF0>>}LD-tVcdbP;rAU|POU$BC?`5?dKO=MF zv0~Aj3hBy%ROy@-je0a}x(OQSQ~@(~O+STNOi}eiUCaI)b-tyA84gUgx-)BBD6awA z+Er)}V^6#!gXFy%ZVvd~-(2e#{SY>~kT|uJ^-gDo(Ewe1CL`X+AvBvNcA-(Vo1(X(Iv#76X)V$npxovT27;RQ@ zo+vO@(wPqUDIqAzFlduy1AYxzVIy%`ikExU8d=^WIn}n48r!KtI(b)T;kp=iTTMdY zN15OGJ>5p59|6m=7Bk~ZAV>xUT}M9Ms7ddo@57lyEpEix|KzWi10($-J6+lE1UXzM zMsh4pdNy74zZ3sESh0``NnE#2S zXC{iy?YmMlm1m0}6v%hiAJqiJM`KC-UN`79xw zj4xJpL+BeODBhFO_Ee0@;G!+0Qt_UQTo;$`HiC;#*QgJYH5}k7r8$CvFu9Z|?|^dR zd|Gy=0P09iju)k}6Y`OJ-$l0U;4dM-&!zt)NM{G-HrIc|zA+jdu9#dx^wjQ5j-C$t z1H6?D!e&!yrd`(U(CE?2Myu_4=yEc#umqEGCkdJ!Au*Vj7N8&ljaidz->24>h=HBF zC;J}eDOrlE+FodTH<5wmt?ZY7hkIM5=R|3}-kmJtO25!=)TD!B#ri4iOoxS;eM?rn z>hnf>SP2abnXo|nV^h`IrTPZPZ<{`3!EpV-NCFcjCYo??E&s~WQf1;4t@dY=D@0^hrt6gkTNFd!ZZO&7kEdayBO}8jPE{tcv}Nhx55vZ8`c=r&qm`0!Mna{ zKN-G%9$Pg2HpD(CiG{jC{4QF490_HYG-LMA^oA*497ZNP!YoVStq0g*{cSohbcfQQ zVLlgu#BQ|J8kEpYc_uJgDrRw~fy*J=2yd1N-Qc>ftsOI*v4JO@#eha8w~(bqxWE!e z7P2nW7KKEx&^rx+`O`9??k%cFyX<@^N?ld=;of@EoNf#Lbe zE3&3B`tBrQ!-h1io!CfZX>9D$)WU3)b9DFQi7PELk?6nK9n+a&tw+J&=T?ailW`UU z>92H4B*uD1#|9O+7>7hBNhW>aXjVkWa5gJqBg;~mEoa4iGT?FA5>LmBN(JOK_m>BYrCtQ zg{CbxhSOZlKqrpVYfgyW6?K8C>FO~)A#94NZt1EGWigA5#ViGDei#gD3+n~l`dAVG3w_zg;p->cwm*3oi6LZI@&Vuo$z}cYs(cgPCi|X3aF$X(hH1#|Av(We%+rn2BgC zXW`L6(b)`6PgfR$c%r0=pxd;)$}VaCpamDCo2ThM@@I zROF1Xg}xAjL_`lW%!vUsUWi?lK~NwXmQD^2N%aOiPML>)lT0#KqLhW zneCbDH4CtSEU!wLQj{8dFTn-BeY&xAvAJRKomwwB3T8OaXi=h~pWVSFEXqvVA#--I zkU#Fz3uAt_hUliMWxCmR=gFqCH>xTZ*w)!rGvw>Fw^`{?DuHxU3X|lb(+s(w4m3az zCrSuZv(1G;V$fDPrqFqy*|o$PoRwb_Leja9M19_zuhU1!Zt57~ zep4KMU)3g(!mw?JTE*6;4iN-BY8RXKaQ?hW%<775M~<>I)reqFl$6|w%KRcHj52Xr zU5^A+w0I7W?V7O)@Ii^T9$S$vjk4hrMWY6 zEc~Pe&UP*G;J5Q}s?bc+?S-T9)=)nt>be;lgI7mBK`;R0v2~Xa#jtWAKC*+FF6?Bi z=&rL8XXZ|xxJ!m6S=$knHkvqX1M%*xF4q@wG6+5`1jHw%0Bzr67iVVw9v3Mx1+EK5 zZ{$v8sQthPnhH|o$c&<5EK_D;+YszJwy^nOPHKFjW}OWqMDSRG_AKyi=ZgEl%-PfKHC8Wg8K}%!Pf2g3zifG zRiwPcwk@YI6Mj6@O=$wD?gL3uEm799p|%djpZui7wP2KrrHyEk4xkTJRs}Mba9U_q z6uLeOO4W^$%p;DHId+=#nY?6iHw+Tv$$po)G_7Cxxx@<8A+7R|Sc~rr3r{6mFDyr>N&<*uN|9*sagD>PiKm=9er*&ij#{AA$>k!2pdOgSJB0Z>4}gqQe0+U z=Zgj`bqT96U8vqH@YQ^)<>USg9Nhup?As{EEIG-348zPl+E=N8 zN)aT*1C2e)AQ%+$$vhqfr*r;gb_>nkH_`RHxNz^D>IuzYBe<0am$H@#%b6@?W-{osiO-i#TcYJAC;Fz zzDcCbr9Yf-)yk)fN7gx-JnzZ%n#t0c8w?8v;9`eSr$VTk#9Y5A&xN}oLQ8+NEgjNR zg>J!7<_>hX6j`H?GY3+*w*aa9OtE<8QD9Xp3llWOHcE_~-IT0jA8fV|IN1z{6|N~o zU&Opa0`<+##I(5xxO(D3*I1uBJIJy+Fh2A#4QlJ2R?&lL>Z_^HS~4~eLANsbC)9Nn zt=iV|p4=tFI6?|^ZL2$Fz4KBYhk_ZsNd8lFanEhlC~t&>0^#3d^ipe5YC#ftnD?$o zvqq7$4c|{wI0F%+z!OQG>FAApIaMIw5BG{=9fK5--W$`H^DN$_Lp$k$*wU10cBX3e z2qCt*mHpAFhQg%-TFyqw{TyU7lr7^xb~77&6NaR-3E#b39Y!*HcAuqlTL4o6opy!g zrxxE>9c4cSMYRW|!D9`$BE7({j}_?cn@Z^ATPCrWDpHzEjgZ-MVEkbdU`yc9&N?9R z*9-y@{heqTlxW9UG`x`t=PZ3L;w9`M+DGZ|B+k=!Fcw-QyQ1N1{!p)wMhc5N&V%}) zH9=T06@35jHVH8~xf--y(wP=|krU3rY1d^1lMzTvnjvk)weBLq$T;CBTc7lve(f1Y zB)>r+aubN9v|x+{>Q4ZSQ{`k+B&j_~Z26kxx?ez?9}X846T~)!#HBTuYNowlCbSjj zGyYJxLH~m?&~=bQpA^eL46##EM^TK2v^Ut`;tE{Irm|3QXun2Pk&(I|)g{ZhNxL{m zp*UfF9Jz5ZW(SO5OH0pMjSx|1haT-V6LF*I#R;o54FxckCJ&wQ{>tynZgI4V;e)P_bZ)~ z2e3?$ZA;c%4j8*sLmWV%5wFOUMx}TmT|k6Nv;cLu+c`TZQO5u{d!lbvw9vZByzN5X zif-J7dJt2j$`kovxX`}S1)pc_7&&qv=~<2$+F}>0(>}E}56Xef_1yCK!n@ejL2ULmNcm!gLbX&2FkLEmt0;(|hswTj2NFIU z|5oaW%1m{9p|Ui^*2lcggh#WnEH5!awsY)S&a9NK9}w`uL7S%Z2Yn_SU4lgj_1li2 zMr^um{K$972M(gkeI@?@`*YdB8)}n}NUD)-L-f{_ji#=#iMYt0nwYzi@~H>26yOGl z+*7iQN@jCXq%$Z=P{q2-S!TsyUOB60954>RcZboRNZ6Il8D9`F`7}+Mu5GN?UDm6% zy*GC_2`kOpnemQY=snQcX{;m5NHobe!K{C)FSCsuip>%tYZAl3{AmtkdN#nx+ov#y z5Za*WMf{qhMJ|wp!B-v&TmV6YtwczG5YEEkPHaR-EAyQIOZVNjhDmHjTg2^zOI&Ug z_C_Bcnn;fIPaqQN=Ae&pHoYT%@gyM*0x^?4Nfq1X{!W$Sc^+_l2G zsd$f>EVNo*-uFsNwWK!r^qIWIzz^o*rLzo~-wterV1jgZ1Ro!REau8YRpz_K?Ob z2`?0OZ>kT?kBl`zY?U0&G4Q&!QxB@&G+1APC}KQYTp<*klxa<(Q1hrjKZFvl-v@|h zq^Y5CF_cl~vR^%xQFlrwlg?!|;oa;;#rF+w^hS6K!DAeKl%s|e5{GGl>qTT1^WJSg z@m`=z4WR^Q5LjqE&Egdq%?YbfljqPxAs?`3_6OfIwLHX0UL{b{U7Veblgw6_tq7|c z4(d-r{A9L4lAvyU7^NeEZi52yrHcT|%$lin?yM3mPxi28=!Yi7-Soobr#@m0rFXrP zCxmh!3Ur!8HF?@WJ-5JC+!Gt+SKPVbLjxooc!DuL`CBsfW#XXF*n2}oXUj-g5IG3bb=(eZ0pSH2o3=LE< zNnODTv_RDD7EJBaPRDR+rQI7%or+%+EEOBxsC`K?hZ`z6#>~hqW-hqPk`$QnXH59D z`3}6sVc0IEL&N5x(FoACKx}d8@kP@}5ZkzNB^=Fyasnskj25S*^YLIQZWZq>C2?g0)X}4zfoJ-7*uvsm^&f_jo648nj%@Z{lAJzlc`?L+x&Z4Df zE5c~zr&p}DUnOb0^|b_R`^=9hTszxj@3>(>Jql6VzHuFK+X~w@R1qENtk0SFVy~_e zxJ|mG8a&q~BAF(e?GOVWf+K=@V%xR|ZIa-sP3LfE4te&G^!%12I&r*Mlptdbf4GUPJ zXiNT0$Qps*<-@b|g1|ujd3D9wuDC!B^RZLHjv2i;ZfahP2*_BmP#2mO0<2SEYHYx9 zx(HWCY9pbBit%t;SImNS#i<7F}W1XADiTc6Mb%s1tB@Yi0(^4Bdn?vgUE zP-W+iT_Kw~l2FHKYO{w~b<-S`{z-VkLM)-uKY?*ZfzMd!$j9akPj%4!ywGi4S?R3S zkd&3j4I=$qDGN>Nub$;d0VULz(SftGnW~b>?5X8O+ql0{Jr`_Z*M2?6mHRPIJG(PsN}K*p^D6N(#yl?L0F?7d>K!(&6` zqm^XQjvM7_U77GmwCqnJRo|6N{jVh9M)e7As+s2;)QzO??8Lkdn{Yh4tx)AKXMSfH z^?EF-^em;v8az5UJ}{vJEA|?~)FLxBh6z>Y?U*_5PS*KW z#OtBxa$}WKRWY~Xt9B+z!+qUx32M5bSBZ2ZEzkM3ag&GfwQ%){-C<_8W4cn^iIPN{ zZ|!h$twv*hVM>yx_hmB5{=7{%F}H!vOehq<+MltiT(ZmAjOQlbDNarp&gJj2#?pT? z20+2ocKEuED7HoIas{oOl@qt@9Zrtv>FD#L#BMoBxhvC#Up8oly~xrHpKcMQBp&nTXU*3F=(hfB{ia&cFIm(xWGbW*D}O!mvho_eQ*uV97IfUK!TgNu#QovU`K zfm>7ub-NBY4csHMSc41obvX+OY`*bf#}4wt!xS z6XOdfU9g<&pJtM`nYQhMltZZCv9uLOR!j*Z8Ctw`=H9QY*m51Q>6{F%$J%8T zwy3-AtE2H+aNRE9q_vpO?w%5}X=!IeX7##ay}d+Obi!t|1NHD4Mv`r zQ=$h69G=I0iJ*Y?P&Kz8aB0|hmUdi2^te~p+8!Zv$2!$>hn=H%rlox9g^uqLZQ>z( zfwH&l99`(Px4SX=70?MAQ4FkS1eqn!P8kU?3GbgqfyBoNfgE+OhqccQZRH>E_J5iOHlMCKH#4OJR8^m7O$-)f^W%9uD0@pjQ?(2dQ+IWcPJ=7TjcC$9t=Xs_ zvg@Vl+N&w(nij{m&YUP5^`uLu z-q|2TN~IN^OTRF2cIp0k?;ciqA1kZ#V8N73$=V}Cv}RgzWFd|m=MqoP%$+0gOq$xR z9`gv9OUkBXQfm7V4r)o`{E)JzK38r{_M@(VBMQ$BCue&Zqg!UTYrG>f0srS|k;l0}trwcl2?XW?lEg>>W zvU`UIpHmdJU453MDQ8nR;Y#Glcg7KasmR<2;4ZESLA`{UFI2Bd3b1JIaCl-VdiHIn;rWRt1 zB`y8K{^gIA&~g#-@3QptM&GRf%6AiH?jByc05&TrBtX+t;dbUiHe)C#6zmu=%M66W z{A7le7!Rj~&(#B$_J-ML9ixou91Qg~?TPRfoU*tx1_qxPwbMeS4D`e&C#mv6s0f~9 zsO|hZPf4#K<|?BnGR!)h&)IAInlZha6{(6;lMeL?f?gFns4;_XW@f=7hN zBYLJ>H+W%nT1{6ug07C;gyHaptWcsqiO$Cpfzp|P7@@!>IAV+<9#p4c@-IA+ezJnc zXvlR2k7aXy#s-gN2O-SpCoy;|x??h=IWxc496L5==x*ySuXTmKnn}vSLKumwZ8dOv zt!(@Ue)+xW_b&lFejDgQ`M$u}pWelUaNA zoFJu;EXBDv(IIn)Wy&}mn@P!$*ux__g3%eKancMA4vr4>U;Pk92_zWQ{Z=GnPuPJF z4~P1P;oLhbM_@7XG}ysw(M6CYwy9DK9mF9LlxH%+4fA4wGi{~=5RBZS%GomE32+~~ zJt5^?`A|+Ob9QFLn6wGr6QlAn>Yyi)j=AaR2D7hI!c;u%GB9H?d6&RVPPSDrUxki_ zIAFfkxC>=lwijyH!z<2n2x$-Y!8(tU1;CyglTv`gPW3l+i2Szy`P#4l2U|apt zx-)h3IIv4o&~d_)$?;wWw9BNg>6|W%#x(rk$8_bx+Jb>rj;c%)K2k?GlGF)#W~zZT z%b0|S9DG2A3vfzWRD#)5F@3(&!sPOyp$Dev#A5< zyJaX7s^M+1u_d7bXNm17+*xAx7T%fI3Z6J6o2n}~wRT7K72V1Eu5<05oI6b}R|Rp+ z;rx7^@|iY9<&RHJYh*%7J1bKfElvUv%TTD2`fXX3)Nb<$rOKE%v_XKute8ZL}2 zW_+c{C$Mpfl0%mC-(Xjsv>%Bw8NO#*?8inbuvA(Ez1EqYB%5h$T}b+>^D|ZM%blN@ zb5?HKjh7~3d@iUkRQVbg=%V-92|X2CFWj`PBMT^1$H#k>$4o4(X1h&H&Mq+yWElii0XfGji`5CL%=-VOM(h67ZAG#ux}diDGI~jzlZCzOj#S?c zGh;h{KpYI$FlaMl6a!;qNWpS#;gAGn=n!k%^!?6qK?mLZ^0XI9GxB2++8~PaY znh@&+B@l;U^l6D*!gqzufp}kcmaUwdj(_E+G={99*LowIeKkPLO zHcM~gvT8{az2Oc$I&;ym8nyyy&{=$oKJv6xRbNx+i#x_RCe(C${UBFUxP>}obI9$c z*iOjPh}5WNBGna4xXIZ(bl8ZRp7(B$YYwj1wc$+IH5e|~lIn}@pYb;esX8|>X-i@k z!(!!lWTw-(31bNs&Nb!C64o|}sZ1Mly-B=_4R+kiqO-Bx7TNd{_AqaMwv(%wBDTcn z_A{eEQt#4He{NY9QTyv1o;zf(xRx4aNo0)^u`A;D<{qGsz>eo(_KD9qgLY}RIoh6g?S za27iuaXS7oMvL_+Aq7C!cC=YLoe#woxr&HdQXBc68FW!H*dQ)@PKk8(Kf~!-?a1=- zk(HGrtE+eDtuxj^wqmA;pKgCMLg*L7To)^#uEDhVumz(o@-Ua`0!DYbU52W?%(S0wdWJesvFki_ zb_Aa3aXa^QhD6LI4R!>3Zk~~2_?3-o3zN~Kc08@&!6wHnww(1Eme6sFs#B?qb9Klj z(G%dClD@Xoe)xO{Uq-zTgO=BB&Cp^)aSf&;OOMS`$FEag#&*=v;LKcJlW``^7bK$2 zg3TRdws{>UCV#uITtniBxO(ex)*=c01r3hzSc65xJaxAIFlB}bn!C)fIjctQM*G-h zhYqenYXbHjU0nf+1?TmJz()7lE_@V;VykJoc`eMQAioY+qornIV(1v^(M28PP5Qv} zoejb}d7NZ`u%i5oM1G#&%3@ovAW=E8PF zFe{u&xL-EZj!$P(ittqm$JI#^lX;+H3wsz)dRt3w*b#)M=4KRdNFY}@oZ1-$a#v|~ z-m+$t({KwD@ct(?ak?X+O#=ie4UblIyy->!jq=`CrJva;<LWM?~tiqMrc5Rt!h! zb?8pMNZ;U0U7~0*Cc&c>Zn<11qfyv34J$!kc3Pe@2&>$*0Y--1kuZ>=%%%&%nA|bh ztZDgk19i{!(dwn55XBxE!0irF;*hA}ZaND056ETynld>hj36K^@&Y>u(1+7{rVO?~0 zk2^F@#^nHZ$G}vBeIbewLP4)C#PMWigq>>l)t7*iR3vSPyMftmwvqbk>jYM>vXhCB zTG*a~Ez$U;9#go@u+HVN&dHv7zAnZ~?(W-H6uBDaH1sn>!8}Hsuv18?A5?aaFJfS>1RA&7gDC5|1%!V$b z4T-CCz!w4f=%S0zCd_BZ!w|U0$vjPlP`T)p;EHqhL69g2fr#fjux|N6oTAR**2Pprp-QV3I>%adr?_T?p}D$hPc8 zGo9J!PVdr&Vhj~JoL3Um1%>O1Q(4k;3)Q8mV5{4k-fMTdi!aKA)(lzq1MPBA?^;AA z&n2)^okkEvDw|+yrp8Y*6WzxQLWL_BoMp)+@%hI@q`KZ^z!F|A}p8%iIPMzya2LV${xkt}#ov?^dHgW3)(`1tnyQa?32G8tHEm17% z=WRL-@iwESh^#OcMOFk(hUC~>(W%ZR&)_xM*?cvSuj=@Wp@vQS3OlX{1A#u9vxp7C` zGjObD{i^2M^tZI8?kbPmQ9gQi@k9|*F5ialC=b~;{MmPv%Xf_GOO88u+1~Bex@+W) z;k%RKiG(d+PH1KE-8FPaSw9xBVi)fkH zNR{7BSn2#dw#7$}@IFM2z!9|a&YLOU9gKSJtlg_iB1a=_aKQ~OlC%USZ*($jNjKN) zc<*&ln(m}qWY=O5ANlfb8y}?+mggQ$UXb8zkTca?aHyZPjnXbw;Dig<0T+GY*pnpU zZ%uG}EHyGI%e$t5PP6S9>yB4(xToeOXgzf*?3w1ST*0CwBQ#rMbtIm4X6nE?B@v5Y z6Fby17+wOeDK4zxMXYz+WU!xuM_jm!l4>t-c`}A*JbGqcTeD@Vgf?T3Bt*gYwN7vvNSE!~~28E4Pj; zEGGKFSeq?QLgAl@eO?=@am;7_(g_n|#qte_9L2_qZ5Q0(btk#U6@}=76&AovV&o(# zTaxRk{K0ywNm8_D8LM37-7l4Zb&V2kfy9(mQcy^376yOql4_JK?>)F|siX&$Ehkga?3$!9)p1a%%r*T} zN-7hIdOC7VqM4BN>N45AU1c)E`D>NQmXL~Wm~7>wsdD*|$x{-dBu@=?m5;P8KPw+u z1gay$!ToU~FBz|8l=0P!b)DO*)L^>Si>;_ zR}pK_bxuu9D$J6kk}&<%U8*u8)sW0dKT5Wb^h3JONd%NJ_hwl& z08gluvS#g2r%eVKSXHUlCt9h&y+o^pC|U*CIB1qRv#JZXbSziKH==id2lGxAN$skI8%LjWH?i>eM=LM zRGd7}i5F3PGL4_0;9#SbqvnDc-1X35Tl5NQ@Drk!_;RCw%y7&v%q>k#aAl5N?3Qk$ zl4&XRB6ZeicB*)&hPOm@DSc^yLvB>X38&`UqO(SawmSVk#&IfW4&SNRqf`MiES2RV z=jyj$K{k|irgFuS8-k|^K@{^5FtvO-o3pL&GzY86pPk^eU#U!Mbye%e6T2F=M~y(2 zrkd^79T)9W`$}9{T9NgQ#`%VhSChrr4;_{RSu49t6Y7qvgwdbdeV)#o&dih~T(@uo z>GBw2jqYmmT$nT~p^Lln5y|HMNsV`=chO=ad(aQXJA`n1F4-Bgfo4>;65WSHNu2dC zW^MtR%>U+DOi5HU3Z@oH8;s^klVd{_IpFce>%bzH8uOer*IRgV76pj=CsII;yOs`a z=JPhiPGe)VDRwo{U7y51aZdIrY6>(%<`Jk}ylT~%cCb60@!MRu_83E9W4oWjt+sO^ zMLq2+R|_b56zwl!xxztdo6!za!fBgj)P@eSz&H-*)B_L-W2v*(oA<0$XZ;avld;$s z3TMqS(fOwB8!fiK3=a;EO?DAOu+5uOaY`2>CHM+P2KY0|pP@nhkx(Hwu@fs?Db|UM z{1C~wvU9Z)9!o;#RZP-1BzK~|3=JlIBkl|1U?ul)`l&e^QxzP~unU;fr@RGlcr0JU z$m7S??Vh%j#P*GpvaGBzsh=hCfW14(;IR)-ZE-gIpE{;ECn5%Ss~;;jp3@fi9E@Kf{>p;SoOqF4_0w|; zvlSgsDd#Gb5`SX|^GTQT>A7ynpd}`X!A+WGABImr%zh zHD)oW=sM*IJL@znPy{a)-plHA-1}Ah&qx2&UZ)xper?<@81d%9FzyQk(9=0k2TlQ}_d zqlT;XYJU1j=cflzdim)yp2E<09CO?37Dkbio3OaYNr?ux)h2LP9=vSAJq}6>z3j`n zCgq^b)Ci~ZTTZMdy_q`$b+x-o(?zLr2#5JJ_E^qx8fl%#lw^rJz%7`Pn}Bma<_vMO zOW5ybmxBFHyHFwAJ~q+`%LM#U1Q9^4+#SmG@ImG!W_(V7r_lT#_9;f-B| zwaXUS>dn{^D$!K!EL|fBT5(7$D63|S3DJ%L2)lrQqWz{ADPEJ-S!dxnfS z8Hd(VxDx^uo3ygAOR$-;`h649$2V&i+;3Kyiw_BAAjp~f!3EU?QGg-oB3))vI%z=Z zddQZ!dK@dtvUJJUosyy0l@xs@p0`1skVPPszLh37OMN!A*T>gf{IKYjkK!@PdDVy< zPnAYTMus`@0pb%WM({~_U0;mIV~LL(O8Poc1(Gp7Te(jZFimY*OP>v4+w<{GT%zCC z?VOrE?PF7dOC(-t<81_ZoD8!92OwOE2GY~e!JfPcGebJ6DT&)NupO@=qncduti~oe z4y-dvOfR1G!8yTL<+g^nxASvi{=@KeYkRnoJMXp$!6y~CkeBB9wN+Zmoh46HUYSpZ6BJWBRm zx1!3!l8uCt4QvRl0T*zqy*#)N?R@-dF3j1=s^MNH+5DQXCz z^H$hr1eH~QHQHoMausm{U$3Fwcmpq+U9VUIA z4q>$xe4kWdolr>|oX-T7GczQQFdlsi~P0?golX zV~titq$$x4{tYH46idfwDe^n*w|lEeJCW!w*9D@g*gx!n`qe%%KM!$M1wY$|`#Fvr zSLRhFPHd7pGjiHq%H0$c<8+ z)HX9gd9QaoMuyd6FDrD>+q9O=v!vswF#llOCc6qXZN+&2Zk&p&&^Kt*5WC%32o_baE2;VS;53S8_Qs|<&jb}77F(X@C znT-M0rrUK>=c<_+stYIgsCx^U_pSORwt{%ZX(nE0LHvwX2^X(yF6$04dFD(sl3-BP z#XLqDI*(q=5{7oj8l);^wbM!*y-Yo(?)*UKqd_F_l95qhpI0hFe=Q?uA$L?3C#u!- z0xlA)t z7H6rzz(kY}-VO6nTTlW5BbKcoGD$6p{!De|OC(XMM|*m4o4uhc`!>I}vAtg7IPC@r zyS1J@E?i^S((C35$4vUbF7+wxs!fLCa@c{m!|do>C_ke*=VKFB0S7Q%+1jaHc2h>6 zlZ7AZLSLpbEy?2bb>oEh#Sw?0qcL>wiMGR>=bo2s>=o;cwVeSooAaW!!GI04FEn^l zzw8g`v?Q7Dd&`SS8K3^t_v7o6py;-5#wKJN+GfL0I2Og+pPCEmAaU}FiGdfrGB}-H zak%=*lE1#GYKOw;+&Rf0?s&?O&U9w(j|nORH^8#1HP-Dk=NIu_`-3`Oda)t&0sJBa zEjwG(W{Uui1%(bK{RCg}&rCNHLX#I+9771ob6b?N#eutIM1_=Ew5PB#WieiKJD6*? zxU-$r;%=6gw@#8yW}dwa#tGTkpqsEOoCdkQ>gW_~|Bb<5h)lXTE;Q_t6aYIY3>gaK zV;D{m0Eih5Ayc7dY`W`Jv){QIin8nLIi9k9^Sf!vXsr%a*x-&;?!0wpDETA@Lna!ym|2si z^`*=5stxCw+5YDC;oQfOBNQrqAU%20b~i{4H^ony@8&Xh_85yLmceEB*EMr$dHsCN z&V((yBgrE6a_RBTbNui$G5gpl$wORLP%Dv#3esZePr-8o48o{o3~ zxCRR1#@!#@d9aytOE)$*OAB-BwF|m2QbTH^Ey%K(d01bEuA#x;nw<)%eC62sA!80% z0w#Kq8RkgA80o@i|9y4@K0QX@F@?f&f#(CGz;71|g|`6@0lx$M74X-mz?*?T1l|Gs5%5mnkAY`Dp-}iD;23ZmxC6KgI01Y)@KWFk@F4I{@Bhp9zvun$ zc>g=z{?OYWdh0_!|5pCE$Dh$-;dO-{ejR^aSNPBF@A1R+;Yf$|G=UA_e&k$KTJ-SzIgM?R17(vW+lBczS%rgc#Qi^30!LZR*E_F?J@dO zxMlu@Hy7;b8Sd@e3vVjuw|n`d?8oT2aO=n|Uz2_D#O#;C(|9}a!oEW8$72*;cqSkm zcpeb&V2tN)0lpP@8}LEkL%@$dwov#n;7cD@D7*mpt6RVi;J4Cd|8Q^}P4!j)rO5mG-?*V=g_zB=Gz;6J52>b=`u`d5U@{tem?_WOj zFX=yf=Fdky_OZWz-~W8~yWa8k-+t?_{QS@T%e90fx9D`uGaqmB3d5-vN9l@Z-Qw06z)*6!6o)Zv$@w{u+2M@HfEU0`CXzVm?m* z=Yacw`+*k&F9Ci8_)*|jfL{fE4fu87t-w>6|EB@{z!6{oC<8;lMc@+f?}6_Cz7u#g z@EYI=;K~z$F9yB@=mWkKcmdD=UIx4h_ws4QUl06S;2VH90zV799r!)q z_klkI-T{ba{~7S-z>}caw*pTFz7%)?a2PlO3;|K969-mQ;6=f8g_yu*`Wc>j1Cpr=38TIe*tX-}TP7zw@nc z=g(W-@cJKn{Tp8YhW`S*{ta)j|MZmp2BweZCGRI^g=~}CorIp3$h*t(PA3o_bhD@I z`|AX5R(~39n#Gxs_`P%f-x#rxVMg|OBy!U~kpE$z@C@`Z-~{jz;7$A#|NUHi;^8y& zOLhpL#}kJNQ@{4rhYE)ZL*Mt_=|kDK{<+(4oyiW8rZZ3O`!gi__L{>h%;Rf;9|C?A z_zU3X&t>TW72qp?uLAxf@Mhqhzz2b6JQEoXI1O9?z7hB#;8%g)1O6U(66^dha3}B* z;3NOsAy5C{4}AY?zvElJ;p@Kg%1-lT^{;qwuGuD4|Gysz^7RMe(^EehejA8SGx6!g z@##u@dTo6AnfUa(@#*j4(-S@xO74qK)A4B~K7DO``hocL3-RgC;?u|D)3ZMwO1>*T zy*NHyiBI1cpMEGl{Yrd#Pkg#5%Ku4xdQN;g5})qk={Z`fpU8QBkhvDE&xuZ-{ql($ zkaQhEg$mEs+6!|c{`;GNc<_6GzW|=}d4~J}t$kZ;wx}jZbfnPmhVKaw~B}+|2O5!?E38y z^Z%z^&szN`>vimlSnI&Q0p1M!3-CqA?ULP31OEy5&%lSW?f$1vmoJZQtN$_E?cQIq zsUGcT(fWXWS?qkKXz#Vm=dUxT4*`D%{4d~v1b++gTHw2ZKLwukoI;@u>;S(H`~eX3 zvOn>kNhA1>3d)OOZeg~de@3lVBSrfIJ$>#?ET}_|o%!d7 zAAZ~+Gig3S&o1qMi%)NePtW?7@b>fc^iHFi;f6$Ya{3f1UZMLB8w_l0B9a709wcvf>H!J;bmEWH3 z{!n=O*YRm9KD|0Vy)8aH`NJW{>G*UeK7D(9`emM;tu@*?r*BlF!oQb?2Yr5N_Df&( zOMDilP2XC0{1+FVfLfE$abk*RhJRS`LL(XG)+ee6MK^~a#u&wXy8 zFbOOJUk&7FL~ha#_@$lg-U0JmPco}!;-)MmI&^ckZucxobhY)bY)7t|YH!)`musSp z#++i-?hlU`BTKTAcAMY-!W{o1@E$;R)Mo?V0LY&DW590$va7xy_+xCUe*%0cV_$tL z_SF$@XPx779rzmHdx19te-7LX2N?q{02z6}`BSfM|0zaJb|OA~MSS|Y`1FJE>F49q zJL1#d$EU|f&FBg7=}3GUh)>h;>12FbjZgLXv=Ftx#rU)vpI#lG-VmSO7@wXSHN)q{ zrw8KGSH-9Q5TAY_KK*HY`e=N5c9f$g;?oLG&(T``M9=kWnC}C!lmEXZ%PAJ0lrO0s zAZqk%tv$`hF9YuZ9(OzT9pEHz9{48U$AGs1e+N7b5%6wc6ZlTx&A_{XC%ypNKhOex z1o#W!afgu@fjM9Y_#WUbzC5BO*TttFk56xpPd7ygzdt_R8=qbt zpI#lGekMNsQGEJPeENbY{~wP}55%We#-|^RPruL8b3R#f|B)<1`|KAMz$a)xTs6TK z@a)cY_?4{1w*vBueiZl^@Wn?8g$ZB3H&qg)B$Y0z$su2_-f#L zf!71S101l62PBJsl^w9p&@b5`@Xt@awII7=>DQiFc--@fHb z{o%Lw#HVlhyYSn$#-|VdefaG|@oDQH!f(y^^v&_<2jkN(#HV-0rw_)br~P9nl=mx+Ha2i+z)_^|--UVDb zL2M21&%pEV#;*i?&cDWw1bj2_$}dB%0G?7Ireqv>U=lb*JOXeG_(|ZdDmG@|JAog1 zAu)u&#d`{cZ<`^eXci07X=uzmF-X7{E%1I3`{Nnnn1Eqm5x4?;EATzQL%_gUd|JQ` z@Cx9E&*7H>F5ZVc1I)jOz5`EqaiOpP{1NaiFTtMu05(tH>0eGAz;l5Y0RIhm7a5v7$j zlvb_84@t=~|M&OYxu0|Im>FYcH2rJtyxwy@XM4^$&+>iN^PFlef_9+}%RH3-t1!?x z*hXGms-4tXQYF6+9hWS1!4IKr7fOwldPZus)MlwIQVo9$xzb4L1F2O~yQHf96gneS z>I11&QiFdE9hW9GQ|c3`xQ(IXnn?|jdQxhx)K012QPnLi<~7XTA>7QSr-Rw`I7kQA z5}OU9;c+kY^JeS!y0Bl-N=_boz&A`g^qhh>IbRAzYgu~C^bQ9sniasdf$Z3s4q1{>Po2xrIty(A=UER zkSnK3owy;i?IfvFrG`t5kgAM@tZwPCAj2`?bjFcGd*}n#!%TP^euZ*vGUffdL($Tf z5i7rk@5$xLZ{g<@t%UnVM7|%Y|5vrNmzywaN4O1vX|N2|!wx8U2JdXa1uy}gh0h_G zvU{j3KQE&!{~61@a2REIE7zY4qrl4dc}V}u*M?$z^tzCWk*X=xO6oGHNm7%gQa%g0 zQc9|UR9~q(r4~y4ELGw2kSh(P+DrA38Z9+jYL(PZsbkiM+&f!pq|_r)OQqIJ?U1S@ z%hy!u0#tQNkB2&JClJ0?f4di~4wuWUtLU%-@Tv$45V_*z|CaVLhmX~RLE1Yd&H(WBvy4%BQQR9`=g`nsk2FV}ti z!Q0E1yz;`+b7#+dc2;#t(4j#RcdeOxF%8;N?j*4TB^dn&>0n_+Dct1b(fSscKbtZ z+bLDap3!@b%2NJ_(1zMZCN97D{ypC>0_GRC!E1$udBw25Oyt`B#~k36@@)f> zLwz5i^!Nbj()vIaLCcGH&ks6W9PASr#?tyl?uW!ng8d`)SXv)RM_3EiR}xEK$v+@o zyd3WN`CbWk%)&o9aztWm_pR;9&vy&*>l!WmPA+NPGRa%KGb>HcD-hDrwK--Lusus##jiOStU~k4zDX z8$PsZ@V0I)vp+n{qV(mo6a>+^mP9)e}?DXf8gP^vd$hM*Z_ zVFwQM{&(YDp_tr6s;yL-)DWqgrTkHFPiot0sSl;LN^O&RRqYC|Nqr%etW@7b>LRHL zQvQ3GuW8#?QcHn~- z(xQz~IinBtI=BXGyvih)49~+F*aF4-QvZX#VB=ZF!7Q+GEqU?kh-@S;4*Z?Z3G?{e zmHlElBP#5y%+mJftL$gtU(RfAL4@}^g!#MhE5u#K*dVA2LttS)+Ja#Nd1Y3@6L$Exg zD>RbwZRr)-HdyLjsr#g!m3mI>A{SBgx1gwdcjlh9J~x)rctOILR%no zhbv($Y=+LfOWXxI4P_3{e|@HuoDL%SF3x{-HLZeksJzq5iZxX;_k3t`$Fyzc_rVGo>jCvku0{(o+#{q1!-H zy3HGcOK+>U@5`NEvVZ5NS)6OG5!n09GL~SojM)spt_<^!wQ5&3Vs77*%p0;A3EIi* zZ+2<;Q{q4}xN;Q&dBXx$<1yUDEeJiy=YPZxLsfx;h+DQ#ZRX1DxSBCS6gmq6S*!-c$wOsqC z8Is`7EB{;C3x&yW^aywe%+{C0p7#W^@pppR`FZdKHa=wMOJdjWg1g}tFgt%3Ha^_e zcgEf?$G)4*-Qhs(acjK&XOQe;ZRPGjm4j%7jLGam*m}W~|3c-lgGr-S4yzC2!OCMxz{+I5z_FCctZX&}tbFzi zG^BiH<+OhAFj#pl!asM1Jyzrx(1<;|!VimBi8w4TD-o_mtVG;s_A3$RM66_gPQ;#w zb0StE4$FQe;+*VPycigaiPrvOHn$+cbJaDJxha2JIlL`g1OEXllYar-M^V0pTfoZV z55ptyHvA5GDF1!PBzM7{jD1q+QswntUj?b=QYT9-mRb^2*zI4XY6joyV_PSwn}Uit zn{JkRSL!_-moC*L_`V*l3(?Sp&@3Zc6zwBdKWRh+0%0A6Dhit-$QoW_dNABT7IBi) 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 vGxTB%ZR&P3d*;gUm{z3!jy~{zYz00M literal 0 HcmV?d00001 diff --git a/doc/i1401_doc.doc b/doc/i1401_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..a081da8b1a121d051ec83edff9eb2ccc88f0d6ae GIT binary patch literal 65024 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 literal 0 HcmV?d00001 diff --git a/doc/i1620_doc.doc b/doc/i1620_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..bdb40704eb5bdc60f2deadef8f244cdcea7feee9 GIT binary patch literal 68096 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 baZ;U0e&;yXb4rcZ7u_kwN&54#E`k3Kk^!4Z literal 0 HcmV?d00001 diff --git a/doc/i7094_doc.doc b/doc/i7094_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..5ef7d0c3c14ff3e70ba1700bcbd0ecbc2cb584fd GIT binary patch literal 89600 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 Udgct{&7!-+I7xiI&?WHy0qBTUF#rGn literal 0 HcmV?d00001 diff --git a/doc/id_doc.doc b/doc/id_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..27eabd6cfebdad6974703812fe046cb30a751b0b GIT binary patch literal 116224 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 literal 0 HcmV?d00001 diff --git a/doc/lgp_doc.doc b/doc/lgp_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..9eebced8c25f008adf0f209f054fa471075ef7df GIT binary patch literal 58880 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

t%Eu>;J<@5>l6I$}(?7fHm2)I!+}g)h?XKCl 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 F_&<{~{G0#) literal 0 HcmV?d00001 diff --git a/doc/nova_doc.doc b/doc/nova_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..5b0785e5a822ed870ddf34e3f7fcda93f3da4e71 GIT binary patch literal 86528 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 literal 0 HcmV?d00001 diff --git a/doc/pdp10_doc.doc b/doc/pdp10_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..baddd5ff26c0ab48121769540f063bf439ad4206 GIT binary patch literal 84480 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

H3(E;GShW2*zZ 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

fN~hr9VrZJ`el%FpQI6 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 KfqPZw!2bZi-g1xt literal 0 HcmV?d00001 diff --git a/doc/pdp1_doc.doc b/doc/pdp1_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..3d475e94642244b60093f59310fb04ad4c3ae273 GIT binary patch literal 83456 zcmeI531C#!*|2XGmO)1l5CU#jL39^X7B$<$rWG0=Nu(+a9weD-R ztqWSKQkM^LYi+-}FQ~27+Pc*Zt#zTTqP1G9{Lg#Ny)$=`363jd{2Qdw{G1k&R4=!z-jXH zEy;n+KYzf;GhOM1@#)a}q!0~*lI4TTiwg{6FQe(WrsF<&;*%$oYuq1K`Uqpp^@efj zTFr}d<1Y6&*}8Rb)Gg6>+e5qhV)oPLa&&$d*WS*DYwzlBzIE^QQ?z4m#}+OPoN5?% zaRb`%zT+1E%Tww{?6J|8Gqt(gxA}rdwgww_EF@@=keM4Xv?#Y_Wk;5EFVtiz7dZ5 z?ECGb$gfX}m5(i_yIjd1=f}R^>DHI;c6w}iBBv=mmaao<4dZ+S?YYP>)^oJuVITVv zMsI%X@a**chWfIn$j|#(-nDfbQ=~q1<{O4x@4hTCj6b7Je?vTU6Vp;{IX@;pJUB`H zlh0H5JCWmy)C2iES7{g@bF|Ox`|NzP>#u#Z)0gO&YP^WFy0W^7Ic9^uqpRH;35LwM zVee9(+mkb~%-1|I*W;P&cDqY!>lV~k&Yaa~*3>pumX^ESjcq=&HQ3%BT;UHaHJgK- zt3v*zZ4omNjQE>F&{8=L>cC!(qZT{b94s7xE!)X~-Lh_*$~e){xI< z23yVMHg9MtktQMDz$&xT7YcJjuqop82PEZQm3HwNX+umn*cw^k4UqvP&KnK~oBdwo z#i!G3^|zBZnUXVO8mv3UOi+Qe_((jdRk>yhTj7ti1-l|<$QO=;{LPYAS$Jx0?`n}a z*q7V=9e$mY>ULEistCHmq(I6j%j^iY_*>=ZQ^~S&ILmDDi|D4V2tLD-?ajV`+(kMj zQ7OW{b}5riDN~hJ%G8RTE=cl+ydiumi&VHP+JYVNDItqmyFvk7sNB;MB+FEY$N8Eg zc6D)9tU!xj(i^67NS*UG1(*9&TH@;)*{updMM9UVRTaZ+UgF;5vocIqCULTpL+ZMk z!VwDIPu_P1Ln^%P$;>AFS>c zxs4`1>Wga{7nrpbW^v5|b53PVS(aHozplQ#p~0-JH!G{_sw&HItE?%lnp;*`Gt(^L zK3bPqRasrxh|tDbQv$R^RhDyKg;`x*UpfoP#U+(hm5mFs%!JBm*kyYY{Km#~qSKHRzq1nsO~gvQ}kCv;^=X z88nwf+5*k8^5QCFQ5-euVzj&{zVemLzRn1(l9ET`_yf8ssA{9@3N4T-7Vvhcrr%9t zn7Sh2Qz{cpN@*o;%X0LOKP>H#b`nHDXoWxQld9Yq3U&k|d_`#3+fHlZuBb0lnmV_I zb#td>*expBpgTi;WZK%!+l3Yg`Hxq+5(P!u>J~*3xu<&=d0c8P3YuebCgzPX7qyv- zjyH!7GiNQRE3YSW=9r7x%`uA`gUvYwMFmAu3iI>Fm?^_^T(K^oLiCes7}aTJd3||> z8RuCfrVP*9XCFdJEVDpl=DKv}QsMJPx=>yTL>BZ-WT6t7o#QI4o0~vVp_Y`toyZkw zNklIcMB{gKP?nXGYRxj=a`axJXclSV1=|rm*%D4f>%6EVvys1Mz0cdi_sqJ+`Uwdl zKe=!6r`Ym|eoTH{SD?8~#MdPfKShf#+;;Q}Jhu2eS1D>Y*zPkMS9SWN5)%K)KqviB zW@BR|-BoQ@#5$`@5NLs?Z-M66f#$m;Ftae%tfGCIbs<09G1*pC*O(}X934c_cG8t= z2T`DdC@AnuDkvy0tNqQPU_^>2v#h*SzD(d-!q9ScXp^@S8V!%?pPidssG9)l+~46t zgOH%5W@&q{d6}76S~Vw8qVoC{jB2?OOp%puc^|1JBNLm4&)G5;PgIS1F4e&vt}aO*@Y^qsl)w-)!)O zq&pVrM7q8@QFN^)zuh3LHlLTBYXy;K)_FtN0lruuiP}zq)%0_6wv!Ik_VZi~t2&y3 zm{4Y!Kit{wU8Sr+)pUAq`UO_g->!Vs_VZn()FW@RG>iscBvIa5?L8-#IPc@$vr){` z4qrzQ3%7+lwJmQ9HM%FQr^EIjfR3bFZ{T)wagxgwZtl!(b93}}ET$V3{SZBG@wJAd zC$0Wq^n1v+Jo+7zcvmEfD)$0> zF8RAS8bx*1+`df7(kGo=v6GhOu;V1u;W&xJzPIaWs@ubnmKKsJ;p_8NBEcQs0csmo zyHOluV5@&AJ)?{jtl^Xxx(Jd%lo%qJ;R%x0GB)#t8HmyKxvXB5@5)jzyE?_%D9oQT zPmESo#;b^iE7&QPER6`uA=rT`Xf_cP@prbbn$+T7?r-tM`N}Dr$Y>`Jph1Lv-|zAT zh(c4y=UrxM-4W+mrJ>C9tz;b5Li}5;F5Zn&Bj}ttZO5BZA`@+$*Q|A(zHfq?elUy9 z%Ha#E-CX>R(Otj5M#m&>YdW+d7jx#<=N%-xp|`%lE&5Z`rycC}G_JGAt%Ag+^LKQ%`()s& zn_q0egVHAJ&2S{xDb*u3_$dyUT(fUe#wR1TE;SgG0c?v;hRlpyW#k$1EoD3>`k}G5 zZgFKzL!)>J`y%e@AcNBg#f*hqwz#@@KGtW8KO}=MZ%Yd{T9^@@3}9P)5gZAprAzf$ zx>_N*m65Vk4a>U@m|o2xdVXo65*=W?iUi+EUo!*C-sSoOv1DkE)LFM!V=KJ=h)zx* zsLZn<)|AzuF&dT;n;QOR`m-^uEkDgc$s(!uv<(J%KFo77*xcL|n&2)r?UvNSKtc8O zW~eJ5BU%~0`%J2`v>-pF!tlRc7hP3taT!I?(IFWd?&_2QV%V&&tfs++XjP_ES<=SU zlBzjzjxx~Fl4Zm%jg*l?dyvZAVz$xZDFxMl)FcD}XO~pgWXS*_%#a>)ZeoclwoYHO zztt~gE0I*9C{1P;m^xwDtE9$)K0G!EVUi$1`Ludz^=d#Ki#1VG35$4_smPl#Wf5Ac zrevg+M9i=ixUQ$bhv*lj$=0b2P$iQOMe7Fwnlr6qT$qQdf3~Qzwl|H5dw*e!E3Y4|UVSs`iNI zu>W{9_UvGIYH4!%Vpl_Xqmo@+c9f*o7w|SwpSlT&d8?__9+}kHw#SB&hMdBf!0q<{ zc0_7w?OW|I`hG86Ku#%vqK;IesKBZ%lQ-H9DUGE>{FXK37sPwloe0xLN~<4i<`I(+4N68PdmOjd59sB^*LD^cWgow3hL6niejWaTH4#f6wJY?I!zlnZV*I?|cZ zG_xk3C>iXcu4cPSlh$GR(pTyH0*r6afb^3xog=L?F!6X_h-pQ}Kw4YIx?FE~nb=q% z@!ske%}pnP8dT#YYsNJu)0zg18C0T)+k@eV==1!R@NVl5^$YT3H(n+3l(oy_SQ?N_XALqJr7l?p=!T z3Y;CX#Wj3H&eX!`)U5`64du$Ln(i@u_Ql3xk;k2OM`d4kyBg=oB_e=D5;0fM^vz5r z(*n#~dzJ00`d(icg-|}fQH)69rR`jqJ;!FQubF8%Ys*NMDl)A?mTrJMF%RW7EK6@zqdYjwDsnu+v08bn|aX)Sk<0$QSXf zBZ5&7Kcs2LFl^UenU~gH8B+UMTu9)vvUZk^rr4&eDPRaVBS=ogE{9h!a-mMqSSW*- zO-g~)l^#jv7fS9+^y*4w#3Jo3XtsN)kjHg(bczWWZG(p^6UXK1K>3jKtjk19?vkO} zQn3a@DiduxAE{)dj2^InyBM0aTJzjdD_i9yV}eRawT!>CGK=brZppU`Qrf~c?uu(5 zmi_N?QENK9D;d6an7B!t{Q*>f9(lxFwuTBl2P1CRym}e)A}X3CYE@26fN0xGG-5Nx zv{+5j6R;}BYzOLQm8}FFnTMHX4M=1HKbkFJbhnx#LC;&7v7Nq!H9^scw%s$Uk`Yz? z0;R4SX4TG9D&BUq1_?5Pk6LWjH4@O=?(>GC@zU+Hhremqye`|MveMAgQvgr8Tx@w+ zX1g!2G}2~HGs)oYF~hqW7OU9Cq;`w{G{kCes#2K@PUs-46+g*h`%bkGXP2uLuHALm z`A#kt78K+a+A`=utfA2MdN}E5twzhTq@IyirOVifF^_+#tlQ99WI0w(PpGzx%@A4P zV^P?n7gnud&jeLeIRz{lvxut7GB((@3d}CABM5D}iKeMKs!B3Lhi1h=g6!5bbhrVx zyTsS*m8Bh@mqDA-_S(o`YDZZa3}wSIdPn0atAydT46zxqTCuberY8jKtlVBkWxIP{ zzHmF11)R$cx~=q>W1CQh;?c6) zD>Dw#5cSj$wW*Plo@t4W&&6*^Ez7A^856ELC9OEAb!_n>17bB`RSGv~n{;ZZFJoQo zE0k_mK-T)5BIF*iy-1jd(c@nh$@P>8X=^M#f-ZKtu8VDKjUXYi0MyDR2zEdq*fP&7 z1I29{C=(KeoU(*6;!ZN>9O#i_WfgqF|Y6s_)Cgn&=FM)pEV`jgm2bwO%9x zeGIS4Y6&JcAJdDOL0!$HGu2&?nzJE4qgoz4rh2tn?s9Z$a)&Pz!j^QG%YnW)(1M}0 zR1^p8OgC?pC(4`54yaE|S~TtW7t@wOy*Cn}@%maMq>xXne;tTYAJU(yUKs5x`!J;F znDpURYsN?ts3N%ox6+iNNpY=A6sn^wJC^u*RDU&9DlNHgf?6+TgrSO>{QRn0v9%n% zs|{JjxMyA03Hdfwbt;CehJJVJdfzH+=?*L!>uN01_tx^Vv|zEVTPL=3F^#*@R2r2n zPmW1{Gm}jaYLgh2oY$-fv5pZiEASoEQm};>{z~`N5DW#Im=jQ&o|r&2D@&@)k_lAZ z$_T-rgJsgr%dA^qDZ^%K%p}S`>elQHu?~r$t?gqrNU5z-jJn1CmjV~>R@p1PDd$lg zrWB+$E$P1;35~6zv*W0}Jvt&+3+~H&tD1r`9VVuL3PrWHI0;seEXCJGo4nN<#pXOP zWR*ZR>9qt`Sgox`G=;M-y}x&)>kV}Go!v^ z9g)sj>Fiha=wo7*2IC364k}$SWf9lML^DzHS9K3EEwS8dP3t>iZDr**CL8+H=f?8N zS^2v6$Gzs2z9BBN`qm-48xwBM&`sI70;e}^d|P@Wy=rK+kho+hbCmTkJ(rGZpncnu z3ehozj1O6iG|MU*WY1ig@?|@g*Jw9;e3&Ih6zeK7+t9wMw=j35DsI!%tE-U(PHY@C z(34i-u=N`BTpsfWSl->P^{GylU|k~~ouJ2&mOAJRDt*Y@M?yQ%s>5GX=jp1#3TDA|ZMsE!bW~rJs_OQ0Y?h&78?iYFbs4vRX@RQcM4BYEhpKp7z5O zB^GliOx?FcV6TQ~4tm*4Yc2ZgoQabU7b!B7i1upC3W!&8vKah~sw1X{2-#7wm*1T8 z;@&2IyFbEA4g);aJJn6hh0B(Jwa4#Jz^;bJ8`ihuxCWJua?Ss z(Mq`4fo)SMMe9p+TrK53S?m(ZJ4@Gsoam_(t(3l19qd^9J20Tc2r6!DEH0fTlO3!u z>l&%9NkLM|v0D#UB_5p(P`hfGE(pr*Og)if50_=`W@3cA*1KZtsNoonI_B6h#MP@@ zWkZY}tuxagJ9(Kb72TuOUv$ zUajKswdknSm$PL-Hg!k+dD~ZbSINY^jNx_8N7tgUYy&M~Z6=E5;X2OIIK@e3FIlHv zc~b*USx=F|v`kTEI?%H;s7T_PymOshS!07*<6+W4OmoMogjvj#Mq`6o7wP3{iCitS zS4~u;t)2jPnJb}pv}QvWkmz-?ip@KWbeJr}#Fr6!YZuFOde)&~ZV5{;jod(5#2}uewT{(pt!Eb^%&*Y9 z(#I9i!#QVSoD$#i<+Vu1$pH_Mk2}y4dl9kPn>}XQ9l`0OFTUk7j3FHV9 z<+99D$VM(H2Q%RFQDM2+c{Ru5QM=c|rn=qjE^f98NH!L!QYFEnv$?UT;1HP+ik6}6 zh51=|v?}4&Uq=sJ7TZ)JBVY+2Zr>cU*KL00maPQhCt}JLJEbs4ukK*!eZ4esZ;RUW zVXecew!739P_;|7Oe!l&yGll0uGzsCQQIcki%nY6bk!)y8nmLHl#bDxip;nb=D5)D z743_d|FkBytyZrixN{A?lt)LTRbo|YF;>E`qSXqRXJWw=J~1cKxL?}S?8i!L8pR5 z?^bIwvXw{QoP%n2-W*>Bz1^+HU)$Sq=-lM3Go_FBF)u2+Lb0mUj#3iiwO2BOC|FfB zTA7r$Cp4mBWuAcrH$ACM&N1EK>qJjV-dRgHQ)Sb+n$S?j9JUWtQg@HCoichwRse}a z7yB!e*0L%Ym68f7n=bUm36}6Mo7pUYB_c8FHWL$J^|gyh_eNiPfL4nAD|_tJ%3eUv z(Niv7c^)S;(ca?LqMrS-!m~`3sFsb}2B)TnwaP$3i_{6rzohX9xjfyn{yIqon;_M* zg5vIWuaHL#RZ!Bhn4M*JUk3@ZhU#{2k)vv*tf3W9iD~bu8Hy4UD?@@+S*A^+#?rb; zm35|Cz(xs23n(`HS9xh0je704MO#ubN-Zm`;xR5BB(s-G>}oFQQ5U41ioWYEkz5Ff zc9Jxy2Pt{zD3_UeSqYOc%}li@hJI8%3`Z&L33f~@6)NiuTvCf8vd1Dk)tp@lJSU?#VINL=}}MwV2`W%~AAtY>q06$^LFGE|)Cg zOw@}wV%4bSTs9}+wf8G5D+DG+huN{nDq{`Rq?TTa>Jr`EyHE*EKHHb=a=VI3c1*b2 zHMs=IdR>mkpd=XkMC%cIxl&3&D&*W!N~J>DWjoK5s*+ZP9vv=NgzE9F=046mv}j=HFCnI@*XUhl%QJ^4!gQDM_R2bD1|K6JEW z0oK$ygS0xVSeVii(t+5+Wx88zCxVawF{D~)lQLgZE31*xG^7Dr3rDKCD%EB`L?KtL zr9*AeJ5`s~3egQ|qLh?^67zyA>Y#Bc10&j$ANhTGT*#@=n!2|FSm^DlNRdon7y)$%SzEGpOE ztTWfz)Dw5J(s)w;VzF1dE-X*lYKRqqR4dDnaTZ}%_hF{$ZYMY`I8wO-%d=SFc{zGs zN-H)!9AOzl1`O1}AnrW1cbpON(o0-|VZk zuj;m=7V%{!qekX0xNJ9IQRQ0q>n7E`n^u{CUXR*%QbYTi31W!bN$d0Su&oN?b4l+_ zao7kgLGsWsM&?Oe=8mMH%Stw*Zkk3hqb=1A9JNFZ&1J)8_ypwb-IGF z5R)|xrP9`UVnQt;XS>xSaXO#$JXus9Dzj1^n479vuri=>^O*m$oqpmT@JD z1K?8^&d&6jE7?n)n>PpX2R<*sQ)YeDV_FsDg$2PZ7 zl-H{<4BNKUmIXb1Fi$-yC4=?Y%wu#TYuxgTJfSN614>h-YXi-cr7Wn)Y>SNLWf@NMA~~NjIhS9DNOQ0y;C*^c9a7(JV11XaHgq%DkLZGUwzt zmOKLp#H&Yp?3&W+Bb~ag^wz?nx@w1Ni{1}Qp{WTzyS}g!w@macDpOKSta%be9GSS$ zdrENBZN{1>nx`g@@UIKsxGy%y4zJUw_$;fgQX;z zy2AFNYOmGOn!gf7oUC`-sdw(gkNU>x|7g$QsB>ZaDPa_3^eJIw0iY?%EI0Hgos#U+ zw|1l2BU060$IXJv)OJ)<*eq@+t*ndB$j`zSAnRnc<)W>oM?-8kG-Yw>xiOPu` z4*!mwvSvqst>`>l&fcj?H4>w7sTW}Mh^+KqdNXNs{G)b3s3wnc#kx$Gp7GMP%6xr~ zgp5&FNX_AsF1ALH*=!t$tjW#k!+BZY%gXixjNB2LM}Q= z8Ex8GIjC{fHbb2_MM5LP;sc|p$UKyE8`hqlXkDd0S(;@wEG(8k4f!Oq=j|Ols?RiV zFf?9v7%%maq3kkrNx`VnQGc?tt+9Z9@Pwe)EF?ZGo62v^Gf3sui;yy5BV}X9#jHd^ ztuE&sj6d(-$zuAjlIZs;AVCU(o$SojsOVF-b}-<^1(m$KXF)9i_qbUCwU=9+l|@>X z-DU`1PvKi_h*ycoxZY0}Zo633AgU^(mOJ}0d0mF&V7qTA@62H(R|+`3xgcI5hB}e= zi>bjhxg4FFkh^I}&Qz=AYH`=gmBdCoNQ3dq8)4+dUG{8U)In-yxBAcM%wtvmQhPs= zdM|^c0~pU(R36k2U9LA|skwUguKBucUSqjiR)(X3u=P+nR3O{NVn6snosA@oqij*0ARwWfWgzG!`6CtZb*#nh2({|d17LiRi6-Y7J>9j#&Ii?!9jtpdft z660dH?@X}U&GW*di#$bYc8u+~`si+wi7ZbMhL+_(1jHqe1qI8+las5|7#0r`Yq49K zL*lUriBXS*;xVs#7;3A!_~n^pYqzmFaUX=^3AObnk=(;P9*Khl;2y&l<$|H7T@DtH z`mJCMmTxOI?y;614%+V_-5ti^Z~{xj){P`gg)$yz6$%!icFE+6r$D8LgL{HHRXO7+ zC~zOj=?P-}SurTelho(B55ryL6c8gE^4(c-%;Ty$xF^a{U6g}6TTbO(b#U|25SJ%c z5-JC`JmBKVmA`Uui@V38uX=La5>t;y{>s5ELOdQV%9H0-;d|sSuK8|>xXx5LxTQQj z9#yIw+>%OF8`Qzg8mG&Xqr+vbh~XZmI^3Kb_f$^fivIBK4oBdiGE>RT%Xd$+98^Ad z3i8}c`70kP5Dz}SXE~_EQ)%2Ya5$m5vdk>2Z9K{JtX*m?Ah!uF;^|phGM?sFe!E(q|@yN|}H`)#= z9=Un$xweCfM{d6RDBD5BBe%dk&vsDp$Sriww;fbGa*NzDfRdQzsd(gh+zV|76%S_T zjTvSp z6}T5$_ellPIp}dOkvr=fop(wrL(REmV4$m%4n(QHLdh_Fj`_=V$uE80qRu6|^tmWR zPocz7pSP-W$t-=oRGmv+>GL)@S9M9B`_;MRls-RB&Q(p)=gZW2EI#e(JQg1rhj{X1 z@nI>7^H_X>>O2;oPIVrO&-dkARUsW-NS(*x6P9yTf%Nr=I**0lrOspFFIVTW@K>nw zSokZ|c`W=@a;~b5mVdlDkA;5%=W)vCL>#2LNtGcd3*9Gm_i?i2L+M6OP9CoeQn}{n z=G^ki*yJaf1IZjn=D@acfH!3y1Y=+<6u|FYhVe8!1AlY!Dz^bEpNU2^vh4ZeBaCW-E#HCSFgOK?c%nDvlebEGKO(*+HvAx?}4Y*&Q3Ls zgt-G#j^)rX%SaDE*T9s~j;q}+83%f1k22)ey4h*!_HG_>QwN@^gXljnW%{8hC5NUa z2&l7-UotQV&KPO?=q77lJ1mK2w`*f{AWk1W6Jm_gzMS#3e5FhLjS&SpAMC^|8hEON zV+?WLpB}@1E~}6F8q$VA$3RU%~Z<&Ja``R_b`nAIEy{*aycGK2B-$75oAR8r{~^z3AG$^$en#`rb2as|QHbYxJ#W*j69cmp)SG%1JskiF0K? zDUVy>Hn<%&z+G@R+yj4rXW@_V9Q+CX45HUxfEVFk@Cp1IK84TWzc3WNKMaOLHcW!I z|M<{753Rd=-RYOFyZn#${ITnvuA?oNnZ#AcdKo?6w#!oY;{Tv0{A$Wdhx>gkFL7?| zvUQTEPHeAk_N~t7T=`hHgudA}`%0O3AO~_G52U{?fI_H;255x2un>-h5QHHD=feeX zAzTC(!zFMjTn0aa4R8nC33tK0@N4)3JPUt>zYDMZ{i*w(+Hn7dE1o**{iH)IMzVe~7-$*R& zJ*T(0lXsj~5}&-?H*bjre6?4cvEh3PO&|L%-U{qyAr93R;@W=7LL4n^?jP_^_y9hH zEg<#bWB3>BO`RAD!(cd!g3(X`Ghr4qK{K>~4_aX2} zwd}v}t4)2^D&O3et@Yhvotnh@Za*oHv*3qtK3o9n;1_T+JOYoxWAHd^geO4s#8dD) zco*J-_hB=92wPwzIwS)|K_28oU;6**f!ixft%aXq{Q1?CmCmgOEiZ9yeJlEZ`HitY z=gPiPCIwIkMKBpe|4)U(VIItf1+Wkn!xA_dPJz|%6Zk1y30J|@a1BTwaxGj3zlHnY zes};Lg~#AC_z!#z`_Rusd;9J7{|__E(C2homgP)+&o)Z9Z(8CBT|>VE{lDb-2p9<& zFbYP4^!@w6{xAim!r^cPd=F+oIaI(*@In(bgAZC^DTw{xhvVQ3I1|1O{eL+96t!WO zOZK;nTl!wBzUlhESf?g&uIwk}aTfd#&W8)&CRhi*fQR7`coZIojqn7BP52c24&H_L z;C5;kKb{RJEZ)1d@@2B(f@W@kTa0MjrI zIS4xtra&dkh1@Z$CmqZ$-@>oqJ$Pv>@q%~ZL&!RW``}TycO2K@uJP2RO!N|Lgc~Ms z9Zo#dFb>RO3S530}owb)=y2JmNGFR&{J=a|luizw_>*?EE&Q~-4cQ7Tm zO-(vg#^vkaE_e{0fmh&F_!v?s@4aAO$b@{D0d;T;*!3d7_lrU5$1QLxJP%*Mp+nIj zupHLH7tUepci`mnok-8WocDZRM7X39|`M??Loe9TCNi`_=LF0@)Dy%Yh)`R_|JU)V~3~Y6{6rKXtC~N{a z5>~)f@DRKUgVE;&a5RW+KMmIJi!O#k(DS0}r@?fX4*^&MKZSeXIrt7V`)_9wViihO zg7=rQ_$Q3sADa&vAqiR#J<|x=~n(y7SFVKcZqlrzkRUwXoOo~{0!<2 zoC4RwtMDdlfx;5%EX)Hh`~b$4vK9e3WzZW}1@A#;4Q&Jts%4G@-h_|f#5(d01|5mAg*mVg zF0R-6F2DGA8~;Ao#v9FdU!6C&?z?=d4Pc ziE&qSwnzJaDT^&IsEE1?Q=t}ua5X#*|APH!%hH}p;Z=AIK83Ng?L)wB=O^%eG3|N@ zoB_^uFYWzFh>Op+=HydHg^l0JlsE~WIPXd9?Q6W^jDT4F_FRyR0R~g7QXU@kujt_b z+ybJHUx%`3F@4<0_mSw}3`-x+<#-E-UVa{4fPKEl+%TL7{{t_=9y7Gw&gA$ru=V!N zB>8h^Vs=JA@*X<}qwQb%(AOZhm@z*rqu*?YHC7*b7soA-Nk2LPT0r{L6X7Jd3H}Tp z!!Y_+>1%Vr57OtJ3a7!nApP&t@HH00zwHFdG4aXQ7=v$^XlH)#-8uKG+P{>CZ4)iT zE;6x)Y}@E=zP|%vBN<{N!FZSjEwBo%fCoTqs7+vCJBckd9x|a8#I9-u+qT-o_qc4@ znTGwDGi7nok|*7kSmH8-;z@&4K>zPAWibL!UGufgXq1bcW2 zh<&^eR)W~c*T7nM48&%B6{cY?+qUyUzCUW&&~b4}o^)#veaw)ZX*asrSUZJ{{bfA! z4rDN%k#Ws5_z}qX=5}}q{tGhJ84fqVjqoS1$3E}#eGX%vDhPr-7FxsiU%|a#G8VGO zMg@HDV+xbrzUr)ssZG`Xr7V`i3fKg1f{a@~h7%aK+T+)A`2H7o1zbnQ#kLJ8DE6NKP2xCE|;yWmlH0pwi)-{i83B`^7HJ2@cs-=3zC zb75P`f$N`{WUhaG+Cl5b_ZtHTU%0m4SU6<;c4Q~eXWbr5E*Jx0FIa3e8bPC(HN^s>NHN7IH1he!1S0(33%p==rhK;sUbs6` zzFPw?+MOxit$|P8ohjd~flt|;Dc_BO7Z{%1m-5{lc+T!j`ECt7cXy_Iw+5cKJ5#<} z1K*7{T*2-%APcZ#cboOPn*-mCW>f(KhuxU%yU~o2q0??m`EE3$3XI(v_--|$B=E2M zGu#->i$YTjzri~}qk)m&5jbBTY#^s#odK&yFOAl=Rei>8a$Qiuq`#Xn8HKclKywHm_Kf9GTs#T93O+m^^2F*&x+Lu9jg)4k^xGN)RvxQE}CmNJ_e2JA1|lBZ1Ntc?wsE1ozn7$ z<73dc0r7VZ=xuo)Cl7Uqj<)at=Dqg z(-^_Tl+S3T_I6S0Bh;TdzK39``rB!=;Z{M*2yoT;Il@>tBgNRFqzvM&cJ7h-Z!!_) zGgd0!skAnU!*Jq|&TFdEd3|&`wPiSMU>J9&a&%LYjYh3e%AL|~QjH<}9cK(z*T=*av^>(~kx5H>wwZQdb5Mqrq#|_B$5D-{@ZaNzE8U zj0Uf{u>Y|j{`T#~pVWXs#AxuE)dP+N_Ba`HXIy7ol#*@LxK&0cr4pi)q>Pr~e@{cd z)6zgmH7*pK>i#GS0d~k zco%+08h;PZz*N$49y|~E#Pw462-=uSeG;a)3}Y?qI|w&;66D>T^4`t2;B6SOC;9}& zLnh=y85{}6fFG8_8n_644D!CWyWl~123~6hqdqL^u*wz*X=NybFUV+yXcn zPKDE8{Ydsh!66ycHJAp|VLk+44g3`Df#=|#FnSdGVWAPia0&b`{1f&Y&3-F522O#W z!?W-OjNg~FSO~y%@GyJ`@?3pAd>_`rZ{a?WXSV0UNpKxJ3!g&n0qoO&Ht<9Gf$YD4 z5-5dV!?W-nybpJq#2?N)h_ZxB;1PHfUV&F3g-X9alz==R{1dnrehn|eOCXIR1v24q zI0BksIjn%I;V!rvPNwmk0_)*+cpNsuW*B$~Wdx0I2HXHQg8gjqX1@O&hL0o9AQNig zL^ugHkLNlZkjXP>PzXh^2+oEZ;3?PwAHg9L$YYoW)1etIg1g~a_zVs^l)3~nVHWIl z81)5CgVSL>+zyY!Mv!MFU0KM6*>D_O1P{TRU`!;h;6N~;0%k%0&W3Yf1H1q)!pYg> z7i3JL&O;@HAp+OHS{Ui!I@}Krz@K3=45b?x2L4>)0awA*a2MPS&%qWLl*e8@moC>GGz3_W@8XAhx zS+Eey67&SfzWTf29e5Y$=8Y5>53@k_*{^~t-~o68Hi4{{rNDT|gj(=HD?9>kz$O?` zPM$$FOoExP2v)#(unwMp*Why)QbGR$3t%CvgjH}2tcAzm6?he<&7^(60$2!-!ej6b zWXz(y!!-C2Tn@LxOYmP9R!Mt>8{kIx6Z{$8gZE+1Z1#~t5IW&>SOdR;d%>JT-GqE7 zfaS0PHo=?l5qu0MR8eMdHk<>0fmgs)P5p-b;Q*Kob6_DH4Hwm*``|`+3?7Hq;X_EP zr5}PUD1&1l0%yRrumK)|mtZq|4uk5j6Ce*t;7C{kK{y%CgDc@?xED6U3-CAi1o|CG zS;Baj43!|y4=#gq;VQTd?t^FG4cG!{_2e@g0);RW=7S%OhjZXcxD|d2PlLTjGqr(o zg0WBl6)+!8fb-xEcnmhd7D#PGx4;<4g%YTTCJ4c4a4}p58{k2B7B;~aNS(|5Fa~m= z1nQv)LU0;f0@uS`@F=_hFT)iyiNPNJ$Y-^Xbdjv!vs(Cib7M%4obTzfcMm^3U557X z^Z(Oj=i<{dr9EACyk-tG(#@2(+_;cpjL8w(KIuZ1$Y=GpH8*rAr&y_wl*E^*jH;3@ zI(v-OUu|xrn6cKRC5ww)7BQDpt8`*6X+2!h<6NBW^s9~YS0gziCEZN*NR%aZJ!2^2 z=lEKebaCc_)qAJZh(bw`a zmF3wlVY`sEx%hVR-Eq-6p}!;T@z%SnFD6~c9{H?J=7v)PBy;1Nl^c3YEta`GrjFNI zvZme_7p)Vd!pj{!?~=9ncsWTIXHEDjb3>Pf^k}`8h3sF5FN>s$vn;+HxuMs#?9~$r zdv$!7%FdCbi)bW1tCP9mtl`Pr__}gKw@P~jQ)*s(8%(-5b3U0H$=sk0&`N}4OOdSL zvsy^zhGYew)j~2iBrEu=7LvIkS;1$u@Kxo8klNqg{21Dwe|KzSBNe!pFQ z!&`pGS$@k`e$PeT(Z<2Zg*?ayw%V&_h$nMoJH5e{d4nzTJf+4xpu#||{2r|QCaC-_ zr2ICZ{63ugMwt9gl>AnZ{9cIsW`z81z^gO#``qOn(()c*d6%rbPgLG1Den~=Lp&rd z9>g>4Xt3R0e%8fc>%1`o7?2wbzh&#YdJPm?%jGrW@(OW-t>8Q{$=+;W+qO{+Y{BMv zIG#NMwm7Rei+rM_o}c-xOWRPd87D79m1!u!KAkSOf3U|Y^@ErUJ z|G5CFDRZ$a7hZ5QYojBDfgjS*<(aS@;Kh03U)pzcp+i>4IkPK`Y2JU1z~B z;8A!SHiA6o^*&^{2n!0K2;|wX1#k-d6t04+L7oS@AN~U)s2>?H3gj8F!=VD2zz3}$ z&yAf0>);W195#YHOZGnOMIAU4CPFsI^JR4qfV1H|I3MJhv-R*Gyb5o?CXnaQkI2+qkcA8`p}qac%N8u1!gJ zP2P!Ga$om}<$0c#T$U6cO-#0})4=J;VvY$s*3uV8F z>?@GfYgzx4wG~+fkvU+QnUXm#nQM{Js5~1Y&l$)^X0BvjLq<`kWJ6Y2P!R@AT)pm& zCdkvKJa+`BXX2z^fj5}rI2_t>C?*bnApCdXPU3I^ai|~;&l87L#Nk!qFrPTwNgQ4$ z4)ck_0!JL=na;x?8}gtKN}&SkpaB-aVrYY9&;={ubT|VpgiGKG_$k~3H^ZH94?F-5 z!_)9A`~~(U5o2K-OoRt%7>~dw@C7WU&sYklz?pD9Tm~E9SMYcE1ok5RBjG;M{Rlh? ze}I=^6Wm8WJPuF5AK+i`CG3?=Uk67(DabQ$XToFfdpKYc&jmpZ90}LM&9KnJbEWVx zdSk-(WL*LWlM_JYPxw z3oB;xyb8Pv@59hJ=w%oWhd~y2U>)2H&%q1u7W@t5UHtFEX80$JsUqLuBv=h6R3jfw zhx6fW_$SCSN}E8QPud@v8tHF9>h1tzzwa>nk~U#y(n!NJUZg3%4e~VhQ#5J2g-Oer z0@AW7L0Z;PAT6s2q-6y_TGk05E$fHiY*|-xE-mXekd}2XNXvQ*q-FgHeyZg={E#TtV}hwv06JO)p}Kj1?!Giebpegg4;ltX!{ z4>laeeemNf(gSb7yKvA%v=+>QIq(o#;9+2Ma@ z50AimCBzNZmf{AfWz-9p09lYx&Xc&1QGtaE$HOUbEnE*jqUU%RHo_C|9=s2uXAw61 z1g?ZT;cj>t{t90}I-1PZX!2C%2k?Eg*>V_zRvHJk#IF=9o!A~f;=fHzc?YkD&dCFAipXhPaRf)JZ1PM$diU2L24sy1ct&e7y}1GF4(_H zP|EjuXaHLihWH+a)8KTt7%qY9;AgM_?tlm3A$S)42%F$d*a9CxDjGEn8N+ZIoDDa@Eg(-bZUn8V^U!2Tl6kNzb->^=0#LTbdbl0l zg1>^iXXLMYprsC^1;Pad*n@Bf+zA!fI#qBw{1EP8!r+&1En4g6@HG4p9-DzShd;ur z@CLjI<;9w19NXbDG|osg$^-Bs*w5{zVL^X&4B)*i!ws>%OL!wslVKVSytk*5H@f(F zrwebZV!mS$Zhqck)y8P91z*j$bn>l}5s>YYZCx3FjPN&1LbH{MG8OkOQsN_h5#nj` zhM@p4msI<3iKutkEal3gZs}OWoJ%MFei8q_?R5bm3>)`JHh8W{U{_xO0|M$ILb-%K8Fzdh!jMm zXc6~pN5sm(Q4uQ#BVy&?9Ztxsp-~aDh9Y9t&>c=l#y(LI8T%k2W1k&P$U7sWBHkH^ zh<8Tra6*1LIx6CqqY?4T(FqcwC%s|?tG=mvu|8$*HFdg*txrM3`jjP{ODXD_D8Dk< z?W69Sk-GPq`@c|Cb4Dun%}8Csxp>azPWxW0l=zRj_ZjZ>=zE`$d!ON6&lloX?#-r| zMDHIEe>*k+&02wY0xA&S4 z{-b0K>4&T#{g!Yp{(6&@jT(uQhl+}RRNU4gZ;6(-R^+Wk-je@_w?y)?QB3hN_l}Cx zarE@xd(AVSsW^K2Bh%A=3FqQ#TQalN#Ohb8>JloMq^grL(>nYAma3C%K0Di+ zuI?s>(;e+i6N>12Z<4Dwa@0-+R-9BKqE&CKRzty=j`#xV`tL z%DPJ2p{8Y|(5dy_p>pf?`qZ=xUPDVC+FPH>?S1K1(=yT$cB_c!YtNdNk&c+&dsf8k zNavcC(GO9*cdm%q(f&0pqd($$?_UwOGhJ+2#sEb2-o+wvXM5SSjDd*ly_ZF7UpiVT zaT()qh<;>z5h)PZEpVlwEUus(Vna3L@&Z})X zDj*yhnc|V@Bbhp?;kbfhJ>kkL-UD1OKu)UBuU|@P%7Ff<{cKy>jyyh$)$*soSj9a} z+}X}q-Z&Nd9{tl(<&!Y;6kwoGMUZ4@h&RruIusPZ)M7cXp}p<)zPd>e(vOU!_=u z<@ghehLz%Z#9UrwZ@w)uT_Yb(!xYIcG)Lc)z=f58n zf4=QAc_nDikFJm6o}PR9ky1`}>+0!OyKLRcs;c_z!`8Jjn8=i~Ox8*(l-JA4)T>Oe zn&<$TMqNsq)SvE?rM*vZTb_63@FnVmcHZMwsfw@v;F>L;)wT_}`J#cwVdL+R#Zm($ zr}`4Pej&)6SAZBBzl3yn7(_Ea2cni<2hky$L1h*m(fe~)6&BgjcUAkF zL&0#cHDb;ShFZ)i*<{`f+>K9e%aydM?=#$i<34^QMSZ`1>Zoh$HmX?@lBM!fREFfM zs0}$LKgk?O=0GwBk~xsffn*LOb0C=m$s9=LKr#oCIgreOoy~zn<9``fr~c`8f4VYz z-yxS=&iFs;v)jsW>(|Xq#_BR_Cu3q6x3+xa0h|jm2Yo5X9PX7MlkwMs zjOlLy8PnehGS~YXkU4;dL1e!T&au9@HTX+|p@?rKU)A_nCe&n{Jk~nObdQ`5JlLhe z;%ma=0YpOLFJbpShp;C;BnC3VmlQSnBkevVU+$|SvGy3<ycgG1 zmMxxDRarBqLAlBNMKSJ7SQ|??iku>zX^`V0>zso+mpnZXM4o))yUdaF{)AeAde+k^ zPiDa6Tt0H#QF)Rkr@T7roWoAZE9xe1_AbgR>?W^l7v-@fHZHx>cTrw`H+gn`;=EJ& zm)A`m4=^Y>J1ft=->!dIyC^TGTl~iDqC8Jj-e{FhbC=}hJKBeqH+mQ4+2vWp?^a4X zk-5N~Z*TePnQh(Pv^;6+yCN^vKD0cU2i+BUvG$?miH_S9dD1?TpJWasb0C=m$s9=L zKr#oCIgreOuP+DeajDpB3`5m;P)4`1UN5$xtkcVSwT#te>?&h&u|Z{w&wyBs>17RH z#_nS4%6=^wL(3RH14e<^)ceAIz|T^v5wwh3O*ja~z`-En_Cr9%2;(6WCcvR^7|2*; zB4ooPkgnW zY0{9YF%(W8KO@*ZWXC*>d-}U%1ZWudtG}u#>2LCP-7R^t$K_hSu9kB?_H(EDY{&l& zGE$@AOFa4_p+P(i(LQt74C$o>wnw*I^+iI=&tA;nrEqHJLF`K6Z%1?KMX$bYKUv%T zsounQ$6pyu`upS55Bi#Zkuc_Z`78IylhPgh^QyA1q!zTQ&1m9cKOe09_Vzb(C-VPX z5oG0mKWczHiyeEOdB@^2nefvQw%rn4}QgH_czr@F}~U6GP*nNC-Z%?eci_}p5%KHe6wxaHo5&bcmlXg{C!VK z;GOILY-F3RRKxhJ-+fYvhC$8p$DOv53}YXoW@*jRt&eSeOx=z6$CWz382YwhTy(Xj zZFR)s4j0?D^$y*O_1$*RsJ@up^tF6Czsucd*Zs9~_3t>#@9Dr`j<7fzwy{l+=IhHw@`9Tlti~cs>uo-TOiE zhR5D3iJ$Aiq-Q?~pxvLH|Jld1dthC*Pp|FH{*-X#uUDP^w8OJMZU6ddxE#jdZ-B#} z?ce^C@F&oE+K1ErTFS@yXZv^Fi|4zYA3Hn=XEXI?hxhyv!;q*3@lO?>b~^0Oc;blW z#*WV}r`u>Rd*g8P;|E@NP5Glq(w;t=ZWwmETRWe+>`B`o9s4)}w8JT+Tr;^Z?N9zz z<4!u%X|x0R`$Y|YX_xl3?a$7q-G1#)JAbi0la1#HwY;D_Bgd@tHnldogFe4m9dIx4 zq-ADh6nJVgGIP?>((=p7=T#I>pHXGbE~_feFHB3TYVer#zQ#u1N^kQLv)0$r=JzgX z2%62lptsgzx?5Try`F#>^qE0iRu-4eFay3;f30VfS>tVX``bpD?&dnP&R5&o%SLag(cEv+?;-avz=&h$2$S(7GZXN=9v%o$~_^m~IrPqSImW>)xW zJpQ0rYF4(kG<%n&<%d#|UOUq1r@h0pa*w~s8we1u=?$0-9>0g+miXPxK~LQ%v)=FV zn7(?mw!!URLZZotySdG5@%RIH@YMv}-e$?UTjgC`1{(+_;HwX=bo(g)GUpBie6?OT z;YH@ttoJrjHtA9_Ln|#GLr1De>O5qg+^SNu16%10HuzeDrr#3?`n|PMR-m1LQ#JXq4IHtMk^&r$=SWD&bLPomYacX$|5sAjMwmX%=7P zV+>6q;AxaPX^}crd8JOR)ai<(d?*{@w~9!`yRyO86qyr>sJ_+TtSc2ibv}wr#kkZ{ z8?>8?vtc#Yc_qIA8i%wwca3j_N9855y;0n%0#qV&ty)bn(BLNRH6E+LbYqfRc6P{J zYfT_X#d|6H7N1|m*FKx0iGN0+Sy@(8H7B>C&@8Sr%PY!`DK021Fo)(=ay@jEIj6X4 zMp<>0iHnNd*;Vt*vLZ8g_B?Y|@$7<8X5rlOio(iDv#i1_E-f!9F63VE?EI4Ig5ufJ z%{=_kyUdc}(&8!tttvAmLMy1^Li`n(rG*vwGYC01uehYRYThWbsJLpjgjqzOxn_B8 z1>Li{B)7sWudXOBt1Kk?0)m}gJiDlZSPDxEXIG6jiI$sY;W1p9l{0cnO3aF~yuykq z=}6V(vx{e$d4;4TH?O2n2TdmOOLB`#N0|k=rMc53H5FzV39L}gtklezQK)Vad@ldz zR~47dmSpFb&9188aum5D65H#X;>yBNW^P4sr4&F>MH#_M@!>yOxgjO1%6O$x635%Dn}TXKx~(DE=v(cQNGA7A+m|xVHy8NKp;;N( zL(K&Z=7QB`|9#CF^U4b=D4bd5f<|-bqAFi)*7%7NGAB)(m^0K&>YwEb4**3XpIrOW zoTe966c(8gjwQsT{@MHOM@+H9oFrk6b?Kp{$m0&SBD`V*IVr9nb23$sqqAK3<<-$c z%E{Crjqf~hIaxZSv97Ah{G5!5Es3vSD zs=?$ii=nJFXhl&LD~bs^ik$6aVxk?zcvndwnJ7WRnB{&i z3I!EWQeG7+{E6{}uezz!_5@eKEGztsBEM&OtEaiP&CGA~)h;vB^GjyMiYG_MGif{d z&|Q~!CQ4Dw%r$fC^cYNi*cF5JLY>S-o>!I4jTN8OueTH5B&%O%kIr#b7336-sj417 z0YRQ0ly;n6RS+ZiNmggi%IrKpldRsJJ$jO>Dp$hKosenfqnvqAB6V*`&yQ6(ldOK8 zm9?E%td2g;Rq9(IgTV|spjqGzEQ`^{Cs})TNmf^%;41R2LfUS(BCPJ6HEuf_-#d6ybAq7K{mbA-QN+TK+%X>0N{`Iz_BwKj$3X-r>G+O+l(uqVc-SM7A9 zv@{-$ak&DuEu$OK`1Cd{Lb(k18a<)wI!}EdbW!j1g}(beD?;CyC@u?Kh~Nufpq2Q; zS52#|3u3Ho7o&YGk=Wl=!1jd-ICP-`4qZvWwK_j7buBq#T=MUtP~z29ZA+^PSYHIg z-|Olf-yQcGbt0AfCdd62$9KQOuYXxM9Dk$Z`>OEwKwBVu5v+5357as?95Dog;yo== z7uD0rb~P-P0P3&ay99MrCh(SxLuQ|KN@G*AgFt#1|b}D^G zdo`Qf&6s7B12HZHL)xm$X3$pCP*w>&LZ$Vg4>Da~IHJ^o9wy@*e4!wYLV+XsqTID8 z4N{G~ex*Ts9$0tp)OnfW}V-=f;y`x5}zS4Ua!P!gN)fxy=G;MGm$SS4E{h` zf%pxJ<{k1|Q6lj&%8schK^W~wiYeUa<7d4dKcgl*xYCzqWw}5~zoV?Tnop>dJj#w| z`Kc-pKOMBP_I`-PF4$5P3+B`cFwYYBeUrrP_9h$~ZDVr!e0?kVKgv^WyS(t{Z9HAf%B~Xb6oO8x!cENs$lGlRuqMbm3Cy+ zi3(1aazT-474ax4%H`5EWl9FMgNhQ{0sgJ0lI8a0rOGK>Xp!Y5ZJwD5tvLRYs=<=e zv6Re-6Qh@qMA4yy>^Y31)ngTs0+qDbWmHfVt&Aiz*9!(q=H z59UFv>ki?hnkq6PudJ+!B&m^!)O#74qV`=eJkw-4Xev!DT3uk#K_X#t-rDSC+%yA0 zUyBq%*l=E4k6z4UBCxEU82ek*I)a&wFFPobQ;Y=~30GELF;bMFI*%;GAjm}JsH`e0 zUsOE1vPzyXdrp&Zkt|vdVzz6|+5N4}vPvLJA|8YJiuSKszh(S{F+kycVLr+Mwp(Lsjl4k+$YIVN}tG1;tPF9{Q-BD?qs+goqMG4H% zmQG7FNg=r#SGwE87%j_6QsuNNmd0$=RmXw5akFTVYTT4mk_sfVEtpAKGF+ z;^8>a+*~vwTfJ3Tm_q2`0CHlu$#J;J8XLnA55gg3O^D@cg2UC=%owhC5Dsf>tfce6 z;VM?*$2wEb>>zqE@E}dPmsNkNa47p4k4P@2Catx0r{OD-zpj)>{hcbhSO1hYmn_lU7EVt3k3UI5JCTM@5FsX1Y25=~xcG16H4o+T_Zikf7#GSx;`uzG^3hTJ0660mOVKFs3*QMLl+N?Cp6Qy$nY zHXN3uU7jdItG|^c9zEHSW-4nr($44~E|&-#=2uMEnCx&jYrMG>;0)Da$v^^jh4_o<>V-Fez~r%giF%<)YF;0vfs1SeM3pLqC!#ME0qB#d$HD zn>DTV^&UU*iLZ$ifSXlQ%U8ABBSq+depwIZL8E&~nyXqui?|;OMY2s{(Sun9^VT!8 z>f%asO|P;-lV?kqGg64u2E&aGw6L_SKqLg=iVGE8dZszW%pGNB@sT%@T$jz(F2Xga zRXz1+Q9)rz?mQJj`{xW#V)Ky(Kp1JR{NkecT;q^7FsFjij7bM+Yhk4JoAqw5EWVQk zX-1StQOH5KuvU0|Oa#@ofv`&zj%rXL?<|Bf1k+umAgJ4dve~L2C`U{6s1wEBdaBi6 z(h`0g4#`q{EvM!AM<1Jc#DwhQwCnPGnMg|?@R^NnWoB7XNZy!c|d-xx{wrx zLl4V+9RTj^QLmlDw2sLNO;yoOEftV*$VED+5kII4LXto!A^rkhR`yUsH8yVrlMrXxPn`(r)(HvhN^|Oqir#5)hUvMhNYS4Z_4JXvm$mYnWS6O zWT_5`WkxX#v0|RCl^JDoB5p>j8_NU5Ufbw#`$Opp39!h3r(`-R$jU>w3a!AVG>2>3 zax=`C@!Y{CX{o-t z-CG$_?S_f7l|9nlER%#r+L_&$(Rh6(ii%pzXCOzlY(*fT(Ca=Mo@>#I)YQYC^bx8( z$<%@?6pcMIQo09nC!}?V*I3F$u|3E~_J^RKU2&1!!B#}j9gxLhCKeHLXui z0*qN%YI4#sP^nlPjWRRC+fmY7g|n^UJtPLKVzCBlYXoyjbLRjS+CC$V!fGk95w6}U zZIPySsRh`q)<~!J&}`8a?D`p<7JUyyTKjDU&bv41m=(t=u>Wp`rCNJBIJ9ctHkN^@kuS89eTbyZdf2GP|$qNQ3&PDdR_ zTA&zHm1eP%ZO}!rBW1JcE-k)*+84;+Vk!T!i$f|t%~e%gDkJsSaW0q07QIzUHr=pg zlL?B_-6*+GB5b{-2k+kyrUvgPlaJ^fU%2+3+djDpn7?T4ofWU)(`He@p?vLV_{Nd&7xmg7-~iFS8fF0oZ) z`24c*4||2FbYbj7IBoZYJRyvlGn67K5-prkWsXHbQ{sGLd3&E$m@#fkRPwj|uw7}c ziFq+XiE%s4m6J!v)|8bZbzJBQwGHUX%77L``C5J6QPollYC|Dgy&D_#xGS?N_H3BT zJZ&{Tx4%xQuc{6aJjKkfc1jQYE{&IAWyev~Du)r{rEa%UFlwBWiTw&x^mL|~nOfno zi^!^JN?BZ^)&|lsYK(>Q>Z1WjyUN#dp_+`mWS$)ufJ5Fut*TJ6oQ0v!;r8NLVFI`?p@zwGUOAUL>JORDn80k;V zlldX%Q9?1Q)G_3g)kqUz{V*ZC!55t_b^@u=&D?OO>vs8Y>S~*_VJ&yIe zR1%cLtCTMF0+m^nUp}U|Tv~&71ygpG{X45%-Kk^g=|`B=`KaiuiHNGM)N~4E#}xJI z{HQ8<)SKxHz`E8)8DmjcLiJY)axn zx4^LP*=5csEhA?*PU*dfHoB^ka+pk;B|R!QjMK6sr;S!!CT2p_&7|{KwjtG3A~jx~ zT1GvshTGzY2vvVnod+o+;y_-Pwb#U=NdvY3s{Jlu8O(CLkEyV{$Q=$rHlA1l$8p;# zc*h+qoNC{R$|9@itf5jGmIJ!AhrPElBh{NP?GRZdZ)R!Bt=8aF0k8qndf(HoNY!24 z>?=~jOF6PE_fm2yRC^J@u_~n2Wt8La>!Xz>@~gqO(yVRu`$gR_~Ee5=qU}?Sf7Vw}@~C)bgJdg|7c_JxI&4#F>`!)@rbtl+I<>)y~c} zSrnEvVYMJD8jOdn(EbRS&CqB-nQD}A!IO( zwsH{hJYwa*X^+(wSb57ja)!zLrd&+BSr|U`v|J1w0d}9!jokHW2(>f~TDR_smO!ww zArr>kQ+lzi+o6)o=(HI3WGPxz9JgiLw#QgafQ0Lp=%eh;msjy+JhnH{svRRD#IOai z#w$znx$MGGo!rrRcz=Oq9$B@DvZ^0wXk|S@X?%>kwv=NRfU+ba8o2LdKDS%%SyWlGEwvF{fK%myUDf_$xqfuON6Ny!ZroEjHoYa zzfVmoMl@Ep9Qz6^Q@)RAYCN@W6c%Ngw{?^@Nvjo@sEB$1NzbksDSM>#IxF#3H}ht- zmI&5{PWz09(88$5eMy?N{K-CG_T1PDYD!O{Bik|AdDQFb+M}ezUUL(vYwszbT%}Cy zeTB{~Sne8cqc@0vWJVXiC@qk&H-A>4yeS|$ znD}K?TYJ`S!!GAkaJGRKDY)<8+*+tjORH81kaacn?gyHwxV1cr5@+w$kElz%X4R$Z!Qlv86}+jW5C<^>(8 z2}^s{qpVJjdL}i)dX+P5J!_&`#Rkl#DIZ6q=w(~%oIZI)T+b==W>$}SXCXsupZa~H zP@>XY8TIOJRw!NEa;sZz=4l+@AzN>1uro8OAR_dh(5GyVbM(4!m(m?jOhOr|^g_Kw zC!6V+^ff7tCbxf?tXJ1A(|d($)SElQvQXH9rvQ}kz$wKQ<-CAuTjpCG@>t#hn*zZWJy}-*B^$gjQZm;rIA$e7%*q6zk zP&TWff@smJXR6lH1AC)shicDDlWaefU4!ICww~1bP%mqPjct}((q+&wJgcFLEh@+^ z3E8%n#k;R!?+8S0qf`kJnNn+&oNQ(jchWZ}jz3gv8lh6PpE0y{@}|4h)p4QwcjN#o zs65ZYWm3Z7)el<@P_LJ1 z$*zh+Z-cM&HgRH=C4THd#wxKGgR4B<&4X)xRlI|%xZL5v)oRt-8CoS@p>a`asgt2q zSD==@F~(cfM#4>O=cYUPRh1RFNG7_y^mxqhwx~3DB}bmhZl@?u^W(g8%-Yo$!o zvIRGf{XP-^o3?ezm@6r5mq#VCTiN+YZ$}hS7~b*{j*ODw6+)2}lIgIEP#<8wFs8iP zHVHsp?TNJk#$M!zC890CoRJmpPMOYk#;6`CZBulDHuVmUoj!DY*&@?!KTHi{nzc_R zVlg4VB41Zbv@klH)4|)swDc&)YozHXyQy#6HmHhO@%C+Txx;-sPQ_W}IcD#+R3GIi z{*Ee&4K^0p@l-L3QCiw8DunK+a!;#3O3TsjX{+6s@}$6ajEv>&(z-g?i69S3?FY62 z$9l;mv7n)@R#8%@hA1KmPZp$? zmQ)r?Ul%XlMy65n<^dtGB@(gC3K9vC z@M5{O&Z*Lgb_9f=6xEsVL@QQFc9`4rNeU{RI8>@O))5YetqWvGqht7xw;n@NB;{Yv zhL{tJdpf|f@N;^)wuPvP=P}s@Xrt=fEG6XCj7)Z!t6;Vxb8WlZc1(QXqKsSQvJe-q z$WvrTo+DMvEwr6F_dp@w=PEUiE@bOx$`&XO)F|S3phpwYmvYrqM_Izc76;TSrYmfn zR1fjjeipP{UCtrz^^r}X_bkJ!S;*}05`wlmTa!CI`@$N=iC_WVq1BTR>tSfraE=ub zQ!D*q5o4&-gnrXN&A;pcMV4;bjVM-0&2?y(?IMp)!*o?rYS_cZjvud=0j+V{DnPg2 z?{52UsG&-p>qg7*e|ox&aah}SbaJuXVEEIjiZV9)J=kba$sI33sCMtvQP~jVZWhVu zh^SUESjRlXSdOt}UU>hmeGHXlKviZgWgZXNU-ed-aZ2!s zmDQ4cDkmMo35mTTGmB%u*r_f@bLq3L%=EG2C(L3MSdEfJ=2+!G*49F)NFUEh3t<=8 z+C_sLpB{EIaYBy6%{b*o?W7Mo$;#yXgm5?xL20L7ty}1&6+IN&^@tdEq}djXQn)*( zXLp>ks%h!i%&>HeoSw!|t=TqhH(@dsMagdGKplf7#&3sR$zJ#2Rd{XuaSE=;Ic#Tg z&mmjd>#BN|tCj7%>WWHbViK{-8{wANv#l?v=rTs2)?2ksUbf@M)hbQ*EPCbZBa>3HL2>0?1lec1kG?NzP2@<0uR83mjrC9+n|k%_2x zS;=MH$K%PUZDSLamN7NV9hTAi<&+>I<9H2~U*6_rZ@UzLEK(_ETmDBC0Fm`XCOeS)@kEq~NnpPY}QmSeQ7QBpuc3%lTbvi7zBC4Kgs>wnqf65`L=TbLPW@A58AajiD71FB@Z%t|D8i4EODu`R^JubfLP%ucAiC(A6q0;6 zi7xp#5+)qYE(<u4Ms1q6) zhO#npSjo_vl0sWC=%nJ*MB542TU!`OW#75jm z=+yD!VoighxE+t%-Mqu7vN})p3}Jj@jwR~|W3(z^4Ux1n`57oNKk0?;iE->jq9sgJ zwk)+3N%^3JqHRU8UBiN#7W zXZm?Y8+X^Cf zY(^eUbsLiw143u4pF@w%Zu~X3icg}3B$4#S69l`NRdZkaSq8N zImbx1H1$3RqAQlDi*OaE!Qxxm)`J|Al^-<>Mcdhv7W-F0boxDLV9z+yGj&{&~7c-QbsVQYjsp#R6o-9?HC+K@tIA{{O(CJZ#Hq#ta{;;aus8h z8hRqKCxeJStuB-pGuWojGLw;nRZn{i?N92DENPZQ zutk5ZGoR<`;NZxII@@*>(q34ycb2C;NyVH>pqXZd znK_X^)mb^`&Tq~aPoa0>td(B9+e-z?)9+VT~LFB!_US z8jvF!(>*L5(Z!YpAJY37FxBqScD9K6P(4koAfIO`z19z{El z^VlP*9>Ejv>fKtFWjWN3S-v72vntRGs!A%!NC(fdT^+T|=N}=_FY!oPX*^zv&SLav z%Z?r{zR@iocM`-&E-;~$~z`zsr~ywK|` z8efb0iC-&4p{5`&*GsaSvB;}}RKLy}SMws_MUEa7S#0SX`Ad5*C>q(m^T?~<^^JA4 z4f1ZT9II^g7~MPLY1{If5V2#9R^}wNOn3FjRCeswz7{!dQL$UACUh7xztzL^H!nOI zFuhQXBwQs-J(*3b7uT%%wtbWFDym;i6Zkr9*!04EFWh&_FE04Ss#_W^XqZ1^ ze&;zHmaZ6j+3wjPIufUgju|ob*RGuD zwOpl2`i%kObvf9XShLH}J_oPk07I>VtA#F$6O%C;cHarc}_A-pC;0tHfM_hd7 ze6q_I?>R&3`it24+2TxS#Kp_bC$TT+cYTethkF{y_ou8n)acctkG^_2Nv;f6Z)2ae z52W;7yE*wdJ{R(7B=x4__BK)uNpc^OWDJ)2Z#&5_zIH~K`2Igo0;#D+Qc{x0>1-GW z<6#0!1nIw%;0QPd=D=K-2lL@r@WN792B*R4@Dn%#&V;i-WWYJ_Q@9C!4eva^>G^wZ zz2}#={_?bYT5oOL^!z4w=+2H8{BR}FS0*tI^-QuQbre|}-^d_hDgKe6vk@THs1e`D z(AgLl&lssof>g(1%3nT;ZC>t! zR`?vgfP;|vKLQhufXVR2QxD$#;7ym@bm}EHUGmi3Pqp6NdaQM4I%(CZUdG7Rd0pyJ z{5?j(-BVXO-sL*H*rjE}Q}UhFT&y;+y|x)&o6)86vF-`+={5&Qog4{MU@9C1GG6CG z9xQ}Kuo&D>2Oc;cPJk2P61WsDgUjIxxDsT{{{{RKeh+_uKf<5jLD&c{!z=JAdW zZ)W}({|L}oU)8;(Qim72w|pa2zaz zMX(s$Py;fC)PV<1fgi)382?3&?ObNWSF?X&-V%SS>P)7@()Huh0lr7#;7!D4X3@o)m12q(iDI0Zy!JQdc$)o=}53%`OJ;U@SqJOB^Ezaf74 ze}lBJxNZ2lhDT~Yoz!rAQbIH?iCM z5UG!PSOQC78Jq{_!v$~)+zPkBdbl0#0GR{c1;2&A!;|n7`~&_8&%&GV7Q79q%oDpo zJo3LUbI8u?Qp^8~2yge)l`gG;I=tAW^}Ue)ms8qtm&yTBC*7eZxS$uv+kKi1)V?`u{|v~Jrgl_63e^I$$4 z2MeJUR=`R)A1;6k;pcEMTmqNEWpFwC4(^5xa1Y!IzlW#c8TcoB2p>T_^8ddBwpW*0 z{;$yPc0*n1()xVA?Zq3<%&W7RTdXM+Kv!;w8O zd=xe+xC+k7FpQtUWpEAj9!>hkpsT{cnTBy-mSJR$WlV$rf{Z~A-?RSKUHK1JZ;q|5WBnwmcxl~7F+_?!yRxhJO)4}Kg9caw_rk}JIS|;ls(MaBVACqDs^>-WPKAo9I8a$RKn zFjxk*tUrzKRmggg`K@pzeh-*@@qGe-GRv2_BV+MR%`A@{tuB^iiLXH1Y7alkjZi6l0LJyw+qLWv{5OnVYAs-r{ z35KG34}%Ss9{viS-O<4(zyc7x{1UKr^N;xcCHlFoqbKU6UA@FvAYX>-Z|4Hg{*eS~ zEI3f+OZ&hCka^Q=D1+nSR(Ks!nL`~4_MB>sHLv;wpY_bAmcR?}FW857B<1W!N`^R76v+a=B-$~Zzl>5}B^-bg9_6tL@G>f&IK`S3K5Iq?!`fOFwm_!T?` z|ArT#8*^rvHxGrk;Xg2hIke29$H91*3qiOT?uHkk4|8joXJ^6g&D0(YEut~(!Fax{ zpsoHdZJ@VQ8Ff(xV*6MDE8!P#JKO=!f!IVohLUXNaIg|q!SCP|*nb?)UwM5}D)R=|3N6#<_wWe33nOw_KZ40{QXXNz)o?RB0sefx z!yN^L1@9Cxmn>o}5^`o>gNB=6J=_Ih(B>g|4*dX3 zI0QyPAr!;85SWJz9Rl-tp90d4rCb*HY6U>i)J{_8;6 z!WwuLq)mJQU&28XS<`_9a3Wj>&w#X<_u-GUn?J#SK-y3WZ73B+Kt3#jU2ew_0emT0 zwErTWbp6G5EN!}!lnx;BU+Ur%xE3A->F-~`VEViC`&`HaFPsP`!Sx{W;9=;FED*Vn z0U{f!zza*^JP=uNBisZJ!4~L=%;@@hi8BRX+RaKnKf0XZi zk>R#HpUU^^;Rg5wM82CxAuC}aoCy!XXE1acZ2(06FNb%)mjCI<{^Q{Uh_i@(Xr&)# zw)dbjL;Z#NztqKV8GnBVf3wD7gK>B&1fdmv4Kg-A01v`DFoZFBDlCGvAmjF(@FvLk zZ7_Z(K{nLDTDTtm1v`_wPj$NWzp*cNCg>luA7`=g-D&$3{eOtmhv-`Gf~{|zkIwbx zbm|c%qF;&rRRf}fT?n7S=Wv^)b3Mf8vzG4F1O4k@^sk{%0iug7g=KIC{0bg~I14?| z|Kl#II7?JFh*1BRx_BABg#Am<{ooil4Sol&fauaa9s2Y~d@n?wE`p0d^y~XTbnFkH z0e#vFmsz^??R?$=o8dj^cJ%JfRGfK_?d*T2owcifsf)od24+GFoCE9N&+r-~GcQU9 znIo0JQjodQDez;s1MY;!;BnXrJ((}bTxuw^fXu0`0GU^9g4k8@Kl&u11%B=n+q<_w z+S&i4E`~6lJrMG&x$QhY=R-4`0oTArcmLshJnYh z<^xB8%$4WCI@rCLN`!_4kFU+N>;F<0V!wD2#DDx-=r@n?1S&!7A3?YP#14|Eu`Viua4S*vU#W|G;9htIK84TV(D|(4 zKq-jLDhN-2*si_;v0sgZP4HJ3yg=Kt3i%Y9)(UVP$9{5{05xzHoDFxw*Wq;R(Tgv? zrFg!r{Ooc(R{u}7?Eg|%Qb$rZH^Hs&2E4O~{e6oWyWu%_8|J#P{X<2`%|)9SFj z!m)4{{0YwYU?+g;dfE+q1Gg+eH-v>=+6T13lkhM2%~IYiT}C^Dvtd{xwkEg;u7F>{ zI=CM;!jVmkRd6|c2&;X>xtw{bpScAL3DEvvCHw=X1+inn99Rf7uoTw8&=rIQo8j;9 z4$NOk9#>)Cgp@YIgnxr^0&7^1bRsrnxB_klIX`PBEx2#J{#Fd1M7JYhtt4fCM|zBU|xiHmQqK*GhYA`kYdrEkE&FbzC#I$RGA!>iyzM#Qf2I3@Pyq%HIpJG8`; zc4bXLt#G`W?%u?lU3#kJLqv2IlK91s1}oa2-4duYW$mY($ypM~gJMbHLH@8a_USPy@L_n~(Sa|f6Vjc_S!fGyA$ zJuMf$p9TH{NOfq;)bd~IVi}13d;w&jKaYm#5P%@qdi6%WAAmkB`gIZ5I`&h17d?Al z^l4kyZsdCt+yJ6y{|WAcCt;UM@w0Fyn5{Z5Vh6o7K4-B5_6ka=?-_}bYp6BplJfrQIl>Hks}L1=}`!M17K z!uM4tY1_uvVLy8`oz7?y-}iV4Nd5OTjjZz;l76&)^B8me%To?sKcd@E7;sF8D#K^g8d=78 zW1=y^$TTMLInl`B+5cwble#kJT^M-|b>C%m-o=q;b!E=GH1e@sne#4&l#WY2@R(GUr_y`Gl^_d6z~$u`6@lrIB}`4wuuF3Saqqm$>>5gs*5Aq^|k)#Xzc^9ftlQ0c+Va~fy zjS_QM7v{VRb+}1gsl!d`N*%5XBNszhm)YUEJn}A6qa^1N`FHKFKR*H7%Sd927rzM{ zN*qFA+K1bc>7RQW-Hq88@cl-U;WpS9WQcKpkde<;<3%%)Qe|^-(+pQ?0D>^zNSc;} zoB8;388ZwIzUm0Q*;rz*)`Z`I#Mb?gB()16)!6sC4~+iT9cfG(&bbnX^&{4^X6PTX zmfzL3e#F{6(=-+s$tvsxQNtD`bs#aTu#@&Ga)zBm+=M+rej|H``W^OENxEq4dI6BYvd)n=FKRj8)2Y zGQCaG(4RD<@-y|R{Cs>W8}<9s2lmBxGM{PGWR+3I%lNwABpZE*X1LK`Js%$NT-tsw zqc7*XeqbyFakpO-chZV`addz0wJ#?v1aUXOkoY3QlUCWw*f)G$EYGFiws$8jt`|A! zz4m^7UHpCo$Z%vsM|aYedKvrSZhh)P5O@1WaVKr17b)t!_Udj6LEH_F;!avdFH+Qd z?Rni7g19>%iaTimy+~2-wQG7T1opNW)zhvu&QBU`wYWB;gkyeY!U)PI9WE!ZH((1q zP98VG-yny4oDEOIG}3w%B(siM50Aj%E}p}Gp|%(MZ(!tJyn_p`L($&s%ZI(v*t-WW zz$DgSFNM$G3$TCJX)=rdM}qve(_HYta**F}Itwm=>){T#7aoIW;5GOFz5)3SpuJ%z zjDg7@zx7iIi$H!$W+j{o=fV}R4&--Z?uWm^bMOXifvxZ<9NL%qglUiq%iv=83w#a3 z`my&68ek2`?+ttmnftQe6mEc*VGA74pZ%@y6SxoVhcDnu=)E6lhhZRRTQ|a5I1Q?( z;A&`vi{UQ#EvyJFk#;W>C7K7@~8 z+II^_Yw!3%3ZelOq`P(PBh4dDg&7wmHwZ2*SD2$%`=a0c82Pe9V)^l=yp(;yd? zKm(i$*TS#hG59yU2;D~E2ZqAi@E;hGL0P~!7!PwH2p7ZM@FMgXO&f+RD1&lX0W0Ab za68-q&%uA;V<;Iz`-YXU3VsK#!2X#$gB5TiY=np4MR*COX3-Ad7?=aALC$L20MEfT zm@t-h1Si89coklQFW^f!D4TP@U;&&6*TFOJ9=s2K9LK(2_z%1TDdVXh7y`V591NxaYk%i$e(7e-7$*2D2| z0{nI=bpwBcC%`z0cpwO^@N2jk9)Jho9T+kVH?RoS!X0oYya{iCkxTo8Y^Z^?a6SAB z-hp?aEswGQIdAXHeEh-00>&DsfeYY5_zXUW+X{J)10I5Bp?eW!3m%-(5 zJKO=A;XUY9N?U<3FcVtf99Rc`hSwl@HuV6rpahn}GB^c(40pht@EAM}TcKwe`Guj- z0?XkFcpNstkaGGmybXIFiyN2+|0*}ISH}BlRd2l}54IAJk_yo2>bq!?>t?)H`0|(X8UZ4g} zgInNMcoZIk_u&KRQAgW`DXvUV!!r$HPtVZ%7Iv58zl>04v}scnscwlvc)DxDYOa2jD^YH@pZ} ztVABbHeh0E^nt$cD9FBlqm4MAH}ruZw8G_Z1>6j`z^c`x3ogY=?@a!YzcoVQjuZud zYlJ;p8htvHe8)R|JGhDGPQMPmzH4_n<|3XHcJ$Tp&h84QV_occPw8o-nn@9LaURVo z9FF{6bK(v~B7bWVrSa{x4c#)6tdf_~k8Fox-AUZh#bc~Vl!miqCQ2hw8medPQol$t z!{eZCQF6zYNb$C@K}o4*a;Bt4e020BR@q27mbl|=y@}FDl!orhiI%W4EkVm4ky_E^ zkF1JB%Af!BJG#V@9VM2YoNA^h87}KTLS%`_icsQ?>ZR!EKjhNTEkSxy^p+s&bdfC~ zamOjOzU|V`^(B2ddVR^dXJmc-&)=EmtS?m>-}yVbmQ!NZvaC2q*7En`j?PzV%zVkp zcx1j3cbu*F+b#`VU)^HXm+Ul%tgpl!XMII44PC0;W0tDyxri*)#2sg;CQ2hw8gw2s z^Y3d*&=R0WObMWNB=IzCuS?uXl!i2UW6hpz38u0P^dzF_^9$LR7CAO0?l@a!qBOd) zG_<8l=1sP3P)l0rII?R|h-|&Gk1=sa%7?!-iPCVk-sq*FTa;MLqPHm7l^WTi5_g=X znkbF$R%vLNDK;5fW=6JN*~Of=BjS<2HHp%2w%$Z(e0!y#`>ELCqW4qTogdjxrLEo)>oo5y0SF1#1=b$bcrqR0!6mo z#2sgSB}(JlER7V$?oeIwa>w2s8gE_bHZPX#=xtu!D~oLNi960({-KtJ%$*|Zz2lwl zYu@#n9kM4!@+538rwKRCHlHYsA3|vun2^Ty;>}^0yccis!fAW+CUP2Y=faQo;jLcY zzWXtBl3Ki_q#wqN_;9+4jV|)m2=pW3R#q1MKJDj(7$8eemajzcF z+uW0Q`};^vqsZlih(g{3o<%x|WD^mrBVhR@c=0fCb##`0$HnaRnocvOl z{92Uc0q+LhjX5wE@XCpAyon5C)39Eg=f__-c>tKo@DnhcCITMdrE$*D;%$21#cyLN z5EW<4af$-?paqDUvzd5v8%To6v&3J-S2;21HFzCTQA7tqHjIY}Ag3wKg{5#hoB?No zoUn8=+y$HANq7q6)TK}0M-1?jVG2xzX|NbhfJ@f8@0mx}o^>9Ai3hUu^kQ1t&g14X>eWxe5Ku)bX9FB%2Xo2M* zCs|zx_rTNeEIbEty49C3kiM4<6JR39iC6Pr1zZ3>hl}A-*Z|MKNAL-3h0j1v_}VwE z|F(VSUbJoBL#wv^eB;kICBAnoho7IbZQEd)c^W-?20b>&iH_l)b&@kK$9D28TRn^Q zb5Igy^k>lAZ4GH>|2rD5wdD3E32{&DC-Ae*%K?P*s6j{ zklW4rR1Y~VgTHCaK&OdrEvx#d7zRU`!4PCvLkVYB%K3%JMnGJWFHV>NlBZ6C?8|3A z*cbZ4elP$A0_p%~ENVF?vhD~xeL|joLY_V#PbZU~E5RgBAC2aO7W9O7$1e!?W-z{2#mzAHmlk1=9<*QYc@;VH8Xj z%%xBk!3qlH1ek#!D}x;JS_Jo@8*PM-;8Vz)f-V7hN0ARWmGU?Xo`sj-5Ba!>IEgwu4dm3Giy*y$ z_74?M4O`(GINXa443ERpFmoAWHSFI=8lh(sMGr5-7Wfj9X&VRo&<$V~%!cRSU$B1* zC+~pi#|>N(pj_Z__&c19!goGw0QvRkjhtBX804))zktVJ6MP7tK+-Du5Ojl{;DWtj z9xQ}bI3AMQcn%)$!j2Vy0^jHcaJyw87j~|0bk8?q!$CV(`G1-H^mr3Q zdVB&RJyJlc$fmYPzHn@2pQWJhX2q^*^A$5PW z@*$)d7C}9{a1i0cKFk&e!oiRWrEm=V2JVD+;X{}<6#wuHBo9Msj-ZZUpLF~~pTm%F zZ~HM0q?=lj6}!4DmWfyk3kZ_J@9*Y4Yoi< zCS?!PvXBPw06Y#yjztQ>>+mMjXEU3GTi`BucO3bFvzZZJ1b>I;U;H3`S2-x3GT_vwBT$w7rud{BZ-%hV?AtyM_|S@@(4@dRCpWS zgXCOBe)t(&0yn_T@G5M9wTvuh!tIPCcfeoZ5qKV6fU4hd;sR@D()7Vbp~!^Y8MQuoB1Qms8@_=H z+>{U81Al-I8Noh*zt+(1Q2jEHg2RsXMwwsJ%`7i_K!*Osn{0v40(1KtA90w=D zNpLgV0x!YKu!xb)4Q+5dTn*R4-ufl5}_P@{fK?01X*TTOu!>1d|{Ot2ABnHUaqxK2L zYxw@gQAiWGt%#8q?uS3a8}Jc)2A{(@NY9_bZ{W9ZAKVYm!OQUZER74@x))4FN*o0q z@WNIk!WS@v-Y+`tIrQ!u;a>O`tfd!U2{*%|V4tFx!c6enrw1q7_oq~QV5<%An+Gk} zVZGRyYx(_wBe3ZfV3V!oeiQav`Ne~PVPe^B#-eLtq4sbms7}yd!jlE&otE5p?fqXXuhWw8 zIxTrI*LW58qY1$F&X5rCmokW7T3Ndp@0r^BX7Rom@0sFVoQwC-6i_IL9uXmsf)s*S zoYHsg)nBO;EKVVa#VL!qCJ1qD2QixTgoBY%4*#VLN+p;N2&Rt?<^u`l1A^%z!H8pL zFr%q1M^Jl(1Clc7Mo?=~`>tK{rApD7RDxQQx|nN%61VMx8ckN6!KFFEOBvLi;QDmy zyY_=GRB(N|5nP{ci@7E^aT+bS(KM!rAbW?yOc~UJAg?CK#X88VCCIA@aeS>80P4@hep2GgJ7Po@9QeC)psXBqKwma^RZCVB~5q6;#h2p`d#9AgG=_ zbWr-&epC>??F8|xD-^`DE`oU0rGw~3O1kM(touO9Dt0Pv+&dJ+je8TsjeF}Lk_aM6 z2XXgyf>_l%6vV3D1hK034rgRWzfce}`Vqv8emk6zLHmV*7_=Wj4BBspGxFxZP!Mkp zB#1W$?r=sn3=RdcVK6~#7#t-d(gp_hk$?4HgKo~o&Ni_qLG5T0JI_uF^KdIQI*9n2 zSj-^eZ(=cnh`))&3?lv}7Bh(Wn^?>s;%{OxgXoeb7Be;ROR<Bf3gQu!`_GGCX!I5O->Z9Svi!x2J(p>=mzc!Q^uFgMt?5OIU8%|4dZtiS^4FthII3iIrJMCkkz~AzyGM#EIk{VMYRtIv@!6{4m&v}JdkihzRgP6$ zj(@_*uyQ`qR@5oqHCDQj8CrQQNK(pYfEy_1*99ahGwIamp!UGb7!n zo)CH6`IY>MPf6tbg3a-?~`eA+KR`n;^6&&}ueG!7qe=W|j+ zYj_|NEqQ((h|fzwX5t$_Wco&ssr5fVMBU3Ea_JpV6@X`%@b>3ZireI~7oSJ+xi_CP z_>^g96`vS*jm3P*oKd=~bhQ>f_vLdHpAx^U8?%(DcD$4qlxO6amENY-Mt9KXH>(5g zB~n51T+$|g@?FwV6KHK|_Acx2%;`?jGu!8HayO2y^I@eGzj80nS7TOc?;-!$6p%a@ zJ8G%7*6$1W>VxJSpTEwWG@57AxNp4NEkkDL>U;T?PbxlsC`o-^v3Bh><&P#wIg%|^ zo+5_iT11h2CjJs7kSKvf2_#A&Q38n)NR&XL1QI2XD1k%?BuXGr0y|p*vF86WuTFmY zuTNh&`hY$cUc&r;)aSPqaIagtdoouSOQ6h&W!~BVGFNW_u>q_Fu>qU|VmG)5WC8X{ zka_TRAanX#K<4y!f$aGD1BeY^BS_e9fOD=d_bR>lK7Y`&imz&ZEJiw+CyUWeKE;G2 zpFM}UR9t+G`FRkDkn~I3(QOE_BV1A-GknQWl{eVvQQ?cfO&B=rIl9TU+{*#+F%9He zzDv3nl@}K*no&|bdsd~oC-#e6?yn_`^Z1l-rWyyT&vUG6KGe08>5o9dlRx<`Hj-%X z&dK{uSv+%wce-`W$4-TpY5B{-$|2#dv99^p;qWH%rq(3OpB>)nT?|jkT+(HShsj1= z^RZLun`rs7!xNLcgfD;cxg+%<`DJUl@@I!9{bg6e8{aOxnq3TUT)XfV>|%I!U$pak z%r1sEwq5$lcQHJ>f7t0`tNbq2N4S6Nr@|@NrSNhb{X>U0br-`6_YWPOeNC_`y*t*P zb9hJ7ZqGVAyMA^yym0@};f=Dw-`ViO{X>U0d>6wD_YWPOxr^b2`-cv1@GgdDmwy)T zf{I+}zl-68`-cus#+sd%S27~m?PahEN9^!BAD&3m$na#0-Ieg9KP3JVC6FkAL%fkQ!bv=NXFBSAKm9S))kX256|1ENca zej+-L=ux7ZiM}T~r0AtGmWzIH1n@epaU@Iu(V>rmX^;zfkPo7(7eWzChZ#@|GAEb? zB~S{pp$y95XsCcnsDf&cInErI3-e$;@QN#M8AYCqwU}!+)IcrNfd}eg2{eEgmclY< zgeGVPAGE-7@IwHC&24*TtDp^5!|`weoCqhu$*=}a0dapSpKIYXI30chXTX_o z7Mu;|z)#_4a4wt&=feeXAzTDMhl}A7xD+mf%i#*R60U+@z%SuyxCX9;U%_>7J=_56 z;6}I!ehoLnEpRK`2ET#za68-qcfwupTlgK^4IAJdxEFp8e}F%NOEnnX2leg-24c?~vbT|2sx!;?(f0GvImXA6?hxf9@%NoBf&T|kTp+Xn literal 0 HcmV?d00001 diff --git a/doc/sds_doc.doc b/doc/sds_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..6e694c44d233b894f95868c0a47f7c5e9cca498b GIT binary patch literal 74240 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ⅈJ^3 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 literal 0 HcmV?d00001 diff --git a/doc/simh_doc.doc b/doc/simh_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..aaa7d367d200afefc014e167bbe25f806f487530 GIT binary patch literal 198144 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 literal 0 HcmV?d00001 diff --git a/doc/simh_swre.doc b/doc/simh_swre.doc new file mode 100644 index 0000000000000000000000000000000000000000..6a3441125bc7f822f84c6c0220c362ce83b46eaa GIT binary patch literal 101376 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 aQk7YLr`gxjrW^0gxJjIop3j$B1OE?1gXuT` literal 0 HcmV?d00001 diff --git a/doc/vax780_doc.doc b/doc/vax780_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..07b7f872347d45714e46581bd3a85291a7d72724 GIT binary patch literal 125440 zcmeF431C#!)yE%;NRSa1LR`nFNT6`%;%G zw*6Xbt@~cBOSQIYtB7l>*4ABX-Iuynt-F@*ckaFK&6`PvjEW5{ME}gpd-vV#oO|v$ z=bn4t!++lP`3tWf_kxx5H`5wo{d--8HOzB;FyH^_{NBd0-sk%u@b7i&*2(2}z`KB- zoB#exdf=@~*H}yM$QWu_pKN!#5Ye)rEPul-EBrgl+S+P3wBgWg=5I4!T}}8WW9S%b zQsp2kI$a}teZuWtKh~`q`tr9C`nP;e8LPjq?{l>CIG;iQ`8mft*VpH0 z*mvn?tuGtRQA>6h2PqcctQxpo)JI%$YyRqSqALwT-h56e1%M~&+i}^B>g%4@E3Wgk3XrG{5hXaI_FdJ_5L~e zIiF5@oiy_M8GihM=f?24(?0r6@~7lKZg`wtPCm)`O8ijLS=Mdvh5WYp?UXO~zR92DBjr2gIC(krn#+A*F{huMPlsO4 zZ|Bo_KGmm_F8R~pN9Qxu^UigreCKzn&*XBP-%dX}zf*lW`8sq={_O95a{3MR+o4yg zdZ)VX)c31?rpixbvpv$XzCbAK1J`e1ZO6Ydqip`$__0nbSJwn9{N+AhuqA9aN7~vVD_T32 z+KrLUo@ndRmM*&^($(4+wnLqrZLQ&$-4(IBNLg1=HQSCwx}%NZEW4q#BNXk)vO^tB zc2lIWyFJ{|73yk@bnN5v)sPFf+sLsgYfqdNYi)1UJ*gg71W_dDj?n_4QI_2vX=-hj&#-Ei>ESH9sa3LW=+#yfVj>#}ZEZinE=@go(wn9@=J55OXhrXeF(?zP>6)lnW#Fo%S&E3%sO;ny~ ziqK`M#6!c4T@Jf=8LOkIRoWYaIfUmz4Uy$x)s{qlqq`LWR3$W34J*c4Le#w>Y&uLc zlU#C|L+iR5VqFlvmA>zcL{)jo&74H}v&-$enpwdGC4q9gqRy@j)Xc9aD=)KmE2-o6 zZdvw%is0;;`k+mUKuLA*0J~tFvnYc12ZfWkosHDysdJ z^<@>+``e{F$LO*vE2=7jWE!lor9hKaMLEySva8Ai{@LVQQd&`25j-Hvo>dX7mON*X zX^CB15@2}NSC$0q+WJ6kO(Tu5*#D zRUP6|fF#mE^)%AS&@L-4sU$DRQLS#e^n!flD;vX|U5rX7kHl&1(5#@?M)L|I5EknQ zwX30@Br$BwNTd{IVn`{e6lz+I{ArEJIAoke$RN6+H5L|D?u;r1c19Z+@``|WvwCnS~}2aV3(VFyY|ooA8cnU}!~BeTn_aHy*r>6IeSBAsVJKY13bJSXL5 z_-pHxfUWC^b%opQvhZ@mRjSO3b>@ZrWIokouCq^3(Wzdm&v^*1!W7&*v-vdf7J`j;LV?upAlG?lPjZ3)qhr7q_eZf zE^Cd!{DFn3iZP?O-(t)#&Yx6}QOR6q*G5}q2-umGwZT+*n{k_)*H077z%9s-%BCP? zff=LyW@ZLy0i+Dn<`hiMDV&@$WpYkYmK~_d$(x*$FISjERL9hY5DjI~*5#r=2WnF_ z#0=qn%Qj=U07?fcF@*w^IqIK0+aHRe5H~FiI|QjrRhAjix&2Iu1!hPW2;JvSk;3NE zPW~zCRoLvgsR}a#JGY;?vcQb&0;peKR#KQ_SJnAzbyMQAg>>OOx_Mry{NtB@%2E|< zMtyES^Jsw?_DJ+lXR0~5z!~NJ%yR{1lo!Gp!73ObSe`p&au+WVBLiizAmz$ed0tM8iD1Z)DYEf=KGg6@${Dm+S=F?VDZZE=xjp)5#wFWCVkI)ef4itkJlNgt8vEG5X#Qp8e%s?{ zi8+oIl=UQy8w)dnZPMO}`mG*~KbB?pM7r(v?pPOQL$iqU`Bh7}oh4bLVQV8CQ)o#= zb#O|77&)B?Fvp11nQASR@9ok+Y>zOOAVr2dLJgD{UWreoiCJ3Q6WGL^VhY=t+F7wQ ziV9D!ceR8%?7aO;@m3_)NJ=j$D+}~lyj!GHZ3W&0non0u&d7*0c1~*X@!8tGq)|_W z?r+)}bAN=zwsL^2uYYzQ7K>?i(7#u9D}p(Xssi+nro%ly zT9$c!v}tD;<>-|8RK4Z@->D+d*#PmdJ5fB33| zx9J?{-QF+>VF-WYVQLcj)eymjApT9CPY+(#Jk~BQbCDd3M;7VAz-Vq=iU}=VMdNrC zml$*qcdNK8GGh~E49PR$7%tn|`iu;*za0-R7kpTrTP#)b-M8_K6_95Hb+G6J*ZzGDWN1Tml3hte9xTXv*5y9vSFD3+rS z(~j#(+ZBUP5=4EN1zEvhO-6>1F*edn%~-y`LQ*?dl}6sIHSs2tTVL6MQbU>IinB#z zy3ZkvJu_W*r+9n{Ci?tRwwkOOh1iHqCMzF0H(zRlW=m!0 zYgLXfEWUQ%?78x=t4d}TO|&V~XswdoLnht(`ne{hKKlZd^0=e*X6E(#bTbZo+j)2% z4|_DrIKSwU64MIT#loa%veSOX&olVu=)<%hDdQ0-xT_`YXAa7Uu9LcIS*N%0D5bCWRNaIkG=x|0btLqfB ztRu3b!>*{U^i?n|bhP4QZi~>Q%+f&V;ga%__qJ%KE1m)htBJSf0Kqc~C4rtnO&awiRFYza3m zi*>iNh{mtBNJuSG>4`%WPSJ_$t7_evFujRWT~$KJ6>gd&vsWJ;Ub(DhHapU(7ish& zm~pYU9!tBTxl>Z4;)W+#eqM@X-0&nTNL3~`Jjs|j`>vWysh+y!sqA{UAeS4Zni-^_ zZkH=AXo;+FX#xu|(v&eI-6wv#koF7O?V(N-kBqw6H49X4Rn*kgmiWu1$0P?ys`=OR zK)lFMTa4iqADOa#su|K#WXN9L8tv+qxtmp#mYx{KYnxjEkNV3OYxWG@`8jD0Hvsx2XA|ZA4rE_GU zi2t#qp2e;5x*%(Cb_@aC*rKXun2Mz=;W-L4=9VXUoN}^Iu2UI7=grmUt7bWg1z4B8 zg)u2ahE#KF6yp#vr&hGh8m&kDQwvr`Q=`U4xkIB^(bC%3;+T5~uiR`=&&a^2dUS_0 z(LA6AFe8@#rR|Z9wjL*8JP}$?V`OOul~ZzhepQ`4KbI$sA{bAIWY%UT2`N=;hDimg z*2N#OyLy;yDPFjnC9w#?O4x&XG=yYPF0pqQ*A)mzS=lx1QG=Q184291(kmQhJ`!O? z7HW14dF7lV{kqjcpS0X7OpR3YUW#{tbd&@WXqE_z)}E0afe(ztB)&j}KsZ{xHorxq zCtZ|uQYn^at7M8WZSZtQ4yj`OrXq*~CSmo_sf8_*sfSD}T8O6zuMD9QD~XSy7w(M2 z=s7igsez>nSM_fYK31v2lTAWBA5fbWecW3Si8jT!*Vf0qwn)cP=YA9SF%Ls_lv!h? zkhv+`*xDXy<5}sm#Cu}j%AJ;8cUq`i{K@ussdlEY>_pKPyy9Q#))`ObwyCzP7W>K0 z6bA}?*3jD4+6BX-CQM9zTu5cQ#3>|DQdY4LA78jb%srw&Xc+}9C#BLbI-|nFMy_Jl z8L7wI+Z~O{WF-ahz_NZH&=Sl^kG0uP0V3+UyYQkrj|dB`zfN(%=seTi?=v0=D)UV= zycCTB5k=og@QR+d5w@-3e?rwlkuj2swR2I8P#}!INIqrU8P@mYC0d5u@hEM|j+H50 zh7q-tF)ubAi%_V8T(1@DB0n!9gK}hXifp@;L6#B7u_sNk1GxqIK0ld*`02|i5nD~3 zVcA|8;Zd&V`7&npbv+-M-q&^VsjU;k%M@-JDQ(BG^1$zKpqU0fzcYS0#W&b%ZaY+`S*Cc2bf$H;IS3NonfcG>V!@cPqpklD2qyUsUFJ zHR}AOVr57gqsBTUY*6dGBDIAeZYo21htkCEc+=&S225_K%kr$t31pH}DL3;dikofW zj-^;h4%2ZvH~wsHuV-`P&tjw}KU?QM>NrUfi>`B@HurnyP*Eq9%bh|$IDuWBPU}Vs zVyQh|+mgCq<$O2=Cg3YIS{`om+^#CAEw7gRT%QasRwDP5lB-n=T3jW18A+H^m0sV0 zUC|z4LS)Q1iGqRJiU2lhvGNRcPL5Zq6Mr!BA8rhkl?SLjIW zS!<7wgz`l=##1WY$Ct4nAVx3Ea353Qdm(JHs7HmvfNt-^C=`V=+$CXWYVs2ilHhY| zZE6z-`2v|4<-3j!iYIA`po@v+!nnX#5!&exN2Q@jb}dp{%@1T$K^~?=F%6m9+-Y2? zN%Dl4AQfc z^X4B(WY;Q3;gmMS%a7}vx(IsCQ8|+m`g&KqFDu-}gGbm9Q4mCviGGGL+}hkK!IX&^ z%FPH2$$W}#VTOxI-6;Lk+{Xi&Ssm4k-eXEtjMzt3;V#LUs6y9+>SccB`5cIx3!PQvI>fn1Sg*W4@q*VrZBkQ)#^Or0Vnb&`K!U z?v(4y`zDR_;*`R|{3%WzlYFUyuQUn0hN12op@R54bc`!LKm0{q%(>Apnp%vi3BxKm zp&jKiNY$j+J1g~+FtsRIZ9T%)U3LpmPfIuqJnS4*wDh6*6e>hqvONQke_mA>UaSCJFAe5Kcyd z7@O^!m9xy>Bv}~ngn#MqGTnW0hb*K!JZ7ddJ9ca4c10>hs0ZSfKM#5)Zzb7MX=~Mi z@_C|=$=q2TUWuZFUn{qO>Lb~en=Ts0uLt3L87ggIa@xYwX~{D&-zlln7A2=G>ND*E zf1RvrNVXEZ8CJ`yj@BbWg84#g{Y+Z^I&oWzdXy@yHXEu+1LE(`&1b@IZHz`5n0=SI zyu=7Bt(fH~W75^iH>#BCZn}jlb&k#}cVn$>daW5dP~EKxnp((RCDj=2qAobxs#2AU z3L|xuRC-!RAw+dmcY{@|uQ+#Q*+m?KPD_oY?RQ-X$+3i*t$JCwaH+#IirJj{2>)xv z-*`1LvFMF~JW-Sf<88~5N?z0rry#}F>2jw(AjFntJ0y0hXqSlU zRW?&7iY2OOgGy6abJSE`)Lhys*lw{qozndr;FL4aPBo0I2gRiS5Ks}e}0WnVF! zn$WU*Cz20ev09>oC57FXQ$tbw>rv5$;VnWCm|b&i#q(wjNsW6%naCI;R=Y(od@P&LheXg%7H=0i_0|Ftikn zKq;!Bwrr#^`i7J=30D*XD=7$7=jSv@uT~~;qViURqKz%cl12il#W5<2nmF%d9cV*# zPKDp^2$7^JISeY3o-^hv)M}^nq?=e7(jK8v9Z$moi4fCtL2^O@SKu)wEtSG6)qTEM z3}4FB>*wN5baFw4gt} zFd?~=sn)SIOS+ylN0OKY3&$hO!ngA5;uW4%v44F4GtFpMs-|YOUj^(SS+N7;f$AFZ z8G9aa6!zZF_=HMoXMo|ULfnDhw+BBd>kjxsLeJXR)+A(*EIg9jyBwtbbE;dFK8=436GcbH;eA5` zlIL|WH|reGQd+H?jw@Q57-}dyp|%yFo|v6Gr9ry0e4#2YXL7En(XIo~Tc}dl5UiLh zu}*R4U{PaxCbj|=%E`{nF}y|#L|3FX=}tmQA)*2@7ER8nbtJiiij$hoRN@4#W2aLB${OTLX{SgBq_Aw*;_belvGrRr;lWgaF8WgRvetII?P|n z%_zpPc9GP(j~H6@`@}4KDyA!%LwKPvM2x27=vNuDsAX~*sW^=6X?|&-Zhin>RXsLm8| zs!7I8yu=k+eGu&-1wY8#?aQe5BA?eam7jNgxqi!rA32dmuv-r0CFt^+Np0u9H-|R?z(MJgDuHZZXJB$;YX(nj2)!m1sOU*afhb64@@W^ZYY*9VH2(ECJ@DV>MMil&B_=FuD-WyONs;Ze0 zdMUE7@>15xyIR_{x$khG#G$G1Gh)pozD&Zjnk`pZ&Tf2~yM4q^wU{B9T)k2Q2QL&B&SJVGhMFic->k@y7RRgXrq45ifJH7EhT(Q;5cv`91uZNF?Z~ z8ODvQ(t}Qnes@4PqfU5A)y=(=I8-3N4h}PIQdv3t=tQl!5>ZW{@dXbFZtY{+F9)>r z+O4bmla}ZmWXi;9CIS{kR-*Q8!uBOL-HjNAmnFJdjaP}Rk|-JKT0}^4k@EBwmx`Jo zmvJV^wp}^JMJ)rz2)oiddE=KzT2!0SLP&i!t0-_V-bZ#4uyht~N^v>MEJt@lIex~rTiKw2nze6d8bsdZ`@A`CMX zj~MSz*kvP-hhht>LGgg7Q)C;vDgb)#V8Q)=H zi06dB(8wU|i?=Jj;Tv_gtxeAuPPxm%Jq;1rf+1p4z)5KU9$AAi)5LZGxWP**3b%E)*g)?#T zm(^68fDSVZn`9t}PeG?Dl0+3IN!(RoT#NB^QzRY7!_XwLXga#vIYmhZl!u2^mnAsE zH94fGh232bYi27;hI-C%`rHYvWf!6xOM$J?)6v)xjbNvUso_dS@uIV3#xQJ+XODdn zsm-889v}+TI+@F7adp$7JV#PBMOJL4w!;-)kJ{pW(5KAE45uAbj>6}%7MrKmbAkb@ zPI9}iVEvE@r9@cBgx4(#?V7O28ok4VVXG*OV$sN?r<~U)kAa091mF7SmdmoK^Q_&G zkXHN5CFOzuhbfg;s~skNBsXPgZc~-@hzIsONDK=S$<-Za$)Z@|#s-Nb)zKYNZOjxo zn1{(K5X{ZZM)s&3J58=s_HHvGuyv`#Z)d1%^*Y)TSp=VHA2D5r2hUuEcU!H*#h8!~ z;abS`$|XU<%PgQbveAd~L-I8HdX0+Qp*Ci)wyIWSBHkr@<5xs@aj+2s9VJxq(Dl*t z0<)8eUY1E99_SFnVV&U*IwP;00vi6uI=c(ys zQeVbGPdcjJ5tHMD)HwB|72lR*SyQ{DqJ~;CnW+6vm})YRRW~q`FrkU>Gp`8eCq3b* zJtt+UXg-XpCN1fio5lPV-;#>cP3a!m-~L#daV zD)2{(yF*!`5>(h@B!{Y%yR8;uRSr;slkp5`E)|y(R~TkkJ$RL54wLlC60G4EFsH>t zSZUil(um?d$yeFyNE9stXfWpvdXGwRrW;ikr9P>uN+}G6ARNy`>beo#(V)j^d}fuQ zp%y?@K1z2WGb|pFaky4gUfp7GVW5dUD?^W*J;t0;fn~j1Z4Xlnx?F{5NZzK-W{4#; z!z0p2neI^gpVoNv)&_~f)ILU|UkFhXRG#!E!Tv_ufD9;_B%`4dPax5+8Q#H=u`<;n?^o zk7$Qop_MWbme$nZ9ujR}<`I(vh5Jk=SfV?uCPDb!afCSu**GnU^yU_$W-wdpJuX=` z_o$kgon$;RlLc7hRH`E*&%4`4D&!=^9Vw;Ckdpb6QAz_Cj(YA>DbZkw+asq4M_#fP zfCo}#?9DP~65G4K>Ul;+6OrAK%7&0L-4e&IyAi&b%{nO4&{(emD6!-&&#;!WVe~Ep zkk-+p;VOH*1&gc33XicNFJB3!GC>AgUD(A`agq zAfGTq73$xm0_McGNRi6mQWLeS0oJCi0g^IJ4Nyf{1W3=JQ~Av3qFJh~X0%f-F{O&~ zsT0WJc~SzF{^ALWB^V$vK{2bVZUWdMIRTdv63CK!LJqY#QxX!$GJ8@2mNcCr#B)_w zaiC}|ZX$PooSGrkJ~&2%o}uGUmX?&2ihj+LTK(>WE^(R|J5BcFIqYUUHFynWGoF}x z5m*bHd{?G8TZarf0u-5cXo6c!ru0 zWP0*e!pLZCj_R6_I%!}!3ytjKk<}6jGDl-VY6P5sUj${d_VFtd7zM0ok=cnSUQ!i_ zEBc-qW)zun|B}BhS3Qh+2ctNyNE1~bAs)M|#B(3_7!G6ft?sD!)ewqG!6j9lHQ!B5!F!?M=3ng+zf}2m)~>IDY3B!O+*gBAiq4%eXRo;{|K=I z<$?TEcNux*es5jM{eJN$G+}3jZK4v&{ob4t?vitrEb%*a?K`fuDxqq9rD2nQW}wOm zwVdtEvL(`{mW&+YdlUAl*K3VF-Z24>Qjc+=Rymo(T+?8^di;QB7E0F3C^o7(p=++< zogumfE5B@M6<@wmK~#DM{^8+hByCN^J(xt!Y|K5PV*c3rXK-BS3~y$kD^<>X92 zS#8Y8`wvWQm1$3Hr2I-#8|kGb-U&gbHZB?2uM^-7jL#T40i#GwD+YSW6a zX1}wEBubn_(zVV4l`2kGN&f_IvjjYpsZbbXvl@A>8zWGuj$4vvl4Hl@mgow-ZlQBy zoT@VgG6R+KbMtT<2P&&-v*e##^>3b<2J~r2-BBznPe>UHlHFKT8F3+Buu3VOsUqvoUdN~L-S?qF2i(QkTm%2~8;|ac= zT$ZdiHMy*KvtPliQhhziJbNz6In?YennhWiJ$He4u;r%Orl*1s<+3Z9<@7yQWY3-( zm*uIHcqve3?LG=*<|cL~RjO zu+!4s*1+t!HD*24F&}2nRRNZ2a*{o@tjtI(lA~5jes#6tYL^svKs|xW-}?NL%W`*G z3#+-))mq!;8RqNHFrLHy%4A7^#bI;w5aA%bPMb3)o5k0FJ!4iKr00fGdaQh0RJ}41 z-=2=zmu)2RgXqNN$*I`NNJpDeE0d&E!Owwto=n|1YesK}_xM4jgLzyG%JTOd@+ba* zc^hoDR4&?n{B=5(S2|ZY>|D3nymaTd04cx994F}m9E8K@b)8XST5!pj7Air0FTdNu ze8=x53Caq4Sub4jYYQ8x0xkVdv!IJymgq`JBO*>90Fwpy|R#Ngqf7d z-cF>UG6|(iN;vpAaKwy`RY}yPRXWn6gN+1x;Wm;dvMb^C^d71#t>!5m^0Ptwi@K)b zf(+TasqjeGN1@C z>P>IPPIb}|lw6yf&doC^ZGClxI^k7SqMJFyRtY?%av%z2>RL*~tvV7^s;Lq>kp!k} z=8hB@sz5eXKnF|oa&AQ81eDm(9xHskXDhfT6=-MdWTSd|6tBA6vXUV6SBh6xxRd?H z5)GtJw-LRM(6@O?eU*ck95U#(sRNo^ZPq`pQf=}j-XJlVJ}gP{sVG}WQN0p~6L}?` zhj=;W#0S%diRA?1F^$_d2FNlakM5k8?BEc3LO6Id0O7>*I|K6TOOYkAVR9FmZ( zwzN(T875sk7yuogcL^%~gHQakDis@h6nI(olW;w`OY{lPGcS3R2q6}J72fC-;NDc? zQsR*nx)>e|s1PZspakPLvI4-W2#U0(CI+Rt9$L}Gk?0Y&@1??`{)QZcT*+{G@W#Y`peWu@~QzQ*X11VjCo$aydzKC z-1cgf7aGaS9rub8(i@-Cy8=3Z#DwioG@Vm-P=5aR@*Nw>^pB2mK}pTeU!V_BxAXHP z0#^>kkvLz8Z&91z^;#Nrl2{SWr;+0tm$SU1HeZ;@ij$zSS%Bd>K6=)c^qwufcYyh* zI^0DHUb{yes`?V{;=P$zS7u65y`UEURpV$Yr{!^K7H9a038vJ!h-MA5!j6PPTqEj{ zK)nk@?TdDIpf{_-n>ZNfD@7Zr_$wW6+ee6z(zH{qOMHbziM|7sf`mG7>U?_dq0xE^ zn$Lv5sGy!#?sUIXMlTtwj2pciX6wzt!v)6PnbgV=5>uMJ?w!OV|kk^Ex-8 z>v^4yoY7rCoCG68-l@a!34NIm{lsRdyJJ8xQGQp05FMTrJUnWi!0t4bh>R3TxNnbw&I7!DO+2IauM#t@@g&J0Cg ztm2q-x|vkn9qL`J3`ys{V}wZ$`b%m{{4?4UyTwT;kGGSRoteXt)NV$ikc*PzJ}*y; z-emg8eO%S!D`|g;OzfU|=fwO7uO(@LK`tdemBjjSCD8HjtXD_T4mG&SnQc4^-Lo7g zQ?m#rh8vrD38)pdQ25XZz*XmmsB?|?KGP$08X()7f4vAFL6~^;yUD^?X6B!+f0)1tZ;w@Z= z*Sh`$VS8wq-nXW@Q^&HTh%I;JS6v@MLqDm5(2a1ZOC>Q9N-=Xloe_YZaFh)pDC%;O z1cf`q`;idNgN}r7pEIICjb3^AS=vLrF7+&zt{D=nb9c{}s1QdoFuLmca*lh4S6x}D zm<=*?y^iSk+GRX5|7^9-UyX8e^1RWzMAaAl*I!a5_F5k)M6q$~BLumTHKd>2cY4`V z<~%^Y+W6@!Uv=6nQYK!vb~Y8s=H8^bRRvsmmy`m1v$aW%%ukSmRSWCHk0WI!rFY#1 zrn_+ukr;`QPGY=KBo-f18ad-vBC$B$(nyTaKw@#irI8rN+=4i<^w^UfOir(P=%rFR zWa^zVkx~odlGfh!Na^=(Txi2P$q}2qp-+5;BAn0{(dHndI*?4nE^5ly) zzTqABDqLCn96hFkQsb3kE`-!9=&Fo(%Fwar6eSbo0KZP>TbrRvQLcoiTimOLS8p-QhzyC&AhMZ>m}E;e7&Sg z+t*9lRIb^0HNS$dH%M2f$}qv#+h1R&t7C0;_2PQO6RKU)n_aydyQ>%F!nlNGle$u2 z;x?}qo{porrgV-R&*q$c8)-O{2zNOHOPx`(*@w*8K3*U4R|y;cDvp3;Ma=|;i>JK1 zJ=yf{rLFl`q{^gMWUpjQ`MjNgUH6>;@f91D$k|b%Pv-EP@M2~)S}0!7vIFhPit6$@Io)3A zD{42UK5mY}S-lg9?zyPm>x}jha^EQ`>O-;FE5}uH@I4pv^YB&3 zj-`-wfrQghw0Cz?IUfavP)DQm?k`s7)dpLvtB~xl)~|MD6_J-O>$UjaB(2$hhR|$= z>{gNu^**2WCdq4ibZ$5sb+CZ5BVH33ns-4l(fsrlAJ2ZLUd2?`RGNZ#yRQy7>bC$< zReANTI%JAt`fxGI_I^1|OzlxlI33qhp!kc0S8MiHMadb!@uFHgwChw1P-&MeT$5Oh z1H*#uK`iQ`bfY{%JLSk7sgv1N%lpsN`Gkqb&WI`6(Sex83r-KQKP*uLnu?ccjo8%P}h0v3ob0iiQXhT?rnUt+MN}s0{^w&rJY5cDt=l%@H@S8P>=p8MN|JDi!+{(?KA;9_6@Vb>NOLv3k#h1hJS- zMYP3#-~&)6{fL_u`a>R;m(>YJNLhK?nk!ucviV-ZQ5KjJ@e(S6A3;@-Cd*M(h+83n zK6}#0XL-3ho!P{Gvqm{9&86`)PvxY)B&S4%i2ED$kz;b=Wby)Hw)3(uErMlLMafa^ z#DXtt%mH>nb|I#7?vb*cDbf=u7?YJqVFR~WD>z5oaEBtLsl1wv41FBlYf}6|M{%N% zURgBDpL(Rz%hE`12C`gg8tl1j*dl%fx2CKyU_i8Kxmz;M4^< zXiK-kDWRj)*3gTk@ZfYSJ1F^MHpX_KjIN@16m&U8EAvG^-5i-&L4IXD@JzL*IoB^ucv~3Z_U&>AnmPse4A>fezq#1ReEqI`P+M!SJp>) z984&J!||*4dZ@0XyjtSJRpa0fdEH2;EyVO-mSB245zwb?OQ4I>ZSFBc1VfmP&X>6Y zH&QU3+Vp@r$Og9`Z*A_KysAvzU$0!I2@=hz4RZz?rps70#Azy<*W>KvCW)(Ey%t7d za`>!>7`*Uuz#yYqPEb%o*u&8(WP*9R&o_?6TDnbAGIewtFGUWZ z2>azoGZE8_&`dw4XQ^s=-ZihTdUutvB#kU0X2fuZ#1>^r{*oVhuP6_asqE&ITj5Dd zCuP}Xk;ZO$wJLJ23O87my?O;LRZ_r4g>G-#m?%c|l%7EK?yZltYrW=TQ2jic_0rW${@q$D>M{{8cQ5Ay8Cx zJ*6sYnzn0QiA}ra$YXk^jCqlL^7evB_8g)wWG+&IyS@X75XCT6M>kYNRxphdux(Dz z5V|O~HxnExziO>?lNxfmO-M1-LVdWW*bRgOMtPAh1oUcdJR9v%Gm+y8MRVaedeyO> zK6R*3AtzFqtYy7YdQE5$ll;B)@)klPrH%fpA|v-pQd(EskLEu#)JW1k7p*izellLnDYnqQj{k2mhJbS(70ld(N+w zmz&GEPh4jXj>o$}klJXZ+0aLhC+1k5ee9O5uFicXPhPQN#iYjAr0!NIG%4KFJ^83Z zg^ZJ>sj`(go7fh9&<6#9vMb51Je@c zFytSczq)*tb_uHtMtn@|py&aw$rPrhhpx+QRoIj5N^eNJSIO!v~#;#?CgMO=LEr{$>DYzfNa zRl$m96yJJflxw}mtE4(w)n9m8y*EyHMUQpGy^caFy_c;2`(N9Vc`tkQQNw&fYS`dhwji)T_Gi3sC)e1|*X$bp}p5sAjpd=F8n@Jh13x1sxTp08`&r_ZgMdR&S zUk?7#>XbPow3kejX1t;`#wgM=sE+N3!mAOcF&RhXWwd+>t9CtHUv z;#RdbhooI4cQ8Lm?5W% z9jjaD)&r3zX_MK)kRU|7GO^TJ0V9~XC4wxWx8-fXat5^~i1A&UPRMkQH5Ur0%Iwt= z=@c@{%Y=LOiaRfGX-Vu(RLJF_s zkmlMoE^bn@SCPY2;eHo$pl^n&UI&xwphgK#$lXhk5#l%rPEp}Xa z%`A~?a%P(zziNNz@I-hLqk7#gK$v$RQfEw2a5 zE{4qNOl~!DBeuT`>rISLsS=bo6ScBL97nQS8>jkCiBcIkmYfo_5O6ldnxQHe-3rUA z!y4p$h3?DS&MPjo8#~*nsZ`X^N~KIBn1ozAnd)Qu zU|5-9I(oDp*K`s4EU;wc=vi*&%BPb%%~1Ion^PNFEas?v6;dTxT2y1xNIg$$0~`b! zm#v=Mk*F2wA-pO2HHC5EqsY+Ijm|3LR$q^>fr5&uS8AHMPtB|{?}+8YU24+K5my*s z*t6muW3nSyfo|ue9bGc>VZy36Jd3AP1w4t6(68k{vXD~<{Z>yKh83i*#C7cv?eXnD z@@C?YC|m2DlZ@<_X->S#X4rY@>#bx~oKw_gc@MGnkQ-x%8mrUe8Csn!Juw-Gde~_e zK*`fxA>qZQ;nc7MCketgB**l!u*M5EnGN)~ig!*kTYh4^7Rm6FBU0%(p@Up@J(i-` zNQdbOK=@ONm&Tc%;_zjqjeoP^ zaq$yy>9z{}Iw#$B-SOfL(o=~{MrPdU_;>hA3gtx@jDVng3kZXm?f7076Upd)#~HYu zSpE$6R9US9nh`8VSjrYPZI`)XOZKoif&5BNB)KZ(eyJ0(suCcXMNGPuU0exMX`P5w zm9|(V6+J~58C}9v*d(nAio}JhlJ*_-?=RC4`;tn8yXl+W$Nu}v+?@p`p)v!V_~9}) zyjkDv#!8U$FuezX_{+-VJ;LHtR*5`e&RKRIoU6Nr6I3f}7RVL{n#y6Cn1OnKsk3{p zkL`0NY*blgauOd8ix*T26!Xr2K%IF5L4Pk7AYsyR^NI_dNDMn0#?~i5wlUV2@#807 ztB_KCoVBy$W@b}X9eUauBAk$Dmzj5!%3!UKg+|SpatM2TBzQdjG3P-Xx>z^}QXX{7 z7bi1BjLX+bLwEFI<&xJEby#tAb|@>mk^XUWbBt%9hc6>rHtjg~6z(- zE==+IZ%D3sp^w)0)oDIn_14)Ef+R3gOD(cBD~afb}Ag&nJB0eLx$M%oXTg z&O|L~Si%dp;|ON7sI!QXmHytO=`Sbq=B-|t8QHFKR&$SHR}&pHM% z;v_LV)fg6aK<%C86NP#A*y4^Xdw1eYazM6PhhxHrnV1{fB-peoEbn9zKauaCKnKfG z83j6}3V##(*1S{OEz7BgFCgJ7g*tVu-)3!;=+-u0W}sstH>UKuk!|i2bvP%(+cs57 zdUS7|EtY3}ySF-(FXk*DF1cH3efvpPq@1b}?zg*ay5JYd^tVt0Z@6I<+jqp?le1Sf zEN)UomylXrXv$D8c+>+?cbbnxlw3jSQ)+J(dD|NQK7tu zFNSD&A!jh)&Rr}bs&%nCojlbXNb3UBXllu)fzLVrDyt)s#GVH)Xkcp(-aOr)|!;e*Wc}m*u zy``?(?o<9bcEWAvNm598+9&+@#Czu(|9Hon+ra-w z-JaLH6;1f@y!Xyi-XH4wmfKmrdxl$sFW6$`cdZdyZmWOYF+}~^M*n(#ko>YTMp;{* zaOaRwCpyU>`6IOb0W-OdxdK z50rpKU@=$%4gn$101g9D5CcB|Z$10g12;c#!Odsh-1BTt%d;(Wd-RoFO>-}3*&uB4 zRb|759sTyU!;g&*Y7t6F!p6!{Qf!sCrjFF`jwg^7^IV zceV6zq@Y(GIRaJ0+gPE`8Q@H?8k_}w2xRR382lf&9^3$a4Q>QCgWrOOz@Ndx;0^F5 zcnkdF(Y23WbKW&SIPV9Y*DN}3QRSnRg^yaMrw&6Nx-?x+Pxasa^jfGn>0g69rKUN{ z^v_A_r@&X4W%}o{^f^a!|q1W5s9q=v?dHo)EA8d`N7zMTg+k!D*M=%bI z2NS>)Py~v>RIm@221Mr105idX;2`ks(|6r;*CjVya`IhWH+3~W-B|gwbHyF_?ibyP zWz4God2V^f%cC11x1`St{qof~q07Nw5oiF7;0SOeSOtCx&IUgN=YXGsbHOjbdEk6- zE4U53^x!SOyyct|&*?aE(TNZK^1;eqR=VW;%3t~)ef_r0NSyG{^myp2_UgASo4<u#{yww84?cmNUack<2&zpnJnSQ*U5T7GDux$!kss~ zEq&el!xH^&%LFYjNkdG~9%Lz?0x9@HF@r_z-*qJ_etFPl52u=im!4 z7M|G&Y@FkN$rhW+_CznkLbq{XJg~v8pcME)8CVRKfI~nCG=N4RvLXzc!ExYt zuyNA=fMJ^o{r~3W^fc)&bUOi@2u=m3fs4T<;8JiqxC5*KcY?LxE+F&7J>XvO5_nlY zH_G|HZp%%D{*QY(Jx%%x-ChB&f;Yiiz}l8+1Plffz|P=1U>9J6U4iHbyMsNzexL+w zob<24Yn6@-@!zliJ?!Q5H0dvND+PWq8&rTrU@=$%dcfh}2yi4=1&#uuA07ja1-}62 zfsK>?`)6z_^#7xm)6=BC(CvJ10k{-g2G)YRz}?_E@H}_{ya-+bF9Wd+UInj#A=m~( z!Ny7d61>%$#`wR>%js#-U+A_47zQ%H2(SyV!LDE$m=0!unP6YA9}v5+6!^gsa0u8q z=|7ECicN$5fADg8n)DaCg+K!cgJy6fSOty(XM>-CbHKUa7vMY~K7k9sh2Zz#4`Ab@ ze<3SVn+E-V>*e$`=`VD<9ozx#2KRucz|-Iv@FDmJd<;GXpMlST_=CO#{|4jm35^FE zC;cb08o6oE{{}Cor%8XI+XV6Hf!)CFpa>L$sh|!7K|NRi7J>tS_yP|C2ZNQM2W*`5 zpU6tara}L!y_}vV{e^CagCoE(;8<`TI3HX9ZUMJ~+rS^d?cfd|e&9R7TJRir9&DWS z-yIL-ra}M9yqumU{e^BXfEU4Q;C1jB_#Auz#^B@M5sU@nz<4kL$Qr%Y60-Oha3w{S~0k?tQgFgUS^S=YE0ndWJgN>8^TOgq} z4f=oI%js#-U+DH6cpkh0UIjZ4!!ZWz2y#Il$OnaB3Mc{+?=cnZ1LlJTVB@6!x=n`u z$9Y?tCjEtO3&8>4V6X@@fJV>+jsi!6W599XcyI!cSf7)?$>3se3D`L4|0x{3X^j6P zy)8|X{zA7)!DZl=;A-#)coaMa-Ua^z?|~1%zrcq;;=DcvpMcTCdhGxTPM7 z^cT9l0A2*IfLFm6;7jmtFqS-b0^`60urv4$kl0=u>1@Izx2}n%;E8tZy7`__p%w-p!0~2|qqhc_$&+<{#_p z#MHf`dv_4qLuDuU&O(cuz@6YB@HBW0d;kW)PuqZ9z$CCAr~?h45v&5If^)#-;6|_p zJOrKruY(W4;GNk=3MPPw;LHDh3V-n5(gagaP6Ciq0Ja5k3cw-GNdOas9#eoHlz{`m zLEsqR$n+obeGL%V{tWmVcn^&D4(En|CU7h`7yJP{0p0?`c42=22!cbwap22uuj4-d z8d-nnedZhgcyoj1_I0Y`R6xuEi@14Qy|RvA1^fd9k?BQ4E_zK*{t=0 zpM!_M;9cUNtUH3M!S!Gbco1AwfPV>m3hpl?Kd}20$^d5yis8kn@E6#5AL;;} z1yiQ6E)7lspMfi;Th?|nIO_&#{Y|(Ez4*k=m(>|Va+;8Q?{zNFHanpgcU)yYC0?YmmWq|p3&L-*hC>4WY<|9o&DI2K$1{tSdCJ^}l{4-RiEBmiHMj@73P$ct%n0ZPmx0GY1~Om<5P8rB zKJ$`0;m0T5JDY!Ofa4Op9jd;g^*eI}d@w=i@jMVY{R#LKY@dxh1?6B7=mzJ2--Bm? zH3_{Al!7L3D!2js8N36wn#?=_=72VEF1Qsu54K<)$OK=9bvHk=0s1Y@5X$}&TGWFW zxEeeJoca1j=H;8fmtark=e^7vUBsOHfSH>=M}kr z2akYtVDBQS1jsjomI_Q5B z`s#n}$9n_bQYxT)0NZS>eL>r7?fU*i222ooTnKIhkAr`KolB6{U?sQ;JP1Aj+m;d= z4ywR1uo~P1o(Ai{-hO-l;7D)@5W9ITIH*k9&oMr`z)wK}4{ZLC)FBDuV8ix~rT$#` zFSNJ;JOJJWzH;aYD#0@FBOrc{tH4dOwEyE}J}2x?>=*bccm#+~WLq$^g0(_WJcsyT zP+Y|)co_TzEUJbFz=my9>fFA?o=jcnMs_Em4-EYW8~b1USlF1_9py%VajV}O?xSO-9RM>f{VbyR%9QTf2d`BcNu=LHu?uV z4_*dufnn{m3rq*MM38~tu1k6PyLE z1CN0(!S3+Jf#75ye3CFk5*T#z4@QCI`TNE{68c(aEVjSQ0XqvVegW128M`}zv0xfl z42}lpfwkaGur1@+8QTqfzZS?Ce;UX*-wK=zz7L#n9-WVW0h|qFyk7?r>a;QcNa+2I zxuR*-&Cnm(EB}ws;(G8W@B;V*j9P%N2b6*kI2l|Eo(7)*k=J9v6d-bY5m*dP1R}%F z1&$mag)DyzJPw8+(?zb22Wi%J6HWFlGF=k=g%%UQzMugd4=w`tf_K4~gP0$I%*CzX zWFT|$ufVn7aqtFs6L{z8am>xDfiquU&G+8{XWrgK37gRD&owRdzX^A~#UF;r=u>|KBbVUA1Jxh`R)g!oU%|*jw9Zw|XEyrPByfSzwSLRz@4(Z* zYGBNRB2WpIfz&M=kX}h$o&U8vhW?KH7h0SGE(dpmm%uP|&TfcF8{!?t9M1P@0BM@8Y zTyO;T&ynClV+;L`&s)G_;2n_B0&jp8a0<8rJP1AnCUa@^^z|r6Wum*e%#2zjHqp^K= z0Mm>eT*qe+M8PTGLU1>D35@C>9XJ^DfHcYXpBfcuR_A{pSQkf+nih4J*w$1|0?+}v=W-U32r;WRQBePV z^hGfE6y_H2-l_N;PD7srUEm?G&*|_Rh=QZQWk0~?1fQIRZ}o@N4V($?27w=;Z-6hs zBR^*T`ak3nI31i1z62wFg3bbd1)c!Ie#-pxGwKe8p2PYFC;(4`AwNeB{sKD}+ztM5 zF>BqIU@u)xUx3H1#0Py9{Cze24Ze2`eF2((75D8v|K#%tF`$XRpMNspW`C|<3%|1V z=}O#ZXwF!4uD*S|>RuZD-+CE~ZvdhH;FYu)d>70H5wIFu2c7_*fU!Na7c_yBz$M@g z@GSTc>~J{!2Mz(Jf?tC_gTe6D1W*H3fiG!``?vYWf38E^PS@jKXd&bNCU7ES|0Hk; z5IJxMSOfkJo&y=H7(ZYVC;%cS7J<3Q3XvCwgDb$}z(Q6y^5X}57a8&(aOB9B@p}B{ z+WvJ4{oGs8PrX0BPHqGL403-67;NOf$n*urV6%ZUz?tAOa5-2Do&x^@qmbun2U4Zg4S>x#2c2@E!3#U4sO!O=zj5{uB?4V*N*G zu@&>P%-8wAnX`YxcbT`}1b$84?GA&5BH&ai!MG5tOBBoUkn}vUw}+>@;P875FPz;@E8zX{cZ3L*yapm z3^)*c<92M$;Oli_()brz907g~?gTG^A!oAw3u?e&;7ssKa36RcSgW!9z+BJ`&I9*@ zkHPlXWwXE`;74E$5L@k2@EI73ohEkMX7UYCA0*LVXi)$PK>*Z&2Fiw!R0< z!>)F0>>j?~41No~0Ah3Rh0UD_4gx2Fn}OKjkAm00>tGLTaIwq3MfxWQ&;J39eZzKD zlK$`bNcMv!rvb-Tasl7J5IOKEE4HknVyFLn>#v(M)`m~kQN0bq}dcpkidvG$v7e+hd*fcVd%AkFG; z%*j6Y_U*=8(S*9`O1t*I(Bi2}(fz>vm&bjZU-12zD;T@r(JQsDbI?_cVK5!c00)Cb z;7qU@h%fYyVA|E%CtAs;_(hk1iPyyaqt$#*sMF>j|G5r{Gp(}!gcjjnX`gi$pWWc- zYdO0E`~aK*_P!2(4mc1T1ft+Vum-#hcDkN150-)x!ByZ9@IKi72G*6qf#5iBCAbP~ zCiwvMK@$CCtwQMT(EEDmeG?Em-wmB|f6bXbV5b|g>A~4Ip$q;N|Nrmc8<4bQ5zl?| zw*l{gG}eDc$ygLR-ve@>v(UR1bb<4M(EfHX7TOCB%ms&oE5ILt@WhLt6}~tW{1ga} z+yT~rcffakgM9(2K_@s0B#i%rnRN3HRu{dzvtfVeoJID_8E`ubEq(?r2X}(Ez}7dj z4huTK+29uN4j9L{F9Xfs93XPwUf{@r1e*R&|L~IMzxKQEz;;&f|08q9{gY1*3A`9(F3cvUY6osx|fGPeE%Cg zpWgD&wx=IwU1iO^ax3AJ;b3d9#0pvwtI^7}3aw%*$C_#tfIMpo_cqPKiw3gg16p|T zK(>593!gfWEg!(b^BM62HqHmQ@Z5oH`G6LlH;^qK(8BWvvgHF>c)>und_W5?9LSar zXyF5>!{ra80-0|Opc*y6g%6+_m5%{2fXc*xs!;=2c)>vGa06WU0IE?1n9Kvl?FCrq zn`+?$s74i716ue1s!;{Fg$9t}22hPEz%e#}EgwJ~u3#W_xPpPy;Rd+y0aT+322zI; z&+`BdwE--=a3FQK0WN$1)u_UO)Zq#TQimJh!Us@|DjY~1u5cjLr~xi~0M)2MrNc3| z{MY?09y;FI&KhKGMKr*cZtaJv<=eCQ-5;h5<2;~#u$=Ya{*Wq90EGQF<>=F^_=9J2@gFfF(te$MHudL<>AQvC6EK|q91G@yqrhm$v}E?6 zq3yFXhIW7$=mK1}_JdUKtsBhe$Zh1e{0+0J2?>c>?N-QY<2PAAdq2lnNG@`8h2-Sq z(qIkRZxCr3JUL`ov#l^sH(9M#hqctQm7cXDa%|WhgVg))hFaTS@=t5@CDX0__9Oz) zDja^Se~xXOdJ& zq?ifbA{IHNOt2PPLsTh?*ISCHE<0L7bSZ-qOBrm9(=8e2Ekd_qoE5N!s{8}%&0qX1 zJ6c0^{zDS;A415E>Zu9RJ0V&Uw6;)r2G^UXOueJ6EqL|d(8LUfj&^%xoMcIFgyxKc z{=-zR)$7ewToa?=mJxeyk(lcirj}!LEyuuJTUx>+UM}m+BeG~Snv^5<9F~|LGGdlB zT-9jSdTUgyau`kyTPEhP`b0p(W|H;*`)yyd9W)yY7f3m+SWevx3YHp2r*pn_%LhG7S5LuL)xs6Tpny~MMjy{GW%ca*6?Y$ z`EIH5vaL$WjH&VmTO(DWW!8c8(EF+_<8(Ew5!9V5)o8YM_ny}Fs-O3?d~T0y!IL$XpLU4JH`o$^GszmQ(oO0!os8%a*0#JG_n+2cAnA8l zPkI@fBhZ&do$&mi#X!=Jv4r#b&R@pb2y1)w?p^iXRnm!+N|j#5(Fj^R>V!LnEC!PQ z*!85B5i-Ksf%Ml6T?{1sPU}f8BVYtI9(BS6TPy~We%yM}3%`$`#-mPHJ!~@SXgC40`fH|#h3yZ<=u-ZSpK=*TxM;~-F zJ+f}y5G%32E`9v+*Y2R7roiPg%9ljLZL!Id1zMvi&t4MWFFnJ+xTb3zxhnfy~9S_I{bu7-u?K>8UOy(X`jCEx z?Th|>|J3rr@)@@uecb&gUUK<&haa@E^Q4Q9c;==hx7GgT;^`0Oj=yyFZ*u-`yHVeN zs^+%9uS%Q#a{o4eom2iyLBk$LUw+nMOP<)}?DKYdeoEydAC3t;QFO?!&b;FOb-!Ml z^T2sEYmUA)>y`4M9YsH`Y<;=m!Yd}fRQLPUSA?&6^g9pV^xID#|B|NkZs@X}pNu)4 z2A&EgfUcHsdw8OhYXlXbq95V8Osu64LZT5R%)rBioKULItYi4=F4S)L8tshzb zbH|n3d%<7Nf98o-UOK+$q31?F_Vc;E1G3KD(sye3!Aal0`JYE-T|WMbr)N*NJFD%5 zdv|#CA1lY+f8!6ff3D)b*t}J{KeqbBYi@ehe*C7rAKUfatY;VhZjVD}oVNdh*B|+K z;)~^P?!D)T!Nq-7KId8g#48w=myG9pwZ1B!E7gAMfSSlNQ%2uD>d6&$SEO;T<>R*O zKK04#f1X`6{;rObzteikPoAv3XurQ!tQ!CHOUDdadrRo#9iD7IIdssmW1hV9^Ma@L zY1{eXYp>fs@WZ-{=w?Hr^17GZg~8oV`}a=^Q4#m z@cuSy18d5j`Q^{fzxl?)x-+g_dfM3sUiX_De-%0Esax7gI{0l`TgM~f3~iB_xQ`^|0M6hSw~;<_xoFavfoFCowxkv$FD9t_{dZK z{l{}3xTgB@N7}+SEWBt~(=Ovf=RzGmmA-(C9XR`;F#>$m58GVYEi4&CX7bVe)5k`URe9mmir!9`p{MF=brFN{p8!feCyBm z?sD;BWOo%!XLx9-2g zKdX-2Km5t+d&(~Q`OCxK{$T9r{P~A{cdy+K`@;@vhd=WEsSob)!Zai|~-M5~${k^yUzG6go{;0Y8zt>SVA@}34)uXqrC>{OR*cZpF z9`W`&fj6G){^@7O&7C>_^-1MBSMFVvcggO1ozwjP?cE1h6ldG$@r7lnqJWBs4Y4;s z5Wx;g6gw)Su|yD1c|kzHUV?(XL}LjmM(o6jCHB~2)L34LiHTio(IlFXW;7=9{qGqT zkg&cg-#OR$zQc0;nB6J&%se~ul-Vh>cSn?(v^40uQqM<4?Hq45(tFc|akDG$_djKM zwtjLoyKhr|ZvJ82%6%48zMZnzdXjcidZ$xI1D}Ks=w3fN!QY|7CyD-VfBfwd&BV^# zZXONTUjO=`GwZj{E;p-c;1>rcH*>AA=ZUY^u@U{IR>`bcKeWw!Gn>^8k4E&?-Mkk) z?ZN15Z8!V<&q~*tccA+=(>)OnW;C&~Y2{&C{?Ng0d&?e9s#hs=a3||>BR2${Z1VKL zv2%3;qtD#BZRxe>bcI1}w$6VxywT<58RL83JNtNM+fU3#?`S!CpZSBUgI4Uxu6en} ze4AhUe|6yYUt7J$=RCcAuXukO13^RcbtyHu={UayAN+K7X- z9=7tWX8L>c_}euFSDG*KYYa^GSp8UqyZ2ZpN0%cAExPy>zR5tJIaAmhSC0W>y{+-@d`JBX2L=GT`$W zQ=+$hx_Rr=<{o?Y+ny`;*7W|Xb~N4IY*EtZRu_XaGHN&RH1AhE)2Yt=%2X=#XV#cm7du_+x9nl1*cP)F zo_^?Pb?M%X@nv1_*|z-EE}+HIc@68;sna>L$JI#B50+Q`WyF=oCt|xzJL#?4*7I(kuy!}V+5bM;>w=a6$g@QY^_*II8jxuR`7z}jj~!unmUTmp};vRr5T z`!i!lvtBKn`ejY3u)cbF)|4xMRk$0Fv!~h6h?HH^+O55^p}JkU$2H1Zw0)e`aOr~< zQ~S2MdZ1y)CARLiz3uv}4|-_ZtY%btWY)$TS6h|yO<(@6_ZJ%_wW#>+kK>p4t_kpJ zc5gy_{kOOOai#K;4K1oIKby9w|Mafy7G6DUvwc{ZAqO@Nj9GGje9YUntr|z}bQ~L` z*?A!-^Yn%1o^N^I4~lH?b?S*T=LUFZ-#&Q4t#1>*de^E~|J&?woB9)m93J(+dgQ4; zR_%6vGG^6G-%CD$gLcd{yP&&JdS2Ry9Z5}7n$(NDvU%i%pfg@SSpAq_b*RpqEwx(A zK72mn;p%4bmz(Vyv*5(P8$P^rWnQBuo?{+|%{rFp-R6|T$&~Y9_gvqekWi-bC%T)Z zYIo^awoCSkPQedWnbj`i^t4fjoe6hbDY^bxFk62yf8}n5RHE3fQ>biHYa>b_U7&c* zt(|nWJmyv|`Hv~1&0}J|+;6j>_VpQ=TfWjJ-}SU^+NNfYhmWkcHZ*sc9&%`D#DNc1 zd|o!x{YK+q8y(G?f46wVvZKTIKAh*%)4tox%Pqn(f~U-j@p@E#=z`95yVkDRv#v|y zl(^D$IxS4ioE7*qajW;5_k!*^uUYSV>OiLdA0sEG{k+_0!e=!<8EiBDqNd`KfMq#5 z|MqsAIn=e9{lMoveB&=q)zw{n;%rupMElZcok83 z4e0!0fWq~+{HfhY&jPi%!V?y*59Lo-k&0r0dXZX3DvzV#_?nA{=+EVa2T_q`coOcy*Ot3Q!NiWkf;faqG{(jv3oSX6I1{?^+$jV%(1&X6 zT9mKAuL#IOYYr8!hqfYjD6GL|&`G`Pv|PgkuPXf@UUdPp(>q zv_IuYz@=>3VDNkmTr*p{@n&c@x@}!nXRz#lIAb0JT zJGaZ-yX6kPau-**lc(IxQSRs`cXg9Hd&%9MLM#Ha)_i~zEX6XgD4JBP zz=v3gG_1mEu$Y>4xTxdK#P|VLrX0gXbF@S&w80?6VIJh@!~!hDPMpUNc!VF34I4Ak z5?*MA=4goln1B>4!*Z;^C%BB?@duvZPdM_uw!!|j4ODIr}z_pp)w76 zZv>(b`l27kVI>aW5Dw!gZs8d!a0t&4l~4t(;Eym2#W4H}vv3?)xP!a+7N#5@bVC<( zM*w;v4lA$^2k{9G<0kA&a|aQ4qA9%57om6;Q;>wISck8WjbHH_9>bn}&=Wlnh~DUf z(O8KCIE2GEid*;_l6O@`6;wkTgkv(2F%{FX0mpCyw{RPh-9BYXUuL#9xeD80HU)>q*hKx^NlGt0W8V8{s{YIu zM~TKijzcCUCdy5?Y&iI6oGn?KjmA8iy;+@zAZ0Y#Y&Sla(U@e{Rr*_GOMt>JV~wRU z9lyL#2~o#yOV=*9zY+cAg6UowtL&=0J#~)t})S)18CZ4jg)!YX3GRJ zI48%6|JD?E{uE*f9Q-bLrL`xAU}c!0tFR3Z^Loj2-Y*%}%-}G&Ak)zNJXmhS!`xpo z%;P1)n!IF~=SzkePBXdu#_)0)P8Sc(Jv20(T;yPQnBjDhv-Ay5XE9JrGB>_PRzn_q>q51X3}TQw)kzQbcdB}8TTo4*syDDb)k;k7M0KJIMQi}Y zLLkL?Z;ElMd+vj&Mh)Xfmy!Gehc(nSZzWRQnnm>&+ZI!u+o+P8Z}IYx96>TNEhLAK zyoQ>OhFXi%M)}cEexgwi=~E)JPU?Lc$RL#;%vc5TB=si}YU2F3q#jtVKvyzOYO?%f zL=^z6qNWNYzoJ&Fu^AW&N?d z6V-Lnz`6(XAq^Jxrbs3YdXom9k_H|lX;NT6X<#&&qMr3XE*4{>DmM)@@3I0@Fcq^f z7t62$8?X@{V=s>4IL;vxS8yHo@jZUW6Bw5zEnx|3IHC&bq5+z~3%>9}H}t>&3_=7V z5setcApw)H0L!of>DYu_IF573#ARH=xA+df;CFDyK-0fG)kqA&V9d2A{jdeQu$C`x z6VCEQWn!8$-xC(pqRNO5YqLFJuPfCUbo8KlgzuZM?vQQP0S)1fMOcSZxQqc!nJ@O> z6WDvPZD1mj@C~lRgc8^ijp2oN5QZe0J~IW|#CwqaV-rr|-`L1@l7R(2G!f9om#QQD z+w!0}M7N_Vh?!UhD?heVxWWgi_z0KqoqT?aw86)0Z+meQw=usf>4Dw7Sr7CJV!f~j z`ymg=y$jnuBs<*UiCzdo0!CvoQm`BQ@C~lOwlCAcb0Ae`ybpQc=0P0BL;M8mci0!< zg2otzNSqr?vk3J=x#1=P(FgL7#_3pxbezEFkT$OtrT@je;f)p;hDglB9BjlEoWZ~G z5I?~>lI4I48bcli*Auab#{w+E4t$I+@il(KA1EKib^~AdVHCz9HJWNS-j8AZp-mv~ zfEDa8X(anDc-Nmr3+T*<`j&OqxnQ zjqUGK^+$!pYBRa=67nX@UrS8V97kKq&=*pu@i3`3BHb@&OtVqXPnDL9Su_yd2#+=1K^I;urx7=;N) z#TtyRL9UI>_!!r44`phym!loJ;5NQRxmuKHxIroX2#$3)5Qtug#AM9EW!yvpP0=yf zf!(--TR2pYoB(C&lM~`}BXWFvgR7YDLXM6j_#6-MI~-g!n(FXFSJZN&1cFOrNDZ66$ixkI)&&?F)I>wHMJEJf7&O!>OwbT+7}%0pH@?D;=-P_X2SKf=Vc2SP$&nF+7>q*_-p69xzHpQfkY(XEG}YMH*#1!=uX<>893`n zKonvz3-geU%{YP6xQqKR>rd$pFEmF6cHs^lz;Xcl3p~*R{^*P~ zgQ&5iMKIql;xHbwFc)9rCfbMa{bDR8Aq{JA24CO?ZlP5;-y!beJJ<}N-EJ%M6X+hIbHx_zC1W7?nu+ zVJ_xl6SiW*6uQX51AH@;b;e_qnZ|cNgMA)d&;z3|9xJg1r*R%#XObu37*4`*7PSjB zMKc7V51!8^E$6Uo7!IGge7{ITI;`fgkHPFcYF98>NE)LuoFI>(=z~NgV>kBW7d%Go zMbwfZkD>^{m6hbN_-PfjQ`BEg>i|LMk5L$pJvfM_>)6&YAf0^}+i?V*AF&PL9Sp%= z&}}4tMg_EhA3QeEB81~+YHE;Mp$Fh2?8F&dK*|>OKXluw))tr2mD=G6oPyKZ{+!^k!{;CcBII*n0=5f>_C7zOiL#?GBis~Q3y%>{hR{v6Bx|!N0XFgSy(an^YZl=L}ma$$I(}itV zUKN!8Fa9g5#Puc}Q`GIyThh^+bWC~Por?_RdEIi&p80{Qq?aN@ zdMP!85h0A!5PSYZh%sgILX0Uxh%seedqw>1@_15PKa7vDeYSis&=0f?J1H*)EFC>Xhw4Kao7!^Tn6e!H8V4 z=-iG;|5Jvi zN2u4${Im|HgeyApBix(he_97KLKdC>5%Nv5K&^v0VT;ZJ3H!>qpiTZZHcZWKHE)^= z&i`kq*UbeDhIsW{&|rvH&jk&Jc=cS+V2D@G1r3IH^<2-5)nmt%B^~K{PrLD(tT1YMVp4y+j z{612rp=NB$3Aq<>t0%we&(x81%kj}B8fls~;HWF)C2cSLdwthfl2Bf9?rdL4Q6EVX z31Ft_%~|`Ah~doqXr-@ORhRMgV@X#|jmkZ*>Ge0NpyAeab5a!GQV&WKUbUGtrBQsNDoxbU(UwFpQ zB+9>DTsttF>k?v=>kd3zl(}1(ni$K=;M{$=8XL9?R=v|OP1Ke#8_vpm6YdY zW}ZJQNqi2;GcPCp%bij}x#}S%uU`k=C(tKCxdxz3D`gqXv=+w3I%5-q%g~OgMk>o8 z*YE37frB%pl{Hu9S>Rv(;^eM*A7x2~a&C%x@0NH*_El5gL`UkIYK={}VN6y|O>P2^ z`&wzFzG=t0ORA}M8Z;_o-Mq^Qv_jlP_$fDmhM6xS359J1m z|BP5YcV8~3=rRC<_(yEZxHRR;jDepPF$sJjI$YBEppG5a6T9Ha-ydx z)P*WVW?PDUu@o72DOS2vQInMP`(K&@&nX8ftp2ffk_l!_UHQw??!#<0Eil(KsI&93 z?8s6Pk?mH7r$DAmgB1QpAiKs{$hIY0xol?-AO+!Xkn+@=iKVGtIX6~ax|V$Qrz?9% zAYIuCgXv1cIf`y+x?|`{t2dFZ4c!@Zr2?gtTXbcw=GPMCH02=QzFyvLPQ43IR9nU>H)ZzNwSH_j)85}<{Haa3wnYQ4tg70N{y2;g?Q7&OI3B#3frJsMy@NlPI zW8)LT)qXOKyI1~lbd3m&i;0gJlHk;R$dHK8aHl>oabb+(1I^ayQ)T|j`$=hOX^%fM zQrk^&_uP?7>A zDNvFEB`Hvn0wpO>k^=uJ1q`+SrCo1)@!Z8!mr6DZKcM~J@aa}R`soVwliUADdtTbY zbU2!ArtvPKFfPq_CWz1{Ra7W>DaAvFQuQXmoNRp zh#_epahj1L(#^>IOh@@F>BGjJe z-(hj$c@&EGVKL*m7m6pxsfx3FjSIzlznJmd^5WSk%QdH1@zjS}$@(?p$eeVi6*Hb} zvjyWN7Be1)!(NCtu9)$f7K)cp%y?X1_QLYX?|5&%y{JzzESP?hCl)7O{{EqUzk`bz zFMt0~;|(Zgy!`z`jTcnRc=`KBc_rNfiWN_8yrTbp)p(q>UX1TUeG0Mq{i^Z&iWx6| z|4`$#E@r&^{X>nX-=7JqtoQ5X_a59%=*9HYZ$EDuFTeaym#<-N{5Or4zkjIlY8Nw} ze*Kzp^Aq`=or)PRfB#V9arnMi+h6|vQBH|du2}Kh3+x|iJgG~(d4A=t)OpnXLyafD zaTF(B{{ErHlR8v!;>rF|@+wJzk`yROf&brAK;I^n{FElB(iW7)t^8gu`L_H{FTc%8 zTV2|%(k7SkL4Jp~fi3JHZFeb$_}5B(wa?16X(gAj}m z3`Quz5RM@jieZSrzYvKi3`aC#5Q`CrLp%~N5~DC0V=xxuz*UsW9f~K?orHIhh{>3O zBqU=hreQi}U?yf^Hs)Y1=HWfe#{#^Mg;<2eSb`6bf~8o7yYKUNjD3(a2t1U7xy5; z@6&yN@9;f-z(YKO4F5aV&$*wapLpGuoVzM#fjY6}%X7lwlr4s!ulTa(>>>R;wM=7b zVXRDfM4i69+EM>!ZS9>P=d%3D$Hd$Le#$v+A-SJkzhkK}&YQn1$E!rxz(`%HsAD!} zuhl>Q>{X^MJWgrmZ$wX1yz2aSGj6$VYNS4-ejIzgAKg&)UO9tL|GYMJjF?GW9t5~=C8Lr z-pt>GP_pjwQlq~7|F<$Ycm77?{Bqu8EIImMC8vG)w1tP-ar9Q5v--dAa6_LZ&;IXv zy~+Ib^OkM*P4bO`^DKG)KQ{%8`1ZAy>i$zW?{;F_$UlEkPF!?q=GBO&S9m!2#e|L= n&J!t=x?$H|GK^lzP9^VM^ut}eHNQ36F+#t!m304KOM(9a__%#` literal 0 HcmV?d00001 diff --git a/doc/vax_doc.doc b/doc/vax_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..19a703292f90cda6f274d74be684cca6da71be7e GIT binary patch literal 123392 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̽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 j++) { /* count units */ uptr = dptr->units + j; - if (uptr->flags & UNIT_DISABLE) - udbl++; - if (!(uptr->flags & UNIT_DIS)) + if (!(uptr->flags & UNIT_DIS)) /* count enabled units */ ucnt++; + else if (uptr->flags & UNIT_DISABLE) + udbl++; /* count user-disabled */ } show_all_mods (st, dptr, dptr->units, MTAB_VDV); /* show dev mods */ if (dptr->numunits == 0) fprintf (st, "\n"); else { - if (udbl && (ucnt == 0)) + if (ucnt == 0) fprintf (st, ", all units disabled\n"); - else if (ucnt > 1) - fprintf (st, ", %d units\n", ucnt); + else if ((ucnt > 1) || (udbl > 0)) + fprintf (st, ", %d units\n", ucnt + udbl); else if (flag) fprintf (st, "\n"); } @@ -1819,7 +1819,7 @@ if (flag) /* dev only? */ for (j = 0; j < dptr->numunits; j++) { /* loop thru units */ uptr = dptr->units + j; if ((uptr->flags & UNIT_DIS) == 0) - show_unit (st, dptr, uptr, ucnt); + show_unit (st, dptr, uptr, ucnt + udbl); } return SCPE_OK; } diff --git a/sigma/Design Notes on the Sigma 7.doc b/sigma/Design Notes on the Sigma 7.doc new file mode 100644 index 0000000000000000000000000000000000000000..fa42bb907269a3017409252d18009152d170e991 GIT binary patch literal 25088 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, instead of > 0. +5. CPU: PSD change instructions were not saving old PC in PC queue. +6. CPU: illegal register pointer does not stop the system on the Sigma 5-7; + instead, registers read as 0's, and writes are ignored. +7. CPU: traps were setting the Sigma 9 vector field unconditionally. +8. CPU: CH does not SEXT Rn<16:31>. +9. CPU: MTW and MTH overflow traps not implemented. +10. CPU: MTH condition code calculations not implemented correctly. +11. CPU: illegal shift opcodes on the Sigma 5-7 are treated as arithmetic + single (according to the AUTO diagnostic). +12. FP: SF did not calculate condition codes correctly. +13. FP: SF left did not detect normalized if the count reached zero. +14. FP: SF right was retaining a guard digit incorrectly. +15. FP: SF right test was not taking into account single/double precision. +16. FP: fp_unpack killed the operand sign before testing it. +17. FP: fp_pack did not recomplement a negative operand. +18. CPU: DW overflow test was incorrect. +19. IO: device status bit field was incorrectly defined. +20. IO: AIO was testing for == 0 instead of != 0. +21. TT: input keyboard character mappings were incorrect. +22. SYS: shifts were not displaying or accepting an index register. +23. CPU: mapping from pulse interrupt number to counter interrupt number + was incorrect. +24. CPU, CIS: handling of instructions aborts was incorrect. +25. CPU: CC2,4 set incorrectly on aborted stack instruction. +26. CPU: CC2,4 set incorrectly on MSP,0 instruction. +27. CPU: PLW not converting operand address to byte address. +28. CPU: PSM, PLM not converting limit operand address to byte address correctly. +29. CPU: PLM wrote registers in inverse order. +30. Definitions: number of virtual, physical pages derived incorrectly. +31. MAP: MMC control set wrap incorrect. +32. MAP: MMC register update of Rn|1 incorrect. +33. CPU: CBS set CC's incorrectly on unequal. +34. CPU: TTBS set CC's incorrectly on early exit. +35. IO: chan_proc_epilog and four other routines extracted device address incorrectly. +36. CPU: DW was fetching halfwords instead of words. +37. CPU: multiples were not setting condition codes on 0 operands. +38. FP: floating add zero test on second operand was inverted. +39. FP: floating add zero cases failed to set the result variable. +40. FP: floating add zero cases failed to go through postnormalization logic. +41. FP: double precision add macro lost high carry out. +42. FP: double precision add macro had an undocumented restriction about operands. +43. FP: all double precision instructions unpacked the wrong low order memory operand. +44. FP: normalization failed to decrement the exponent. +45. FP: in single precision, removing the guard digit created a spurious low-order digit. +46. FP: denormalization failed to clear the low word (single precision). +47. FP: denormalization failed to clear the guard digit (double precision). +48. FP: add/subtract failed to treat abnormal 0's as normal numbers. +49. CIS: WriteDecA set local rather than global condition codes. +50. CIS: Illegal digit check missed byte 0. +51. CIS: Overflow check set wrong condition codes. +52. CIS: NibbleLShift routine overflow check was (also broken in VAX, PDP11). +53. CIS: WordLShift routine overflow check was wrong (also broken in VAX, PDP11). +54. CIS: WordLShift had signed/unsigned variable conflict in compare. +55. CIS: WriteDecA not setting correct condition codes for -0. +55. CIS: WriteDECA not clearing CC3/4 before setting. +56. CIS: DM shift-and-test loop did 14 iterations instead of 15. +57. CIS: DM final shift of 16 done outside non-zero case instead of inside. +58. CIS: DD put quotient and remainder in wrong registers. +59. CIS: DD did not shift remainder to proper place, based on dividend/divisor widths. +60. CIS: DD overflow test missed exact 16 digit quotient case. +61. CIS: algorithm to compute length of operand failed for certain lengths (also broken + in VAX, PDP11). +62. CIS: DM and DD answer was wrong on restart cases. [NOT FIXED YET] +63. CIS: EBS fetched pattern from wrong address pointer. +64. CIS: EBS field separator wrote wrong byte. +65. MAP: Access codes defined incorrectly for access protection check. +66. CPU: LPSD fetching operands with write check rather than read check. +67. CPU: Illegal instruction stop (and other trap stops) weren't rolling back the PC. +68. CPU: History routine merged CC's into history array incorrectly. +69. CPU: History routine stored incremented rather than actualy PC. +70. CPU: History reporting routine printed wrong operand value, due to colliding declarations. +71. IO: Power up/down interrupts should not be implemented. +72. IO: WD was not recalculating int_hiact. +73. IO: Interrupt chain was not linked at powerup. +74. IO: Interrupt chain link algorithm was wrong. +75. IO: WD processing was spanning [beg,end) rather than [beg,end]. +76. RTC: RTC interrupts were happening at the wrong level. +77. PTR: leader skip was testing for channel end. +78. PTR: leader skip was testing per command instead of per reel/file. +79. PTR: end of file was treated as fatal error instead of channel end + length error. +80. PTR, PTP: units were not marked UNIT_SEQ. +81. LPT: unit was not marked UNIT_SEQ. +82. IO: device address set/show updated/displayed wrong field in single unit devices. +83. CPU: address calculation for MTx in interrupt location used incorrect length. +84. LPT: print, format opcode definitions inverted. +85. LPT: wrong index used to count buffer fill loop. +86. IO: CPU/IOP communications through 20/21 were not modelled. +87. CIS: Multiply algorithm incorrect, multiply restart not modelled. +88. CIS: Divide algorithm incorrect, divide restart not modelled. +89. IO: WD .44 not recognized as effective NOP. +90. CPU: Sigma 5 (uniquely) does not implement CVA or CVS. +91. IO: AIO merging status incorrectly. +92. IO: system for returning status byte from IO was muddled; rewrite required. +93. RAD: 7232 track shift offset was incorrectly defined. +94. CPU: MTX for interrupts returned wrong value. +95. CPU: Counter overflow trigger equation was incorrect. +96. CPU: MTX interrupts not recalculating interrupt summary values. +97. RTC: SET/SHOW C1-C4 routines were broken. +98. DP: comparison for sector field overflow was incorrect. +99. DP: cross-cylinder incorrectly set on read to end of cylinder. +100. DP: seek never executed. +101. DP: seek followon state codes set incorrectly. +102. DP: cylinder offset defined incorrectly. +103. DP: SIO not initing unit thread properly for non-zero units. +104. MUX: Line enable must be remembered for lines that are not currently connected. +105. RAD: write check was reading words off disk instead of bytes. +106. RAD: end of transfer routine checking for address error incorrectly. +107. DK: end of transfer routine checking for address error incorrectly. + + +Diagnostic Notes +---------------- + +1. PATTERN paper tape (SA = 60, end pass = 1AC), SET CPU RBLKS=32. + Break at 60 is triggered once during loading process. +2. VERIFY paper tape (SA = 140, end pass = 8E6). +3. AUTO paper tape (SA = 105), SET CPU LASLMS to suppress spurious error message. + AUTO magtape runs correctly with no messages. +4. SUFFIX magtape (SA = 100, end pass = 115), no printouts. +5. FLOAT magtape. +6. DECIMAL paper tape (SA = EE). +7. PROTECT paper tape (SA = F9), long runtime until printout. +8. MAP paper tape (SA = 7C). +9. MEDIC paper tape (SA = 68), set SSW2 after breakpoint, long runtime. +10. INT magtape, stops after M6, set SSW2 and continue, + enters pattern generator and loops forever, as expected. +11. RTC paper tape, clocks must be 500Mhz, reports clocks as "too slow" due + to faster simulation speed. + Runs correctly with SET THROTTLE 500K. + + + + + + + + + + + + + + + diff --git a/sigma/sigma_cis.c b/sigma/sigma_cis.c new file mode 100644 index 00000000..3205ac05 --- /dev/null +++ b/sigma/sigma_cis.c @@ -0,0 +1,990 @@ +/* sigma_cis.c: Sigma decimal instructions + + Copyright (c) 2007-2008, Robert 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. + + Questions: + + 1. On the Sigma 9, in ASCII mode, is an ASCII blank used in EBS? +*/ + +#include "sigma_defs.h" + +/* Decimal string structure */ + +#define DSTRLNT 4 /* words per dec string */ +#define DECA 12 /* first dec accum reg */ + +/* Standard characters */ + +#define ZONE_E 0xF0 /* EBCDIC zone bits */ +#define ZONE_A 0x30 /* ASCII zone bits */ +#define ZONE ((PSW1 & PSW1_AS)? ZONE_A: ZONE_E) +#define PKPLUS_E 0xC /* EBCDIC preferred plus */ +#define PKPLUS_A 0xA /* ASCII preferred plus */ +#define PKPLUS ((PSW1 & PSW1_AS)? PKPLUS_A: PKPLUS_E) +#define BLANK_E 0x40 /* EBCDIC blank */ +#define BLANK_A 0x20 /* ASCII blank */ +#define BLANK ((PSW1 & PSW1_AS)? BLANK_A: BLANK_E) + +/* Edit special characters */ + +#define ED_DS 0x20 /* digit select */ +#define ED_SS 0x21 /* start significance */ +#define ED_FS 0x22 /* field separator */ +#define ED_SI 0x23 /* immediate significance */ + +/* Decimal strings run low order (word 0/R15) to high order (word 3/R12) */ + +typedef struct { + uint32 sign; + uint32 val[DSTRLNT]; + } dstr_t; + +/* Copy decimal accumulator to decimal string, no validation or sign separation */ + +#define ReadDecA(src) for (i = 0; i < DSTRLNT; i++) \ + src.val[DSTRLNT - 1 - i] = R[DECA + i]; + +static dstr_t Dstr_zero = { 0, 0, 0, 0, 0 }; + +extern uint32 *R; +extern uint32 CC; +extern uint32 PSW1; +extern uint32 bvamqrx; +extern uint32 cpu_model; + +uint32 ReadDstr (uint32 lnt, uint32 addr, dstr_t *dec); +uint32 WriteDstr (uint32 lnt, uint32 addr, dstr_t *dec); +void WriteDecA (dstr_t *dec, t_bool cln); +void SetCC2Dstr (uint32 lnt, dstr_t *dst); +uint32 TestDstrValid (dstr_t *src); +uint32 DstrInvd (void); +uint32 AddDstr (dstr_t *src1, dstr_t *src2, dstr_t *dst, uint32 cin); +void SubDstr (dstr_t *src1, dstr_t *src2, dstr_t *dst); +int32 CmpDstr (dstr_t *src1, dstr_t *src2); +uint32 LntDstr (dstr_t *dsrc); +uint32 NibbleLshift (dstr_t *dsrc, uint32 sc, uint32 cin); +uint32 NibbleRshift (dstr_t *dsrc, uint32 sc, uint32 cin); +t_bool GenLshift (dstr_t *dsrc, uint32 sc); +void GenRshift (dstr_t *dsrc, uint32 sc); +uint32 ed_getsrc (uint32 sa, uint32 *c, uint32 *d); +void ed_advsrc (uint32 rn, uint32 c); +t_bool cis_test_int (dstr_t *src1, uint32 *kint); +void cis_dm_int (dstr_t *src, dstr_t *dst, uint32 kint); +void cis_dd_int (dstr_t *src, dstr_t *dst, uint32 t, uint32 *kint); + +/* Decimal instructions */ + +uint32 cis_dec (uint32 op, uint32 lnt, uint32 bva) +{ +dstr_t src1, src2, src2x, dst; +uint32 i, t, kint, ldivr, ldivd, ad, c, d, end; +int32 sc; +uint32 tr; + +if (lnt == 0) /* adjust length */ + lnt = 16; +CC &= ~(CC1|CC2); /* clear CC1, CC2 */ + +switch (op) { /* case on opcode */ + + case OP_DL: /* decimal load */ + if ((tr = ReadDstr (lnt, bva, &dst)) != 0) /* read mem string */ + return tr; + WriteDecA (&dst, FALSE); /* store result */ + break; + + case OP_DST: /* decimal store */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + if ((tr = WriteDstr (lnt, bva, &dst)) != 0) /* write to mem */ + return tr; + break; + + case OP_DS: /* decimal subtract */ + case OP_DA: /* decimal add */ + ReadDecA (src1); /* read dec accum */ + if ((tr = TestDstrValid (&src1)) != 0) /* valid? */ + return tr; + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + if (op == OP_DS) /* sub? invert sign */ + src2.sign = src2.sign ^ 1; + if (src1.sign ^ src2.sign) { /* opp signs? sub */ + if (CmpDstr (&src1, &src2) < 0) { /* src1 < src2? */ + SubDstr (&src1, &src2, &dst); /* src2 - src1 */ + dst.sign = src2.sign; /* sign = src2 */ + } + else { + SubDstr (&src2, &src1, &dst); /* src1 - src2 */ + dst.sign = src1.sign; /* sign = src1 */ + } + } + else { /* addition */ + if (AddDstr (&src1, &src2, &dst, 0)) { /* add, overflow? */ + CC |= CC2; /* set CC2 */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + dst.sign = src1.sign; /* set result sign */ + } + WriteDecA (&dst, TRUE); /* store result */ + break; + + case OP_DC: /* decimal compare */ + ReadDecA ( src1); /* read dec accum */ + if ((tr = TestDstrValid (&src1)) != 0) /* valid? */ + return tr; + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + LntDstr (&src1); /* clean -0 */ + LntDstr (&src2); + if (src1.sign ^ src2.sign) /* signs differ? */ + CC = src1.sign? CC4: CC3; /* set < or > */ + else { /* same signs */ + t = CmpDstr (&src1, &src2); /* compare strings */ + if (t < 0) + CC = (src1.sign? CC3: CC4); + else if (t > 0) + CC = (src1.sign? CC4: CC3); + else CC = 0; + } + break; + +/* Decimal multiply - algorithm from George Plue. + + The Sigma does decimal multiply one digit at a time, using the multiplicand + and a doubled copy of the multiplicand. Multiplying by digits 1-5 is + synthesized by 1-3 adds; multiplying by digits 6-9 is synthesized by 1-2 + subtractions, and adding 1 to the next multiplier digit. (That is, + multiplying by 7 is done by multiplying by "10 - 3".) This requires at + most one extra add to fixup the last digit, and minimizes the overall + number of adds (average 1.5 adds per multiplier digit). Note that + multiplication proceeds from right to left. + + The Sigma 5-9 allowed decimal multiply to be interrupted; the 5X0 series + did not. An interrupted multiply uses a sign digit in R12 and R13 as the + divider between the remaining multiplier (to the left of the sign, and + in the low-order digit of R15) and the partial product (to the right of + the sign). Because the partial product may be negative, leading 0x99's + may have been stripped and need to be restored. + + The real Sigma's probably didn't run a validty test after separation of + the partial product and multiplier, but it doesn't hurt, and prevents + certain corner cases from causing errors. */ + + case OP_DM: /* decimal multiply */ + if (lnt >= 9) /* invalid length? */ + return DstrInvd (); + ReadDecA (src1); /* get dec accum */ + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + dst = Dstr_zero; /* clear result */ + kint = 0; /* assume no int */ + if (!QCPU_5X0 && /* S5-9? */ + (cis_test_int (&src1, &kint))) /* interrupted? */ + cis_dm_int (&src1, &dst, kint); /* restore */ + else if ((tr = TestDstrValid (&src1)) != 0) /* mpyr valid? */ + return tr; + if (LntDstr (&src1) && LntDstr (&src2)) { /* both opnds != 0? */ + dst.sign = src1.sign ^ src2.sign; /* sign of result */ + AddDstr (&src2, &src2, &src2x, 0); /* get 2*mplcnd */ + for (i = 1; i <= 16; i++) { /* 16 iterations */ + if (i >= kint) { /* past int point? */ + NibbleRshift (&src1, 1, 0); /* mpyr right 4 */ + d = src1.val[0] & 0xF; /* get digit */ + switch (d) { /* case */ + case 5: /* + 2 + 2 + 1 */ + AddDstr (&src2x, &dst, &dst, 0); + case 3: /* + 2 + 1 */ + AddDstr (&src2x, &dst, &dst, 0); + case 1: /* + 1 */ + AddDstr (&src2, &dst, &dst, 0); + case 0: + break; + case 4: /* + 2 + 2 */ + AddDstr (&src2x, &dst, &dst, 0); + case 2: /* + 2 */ + AddDstr (&src2x, &dst, &dst, 0); + break; + case 6: /* - 2 - 2 + 10 */ + SubDstr (&src2x, &dst, &dst); + case 8: /* - 2 + 10 */ + SubDstr (&src2x, &dst, &dst); + src1.val[0] += 0x10; /* + 10 */ + break; + case 7: /* -2 - 1 + 10 */ + SubDstr (&src2x, &dst, &dst); + case 9: /* -1 + 10 */ + SubDstr (&src2, &dst, &dst); + default: /* + 10 */ + src1.val[0] += 0x10; + } /* end switch */ + } /* end if >= kint */ + NibbleLshift (&src2, 1, 0); /* shift mplcnds */ + NibbleLshift (&src2x, 1, 0); + } /* end for */ + } /* end if != 0 */ + WriteDecA (&dst, TRUE); /* store result */ + break; + +/* Decimal divide overflow calculation - if the dividend has true length d, + and the divisor true length r, then the quotient will have (d - r) or + (d - r + 1) digits. Therefore, if (d - r) > 15, the quotient will not + fit. However, if (d - r) == 15, it may or may not fit, depending on + whether the first subtract succeeds. Therefore, it's necessary to test + after the divide to see if the quotient has one extra digit. */ + + case OP_DD: /* decimal divide */ + if (lnt >= 9) /* invalid length? */ + return DstrInvd (); + ReadDecA (src1); /* read dec accum */ + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + dst = Dstr_zero; /* clear result */ + kint = 0; /* no interrupt */ + if (!QCPU_5X0 && /* S5-9? */ + (cis_test_int (&src1, &t))) { /* interrupted? */ + cis_dd_int (&src1, &dst, t, &kint); /* restore */ + t = t - 1; + } + else { /* normal start? */ + if ((tr = TestDstrValid (&src1)) != 0) /* divd valid? */ + return tr; + ldivr = LntDstr (&src2); /* divr lnt */ + ldivd = LntDstr (&src1); /* divd lnt */ + if ((ldivr == 0) || /* div by zero? */ + (ldivd > (ldivr + 15))) { /* quo too big? */ + CC |= CC2; /* divide check */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + if (CmpDstr (&src1, &src2) < 0) { /* no divide? */ + R[12] = src1.val[1]; /* remainder */ + R[13] = src1.val[0] | (PKPLUS + src1.sign); + R[14] = 0; /* quotient */ + R[15] = PKPLUS; + CC = 0; + return SCPE_OK; + } + t = ldivd - ldivr; + } + dst.sign = src1.sign ^ src2.sign; /* calculate sign */ + GenLshift (&src2, t); /* align */ + for (i = 0; i <= t; i++) { /* divide loop */ + for (d = kint; /* find digit */ + (d < 10) && (CmpDstr (&src1, &src2) >= 0); + d++) + SubDstr (&src2, &src1, &src1); + dst.val[0] = (dst.val[0] & ~0xF) | d; /* insert quo dig */ + NibbleLshift (&dst, 1, 0); /* shift quotient */ + NibbleRshift (&src2, 1, 0); /* shift divisor */ + kint = 0; /* no more int */ + } /* end divide loop */ + if (dst.val[2]) { /* quotient too big? */ + CC |= CC2; /* divide check */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + CC = dst.sign? CC4: CC3; /* set CC's */ + R[12] = src1.val[1]; /* remainder */ + R[13] = src1.val[0] | (PKPLUS + src1.sign); + R[14] = dst.val[1]; /* quotient */ + R[15] = dst.val[0] | (PKPLUS + dst.sign); + break; + + case OP_DSA: /* decimal shift */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + CC = 0; /* clear CC's */ + sc = SEXT_H_W (bva >> 2); /* shift count */ + if (sc > 31) /* sc in [-31,31] */ + sc = 31; + if (sc < -31) + sc = -31; + if (sc < 0) { /* right shift? */ + sc = -sc; /* |shift| */ + GenRshift (&dst, sc); /* do shift */ + dst.val[0] = dst.val[0] & ~0xF; /* clear sign */ + } /* end right shift */ + else if (sc) { /* left shift? */ + if (GenLshift (&dst, sc)) /* do shift */ + CC |= CC2; + } /* end left shift */ + WriteDecA (&dst, FALSE); /* store result */ + break; + + case OP_PACK: /* zoned to packed */ + dst = Dstr_zero; /* clear result */ + end = (2 * lnt) - 1; /* zoned length */ + for (i = 1; i <= end; i++) { /* loop thru char */ + ad = (bva + end - i) & bvamqrx; /* zoned character */ + if ((tr = ReadB (ad, &c, VR)) != 0) /* read char */ + return tr; + if (i == 1) { /* sign + digit? */ + uint32 s; + s = (c >> 4) & 0xF; /* get sign */ + if (s < 0xA) + return DstrInvd (); + if ((s == 0xB) || (s == 0xD)) /* negative */ + dst.sign = 1; + } + d = c & 0xF; /* get digit */ + if (d > 0x9) + return DstrInvd (); + dst.val[i / 8] = dst.val[i / 8] | (d << ((i % 8) * 4)); + } + WriteDecA (&dst, FALSE); /* write result */ + break; + + case OP_UNPK: /* packed to zoned */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + end = (2 * lnt) - 1; /* zoned length */ + if ((tr = ReadB (bva, &c, VW)) != 0) /* prove writeable */ + return tr; + for (i = 1; i <= end; i++) { /* loop thru chars */ + c = (dst.val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */ + if (i == 1) /* first? */ + c |= ((PKPLUS + dst.sign) << 4); /* or in sign */ + else c |= ZONE; /* no, or in zone */ + ad = (bva + end - i) & bvamqrx; + if ((tr = WriteB (ad, c, VW)) != 0) /* write to memory */ + return tr; + } + SetCC2Dstr (lnt, &dst); /* see if too long */ + break; + } +return 0; +} + +/* Test for interrupted multiply or divide */ + +t_bool cis_test_int (dstr_t *src, uint32 *kint) +{ +int32 i; +uint32 wd, sc, d; + +for (i = 15; i >= 1; i--) { /* test 15 nibbles */ + wd = (DSTRLNT/2) + (i / 8); + sc = (i % 8) * 4; + d = (src->val[wd] >> sc) & 0xF; + if (d >= 0xA) { + *kint = (uint32) i; + return TRUE; + } + } +return FALSE; +} + +/* Resume interrupted multiply + + The sign that was found is the "fence" between the the remaining multiplier + and the partial product: + R val + +--+--+--+--+--+--+--+--+ + | mpyer |sn|pp| 12 3 + +--+--+--+--+--+--+--+--+ + | partial product | 13 2 + +--+--+--+--+--+--+--+--+ + | partial product | 14 1 + +--+--+--+--+--+--+--+--+ + | partial product |mp| 15 0 + +--+--+--+--+--+--+--+--+ + + This routine separates the multiplier and partial product, returns the + multiplier as a valid decimal string in src, and the partial product + as a value with no sign in dst */ + +void cis_dm_int (dstr_t *src, dstr_t *dst, uint32 kint) +{ +uint32 ppneg, wd, sc, d, curd; +int32 k; + +*dst = *src; /* copy input */ +wd = (DSTRLNT/2) + (kint / 8); +sc = (kint % 8) * 4; +d = (src->val[wd] >> sc) & 0xF; /* get sign fence */ +ppneg = ((d >> 2) & 1) ^ 1; /* partial prod neg? */ +curd = (src->val[0] & 0xF) + ppneg; /* bias cur digit */ +src->val[wd] = (src->val[wd] & ~(0xF << sc)) | /* replace sign */ + (curd << sc); /* with digit */ +GenRshift (src, kint + 15); /* right justify */ +src->sign = ((d == 0xB) || (d == 0xD))? 1: 0; /* set mpyr sign */ +src->val[0] = src->val[0] & ~0xF; /* clear sign pos */ + +/* Mask out multiplier */ + +for (k = DSTRLNT - 1; k >= (int32) wd; k--) /* words hi to lo */ + dst->val[k] &= ~(0xFFFFFFFFu << + ((k > (int32) wd)? 0: sc)); + +/* Recreate missing high order digits for negative partial product */ + +if (ppneg) { /* negative? */ + for (k = (DSTRLNT * 4) - 1; k != 0; k--) { /* bytes hi to lo */ + wd = k / 4; + sc = (k % 4) * 8; + if (((dst->val[wd] >> sc) & 0xFF) != 0) + break; + dst->val[wd] |= (0x99 << sc); /* repl 00 with 99 */ + } /* end for */ + } +dst->val[0] &= ~0xF; /* clear pp sign */ +return; +} + +/* Resume interrupted divide + + The sign that was found is the "fence" between the the quotient and the + remaining dividend product: + R val + +--+--+--+--+--+--+--+--+ + | quotient |sn|dv| 12 3 + +--+--+--+--+--+--+--+--+ + | dividend | 13 2 + +--+--+--+--+--+--+--+--+ + | dividend | 14 1 + +--+--+--+--+--+--+--+--+ + | dividend |qu| 15 0 + +--+--+--+--+--+--+--+--+ + + This routine separates the quotient and the remaining dividend, returns + the dividend as a valid decimal string, the quotient as a decimal string + without sign, and kint is the partial value of the last quotient digit. */ + +void cis_dd_int (dstr_t *src, dstr_t *dst, uint32 nib, uint32 *kint) +{ +uint32 wd, sc, d, curd; +int32 k; + +wd = (DSTRLNT/2) + (nib / 8); +sc = (nib % 8) * 4; +curd = src->val[0] & 0xF; /* last quo digit */ +*dst = *src; /* copy input */ +GenRshift (dst, nib + 16); /* right justify quo */ +d = dst->val[0] & 0xF; /* get sign fence */ +dst->val[0] = (dst->val[0] & ~0xF) | curd; /* repl with digit */ +*kint = curd; + +/* Mask out quotient */ + +for (k = DSTRLNT - 1; k >= (int32) wd; k--) /* words hi to lo */ + src->val[k] &= ~(0xFFFFFFFFu << + ((k > (int32) wd)? 0: sc)); +src->sign = ((d == 0xB) || (d == 0xD))? 1: 0; /* set divd sign */ +src->val[0] = src->val[0] & ~0xF; /* clr sign digit */ +return; +} + +/* Get packed decimal string from memory + + Arguments: + lnt = decimal string length + adr = decimal string address + src = decimal string structure + Output: + trap or abort signal + + Per the Sigma spec, bad digits or signs cause a fault or abort */ + +uint32 ReadDstr (uint32 lnt, uint32 adr, dstr_t *src) +{ +uint32 i, c, bva; +uint32 tr; + +*src = Dstr_zero; /* clear result */ +for (i = 0; i < lnt; i++) { /* loop thru string */ + bva = (adr + lnt - i - 1) & bvamqrx; /* from low to high */ + if ((tr = ReadB (bva, &c, VR)) != 0) /* read byte */ + return tr; + src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8)); + } /* end for */ +return TestDstrValid (src); +} + +/* Separate sign, validate sign and digits of decimal string */ + +uint32 TestDstrValid (dstr_t *src) +{ +uint32 i, j, s, t; + +s = src->val[0] & 0xF; /* get sign */ +if (s < 0xA) /* valid? */ + return DstrInvd (); +if ((s == 0xB) || (s == 0xD)) /* negative? */ + src->sign = 1; +else src->sign = 0; +src->val[0] &= ~0xF; /* clear sign */ + +for (i = 0; i < DSTRLNT; i++) { /* check 4 words */ + for (j = 0; j < 8; j++) { /* 8 digit/word */ + t = (src->val[i] >> (28 - (j * 4))) & 0xF; /* get digit */ + if (t > 0x9) /* invalid digit? */ + return DstrInvd (); /* exception */ + } + } +return 0; +} + +/* Invalid digit or sign: set CC1, trap or abort instruction */ + +uint32 DstrInvd (void) +{ +CC |= CC1; /* set CC1 */ +if (PSW1 & PSW1_DM) /* if enabled, trap */ + return TR_DEC; +return WSIGN; /* otherwise, abort */ +} + +/* Store decimal string + + Arguments: + lnt = decimal string length + adr = decimal string address + dst = decimal string structure + + Returns memory management traps (if any) + Bad digits and invalid sign are impossible +*/ + +uint32 WriteDstr (uint32 lnt, uint32 adr, dstr_t *dst) +{ +uint32 i, bva, c; +uint32 tr; + +dst->val[0] = dst->val[0] | (PKPLUS + dst->sign); /* set sign */ +if ((tr = ReadB (adr, &c, VW)) != 0) /* prove writeable */ + return tr; +for (i = 0; i < lnt; i++) { /* loop thru bytes */ + c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF; /* from low to high */ + bva = (adr + lnt - i - 1) & bvamqrx; + if ((tr = WriteB (bva, c, VW)) != 0) /* store byte */ + return tr; + } /* end for */ +SetCC2Dstr (lnt, dst); /* check overflow */ +return 0; +} + +/* Store result in decimal accumulator + + Arguments: + dst = decimal string structure + cln = clean -0 if true + + Sets condition codes CC3 and CC4 + Bad digits and invalid sign are impossible */ + +void WriteDecA (dstr_t *dst, t_bool cln) +{ +uint32 i, nz; + +CC &= ~(CC3|CC4); /* assume zero */ +for (i = 0, nz = 0; i < DSTRLNT; i++) { /* save 32 digits */ + R[DECA + i] = dst->val[DSTRLNT - 1 - i]; + nz |= dst->val[DSTRLNT - 1 - i]; + } +if (nz) /* non-zero? */ + CC |= (dst->sign)? CC4: CC3; /* set CC3 or CC4 */ +else if (cln) /* zero, clean? */ + dst->sign = 0; /* clear sign */ +R[DECA + DSTRLNT - 1] |= (PKPLUS + dst->sign); /* or in sign */ +return; +} + +/* Set CC2 for decimal string store + + Arguments: + lnt = string length + dst = decimal string structure + Output: + sets CC2 if information won't fit */ + +void SetCC2Dstr (uint32 lnt, dstr_t *dst) +{ +uint32 i, limit, mask; +static uint32 masktab[8] = { + 0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000, + 0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000 + }; + +lnt = (lnt * 2) - 1; /* number of digits */ +mask = 0; /* can't ovflo */ +limit = lnt / 8; /* limit for test */ +for (i = 0; i < DSTRLNT; i++) { /* loop thru value */ + if (i == limit) /* @limit, get mask */ + mask = masktab[lnt % 8]; + else if (i > limit) /* >limit, test all */ + mask = 0xFFFFFFFF; + if (dst->val[i] & mask) /* test for ovflo */ + CC |= CC2; + } +return; +} + +/* Add decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + ds = dest decimal string + cy = carry in + Output: + 1 if carry, 0 if no carry + + This algorithm courtesy Anton Chernoff, circa 1992 or even earlier. + + We trace the history of a pair of adjacent digits to see how the + carry is fixed; each parenthesized item is a 4b digit. + + Assume we are adding: + + (a)(b) I + + (x)(y) J + + First compute I^J: + + (a^x)(b^y) TMP + + Note that the low bit of each digit is the same as the low bit of + the sum of the digits, ignoring the carry, since the low bit of the + sum is the xor of the bits. + + Now compute I+J+66 to get decimal addition with carry forced left + one digit: + + (a+x+6+carry mod 16)(b+y+6 mod 16) SUM + + Note that if there was a carry from b+y+6, then the low bit of the + left digit is different from the expected low bit from the xor. + If we xor this SUM into TMP, then the low bit of each digit is 1 + if there was a carry, and 0 if not. We need to subtract 6 from each + digit that did not have a carry, so take ~(SUM ^ TMP) & 0x11, shift + it right 4 to the digits that are affected, and subtract 6*adjustment + (actually, shift it right 3 and subtract 3*adjustment). +*/ + +uint32 AddDstr (dstr_t *s1, dstr_t *s2, dstr_t *ds, uint32 cy) +{ +uint32 i; +uint32 sm1, sm2, tm1, tm2, tm3, tm4; + +for (i = 0; i < DSTRLNT; i++) { /* loop low to high */ + tm1 = s1->val[i] ^ (s2->val[i] + cy); /* xor operands */ + sm1 = s1->val[i] + (s2->val[i] + cy); /* sum operands */ + sm2 = sm1 + 0x66666666; /* force carry out */ + cy = ((sm1 < s1->val[i]) || (sm2 < sm1)); /* check for ovflo */ + tm2 = tm1 ^ sm2; /* get carry flags */ + tm3 = (tm2 >> 3) | (cy << 29); /* compute adjust */ + tm4 = 0x22222222 & ~tm3; /* clrr where carry */ + ds->val[i] = (sm2 - (3 * tm4)) & WMASK; /* final result */ + } +return cy; +} + +/* Subtract decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + ds = dest decimal string + + Note: the routine assumes that s1 <= s2 + +*/ + +void SubDstr (dstr_t *s1, dstr_t *s2, dstr_t *ds) +{ +uint32 i; +dstr_t compl; + +for (i = 0; i < DSTRLNT; i++) /* 9's comp s2 */ + compl.val[i] = 0x99999999 - s1->val[i]; +AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */ +return; +} + +/* Compare decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + Output: + 1 if >, 0 if =, -1 if < +*/ + +int32 CmpDstr (dstr_t *s1, dstr_t *s2) +{ +int32 i; + +for (i = DSTRLNT - 1; i >=0; i--) { + if (s1->val[i] > s2->val[i]) + return 1; + if (s1->val[i] < s2->val[i]) + return -1; + } +return 0; +} + +/* Get exact length of decimal string, clean -0 + + Arguments: + dst = decimal string structure + Output: + number of non-zero digits +*/ + +uint32 LntDstr (dstr_t *dst) +{ +int32 nz, i; + +for (nz = DSTRLNT - 1; nz >= 0; nz--) { + if (dst->val[nz]) { + for (i = 7; i >= 0; i--) { + if ((dst->val[nz] >> (i * 4)) & 0xF) + return (nz * 8) + i; + } + } + } +dst->sign = 0; +return 0; +} + +/* Word shift right + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles +*/ + +void GenRshift (dstr_t *dsrc, uint32 cnt) +{ +uint32 i, sc, sc1; + +sc = cnt / 8; +sc1 = cnt % 8; +if (sc) { + for (i = 0; i < DSTRLNT; i++) { + if ((i + sc) < DSTRLNT) + dsrc->val[i] = dsrc->val[i + sc]; + else dsrc->val[i] = 0; + } + } +if (sc1) + NibbleRshift (dsrc, sc1, 0); +return; +} + +/* General shift left + + Arguments: + dsrc = decimal string structure + cnt = shift count in nibbles +*/ + +t_bool GenLshift (dstr_t *dsrc, uint32 cnt) +{ +t_bool i, c, sc, sc1; + +c = 0; +sc = cnt / 8; +sc1 = cnt % 8; +if (sc) { + for (i = DSTRLNT - 1; (int32) i >= 0; i--) { + if (i >= sc) + dsrc->val[i] = dsrc->val[i - sc]; + else { + c |= dsrc->val[i]; + dsrc->val[i] = 0; + } + } + } +if (sc1) + c |= NibbleLshift (dsrc, sc1, 0); +return (c? TRUE: FALSE); +} + +/* Nibble shift right + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles + cin = carry in +*/ + +uint32 NibbleRshift (dstr_t *dsrc, uint32 sc, uint32 cin) +{ +int32 i; +uint32 s, nc; + +if (s = sc * 4) { + for (i = DSTRLNT - 1; (int32) i >= 0; i--) { + nc = (dsrc->val[i] << (32 - s)) & WMASK; + dsrc->val[i] = ((dsrc->val[i] >> s) | + cin) & WMASK; + cin = nc; + } + return cin; + } +return 0; +} + +/* Nibble shift left + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles + cin = carry in +*/ + +uint32 NibbleLshift (dstr_t *dsrc, uint32 sc, uint32 cin) +{ +uint32 i, s, nc; + +if (s = sc * 4) { + for (i = 0; i < DSTRLNT; i++) { + nc = dsrc->val[i] >> (32 - s); + dsrc->val[i] = ((dsrc->val[i] << s) | + cin) & WMASK; + cin = nc; + } + return cin; + } +return 0; +} +/* Edit instruction */ + +uint32 cis_ebs (uint32 rn, uint32 disp) +{ +uint32 sa, da, c, d, dst, fill, pat; +uint32 tr; + +disp = SEXT_LIT_W (disp) & WMASK; /* sext operand */ +fill = S_GETMCNT (R[rn]); /* fill char */ +while (S_GETMCNT (R[rn|1])) { /* while pattern */ + sa = (disp + R[rn]) & bvamqrx; /* dec str addr */ + da = R[rn|1] & bvamqrx; /* pattern addr */ + if ((tr = ReadB (da, &pat, VR)) != 0) /* get pattern byte */ + return tr; + switch (pat) { /* case on pattern */ + + case ED_DS: /* digit select */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + if (CC & CC4) /* signif? unpack */ + dst = ZONE | d; + else if (d) { /* non-zero? */ + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + CC |= CC4; /* set signif */ + } + else dst = fill; /* otherwise fill */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_SS: /* signif start */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + if (CC & CC4) /* signif? unpack */ + dst = ZONE | d; + else if (d) { /* non-zero? */ + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + } + else { /* otherwise */ + R[1] = da + 1; /* save next */ + dst = fill; /* fill */ + } + CC |= CC4; /* set signif */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_SI: /* signif immediate */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + CC |= CC4; /* set signif */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_FS: /* field separator */ + CC &= ~(CC1|CC3|CC4); /* clr all exc CC2 */ + if ((tr = WriteB (da, fill, VW)) != 0) /* overwrite dst */ + return tr; + break; + + default: /* all others */ + if ((CC & CC4) == 0) { /* signif off? */ + dst = (CC & CC1)? BLANK: fill; /* blank or fill */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + } + break; + } /* end switch dst */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* next pattern */ + } /* end while */ +return 0; +} + +/* Routine to get and validate the next source digit */ + +uint32 ed_getsrc (uint32 sa, uint32 *c, uint32 *d) +{ +uint32 tr; + +if ((tr = ReadB (sa, c, VR)) != 0) /* read source byte */ + return tr; +*d = ((CC & CC2)? *c: *c >> 4) & 0xF; /* isolate digit */ +if (*d > 0x9) /* invalid? */ + return TR_DEC; +if (*d) /* non-zero? */ + CC |= CC3; +return 0; +} + +/* Routine to advance source string */ + +void ed_advsrc (uint32 rn, uint32 c) +{ +c = c & 0xF; /* get low digit */ +if (((CC & CC2) == 0) && (c > 0x9)) { /* sel left, with sign? */ + if ((c == 0xB) || (c == 0xD)) /* minus? */ + CC = CC | (CC1|CC4); /* CC1, CC4 */ + else CC = (CC | CC1) & ~CC4; /* no, CC1, ~CC4 */ + R[rn] = R[rn] + 1; /* skip two digits */ + } +else { /* adv 1 digit */ + if (CC & CC2) + R[rn] = R[rn] + 1; + CC = CC ^ CC2; + } +return; +} diff --git a/sigma/sigma_coc.c b/sigma/sigma_coc.c new file mode 100644 index 00000000..d7af5c9b --- /dev/null +++ b/sigma/sigma_coc.c @@ -0,0 +1,620 @@ +/* sigma_coc.c: Sigma character-oriented communications subsystem simulator + + Copyright (c) 2007-2008, Robert 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 substanXIAl 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. + + coc 7611 communications multiplexor + +*/ + +#include "sigma_io_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +/* Constants */ + +#define MUX_LINES 64 /* max lines */ +#define MUX_LINES_DFLT 8 /* default lines */ +#define MUX_INIT_POLL 8000 +#define MUXL_WAIT 500 +#define MUX_NUMLIN mux_desc.lines /* curr # lines */ + +#define MUXC 0 /* channel thread */ +#define MUXI 1 /* input thread */ + +/* Line status */ + +#define MUXL_XIA 0x01 /* xmt intr armed */ +#define MUXL_XIR 0x02 /* xmt intr req */ +#define MUXL_REP 0x04 /* rcv enable pend */ +#define MUXL_RBP 0x10 /* rcv break pend */ + +/* Channel state */ + +#define MUXC_IDLE 0 /* idle */ +#define MUXC_INIT 1 /* init */ +#define MUXC_RCV 2 /* receive */ +#define MUXC_END 3 /* end */ + +/* DIO address */ + +#define MUXDIO_V_FNC 0 /* function */ +#define MUXDIO_M_FNC 0xF +#define MUXDIO_V_COC 4 /* ctlr num */ +#define MUXDIO_M_COC 0xF +#define MUXDIO_GETFNC(x) (((x) >> MUXDIO_V_FNC) & MUXDIO_M_FNC) +#define MUXDIO_GETCOC(x) (((x) >> MUXDIO_V_COC) & MUXDIO_M_COC) + +#define MUXDAT_V_LIN 0 /* line num */ +#define MUXDAT_M_LIN (MUX_LINES - 1) +#define MUXDAT_V_CHR 8 /* output char */ +#define MUXDAT_M_CHR 0xFF +#define MUXDAT_GETLIN(x) (((x) >> MUXDAT_V_LIN) & MUXDAT_M_LIN) +#define MUXDAT_GETCHR(x) (((x) >> MUXDAT_V_CHR) & MUXDAT_M_CHR) + +uint8 mux_rbuf[MUX_LINES]; /* rcv buf */ +uint8 mux_xbuf[MUX_LINES]; /* xmt buf */ +uint8 mux_sta[MUX_LINES]; /* status */ +uint32 mux_tps = RTC_HZ_50; /* polls/second */ +uint32 mux_scan = 0; /* scanner */ +uint32 mux_slck = 0; /* scanner locked */ +uint32 muxc_cmd = MUXC_IDLE; /* channel state */ +uint32 mux_rint = INTV (INTG_E2, 0); +uint32 mux_xint = INTV (INTG_E2, 1); + +TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descrs */ +TMXR mux_desc = { MUX_LINES_DFLT, 0, 0, mux_ldsc }; /* mux descrr */ + +extern uint32 chan_ctl_time; +extern uint32 CC; +extern uint32 *R; + +uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 mux_dio (uint32 op, uint32 rn, uint32 ad); +uint32 mux_tio_status (void); +t_stat mux_chan_err (uint32 st); +t_stat muxc_svc (UNIT *uptr); +t_stat muxo_svc (UNIT *uptr); +t_stat muxi_rtc_svc (UNIT *uptr); +t_stat mux_reset (DEVICE *dptr); +t_stat mux_attach (UNIT *uptr, char *cptr); +t_stat mux_detach (UNIT *uptr); +t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc); +void mux_reset_ln (int32 ln); +void mux_scan_next (t_bool clr); +t_stat muxi_put_char (uint32 c, uint32 ln); + +/* MUX data structures + + mux_dev MUX device descriptor + mux_unit MUX unit descriptor + mux_reg MUX register list + mux_mod MUX modifiers list +*/ + +dib_t mux_dib = { DVA_MUX, &mux_disp, DIO_MUX, &mux_dio }; + +UNIT mux_unit[] = { + { UDATA (&muxc_svc, UNIT_ATTABLE, 0) }, + { UDATA (&muxi_rtc_svc, UNIT_DIS, 0) } + }; + +REG mux_reg[] = { + { BRDATA (STA, mux_sta, 16, 8, MUX_LINES) }, + { BRDATA (RBUF, mux_rbuf, 16, 8, MUX_LINES) }, + { BRDATA (XBUF, mux_xbuf, 16, 8, MUX_LINES) }, + { DRDATA (SCAN, mux_scan, 6) }, + { FLDATA (SLCK, mux_slck, 0) }, + { DRDATA (CMD, muxc_cmd, 2) }, + { DRDATA (TPS, mux_tps, 8), REG_HRO }, + { NULL } + }; + +MTAB mux_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &mux_desc }, + { UNIT_ATT, UNIT_ATT, "summary", NULL, + NULL, &tmxr_show_summ, (void *) &mux_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &tmxr_show_cstat, (void *) &mux_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &tmxr_show_cstat, (void *) &mux_desc }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", + &mux_vlines, &tmxr_show_lines, (void *) &mux_desc }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_COC, "POLL", "POLL", + &rtc_set_tps, &rtc_show_tps, (void *) &mux_tps }, + { 0 } + }; + +DEVICE mux_dev = { + "MUX", mux_unit, mux_reg, mux_mod, + 2, 10, 31, 1, 16, 8, + &tmxr_ex, &tmxr_dep, &mux_reset, + NULL, &mux_attach, &mux_detach, + &mux_dib, DEV_NET | DEV_DISABLE + }; + +/* MUXL data structures + + muxl_dev MUXL device descriptor + muxl_unit MUXL unit descriptor + muxl_reg MUXL register list + muxl_mod MUXL modifiers list +*/ + +UNIT muxl_unit[] = { + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT } + }; + +MTAB muxl_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, + { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &mux_desc }, + { 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[] = { + { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, + MUX_LINES, REG_NZ + PV_LEFT) }, + { NULL } + }; + +DEVICE muxl_dev = { + "MUXL", muxl_unit, muxl_reg, muxl_mod, + MUX_LINES, 10, 31, 1, 8, 8, + NULL, NULL, &mux_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* MUX: IO dispatch routine */ + +uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = mux_tio_status (); /* get status */ + if ((*dvst & DVS_CST) == 0) { /* ctrl idle? */ + muxc_cmd = MUXC_INIT; /* start dev thread */ + sim_activate (&mux_unit[MUXC], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = mux_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = 0; /* no status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = mux_tio_status (); /* get status */ + muxc_cmd = MUXC_IDLE; /* stop dev thread */ + sim_cancel (&mux_unit[MUXC]); + io_sclr_req (mux_rint, 0); /* clr rcv int */ + io_sclr_req (mux_xint, 0); + break; + + case OP_AIO: /* acknowledge int */ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* MUX: DIO dispatch routine */ + +uint32 mux_dio (uint32 op, uint32 rn, uint32 ad) +{ +int32 ln; +uint32 fnc = MUXDIO_GETFNC (ad); +uint32 coc = MUXDIO_GETCOC (ad); + +if (op == OP_RD) { /* read direct */ + if (coc != 0) /* nx COC? */ + return 0; + R[rn] = mux_scan | 0x40; /* return line num */ + mux_sta[mux_scan] &= ~MUXL_XIR; /* clear int req */ + return 0; + } +ln = MUXDAT_GETLIN (R[rn]); /* get line num */ +if (fnc & 0x4) { /* transmit */ + if ((coc != 0) || /* nx COC or */ + (ln >= MUX_NUMLIN)) { /* nx line? */ + CC |= CC4; + return 0; + } + if ((fnc & 0x7) == 0x5) { /* send char? */ + if (fnc & 0x8) /* space? */ + mux_xbuf[ln] = 0; + else mux_xbuf[ln] = MUXDAT_GETCHR (R[rn]); /* no, get char */ + sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); + mux_sta[ln] = (mux_sta[ln] | MUXL_XIA) & ~MUXL_XIR; + mux_scan_next (1); /* unlock scanner */ + } + else if (fnc == 0x06) { /* stop transmit */ + mux_sta[ln] &= ~MUXL_XIA|MUXL_XIR; /* disable int */ + mux_scan_next (1); /* unlock scanner */ + } + else if (fnc == 0x07) { /* disconnect */ + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + mux_reset_ln (ln); /* reset state */ + } + CC = (sim_is_active (&muxl_unit[ln])? 0: CC4) | + (mux_ldsc[ln].conn? CC3: 0); + } +else { /* receive */ + if ((coc != 0) || /* nx COC or */ + (ln >= MUX_NUMLIN)) /* nx line */ + return 0; + if (fnc == 0x01) { /* set rcv enable */ + if (mux_ldsc[ln].conn) /* connected? */ + mux_ldsc[ln].rcve = 1; /* just enable */ + else mux_sta[ln] |= MUXL_REP; /* enable pending */ + } + else if (fnc == 0x02) { /* clr rcv enable */ + mux_ldsc[ln].rcve = 0; + mux_sta[ln] &= ~MUXL_REP; + } + else if (fnc == 0x03) { /* disconnect */ + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + mux_reset_ln (ln); /* reset state */ + } + if (mux_sta[ln] & MUXL_RBP) /* break pending? */ + CC = CC3|CC4; + else CC = mux_ldsc[ln].rcve? CC4: CC3; + } +return 0; +} + +/* Unit service - channel overhead */ + +t_stat muxc_svc (UNIT *uptr) +{ +uint32 st; +uint32 cmd; + +if (muxc_cmd == MUXC_INIT) { /* init state? */ + st = chan_get_cmd (mux_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + mux_chan_err (st); /* go idle */ + else muxc_cmd = MUXC_RCV; /* no, receive */ + } +else if (muxc_cmd == MUXC_END) { /* end state? */ + st = chan_end (mux_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + mux_chan_err (st); /* go idle */ + else if (st == CHS_CCH) { /* command chain? */ + muxc_cmd = MUXC_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + } + else muxc_cmd = MUXC_IDLE; /* else idle */ + } +return SCPE_OK; +} + +/* Unit service - polled input - called from rtc scheduler + + Poll for new connections + Poll all connected lines for input +*/ + +t_stat muxi_rtc_svc (UNIT *uptr) +{ +t_stat r; +int32 newln, ln, c; + +if ((mux_unit[MUXC].flags & UNIT_ATT) == 0) /* attached? */ + return SCPE_OK; +newln = tmxr_poll_conn (&mux_desc); /* look for connect */ +if ((newln >= 0) && (mux_sta[newln] & MUXL_REP)) { /* rcv enb pending? */ + mux_ldsc[newln].rcve = 1; /* enable rcv */ + mux_sta[newln] &= ~MUXL_REP; /* clr pending */ + } +tmxr_poll_rx (&mux_desc); /* poll for input */ +for (ln = 0; ln < MUX_NUMLIN; ln++) { /* loop thru lines */ + if (mux_ldsc[ln].conn) { /* connected? */ + if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */ + if (c & SCPE_BREAK) /* break? */ + mux_sta[ln] |= MUXL_RBP; /* set rcv brk */ + else { /* normal char */ + mux_sta[ln] &= ~MUXL_RBP; /* clr rcv brk */ + c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); + mux_rbuf[ln] = c; /* save char */ + if ((muxc_cmd == MUXC_RCV) && /* chan active? */ + (r = muxi_put_char (c, ln))) /* char to chan */ + return r; + } /* end else char */ + } /* end if char */ + } /* end if conn */ + else mux_sta[ln] &= ~MUXL_RBP; /* disconnected */ + } /* end for */ +return SCPE_OK; +} + +/* Put character and line number in memory via channel */ + +t_stat muxi_put_char (uint32 c, uint32 ln) +{ +uint32 st; + +st = chan_WrMemB (mux_dib.dva, c); /* write char */ +if (CHS_IFERR (st)) /* channel error? */ + return mux_chan_err (st); +st = chan_WrMemB (mux_dib.dva, ln); /* write line */ +if (CHS_IFERR (st)) /* channel error? */ + return mux_chan_err (st); +if (st == CHS_ZBC) { /* bc == 0? */ + muxc_cmd = MUXC_END; /* end state */ + sim_activate (&mux_unit[MUXC], chan_ctl_time); /* quick schedule */ + } +io_sclr_req (mux_rint, 1); /* req ext intr */ +return SCPE_OK; +} + +/* Channel error */ + +t_stat mux_chan_err (uint32 st) +{ +chan_uen (mux_dib.dva); /* uend */ +muxc_cmd = MUXC_IDLE; /* go idle */ +if (st < CHS_ERR) + return st; +return 0; +} + +/* Unit service - transmit side */ + +t_stat muxo_svc (UNIT *uptr) +{ +int32 c; +uint32 ln = uptr - muxl_unit; /* line # */ + +if (mux_ldsc[ln].conn) { /* connected? */ + if (mux_ldsc[ln].xmte) { /* xmt enabled? */ + c = sim_tt_outcvt (mux_xbuf[ln], TT_GET_MODE (muxl_unit[ln].flags)); + if (c >= 0) + tmxr_putc_ln (&mux_ldsc[ln], c); /* output char */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + if (mux_sta[ln] & MUXL_XIA) { /* armed? */ + mux_sta[ln] |= MUXL_XIR; /* req intr */ + mux_scan_next (0); /* kick scanner */ + } + } + else { /* buf full */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + sim_activate (uptr, muxl_unit[ln].wait); /* wait */ + return SCPE_OK; + } + } +return SCPE_OK; +} + +/* MUX status routine */ + +uint32 mux_tio_status (void) +{ +if (muxc_cmd == MUXC_IDLE) /* idle? */ + return DVS_AUTO; +else return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC)); +} + +/* Kick scanner */ + +void mux_scan_next (t_bool clr) +{ +int32 i; + +if (clr) /* unlock? */ + mux_slck = 0; +else if (mux_slck) /* locked? */ + return; +for (i = 0; i < MUX_NUMLIN; i++) { /* scan lines */ + mux_scan = mux_scan + 1; /* next line */ + if (mux_scan >= (uint32) MUX_NUMLIN) + mux_scan = 0; + if (mux_sta[mux_scan] & MUXL_XIR) { /* flag set? */ + mux_slck = 1; /* lock scanner */ + io_sclr_req (mux_xint, 1); /* req ext int */ + return; + } + } +return; +} + +/* Reset routine */ + +t_stat mux_reset (DEVICE *dptr) +{ +int32 i; + +if (mux_dev.flags & DEV_DIS) /* master disabled? */ + muxl_dev.flags = muxl_dev.flags | DEV_DIS; /* disable lines */ +else muxl_dev.flags = muxl_dev.flags & ~DEV_DIS; +if (mux_unit[MUXC].flags & UNIT_ATT) /* master att? */ + rtc_register (RTC_COC, mux_tps, &mux_unit[MUXI]); /* register timer */ +else rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* else dereg */ +for (i = 0; i < MUX_LINES; i++) /* reset lines */ + mux_reset_ln (i); +return SCPE_OK; +} + +/* Attach master unit */ + +t_stat mux_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) /* error */ + return r; +rtc_register (RTC_COC, mux_tps, &mux_unit[MUXC]); /* register timer */ +return SCPE_OK; +} + +/* Detach master unit */ + +t_stat mux_detach (UNIT *uptr) +{ +int32 i; +t_stat r; + +r = tmxr_detach (&mux_desc, uptr); /* detach */ +for (i = 0; i < MUX_LINES; i++) /* disable rcv */ + mux_reset_ln (i); +rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* dereg */ +return r; +} + + +/* Change number of lines */ + +t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 newln, i, t; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; +newln = get_uint (cptr, 10, MUX_LINES, &r); +if ((r != SCPE_OK) || (newln == MUX_NUMLIN)) + return r; +if (newln == 0) return SCPE_ARG; +if (newln < MUX_NUMLIN) { + for (i = newln, t = 0; i < MUX_NUMLIN; i++) t = t | mux_ldsc[i].conn; + if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) + return SCPE_OK; + for (i = newln; i < MUX_NUMLIN; i++) { + if (mux_ldsc[i].conn) { + 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); + } + } +else { + for (i = MUX_NUMLIN; i < newln; i++) { + muxl_unit[i].flags = muxl_unit[i].flags & ~UNIT_DIS; + mux_reset_ln (i); + } + } +MUX_NUMLIN = newln; +return SCPE_OK; +} + +/* Reset an individual line */ + +void mux_reset_ln (int32 ln) +{ +sim_cancel (&muxl_unit[ln]); +mux_sta[ln] = 0; +mux_rbuf[ln] = 0; +mux_xbuf[ln] = 0; +mux_ldsc[ln].rcve = 0; +return; +} diff --git a/sigma/sigma_cpu.c b/sigma/sigma_cpu.c new file mode 100644 index 00000000..22e1a44a --- /dev/null +++ b/sigma/sigma_cpu.c @@ -0,0 +1,2848 @@ +/* sigma_cpu.c: XDS Sigma CPU simulator + + Copyright (c) 2007-2008, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + cpu central processor + + The system state for the Sigma CPU is as follows: + + RF[0:15][0:31]<0:31> register blocks + PSW1<0:31> processor status word 1 + CC<0:3> condition codes + PC<0:17> program counter (called IA in Sigma documentation) + PSW2<0:31> processor status word 2 + PSW2_WLK<0:3> write key (2b on S5-9) + PSW4<0:31> processor status word 4 (5X0 only) + MAP[0:511]<0:10> memory map (8b on S5-8) + WLK[0:2047]<0:3> write locks (256 2b entries on S5-9) + SSW<0:3> sense switches + PDF processor detected fault flag (S8-9, 5X0 only) + + Notes on features not documented in the Reference Manuals: + + 1. Memory mapping was available for the Sigma 5 (see map diagnostic). + 2. The Sigma 6/7 were field retrofitted with the LAS/LMS instructions + (see auto diagnostic). + 3. The Sigma 8/9 returned different results for WD .45 (see Telefile + System exerciser). + 4. Expanded memory beyond 128KB was retrofitted to the Sigma 5/6/7, + creating the so-called "Big 5/6/7." As a minimum, these systems + also included the "mode altered" feature and the 11b relocation map. + + The Sigma CPU has two instruction formats, memory reference and immediate. + The memory reference format is: + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |I| | | | | + |N| opcode | R | X | address | memory + |D| | | | | reference + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + where + + IND = indirect flag + opcode = operation code + R = source/destination register + X = index register (0 if none) + address = operand address + + The immediate format is: + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | + |0| opcode | R | immediate | immediate + | | | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + This routine is the instruction decode routine for the Sigma CPU. + It is called from the simulator control program to execute + instructions in simulated memory, starting at the simulated PC. + It runs until 'reason' is set non-zero. + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + HALT instruction + breakpoint encountered + invalid instruction and stop_op flag set + I/O error in I/O simulator + EXU loop exceeding limit + illegal interrupt or trap instruction + illegal register pointer + illegal vector + + 2. Interrupts. The interrupt structure consists of the following: + Each interrupt is part of a group that determines its priority. + The interrupt group is either controlled by a PSW inhibit or is + unconditional. Interrupts can be armed or disarmed (which controls + whether they are recognized at all) and enabled or disabled (which + controls whether they occur). See the sigma_io.c module for details. + + 3. Channels. The Sigma system has a channel-based I/O structure. Each + channel is represented by a set of registers. Channels test the + I/O transfer requests from devices. + + 4. Non-existent memory. On the Sigma, accesses to non-existent memory + trap. + + 5. Adding I/O devices. These modules must be modified: + + sigma_defs.h add definitions + sigma_io.c add dispatches + sigma_sys.c add pointer to data structures to sim_devices +*/ + +#include "sigma_io_defs.h" + +#define CPUF_V_MODEL (UNIT_V_UF + 6) /* CPU model */ +#define CPUF_M_MODEL 0x7 +#define CPUF_MODEL (CPUF_M_MODEL << CPUF_V_MODEL) +#define CPUF_S5 (CPU_V_S5 << CPUF_V_MODEL) +#define CPUF_S6 (CPU_V_S6 << CPUF_V_MODEL) +#define CPUF_S7 (CPU_V_S7 << CPUF_V_MODEL) +#define CPUF_S8 (CPU_V_S8 << CPUF_V_MODEL) +#define CPUF_S7B (CPU_V_S7B << CPUF_V_MODEL) +#define CPUF_S9 (CPU_V_S9 << CPUF_V_MODEL) +#define CPUF_550 (CPU_V_550 << CPUF_V_MODEL) +#define CPUF_560 (CPU_V_560 << CPUF_V_MODEL) +#define CPUF_GETMOD(x) (((x) >> CPUF_V_MODEL) & CPUF_M_MODEL) + +#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] = real_pc; + +#define HIST_MIN 64 +#define HIST_MAX (1u << 20) +#define H_INST 0x00800000 +#define H_CHAN 0x00400000 +#define H_ITRP 0x00200000 +#define H_ABRT 0x00100000 + +typedef struct { + uint32 typ_cc_pc; + uint32 ir; + uint32 rn; + uint32 rn1; + uint32 x; /* unused */ + uint32 ea; + uint32 op; + uint32 op1; + } InstHistory; + +uint32 cpu_model = CPU_V_S7; /* CPU model */ +uint32 *M; /* memory */ +uint32 rf[RF_NBLK * RF_NUM] = { 0 }; /* register files */ +uint32 *R = rf; /* cur reg file */ +uint32 PSW1 = PSW1_DFLT; /* PSD */ +uint32 PSW2 = PSW2_DFLT; +uint32 PSW4 = 0; /* 5X0 only */ +uint32 CC; +uint32 PC; +uint32 PSW2_WLK = 0; /* write lock key */ +uint32 PSW_QRX9; /* Sigma 9 real extended */ +uint32 bvamqrx = BVAMASK; /* BVA mask, 17b/20b */ +uint32 SSW = 0; /* sense switches */ +uint32 cpu_pdf = 0; /* proc detected fault */ +uint32 cons_alarm = 0; /* console alarm */ +uint32 cons_alarm_enb = 0; /* alarm enable */ +uint32 cons_pcf = 0; +uint32 rf_bmax = 4; /* num reg blocks */ +uint32 exu_lim = 32; /* nested EXU limit */ +uint32 stop_op = 0; /* stop on ill op */ +uint32 cpu_astop = 0; /* address stop */ +uint32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ +int32 hst_p = 0; /* history pointer */ +int32 hst_lnt = 0; /* history length */ +InstHistory *hst = NULL; /* inst history */ + +extern int32 sim_int_char; +extern int32 sim_interval; +extern int32 sim_switches; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern uint32 int_hiact; /* highest act int */ +extern uint32 int_hireq; /* highest int req */ + +t_stat cpu_svc (UNIT *uptr); +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_rblks (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_rblks (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_alarm (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_alarm (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); +void set_rf_display (uint32 *rfbase); +void inst_hist (uint32 ir, uint32 pc, uint32 typ); +uint32 cpu_one_inst (uint32 real_pc, uint32 IR); +uint32 ImmOp (uint32 ir, uint32 *imm); +uint32 EaP20 (uint32 IR, uint32 *bva, uint32 lnt); +uint32 EaSh (uint32 ir, uint32 *stype, uint32 *sc); +uint32 Add32 (uint32 s1, uint32 s2, uint32 cin); +uint32 SMul64 (uint32 a, uint32 b, uint32 *lo); +t_bool SDiv64 (uint32 dvdh, uint32 dvdl, uint32 dvr, uint32 *res, uint32 *rem); +uint32 Cmp32 (uint32 a, uint32 b); +uint32 Shift (uint32 rn, uint32 stype, uint32 sc); +uint32 TestSP1 (uint32 sp1, int32 mod); +uint32 ModWrSP (uint32 bva, uint32 sp, uint32 sp1, int32 mod); +uint32 cpu_int_mtx (uint32 vec, uint32 *cc); +uint32 cpu_trap_or_int (uint32 vec); +uint32 cpu_xpsd (uint32 ir, uint32 bva, uint32 ra); +uint32 cpu_pss (uint32 ir, uint32 bva, uint32 acc); +uint32 cpu_pls (uint32 IR); +void cpu_assemble_PSD (void); +uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2); +uint32 cpu_new_RP (uint32 rp); +uint32 cpu_new_PC (uint32 bva); +uint32 cpu_add_PC (uint32 pc, uint32 val); +t_stat cpu_bad_rblk (UNIT *uptr); +void cpu_fprint_one_inst (FILE *st, uint32 tcp, uint32 ir, uint32 rn, + uint32 rn1, uint32 ea, uint32 op, uint32 op1); + +extern uint32 fp (uint32 op, uint32 rn, uint32 bva); +extern uint32 cis_dec (uint32 op, uint32 rn, uint32 bva); +extern uint32 cis_ebs (uint32 rn, uint32 disp); +extern void ShiftF (uint32 rn, uint32 stype, uint32 sc); +extern uint32 map_mmc (uint32 rn, uint32 map); +extern uint32 map_lra (uint32 rn, uint32 inst); +extern uint32 map_las (uint32 rn, uint32 bva); +extern uint32 map_lms (uint32 rn, uint32 bva); +extern t_stat io_init (void); +extern uint32 io_eval_int (void); +extern uint32 io_actv_int (void); +extern t_bool io_poss_int (void); +extern uint32 io_ackn_int (uint32 hireq); +extern uint32 io_rels_int (uint32 hiact, t_bool arm); +extern uint32 io_rwd (uint32 op, uint32 rn, uint32 bva); +extern uint32 io_sio (uint32 rn, uint32 bva); +extern uint32 io_tio (uint32 rn, uint32 bva); +extern uint32 io_tdv (uint32 rn, uint32 bva); +extern uint32 io_hio (uint32 rn, uint32 bva); +extern uint32 io_aio (uint32 rn, uint32 bva); +extern uint32 int_reset (DEVICE *dev); +extern void io_set_eimax (uint32 lnt); +extern void io_sclr_req (uint32 inum, uint32 val); +extern void io_sclr_arm (uint32 inum, uint32 val); +extern t_stat io_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat io_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc); + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit + cpu_reg CPU register list + cpu_mod CPU modifier list +*/ + +UNIT cpu_unit = { + UDATA (&cpu_svc, UNIT_FIX+CPUF_S7+CPUF_ALLOPT+UNIT_BINK, MAXMEMSIZE), + }; + +UNIT cpu_rblk_unit = { + UDATA (&cpu_bad_rblk, UNIT_DIS, 0) + }; + +REG cpu_reg[] = { + { GRDATA (PC, PSW1, 16, VASIZE, PSW1_V_PC) }, + { HRDATA (R0, rf[0], 32) }, /* addr in memory */ + { HRDATA (R1, rf[1], 32) }, /* modified at exit */ + { HRDATA (R2, rf[2], 32) }, /* to SCP */ + { HRDATA (R3, rf[3], 32) }, + { HRDATA (R4, rf[4], 32) }, + { HRDATA (R5, rf[5], 32) }, + { HRDATA (R6, rf[6], 32) }, + { HRDATA (R7, rf[7], 32) }, + { HRDATA (R8, rf[8], 32) }, + { HRDATA (R9, rf[9], 32) }, + { HRDATA (R10, rf[10], 32) }, + { HRDATA (R11, rf[11], 32) }, + { HRDATA (R12, rf[12], 32) }, + { HRDATA (R13, rf[13], 32) }, + { HRDATA (R14, rf[14], 32) }, + { HRDATA (R15, rf[15], 32) }, + { HRDATA (PSW1, PSW1, 32) }, + { HRDATA (PSW2, PSW2, 32) }, + { HRDATA (PSW4, PSW4, 32) }, + { GRDATA (CC, PSW1, 16, 4, PSW1_V_CC) }, + { GRDATA (RP, PSW2, 16, 4, PSW2_V_RP) }, + { FLDATA (SSW1, SSW, 3) }, + { FLDATA (SSW2, SSW, 2) }, + { FLDATA (SSW3, SSW, 1) }, + { FLDATA (SSW4, SSW, 0) }, + { FLDATA (PDF, cpu_pdf, 0) }, + { FLDATA (ALARM, cons_alarm, 0) }, + { FLDATA (ALENB, cons_alarm_enb, 0), REG_HRO }, + { FLDATA (PCF, cons_pcf, 0) }, + { DRDATA (EXULIM, exu_lim, 8), PV_LEFT + REG_NZ }, + { FLDATA (STOP_ILL, stop_op, 0) }, + { BRDATA (REG, rf, 16, 32, RF_NUM * RF_NBLK) }, + { DRDATA (RBLKS, rf_bmax, 5), REG_HRO }, + { BRDATA (PCQ, pcq, 16, VASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, + { DRDATA (PCQP, pcq_p, 6), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } + }; + +MTAB cpu_mod[] = { + { CPUF_MODEL, CPUF_S5, "Sigma 5", "SIGMA5", &cpu_set_type }, + { CPUF_MODEL, CPUF_S6, "Sigma 6", "SIGMA6", &cpu_set_type }, + { CPUF_MODEL, CPUF_S7, "Sigma 7", "SIGMA7", &cpu_set_type }, +// { CPUF_MODEL, CPUF_S8, "Sigma 8", "SIGMA8", &cpu_set_type }, +// { CPUF_MODEL, CPUF_S9, "Sigma 9", "SIGMA9", &cpu_set_type }, +// { CPUF_MODEL, CPUF_550, "550", "550", &cpu_set_type }, +// { CPUF_MODEL, CPUF_560, "560", "560", &cpu_set_type }, + { MTAB_XTD|MTAB_VDV, 0, "register blocks", "RBLKS", + &cpu_set_rblks, &cpu_show_rblks }, + { MTAB_XTD|MTAB_VDV, 0, "channels", "CHANNELS", + &io_set_nchan, &io_show_nchan }, + { CPUF_FP, CPUF_FP, "floating point", "FP", &cpu_set_opt }, + { CPUF_FP, 0, "no floating point", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_FP, NULL, "NOFP", &cpu_clr_opt }, + { CPUF_DEC, CPUF_DEC, "decimal", "DECIMAL", &cpu_set_opt }, + { CPUF_DEC, 0, "no decimal", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_DEC, NULL, "NODECIMAL", &cpu_clr_opt }, + { CPUF_LAMS, CPUF_LAMS, "LAS/LMS", "LASLMS", &cpu_set_opt }, + { CPUF_LAMS, 0, "no LAS/LMS", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_LAMS, NULL, "NOLASLMS", &cpu_clr_opt }, + { CPUF_MAP, CPUF_MAP, "map", "MAP", &cpu_set_opt }, + { CPUF_MAP, 0, "no map", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_MAP, NULL, "NOMAP", &cpu_clr_opt }, + { CPUF_WLK, CPUF_WLK, "write lock", "WRITELOCK", &cpu_set_opt }, + { CPUF_WLK, 0, "no write lock", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_WLK, NULL, "NOWRITELOCK", &cpu_clr_opt }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "ALARM", "ALON", &cpu_set_alarm, &cpu_show_alarm }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "ALOFF", & cpu_set_alarm }, + { CPUF_MSIZE, (1u << 15), NULL, "32K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 16), NULL, "64K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 17), NULL, "128K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 18), NULL, "256K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 19), NULL, "512K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 20), NULL, "1M", &cpu_set_size }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, BY, "BA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, HW, "HA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, WD, "WA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, DW, "DA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", + &cpu_set_hist, &cpu_show_hist }, + { 0 } + }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 16, 20, 1, 16, 32, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL, + }; + +static uint8 anlz_tab[128] = { + 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, /* 00 - 0F */ + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, /* 10 - 1F */ + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, + 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, /* 20 - 2F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, /* 30 - 3F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x1, 0x1, 0x1, 0x1, 0x8, 0x8, 0x8, 0x8, /* 40 - 4F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, /* 50 - 5F */ + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, + 0x1, 0x1, 0x1, 0x1, 0x8, 0x8, 0x8, 0x8, /* 60 - 6F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 70 - 7F */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }; + +cpu_var_t cpu_tab[] = { + +/* psw1_mbz psw2_mbz m_map1 pamask eint chan + cc standard optional */ + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S5 */ + CC1|CC2, 0, CPUF_MAP|CPUF_WLK|CPUF_FP }, + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S6 */ + CC1|CC2, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC, CPUF_FP|CPUF_LAMS }, + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S7 */ + CC1|CC2, CPUF_STR|CPUF_MAP|CPUF_WLK, CPUF_FP|CPUF_DEC|CPUF_LAMS }, + { 0x084E0000, 0xC8FF00C7, 0x0FC, PAMASK17, 14, 8, /* S8 */ + CC1|CC2|CC3, CPUF_STR|CPUF_FP|CPUF_WLK|CPUF_LAMS, 0 }, + { 0x08060000, 0xC8400007, 0x0FC, PAMASK22, 14, 8, /* S9 */ + CC1|CC2|CC3, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC|CPUF_FP|CPUF_LAMS, 0 }, + { 0x002E0000, 0x080FFFC3, 0x7FE, PAMASK20, 4, 4, /* 550 */ + CC1|CC2|CC3|CC4, CPUF_MAP|CPUF_WLK|CPUF_LAMS, CPUF_FP }, + { 0x000E0000, 0x080FFFC3, 0x7FE, PAMASK20, 4, 4, /* 560 */ + CC1|CC2|CC3|CC4, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC|CPUF_FP|CPUF_LAMS, 0 } + }; + +/* Simulation loop */ + +t_stat sim_instr (void) +{ +uint32 ir, rpc, old_PC; +t_stat reason, tr, tr2; + +/* Restore register state */ + +if (io_init ()) /* init IO; conflict? */ + return STOP_INVIOC; +reason = 0; +if (cpu_new_PSD (1, PSW1, PSW2)) /* restore PSD, RP etc */ + return STOP_INVPSD; +int_hireq = io_eval_int (); + +/* Main instruction fetch/decode loop */ + +while (reason == 0) { /* loop until stop */ + + PSW2 &= ~PSW2_RA; /* clr reg altered */ + if (cpu_astop) { /* debug stop? */ + cpu_astop = 0; + return STOP_ASTOP; + } + + if (sim_interval <= 0) { /* event queue? */ + if (reason = sim_process_event ()) /* process */ + break; + int_hireq = io_eval_int (); /* re-evaluate intr */ + } + sim_interval = sim_interval - 1; /* count down */ + + if (int_hireq < NO_INT) { /* interrupt req? */ + uint32 sav_hi, vec, wd, op; + + vec = io_ackn_int (sav_hi = int_hireq); /* get vector */ + if (vec == 0) { /* illegal vector? */ + reason = STOP_ILLVEC; /* something wrong */ + break; + } + ReadPW (vec, &wd); /* read vector */ + op = I_GETOP (wd); /* get opcode */ + if ((op == OP_MTB) || (op == OP_MTH) || (op == OP_MTW)) { + uint32 res; + tr2 = cpu_int_mtx (vec, &res); /* do single cycle */ + io_sclr_req (sav_hi, 0); /* clear request */ + io_sclr_arm (sav_hi, 1); /* set armed */ + if ((res == 0) && /* count overflow */ + ((vec >= VEC_C1P) || (vec <= VEC_C4P))) /* on clock? */ + io_sclr_req (INTV (INTG_CTR, vec - VEC_C1P), 1); + int_hiact = io_actv_int (); /* re-eval active */ + int_hireq = io_eval_int (); /* re-eval intr */ + } + else tr2 = cpu_trap_or_int (vec); /* XPSD/PSS intr */ + if (tr2 & TR_FL) { /* trap? */ + if (QCPU_S89_5X0) /* S89 or 5X0? */ + tr2 = cpu_trap_or_int (tr2); /* try again */ + reason = (tr2 == TR_INVTRP)? STOP_ILLTRP: STOP_TRPT; + } + else reason = tr2; /* normal status code */ + } + else { /* normal instruction */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + if (PSW_QRX9 && (PC & PSW1_XA)) /* S9 real ext && ext? */ + rpc = (PSW2 & PSW2_EA) | (PC & ~PSW1_XA); /* 22b phys address */ + else rpc = PC; /* standard 17b PC */ + PC = cpu_add_PC (old_PC = PC, 1); /* increment PC */ + if (((tr = ReadW (rpc << 2, &ir, VI)) != 0) || /* fetch inst, err? */ + ((tr = cpu_one_inst (rpc, ir)) != 0)) { /* exec inst, error? */ + if (tr & TR_FL) { /* trap? */ + PC = old_PC; /* roll back PC */ + tr2 = cpu_trap_or_int (tr); /* do trap */ + if (tr2 & TR_FL) { /* trap? */ + if (QCPU_S89_5X0) /* S89 or 5X0? */ + tr2 = cpu_trap_or_int (tr2); /* try again */ + reason = (tr2 == TR_INVTRP)? STOP_ILLTRP: STOP_TRPT; + } /* end if trap-in-trap */ + else reason = tr2; /* normal status */ + } /* end if trap */ + else reason = tr; /* normal status */ + if ((reason >= STOP_ROLLBACK) && /* roll back PC? */ + (reason <= STOP_MAX)) + PC = old_PC; + } /* end if abnormal status */ + } /* end else normal */ + } /* end while */ + +/* Simulation halted */ + +pcq_r->qptr = pcq_p; /* update pc q ptr */ +cpu_assemble_PSD (); /* visible PSD */ +set_rf_display (R); /* visible registers */ +return reason; +} + +/* Execute one instruction */ + +uint32 cpu_one_inst (uint32 real_pc, uint32 IR) +{ +uint32 op, rn, bva, opnd, opnd1, opnd2, t; +uint32 res, res1, tr, stype, sc, cnt; +uint32 sa, da, mask, c, c1, i, lim, aop, exu_cnt; +int32 sop, sop1; +t_bool mprot; + +exu_cnt = 0; /* init EXU count */ +EXU_LOOP: +if (hst_lnt) /* history? record */ + inst_hist (IR, real_pc, H_INST); +op = I_GETOP (IR); /* get opcode */ +rn = I_GETRN (IR); /* get reg num */ +switch (op) { + +/* Loads and stores */ + + case OP_LI: /* load immediate */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LB: /* load byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LH: /* load halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LCH: /* load comp hw */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd); /* sext to 32b */ + opnd = NEG_W (opnd); /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LAH: /* load abs hw */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + if (opnd & HSIGN) /* negative? */ + opnd = NEG_W (opnd) & HMASK; /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LW: /* load word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LCW: /* load comp word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + opnd = NEG_W (opnd); /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + if (opnd == WSIGN) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LAW: /* load abs word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if (opnd & WSIGN) /* negative? */ + opnd = NEG_W (opnd); /* take abs value */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + if (opnd == WSIGN) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LS: /* load selective */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = (R[rn] & ~R[rn|1]) | (opnd & R[rn|1]); /* load under mask */ + CC34_W (res); /* set cc's */ + R[rn] = res; /* store result */ + break; + + case OP_LAS: /* load and set */ + if ((cpu_unit.flags & CPUF_LAMS) == 0) /* not included? */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = map_las (rn, bva)) != 0) /* do instruction */ + return tr; + CC34_W (R[rn]); /* set CC's */ + break; + + case OP_LVAW: /* load virt addr */ + if (!QCPU_5X0) /* 5X0 only */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + R[rn] = bva >> 2; /* store */ + break; + + case OP_LD: /* load doubleword */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + break; + + case OP_LCD: /* load comp double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + NEG_D (opnd, opnd1); /* negate */ + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + if ((opnd == WSIGN) && (opnd1 == 0)) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LAD: /* load abs double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + if (opnd & WSIGN) /* negative? */ + NEG_D (opnd, opnd1); /* take abs value */ + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + if ((opnd == WSIGN) && (opnd1 == 0)) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + +/* Note: the Sigma 7 does not prove the instruction can execute successfully + before starting to load registers; the Sigma 9 (and the simulator) do. */ + + case OP_LM: /* load multiple */ + lim = CC? CC: 16; /* CC sets count */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW ((bva + ((lim - 1) << 2)) & bvamqrx, &opnd, VR)) != 0) + return tr; /* test readability */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read next */ + return tr; + R[rn] = opnd; /* store in reg */ + bva = (bva + 4) & bvamqrx; /* next word */ + rn = (rn + 1) & RNMASK; /* next reg */ + PSW2 |= PSW2_RA; /* reg altered */ + } + break; + + case OP_LCFI: /* load cc, flt immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + if (IR & IRB(10)) /* load CC's? */ + CC = (opnd >> 4) & 0xF; + if (IR & IRB(11)) /* load FP ctrls? */ + PSW1 = ((PSW1 & ~PSW1_FPC) | /* set ctrls */ + ((opnd & PSW1_M_FPC) << PSW1_V_FPC)) & + ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz */ + break; + + case OP_LCF: /* load cc, flt */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* get byte */ + return tr; + if (IR & IRB(10)) /* load CC's? */ + CC = (opnd >> 4) & 0xF; + if (IR & IRB(11)) /* load FP ctrls? */ + PSW1 = ((PSW1 & ~PSW1_FPC) | /* set ctrls */ + ((opnd & PSW1_M_FPC) << PSW1_V_FPC)) & + ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz */ + break; + + case OP_XW: /* exchange word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* write reg */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_STB: /* store byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteB (bva, R[rn], VW)) != 0) /* store */ + return tr; + break; + + case OP_STH: /* store halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteH (bva, R[rn], VW)) != 0) /* store */ + return tr; + if (R[rn] == (SEXT_H_W (R[rn]) & WMASK)) /* rn a sext hw? */ + CC &= ~CC2; /* yes, clr CC2 */ + else CC |= CC2; + break; + + case OP_STW: /* store word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* store */ + return tr; + break; + + case OP_STD: /* store doubleword */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteD (bva, R[rn], R[rn|1], VW)) != 0) /* store */ + return tr; + break; + + case OP_STS: /* store selective */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = (opnd & ~R[rn|1]) | (R[rn] & R[rn|1]); /* set under mask */ + if ((tr = WriteW (bva, res, VW)) != 0) /* store */ + return tr; + break; + +/* Note: the Sigma 7 does not prove the instruction can execute successfully + before starting to store registers; the Sigma 9 (and the simulator) do. */ + + case OP_STM: /* store multiple */ + lim = CC? CC: 16; /* CC sets count */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW ((bva + ((lim - 1) << 2)) & bvamqrx, &opnd, VW)) != 0) + return tr; /* test writeability */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* write reg */ + return tr; + bva = (bva + 4) & bvamqrx; /* next address */ + rn = (rn + 1) & RNMASK; /* next register */ + } + break; + + case OP_STCF: /* store cc, flt */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + res = (CC << 4) | ((PSW1 >> PSW1_V_FPC) & PSW1_M_FPC); + if ((tr = WriteB (bva, res, VW)) != 0) /* store */ + return tr; + break; + +/* Analyze: Sigma 9 uses <5:7> for trap codes, the 5X0 uses <1:3> */ + + case OP_ANLZ: /* analyze */ + mprot = ((PSW1 & (PSW1_MS|PSW1_MM)) == PSW1_MM) && + ((PSW2 & (PSW2_MA9|PSW2_MA5X0)) != 0); /* mstr prot */ + sc = QCPU_5X0? 4: 0; /* 5X0 vs S9 */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) { /* get eff address */ + if (mprot && QCPU_S9) { /* S9 mprot? */ + R[rn] = 0x07000000 | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + if ((tr = ReadW (bva, &opnd, VR)) != 0) { /* get word */ + if (mprot) { /* trap, mprot? */ + R[rn] = (0x30000000 >> sc) | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + aop = I_GETOP (opnd); /* get opcode */ + CC = anlz_tab[aop] & (CC1|CC2|CC4); /* set CC1,CC2,CC4 */ + if (TST_IND (opnd)) /* indirect? */ + CC |= CC3; /* set CC3 */ + if ((anlz_tab[aop] & CC4) == 0) { /* mem ref? */ + uint32 aln = anlz_tab[aop] >> 2; /* get length */ + if ((tr = Ea (opnd, &bva, VR, aln)) != 0) { /* get eff addr */ + if (mprot) { /* trap, mprot? */ + R[rn] = (0x10000000 >> sc) | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + R[rn] = bva >> aln; /* cvt addr */ + } + break; + +/* Interpret */ + + case OP_INT: /* interpret */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + CC = (opnd >> 28) & 0xF; /* <0:3> -> CC */ + R[rn] = (opnd >> 16) & 0xFFF; /* <4:15> -> Rn */ + R[rn|1] = opnd & 0xFFFF; /* <16:31> -> Rn|1 */ + break; + +/* Arithmetic */ + + case OP_AI: /* add immediate */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovfo, enabled? */ + return TR_FIX; + break; + + case OP_AH: /* add halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AW: /* add word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AD: /* add doubleword */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + res1 = Add32 (R[rn|1], opnd1, 0); /* add low, high */ + res = Add32 (R[rn], opnd, (CC & CC1) != 0); + if ((res == 0) && (res1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + R[rn|1] = res1; /* store */ + R[rn] = res; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AWM: /* add word to memory */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + if ((tr = WriteW (bva, res, VW)) != 0) /* store */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SH: /* subtract halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd ^ WMASK, 1); /* subtract, set CC's */ + R[rn] = res; /* store */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SW: /* subtract word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd ^ WMASK, 1); /* subtract */ + R[rn] = res; /* store */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SD: /* subtract doubleword */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + res1 = Add32 (R[rn|1], opnd1 ^ WMASK, 1); /* sub low, high */ + res = Add32 (R[rn], opnd ^ WMASK, (CC & CC1) != 0); + if ((res == 0) && (res1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + R[rn|1] = res1; /* store */ + R[rn] = res; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_MI: /* multiply immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + res = SMul64 (R[rn|1], opnd, &res1); /* 64b product */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + + case OP_MH: /* multiply half */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + sop = (int32) SEXT_H_W (R[rn]); /* sext operands */ + sop1 = (int32) SEXT_H_W (opnd); + res = (uint32) ((sop * sop1) & WMASK); /* product */ + CC34_W (res); /* set CC's */ + R[rn|1] = res; /* store */ + break; + + case OP_MW: /* multiply word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = SMul64 (R[rn|1], opnd, &res1); /* 64b product */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + + case OP_DH: /* divide halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + sop = (int32) R[rn]; /* sext operands */ + sop1 = (int32) SEXT_H_W (opnd); + if ((opnd == 0) || /* div by zero? */ + ((R[rn] == WSIGN) && /* -2^31 / -1? */ + (opnd == HMASK))) { + CC |= CC2; /* overflow */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else { + res = (uint32) ((sop / sop1) & WMASK); /* quotient */ + CC &= ~CC2; /* no overflow */ + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + } + break; + + case OP_DW: /* divide word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd2, VR)) != 0) /* get divisor */ + return tr; + if (rn & 1) /* odd reg? */ + opnd = (R[rn] & WSIGN)? WMASK: 0; /* high is sext low */ + else opnd = R[rn]; + opnd1 = R[rn|1]; /* low divd */ + if (SDiv64 (opnd, opnd1, opnd2, &res, &res1)) { /* 64b/32b divide */ + CC |= CC2; /* overflow, set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else { + CC &= ~CC2; /* clear CC2 */ + CC34_W (res); /* set CC's from quo */ + R[rn] = res1; /* store */ + R[rn|1] = res; + } + break; + + case OP_MTB: /* mod and test byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + opnd1 = SEXT_RN_W (rn) & BMASK; /* mod is sext rn */ + res = (opnd + opnd1) & BMASK; /* do zext add */ + if (res < opnd) /* carry out? */ + CC = CC1; + else CC = 0; + CC34_W (res); /* set cc's */ + if (rn && /* any mod? */ + ((tr = WriteB (bva, res, VW)) != 0)) /* rewrite */ + return tr; + break; + + case OP_MTH: /* mod and test half */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = opnd & HMASK; /* 16 operands */ + opnd1 = SEXT_RN_W (rn) & HMASK; /* mod is sext rn */ + res = opnd + opnd1; /* 16b add */ + if ((res & HMASK) == 0) /* 16b CC tests */ + CC = 0; + else if (res & HSIGN) + CC = CC4; + else CC = CC3; + if ((res & ~HMASK) != 0) /* carry? */ + CC |= CC1; + if (((opnd ^ ~opnd1) & (opnd ^ res)) & HSIGN) /* set overflow */ + CC |= CC2; + if (rn && /* any mod? */ + ((tr = WriteH (bva, res, VW)) != 0)) /* rewrite */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_MTW: /* mod and test word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + opnd1 = SEXT_RN_W (rn) & WMASK; /* mod is sext rn */ + res = Add32 (opnd, opnd1, 0); /* do add */ + if (rn && /* any mod? */ + ((tr = WriteW (bva, res, VW)) != 0)) /* rewrite */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + +/* Logical */ + + case OP_AND: /* and */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] & opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_OR: /* or */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] | opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_EOR: /* xor */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] ^ opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + +/* Compares */ + + case OP_CI: /* compare immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CB: /* compare byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + opnd1 = R[rn] & BMASK; /* zext operand */ + CC234_CMP (opnd1, opnd); /* set CC's */ + break; + + case OP_CH: /* compare halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CW: /* compare word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CD: /* compare double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + CC &= ~(CC3|CC4); + if (R[rn] != opnd) /* hi unequal? */ + CC |= Cmp32 (R[rn], opnd); + else if (R[rn|1] != opnd1) /* low unequal? */ + CC |= (R[rn|1] < opnd1)? CC4: CC3; /* like signs */ + break; + + case OP_CS: /* compare select */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + opnd1 = R[rn] & R[rn|1]; /* mask operands */ + opnd = opnd & R[rn|1]; + if (opnd1 < opnd) /* unsigned compare */ + CC = (CC & ~CC3) | CC4; + else if (opnd1 > opnd) + CC = (CC & ~CC4) | CC3; + else CC &= ~(CC3|CC4); + break; + + case OP_CLR: /* compare limit reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC = Cmp32 (R[rn], opnd) | /* compare high reg */ + (Cmp32 (R[rn|1], opnd) << 2); /* compare low reg */ + break; + + case OP_CLM: /* compare limit mem */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* get doubleword */ + return tr; + CC = Cmp32 (R[rn], opnd) | /* compare high mem */ + (Cmp32 (R[rn], opnd1) << 2); /* compare low mem */ + break; + +/* Shift and convert instructions */ + + case OP_S: /* shift */ + if ((tr = EaSh (IR, &stype, &sc)) != 0) /* get type, count */ + return tr; + if ((stype >= 0x6) && QCPU_S567) /* invalid, S5-7? */ + stype = 0x4; /* treat as arith */ + CC = (CC & ~(CC1|CC2|CC4)) | /* shift, set CC's */ + Shift (rn, stype, sc); + break; + + case OP_SF: /* shift floating */ + if ((tr = EaSh (IR, &stype, &sc)) != 0) /* get type, count */ + return tr; + ShiftF (rn, stype & 1, sc); /* shift, set CC's */ + break; + + case OP_CVA: /* cvt by addition */ + if (QCPU_S5) /* not on Sigma 5 */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + CC &= ~CC1; /* clear CC1 (carry) */ + for (i = 0, res = 0; i < 32; i++) { /* 32 iterations */ + if ((R[rn|1] >> (31 - i)) & 1) { /* bit set? */ + uint32 ad = (bva + (i << 2)) & bvamqrx; /* table offset */ + if ((tr = ReadW (ad, &opnd, VR)) != 0) + return tr; /* read table word */ + res = (res + opnd) & WMASK; /* add into result */ + if (res < opnd) /* carry? set CC1 */ + CC |= CC1; + } /* end bit set */ + } /* end for */ + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_CVS: /* cvt by subtraction */ + if (QCPU_S5) /* not on Sigma 5 */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + for (i = 0, res = R[rn], res1 = 0; i < 32; i++) { /* 32 iterations */ + uint32 ad = (bva + (i << 2)) & bvamqrx; /* table offset */ + if ((tr = ReadW (ad, &opnd, VR)) != 0) /* read table word */ + return tr; + if (opnd <= res) { /* residue >= entry? */ + res = (res - opnd) & WMASK; /* subtract entry */ + res1 |= 1u << (31 - i); /* set bit */ + } + } + CC34_W (res1); /* set CC's */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + +/* Push down instructions */ + + case OP_PSW: /* push word */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + if ((tr = TestSP1 (opnd1, 1)) != 0) /* will push work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = WriteW (((opnd + 1) << 2) & bvamqrx, R[rn], VW)) != 0) + return tr; /* push word */ + if ((tr = ModWrSP (bva, opnd, opnd1, 1)) != 0) /* mod, rewrite sp */ + return tr; + break; + + case OP_PLW: /* pull word */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + if ((tr = TestSP1 (opnd1, -1)) != 0) /* will pull work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ReadW (opnd << 2, &res, VR)) != 0) /* pull word */ + return tr; + if ((tr = ModWrSP (bva, opnd, opnd1, -1)) != 0) /* mod, rewrite sp */ + return tr; + R[rn] = res; + break; + + case OP_PSM: /* push multiple */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + lim = CC? CC: 16; /* words to push */ + if ((tr = TestSP1 (opnd1, lim)) != 0) /* will push work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ReadW (((opnd + lim) << 2) & bvamqrx, &res, VW)) != 0) + return tr; /* will last work? */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = WriteW (((opnd + i + 1) << 2) & bvamqrx, R[rn], VW)) != 0) + return tr; /* push word */ + rn = (rn + 1) & RNMASK; + } + if ((tr = ModWrSP (bva, opnd, opnd1, lim)) != 0) /* mod, rewrite sp */ + return tr; + break; + + case OP_PLM: /* pull multiple */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + lim = CC? CC: 16; /* words to pull */ + if ((tr = TestSP1 (opnd1, -((int32)lim))) != 0) /* will pull work? */ + return ((tr & WSIGN)? 0: tr); + rn = (rn + lim - 1) & RNMASK; + if ((tr = ReadW (((opnd - (lim - 1)) << 2) & bvamqrx, &res, VR)) != 0) + return tr; /* will last work? */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = ReadW (((opnd - i) << 2) & bvamqrx, &res, VR)) != 0) + return tr; /* pull word */ + R[rn] = res; + rn = (rn - 1) & RNMASK; + } + if ((tr = ModWrSP (bva, opnd, opnd1, -((int32) lim))) != 0) + return tr; + break; + + case OP_MSP: /* modify stack ptr */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + sop = SEXT_H_W (R[rn]); /* get modifier */ + if ((tr = TestSP1 (opnd1, sop)) != 0) /* will mod work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ModWrSP (bva, opnd, opnd1, sop)) != 0) /* mod, rewrite sp */ + return tr; + break; + +/* Control instructions */ + + case OP_EXU: /* execute */ + if (exu_cnt++ > exu_lim) /* too many? */ + return STOP_EXULIM; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + IR = opnd; /* new instruction */ + goto EXU_LOOP; + + case OP_BCS: /* branch cond set */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((CC & rn) != 0) { /* branch taken? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + break; + + case OP_BCR: /* branch cond reset */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((CC & rn) == 0) { /* branch taken? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + break; + + case OP_BIR: /* branch incr reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + res = (R[rn] + 1) & WMASK; /* ++R[rn] */ + if ((res & WSIGN) != 0) { /* < 0? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + R[rn] = res; /* actual increment */ + break; + + case OP_BDR: /* branch decr reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + res = (R[rn] - 1) & WMASK; /* --R[rn] */ + if (((res & WSIGN) == 0) && (res != 0)) { /* > 0? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + R[rn] = res; /* actual decrement */ + break; + + case OP_BAL: /* branch and link */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + R[rn] = cpu_add_PC (real_pc, 1); /* save incr PC */ + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + break; + + case OP_CAL1: /* CALL 1 */ + return TR_C1 (rn); + + case OP_CAL2: /* CALL 2 */ + return TR_C2 (rn); + + case OP_CAL3: /* CALL 3 */ + return TR_C3 (rn); + + case OP_CAL4: /* CALL 4 */ + return TR_C4 (rn); + +/* Privileged instructions */ + + case OP_MMC: /* MMC */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if (TST_IND (IR) && /* indirect? */ + ((tr = ReadW (I_GETADDR (IR) << 2, &opnd, VNT)) != 0)) + return tr; + return map_mmc (rn, I_GETXR (IR)); + + case OP_LPSD: /* load PSD */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read stack ptr */ + return tr; + if ((tr = cpu_new_PSD (IR & IRB (8), opnd, opnd1)) != 0) + return tr; + PCQ_ENTRY; /* no traps, upd PCQ */ + if (IR & IRB (10)) /* clr hi pri int? */ + int_hireq = io_rels_int (int_hiact, IR & IRB (11)); + else if (IR & IRB (11)) /* clr PDF flag? */ + cpu_pdf = 0; + break; + + case OP_XPSD: /* exchange PSD */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = cpu_xpsd (IR & ~IRB (11), bva, VR)) != 0) /* do XPSD */ + return tr; + PCQ_ENTRY; /* no traps, upd PCQ */ + break; + + case OP_LRP: + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + return cpu_new_RP (opnd); /* update RP */ + + case OP_RD: /* direct I/O */ + case OP_WD: + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_rwd (op, rn, bva)) != 0) /* do direct I/O */ + return tr; + int_hiact = io_actv_int (); /* re-eval active */ + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_WAIT: /* wait for int */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if (!io_poss_int ()) /* intr possible? */ + return STOP_WAITNOINT; /* machine is hung */ +// put idle here + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_AIO: /* acknowledge int */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_aio (rn, bva)) != 0) /* do AIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_SIO: /* start IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_sio (rn, bva)) != 0) /* do SIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_HIO: /* halt IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_hio (rn, bva)) != 0) /* do HIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_TIO: /* test IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_tio (rn, bva)) != 0) /* do AIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_TDV: /* test device */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_tdv (rn, bva)) != 0) /* do I/O */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_LRA: /* load real addr */ + if (QCPU_S89_5X0) { /* late models only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + return map_lra (rn, IR); /* in map */ + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + + case OP_LMS: /* load mem system */ + if ((cpu_unit.flags & CPUF_LAMS) == 0) /* implemented? */ + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if (QCPU_S567) /* old CPU? */ + R[rn] = IR; /* loads inst to IR */ + else if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + else return map_lms (rn, bva); /* in map */ + break; + + case OP_PSS: /* push status */ + if (QCPU_5X0) { /* 5X0 only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = cpu_pss (IR, bva, VR)) != 0) /* push status */ + return tr; + PCQ_ENTRY; + break; + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + + case OP_PLS: /* pull status */ + if (QCPU_5X0) { /* 5X0 only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = cpu_pls (IR)) != 0) /* pull status */ + return tr; + PCQ_ENTRY; + break; + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + +/* String instructions */ + + case OP_MBS: /* move byte string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any move? */ + sa = (opnd + (rn? R[rn] + cnt - 1: 0)) & bvamqrx; /* last src addr */ + da = (R[rn|1] + cnt - 1) & bvamqrx; /* last dst addr */ + if (((tr = ReadB (sa, &c, VR)) != 0) || /* test last bytes */ + ((tr = ReadB (da, &c, VW)) != 0)) + return tr; + } + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (sa, &c, VR)) != 0) /* read src */ + return tr; + if ((tr = WriteB (da, c, VW)) != 0) /* write dst */ + return tr; + if (rn && !(rn & 1)) /* rn even, > 0? */ + R[rn] = (R[rn] + 1) & WMASK; /* inc saddr */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_CBS: /* compare byte str */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any compare? */ + sa = (opnd + (rn? R[rn] + cnt - 1: 0)) & bvamqrx; /* last src addr */ + da = (R[rn|1] + cnt - 1) & bvamqrx; /* last dst addr */ + if (((tr = ReadB (sa, &c, VR)) != 0) || /* test last bytes */ + ((tr = ReadB (da, &c, VR)) != 0)) + return tr; + } + CC = CC & ~(CC3|CC4); /* assume equal */ + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (sa, &c, VR)) != 0) /* read src */ + return tr; + if ((tr = ReadB (da, &c1, VR)) != 0) /* read dst */ + return tr; + if (c != c1) { /* not a match */ + CC |= ((c < c1)? CC4: CC3); + break; /* set CC's, done */ + } + if (rn && !(rn & 1)) /* rn even, > 0? */ + R[rn] = (R[rn] + 1) & WMASK; /* inc saddr */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_TBS: /* xlate byte string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any translate? */ + da = (R[rn] + cnt - 1) & bvamqrx; /* last dst addr */ + if ((tr = ReadB (da, &c, VW)) != 0) /* test last byte */ + return tr; + } + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* read dst */ + return tr; + if ((tr = ReadB ((sa + c) & bvamqrx, &c1, VR)) != 0) + return tr; /* translate byte */ + if ((tr = WriteB (da, c1, VW)) != 0) /* write dst */ + return tr; + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_TTBS: /* xlate, test string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + mask = rn? S_GETMCNT (R[rn]): 0xFF; /* get mask */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any translate? */ + da = (R[rn] + cnt - 1) & bvamqrx; /* last dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* test last byte */ + return tr; + } + CC &= ~CC4; /* clear CC4 */ + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* read dst */ + return tr; + if ((tr = ReadB ((sa + c) & bvamqrx, &c1, VR)) != 0) + return tr; /* translate byte */ + if ((t = c1 & mask) != 0) { /* byte & mask != 0? */ + if (rn) /* if !r0, repl mask */ + R[rn] = (R[rn] & ~S_MCNT) | (t << S_V_MCNT); + CC |= CC4; /* set CC4, stop */ + break; + } + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + +/* Optional floating point instructions */ + + case OP_FAS: + case OP_FSS: + case OP_FMS: + case OP_FDS: /* short fp */ + if((cpu_unit.flags & CPUF_FP) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + return fp (op, rn, bva); /* go process */ + + case OP_FAL: + case OP_FSL: + case OP_FML: + case OP_FDL: /* long fp */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if((cpu_unit.flags & CPUF_FP) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + return fp (op, rn, bva); /* go process */ + +/* Optional decimal instructions */ + + case OP_DL: + case OP_DST: + case OP_DA: + case OP_DS: + case OP_DM: + case OP_DD: + case OP_DC: + case OP_DSA: + case OP_PACK: + case OP_UNPK: /* decimal */ + if((cpu_unit.flags & CPUF_DEC) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = cis_dec (op, rn, bva)) & WSIGN) /* process, abort? */ + return 0; + else return tr; + + case OP_EBS: /* edit byte string */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + if ((cpu_unit.flags & CPUF_DEC) == 0) /* option present? */ + return TR_UNI; + if (QCPU_S89_5X0 && ((rn == 0) || (rn & 1))) /* invalid reg? */ + return TR_INVREG; + if ((tr = cis_ebs (rn, opnd)) & WSIGN) /* process, abort? */ + return 0; + else return tr; + + default: /* undefined inst */ + return (stop_op? STOP_ILLEG: TR_NXI); + } +return 0; +} + +/* Execute MTx in an interrupt location + + Sigma 5/6/7/8 - 17b virtual or real addressing + Sigma 9/5X0 - 17b virtual or 20b real addressing, no indexing + + acc is either PH (physical) or VNT (no traps) + Memory map traps are suppressed, NXM's cause undefined behavior + (returns a nested trap fault) */ + +uint32 cpu_int_mtx (uint32 vec, uint32 *res) +{ +uint32 IR, bva, wd, op, rn, lnt, acc; + +ReadPW (vec, &IR); /* get instruction */ +op = I_GETOP (IR); /* get op */ +lnt = 3 - (op >> 5); /* 73, 53, 33 */ +acc = (vec == VEC_C4P)? VNT: PH; /* access */ +rn = I_GETRN (IR); /* register */ +if (hst_lnt) /* if history */ + inst_hist (IR, PC, H_ITRP); /* record inst */ +if ((acc || QCPU_S567)? /* virt or S5-7? */ + (Ea (IR, &bva, acc, lnt) != 0): /* get eff addr */ + (EaP20 (IR, &bva, lnt) != 0)) /* get real addr */ + return TR_NESTED; + + switch (lnt) { + case BY: + if (ReadB (bva, &wd, acc) != 0) /* read byte */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & BMASK; /* modify */ + if (rn && (WriteB (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + case HW: + if (ReadH (bva, &wd, acc) != 0) /* read halfword */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & HMASK; /* modify */ + if (rn && (WriteB (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + case WD: + if (ReadW (bva, &wd, acc) != 0) /* read word */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & WMASK; /* modify */ + if (rn && (WriteW (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + } + +*res = wd; +return 0; +} + +/* Execute XSPD or PSS in trap or interrupt location */ + +uint32 cpu_trap_or_int (uint32 vec) +{ +uint32 IR, op, bva, acc, cc; + +ReadPW (TR_GETVEC (vec), &IR); /* read vector */ +op = I_GETOP (IR); /* get op */ +if (hst_lnt) { /* if history */ + if (vec & TR_FL) /* trap? */ + hst[hst_p].typ_cc_pc |= H_ABRT; /* mark prev abt */ + inst_hist (IR, PC, H_ITRP); /* record inst */ + } +if (vec & TR_FL) { /* trap? */ + if (QCPU_S89) /* Sigma 89? */ + PSW2 = (PSW2 & ~PSW2_TSF) | ((vec & PSW2_M_TSF) << PSW2_V_TSF); + if (vec == TR_INVRPN) /* non-trap reg ptr? */ + vec = TR_INVRPT; /* cvt to trapped */ + if (vec & TR_PDF) /* trap sets PDF? */ + cpu_pdf = 1; + } +if (op == OP_XPSD) { /* XPSD? */ + acc = (IR & IRB (10))? VNT: PH; /* virt vs phys */ + if ((acc || QCPU_S567)? /* virt or S5-7? */ + (Ea (IR, &bva, acc, DW) != 0): /* get eff addr */ + (EaP20 (IR, &bva, DW) != 0)) /* get real addr */ + return TR_NESTED; + if (cpu_xpsd (IR, bva, acc) != 0) /* do XPSD */ + return TR_NESTED; + if ((cc = TR_GETCC (vec)) != 0) { /* modify CC's? */ + CC = CC | cc; /* modify new CC's */ + if (IR & IRB (9)) /* and maybe new PC */ + PC = cpu_add_PC (PC, cc); + } + return 0; + } +if (QCPU_5X0 && (op == OP_PSS)) { /* 5X0 PSS? */ + if (EaP20 (IR, &bva, DW) != 0) /* get real addr */ + return TR_NESTED; + if (cpu_pss (IR, bva, PH)) /* do PSS */ + return TR_NESTED; + } +return TR_INVTRP; +} + +/* Immediate operand */ + +uint32 ImmOp (uint32 IR, uint32 *imm) +{ +if (TST_IND (IR)) /* indirect traps */ + return TR_NXI; +*imm = I_GETLIT (IR); +if (hst_lnt) /* record history */ + hst[hst_p].ea = hst[hst_p].op = *imm; +return 0; +} + +/* Calculate effective address for normal instructions + Note that in the event of a failure reading the ind addr, + Ea must return that value in bva (for ANLZ) */ + +uint32 Ea (uint32 IR, uint32 *bva, uint32 acc, uint32 lnt) +{ +uint32 ad, xr, wd; +uint32 tr; + +xr = I_GETXR (IR); /* get index reg */ +ad = I_GETADDR (IR) << 2; /* get byte address */ +if (TST_IND (IR)) { /* indirect */ + if ((tr = ReadW (ad, &wd, acc)) != 0) { /* read ind word */ + *bva = ad; /* err? return addr */ + return tr; + } + if (PSW_QRX9 && (wd & WSIGN)) { /* S9 real ext special? */ + wd = wd & VAMASK; /* use only 17b */ + ad = (wd & PSW1_XA)? /* extended word? */ + (PSW2 & PSW2_EA) | (wd & ~PSW1_XA): wd; + ad = ad << 2; + } + else ad = (wd & bvamqrx) << 2; /* get byte address */ + } +*bva = (ad + (xr? (R[xr] << lnt): 0)) & bvamqrx; /* index, mask */ +if (hst_lnt) { /* history? */ + hst[hst_p].ea = *bva; + ReadHist (*bva, &hst[hst_p].op, &hst[hst_p].op1, acc? VNT: PH, lnt); + } +return 0; +} + +/* Calculate effective address for 20b interrupt/trap instructions */ + +uint32 EaP20 (uint32 IR, uint32 *bva, uint32 lnt) +{ +uint32 pa, wd; + +pa = I_GETADDR20 (IR); /* get 20b ref addr */ +if (TST_IND (IR)) { /* indirect? */ + if (ReadPW (pa, &wd)) { /* valid? */ + *bva = pa << 2; + return TR_NXM; + } + pa = wd & cpu_tab[cpu_model].pamask; /* get indirect */ + } +*bva = pa << 2; +if (hst_lnt) { /* history? */ + hst[hst_p].ea = *bva; + ReadHist (*bva, &hst[hst_p].op, &hst[hst_p].op1, PH, lnt); + } +return 0; +} + +/* Calculate effective address for shift */ + +uint32 EaSh (uint32 IR, uint32 *stype, uint32 *sc) +{ +uint32 ad, xr, wd, tr; + +xr = I_GETXR (IR); /* get index reg */ +ad = I_GETADDR (IR); /* get word addr */ +if (TST_IND (IR)) { /* indirect? */ + if ((tr = ReadW (ad << 2, &wd, VR)) != 0) /* read ind word */ + return tr; + ad = I_GETADDR (wd); /* get word addr */ + } +if (xr) + ad = (ad & ~SHF_M_SC) | ((ad + R[xr]) & SHF_M_SC); /* indexing? */ +*stype = SHF_GETSOP (ad); /* extract type */ +*sc = SHF_GETSC (ad); /* extract count */ +if (hst_lnt) { + hst[hst_p].ea = ad << 2; + hst[hst_p].op = ad; + } +return 0; +} + +/* Shift routines */ + +uint32 Shift (uint32 rn, uint32 stype, uint32 sc) +{ +uint32 i, opnd, opnd1, t, cc; + +opnd = R[rn]; /* get operand(s) */ +opnd1 = R[rn|1]; +cc = CC & CC4; + +if (sc & SCSIGN) { /* right? */ + sc = SHF_M_SC + 1 - sc; + switch (stype) { + + case 0x0: /* right log sgl */ + if (sc > 31) /* >31? res = 0 */ + R[rn] = 0; + else R[rn] = R[rn] >> sc; + break; + + case 0x1: /* right log dbl */ + if (sc > 63) /* >63? res = 0 */ + opnd = opnd1 = 0; + else if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd1 = opnd >> sc; + opnd = 0; + } + else { + opnd1 = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd = opnd >> sc; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x2: /* right circ sgl */ + sc = sc % 32; /* mod 32 */ + R[rn] = ((R[rn] >> sc) | (R[rn] << (32 - sc))) & WMASK; + break; + + case 0x3: /* right circ dbl */ + sc = sc % 64; /* mod 64 */ + t = opnd; + if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd1 = ((t >> sc) | (opnd1 << (32 - sc))) & WMASK; + } + else { + opnd = ((opnd >> sc) | (opnd1 << (32 - sc))) & WMASK; + opnd1 = ((opnd1 >> sc) | (t << (32 - sc))) & WMASK; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x4: /* right arith sgl */ + t = (R[rn] & WSIGN)? WMASK: 0; + if (sc > 31) /* >31? res = sign */ + R[rn] = t; + else R[rn] = ((R[rn] >> sc) | (t << (32 - sc))) & WMASK; + break; + + case 0x5: /* right arith dbl */ + t = (R[rn] & WSIGN)? WMASK: 0; + if (sc > 63) /* >63? res = sign */ + opnd = opnd1 = t; + else if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd1 = ((opnd >> sc) | (t << (32 - sc))) & WMASK; + opnd = t; + } + else { + opnd1 = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd = ((opnd >> sc) | (t << (32 - sc))) & WMASK; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x6: /* right search sgl */ + for (i = 0; (i < sc) && !(opnd & WSIGN); i++) { + opnd = ((opnd >> 1) | (opnd << 31)) & WMASK; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn] = opnd; + R[1] = sc - i; + break; + + case 0x7: /* right search dbl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + t = opnd; + opnd = ((opnd >> 1) | (opnd1 << 31)) & WMASK; + opnd1 = ((opnd1 >> 1) | (t << 31)) & WMASK; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn|1] = opnd1; + R[rn] = opnd; + R[1] = sc - i; + break; + } + } /* end if */ + +else { /* left shift */ + switch (stype) { /* switch on type */ + + case 0x0: /* left log sgl */ + case 0x4: /* left arith sgl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = (opnd << 1) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn] = opnd; + break; + + case 0x1: /* left log dbl */ + case 0x5: /* left arith dbl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = (opnd1 << 1) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x2: /* left circ sgl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn] = opnd; + break; + + case 0x3: /* left circ dbl */ + for (i = 0; i < sc; i++) { + if ((t = opnd & WSIGN) != 0) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = ((opnd1 << 1) | (t >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x6: /* left search sgl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + opnd = ((opnd << 1) | (opnd >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn] = opnd; + R[1] = sc - i; + break; + + case 0x7: /* left search dbl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + t = opnd; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = ((opnd1 << 1) | (t >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn|1] = opnd1; + R[rn] = opnd; + R[1] = sc - i; + break; + } /* end switch */ + } /* end else */ +return cc; +} + +/* Arithmetic routines */ + +uint32 Add32 (uint32 s1, uint32 s2, uint32 cin) +{ +uint32 t = (s1 + s2 + cin) & WMASK; /* add + carry in */ + +if (t & WSIGN) /* set CC34 */ + CC = CC4; +else if (t != 0) + CC = CC3; +else CC = 0; +if (cin? (t <= s1): (t < s1)) /* set carry out */ + CC |= CC1; +if (((s1 ^ ~s2) & (s1 ^ t)) & WSIGN) /* set overflow */ + CC |= CC2; +return t; +} + +uint32 SMul64 (uint32 a, uint32 b, uint32 *lo) +{ +uint32 ah, bh, al, bl, rhi, rlo, rmid1, rmid2, sign; + +CC &= CC1; /* clr CC2-4 */ +if ((a == 0) || (b == 0)) { /* zero argument? */ + *lo = 0; /* result is zero */ + return 0; + } +sign = a ^ b; /* sign of result */ +if (a & WSIGN) /* |a|, |b| */ + a = NEG_W (a); +if (b & WSIGN) + b = NEG_W (b); +ah = (a >> 16) & HMASK; /* split operands */ +bh = (b >> 16) & HMASK; /* into 16b chunks */ +al = a & HMASK; +bl = b & HMASK; +rhi = ah * bh; /* high result */ +rmid1 = ah * bl; +rmid2 = al * bh; +rlo = al * bl; +rhi = rhi + ((rmid1 >> 16) & HMASK) + ((rmid2 >> 16) & HMASK); +rmid1 = (rlo + (rmid1 << 16)) & WMASK; /* add mid1 to lo */ +if (rmid1 < rlo) /* carry? incr hi */ + rhi = rhi + 1; +rmid2 = (rmid1 + (rmid2 << 16)) & WMASK; /* add mid2 to to */ +if (rmid2 < rmid1) /* carry? incr hi */ + rhi = rhi + 1; +rhi = rhi & WMASK; +if (sign & WSIGN) /* neg result? */ + NEG_D (rhi, rmid2); +if (rhi & WSIGN) /* < 0, set CC4 */ + CC |= CC4; +else if (rhi || rmid2) /* > 0, set CC3 */ + CC |= CC3; +if (rhi != ((rmid2 & WSIGN)? WMASK: 0)) /* fit in 32b? */ + CC |= CC2; /* set CC2 */ +*lo = rmid2; +return rhi; +} + +t_bool SDiv64 (uint32 dvdh, uint32 dvdl, uint32 dvr, uint32 *res, uint32 *rem) +{ +uint32 i, quo, quos, rems; + +quos = dvdh ^ dvr; +rems = dvdh; +if (dvdh & WSIGN) { /* |dividend| */ + NEG_D (dvdh, dvdl); + } +if (dvr & WSIGN) /* |divisor| */ + dvr = NEG_W (dvr); +if (dvdh >= dvr) /* divide work? */ + return TRUE; +for (i = quo = 0; i < 32; i++) { /* 32 iterations */ + quo = (quo << 1) & WMASK; /* shift quotient */ + dvdh = ((dvdh << 1) | (dvdl >> 31)) & WMASK; /* shift dividend */ + dvdl = (dvdl << 1) & WMASK; + if (dvdh >= dvr) { /* step work? */ + dvdh = (dvdh - dvr) & WMASK; /* subtract dvr */ + quo = quo + 1; + } + } +if (quo & WSIGN) /* quotient ovflo? */ + return TRUE; +*rem = (rems & WSIGN)? NEG_W (dvdh): dvdh; /* sign of rem */ +*res = (quos & WSIGN)? NEG_W (quo): quo; +return FALSE; /* no overflow */ +} + +uint32 Cmp32 (uint32 a, uint32 b) +{ +if (a == b) /* ==? */ + return 0; +if ((a ^ b) & WSIGN) /* unlike signs? */ + return (a & WSIGN)? CC4: CC3; +return (a < b)? CC4: CC3; /* like signs */ +} + +/* Test stack pointer space/words to see if it can be modified - + returns special abort status (WSIGN) */ + +uint32 TestSP1 (uint32 sp1, int32 mod) +{ +int32 spc, wds; +uint32 cc; + +cc = 0; +spc = (int32) SP_GETSPC (sp1); /* get space */ +wds = (int32) SP_GETWDS (sp1); /* get words */ +if (((wds + mod) > SP_M_WDS) || ((wds + mod) < 0)) { /* words overflow? */ + if ((sp1 & SP_TW) == 0) /* trap if enabled */ + return TR_PSH; + cc |= CC3; + } +if (((spc - mod) > SP_M_WDS) || ((spc - mod) < 0)) { /* space overflow? */ + if ((sp1 & SP_TS) == 0) /* trap if enabled */ + return TR_PSH; + cc |= CC1; + } +CC = cc; +if (cc || (mod == 0)) { /* mod fails? */ + CC |= ((spc? 0: CC2) | (wds? 0: CC4)); + return WSIGN; + } +return 0; +} + +/* Actually modify stack pointer space/words and set CC's, + used by PSW/PLW/PSM/PLM */ + +uint32 ModWrSP (uint32 bva, uint32 sp, uint32 sp1, int32 mod) +{ +uint32 tr; + +sp = (sp + mod) & WMASK; +sp1 = (sp1 & (SP_TS|SP_TW)) | + (((SP_GETSPC (sp1) - mod) & SP_M_SPC) << SP_V_SPC) | + (((SP_GETWDS (sp1) + mod) & SP_M_WDS) << SP_V_WDS); +if ((tr = WriteD (bva, sp, sp1, VW)) != 0) + return tr; +if ((mod > 0) && SP_GETSPC (sp1) == 0) + CC |= CC2; +if ((mod < 0) && SP_GETWDS (sp1) == 0) + CC |= CC4; +return 0; +} + +/* XPSD instruction */ + +uint32 cpu_xpsd (uint32 IR, uint32 bva, uint32 ra) +{ +uint32 wa, wd, wd1, wd3; +uint32 tr; + +if (ra == VR) /* virtual? */ + wa = VW; /* set write virt */ +else wa = ra; /* no, phys */ +cpu_assemble_PSD (); +wd = PSW1; /* no more changes */ +wd1 = PSW2; +wd3 = PSW4; +if ((tr = WriteD (bva, wd, wd1, wa)) != 0) /* write curr PSD */ + return tr; +bva = bva + 8; +if (QCPU_5X0 && (IR & IRB (11))) { /* extra words? */ + if ((tr = WriteW (bva | 4, wd3, VW)) != 0) + return tr; + bva = bva + 8; + } +if ((tr = ReadD (bva, &wd, &wd1, ra)) != 0) /* read new PSD */ + return tr; +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +return 0; +} + +/* PSS instruction */ + +uint32 cpu_pss (uint32 IR, uint32 bva, uint32 acc) +{ +uint32 i, wd, wd1, tos, swc; +uint32 tr; + +cpu_assemble_PSD (); /* get old PSD */ +if ((tr = ReadD (bva, &wd, &wd1, acc)) != 0) /* read new PSD */ + return tr; +ReadPW (SSP_TOS, &tos); /* read system SP */ +ReadPW (SSP_SWC, &swc); +for (i = 0; i < RF_NUM; i++) { /* push registers */ + if (WritePW (tos + SSP_FR_RN + i + 1, R[i])) + return TR_NXM; + } +if (WritePW (tos + SSP_FR_PSW1 + 1, PSW1) || /* push PSD */ + WritePW (tos + SSP_FR_PSW2 + 1, PSW2)) + return TR_NXM; +WritePW (SSP_TOS, (tos + SSP_FR_LNT) & WMASK); /* tos + 28 */ +swc = (swc & (SP_TS|SP_TW)) | /* spc-28, wds+28 */ + (((SP_GETWDS (swc) + SSP_FR_LNT) & SP_M_WDS) << SP_V_WDS) | + (((SP_GETSPC (swc) - SSP_FR_LNT) & SP_M_SPC) << SP_V_SPC); +if (SP_GETWDS (swc) < SSP_FR_LNT) /* wds overflow? */ + swc |= SP_TW; /* set sticky bit */ +WritePW (SSP_SWC, swc); +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +return 0; +} + +/* PLS instruction */ + +uint32 cpu_pls (uint32 IR) +{ +uint32 i, wd, wd1, tos, swc, spc; +uint32 tr; + +ReadPW (SSP_TOS, &tos); /* read system SP */ +ReadPW (SSP_SWC, &swc); +spc = SP_GETSPC (swc); /* space left */ +if (spc == 0) { /* none? */ + ReadPW (SSP_DFLT_PSW1, &wd); /* use default PSD */ + ReadPW (SSP_DFLT_PSW2, &wd1); + } +else if (spc < SSP_FR_LNT) /* not enough? */ + return TR_INVSSP; +else { + tos = (tos - SSP_FR_LNT) & WMASK; /* modify TOS */ + for (i = 0; i < RF_NUM; i++) { /* pull registers */ + if (ReadPW (tos + SSP_FR_RN + i + 1, &wd)) + return TR_NXM; + R[i] = wd; + } + if (ReadPW (tos + SSP_FR_PSW1 + 1, &wd) || /* pull new PSD */ + ReadPW (tos + SSP_FR_PSW2 + 1, &wd1)) + return TR_NXM; + WritePW (SSP_TOS, tos); /* rewrite SP */ + swc = (swc & (SP_TS|SP_TW)) | /* spc+28, wds-28 */ + (((SP_GETWDS (swc) - SSP_FR_LNT) & SP_M_WDS) << SP_V_WDS) | + (((SP_GETSPC (swc) + SSP_FR_LNT) & SP_M_SPC) << SP_V_SPC); + if (SP_GETSPC (swc) < SSP_FR_LNT) /* spc overflow? */ + swc |= SP_TS; /* set sticky bit */ + WritePW (SSP_SWC, swc); + } +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +if (IR & IRB (10)) /* clr hi pri int? */ + int_hireq = io_rels_int (int_hiact, IR & IRB (11)); +else if (IR & IRB (11)) /* clr PDF flag? */ + cpu_pdf = 0; + +return 0; +} + +/* Load new PSD */ + +uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2) +{ +uint32 tr; + +PSW1 = p1 & ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz bits */ +PSW2 = ((p2 & ~PSW2_RP) | (PSW2 & PSW2_RP)) & /* save reg ptr */ + ~cpu_tab[cpu_model].psw2_mbz; +if (lrp && /* load reg ptr? */ + ((tr = cpu_new_RP (p2)) != 0)) /* invalid? */ + return tr; /* trap */ +CC = PSW1_GETCC (PSW1); /* extract CC's */ +PC = PSW1_GETPC (PSW1); /* extract PC */ +PSW2_WLK = PSW2_GETWLK (PSW2); /* extract lock */ +int_hireq = io_eval_int (); /* update intr */ +if ((PSW1 & PSW1_MM) || /* mapped or */ + ((PSW2 & (PSW2_MA9|PSW2_MA5X0)) == 0)) { /* not real ext? */ + bvamqrx = BVAMASK; /* 17b masks */ + PSW_QRX9 = 0; + } +else { /* phys real ext */ + if ((PSW_QRX9 = PSW2 & PSW2_MA9) != 0) /* Sigma 9? */ + bvamqrx = BPAMASK22; /* yes, 22b masks */ + else bvamqrx = BPAMASK20; /* no, 20b masks */ + } +return 0; +} + +/* Load new RP */ + +uint32 cpu_new_RP (uint32 rp) +{ +uint32 rp1, j; + +PSW2 = (PSW2 & ~PSW2_RP) | (rp & PSW2_RP); /* merge to PSW2 */ +PSW2 = PSW2 & ~cpu_tab[cpu_model].psw2_mbz; /* clear nx bits */ +rp1 = PSW2_GETRP (rp); +if (rp1 >= rf_bmax) { /* nx reg file? */ + if (QCPU_S89) + return TR_INVRPN; + if (QCPU_5X0) + return TR_INVREG; + for (j = 0; j < RF_NUM; j++) /* clear nx set */ + rf[(rp1 * RF_NUM) + j] = 0; + sim_activate (&cpu_rblk_unit, 1); /* sched cleaner */ + } +R = rf + (rp1 * RF_NUM); +return 0; +} + +/* This routine is scheduled if the current registr block doesn't exist */ + +t_stat cpu_bad_rblk (UNIT *uptr) +{ +uint32 rp1, j; + +rp1 = PSW2_GETRP (PSW2); /* get reg ptr */ +if (rp1 >= rf_bmax) { /* still bad? */ + for (j = 0; j < RF_NUM; j++) /* clear nx set */ + rf[(rp1 * RF_NUM) + j] = 0; + sim_activate (uptr, 1); /* sched again */ + } +return SCPE_OK; +} + +/* Load new PC for branch instruction */ + +uint32 cpu_new_PC (uint32 bva) +{ +uint32 npc = bva >> 2; + +if (PSW_QRX9 && (npc & PSW1_XA)) /* S9 real ext, XA? */ + PSW2 = (PSW2 & ~PSW2_EA) | (npc & PSW2_EA); /* change PSW2 EA */ +return npc & BVAMASK; +} + +/* Add value to PC for fetch, BAL, trap */ + +uint32 cpu_add_PC (uint32 pc, uint32 inc) +{ +if (PSW_QRX9) /* S9 real ext? */ + return ((pc & ~(PSW1_M_PC & ~PSW1_XA)) | /* modulo 16b inc */ + ((pc + inc) & (PSW1_M_PC & ~PSW1_XA))); +return ((pc + inc) & BVAMASK); /* no, mod 17b inc */ +} + +/* Assemble PSD */ + +void cpu_assemble_PSD (void) +{ +PSW1 = (PSW1 & ~(PSW1_CCMASK|PSW1_PCMASK|cpu_tab[cpu_model].psw1_mbz)) | + (CC << PSW1_V_CC) | (PC << PSW1_V_PC); +PSW2 = (PSW2 & ~(PSW2_WLKMASK|cpu_tab[cpu_model].psw2_mbz)) | + (PSW2_WLK << PSW2_V_WLK); +return; +} + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +cpu_new_PSD (1, PSW1_DFLT | (PSW1 & PSW1_PCMASK), PSW2_DFLT); +cpu_pdf = 0; +cons_alarm = 0; +cons_pcf = 0; +set_rf_display (R); +if (M == NULL) + M = (uint32 *) calloc (MAXMEMSIZE, sizeof (uint32)); +if (M == NULL) + return SCPE_MEM; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r->qptr = 0; +else return SCPE_IERR; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +rtc_register (RTC_ALARM, RTC_HZ_2, &cpu_unit); +return int_reset (dptr); +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +uint32 lnt; + +if (sw & SWMASK ('C')) + lnt = 2; +else if ((sw & SWMASK ('B')) || (sw & SWMASK ('A')) || (sw & SWMASK ('E'))) + lnt = 0; +else if (sw & SWMASK ('H')) + lnt = 1; +else lnt = 2; +if (sw & SWMASK ('V')) { + if (ReadW (addr << lnt, vptr, VNT) != 0) + return SCPE_REL; + } +else if (ReadW (addr << lnt, vptr, PH) != 0) + return SCPE_NXM; +return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +uint32 lnt; + +if (sw & SWMASK ('C')) + lnt = 2; +else if ((sw & SWMASK ('B')) || (sw & SWMASK ('A')) || (sw & SWMASK ('E'))) + lnt = 0; +else if (sw & SWMASK ('H')) + lnt = 1; +else lnt = 2; +if (sw & SWMASK ('V')) { + if (WriteW (addr << lnt, val, VNT) != 0) + return SCPE_REL; + } +else if (WriteW (addr << lnt, val, PH) != 0) + return SCPE_NXM; +return SCPE_OK; +} + +/* CPU configuration management + + These routines (for type, memory size, options, number of reg blocks, + number of external int blocks) must generate a consistent result. + To assure this, all changes (except memory size) reset the CPU. */ + +/* Set CPU type */ + +t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 model = CPUF_GETMOD (val); + +if (model == cpu_model) /* no change? */ + return SCPE_OK; +cpu_reset (&cpu_dev); +if (MEMSIZE > (cpu_tab[cpu_model].pamask + 1)) + cpu_set_size (uptr, cpu_tab[cpu_model].pamask + 1, NULL, (void *) uptr); +cpu_model = model; +cpu_unit.flags = (cpu_unit.flags | cpu_tab[model].std) & ~cpu_tab[model].opt; +rf_bmax = RF_DFLT; +io_set_eimax (EIGRP_DFLT); +return SCPE_OK; +} + +/* Set memory size */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 mc = 0; +uint32 i; + +if ((val <= 0) || (val > (int32)(cpu_tab[cpu_model].pamask + 1))) + return SCPE_ARG; +if (!desc) { /* force trunc? */ + for (i = val; i < MEMSIZE; i++) + mc = mc | M[i]; + if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) + return SCPE_OK; + } +MEMSIZE = val; +for (i = MEMSIZE; i < MAXMEMSIZE; i++) + M[i] = 0; +return SCPE_OK; +} + +/* Set and clear options */ + +t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if ((val & (cpu_tab[cpu_model].std | cpu_tab[cpu_model].opt)) == 0) + return SCPE_NOFNC; +cpu_unit.flags |= val; +return SCPE_OK; +} + +t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val & cpu_tab[cpu_model].std) + return SCPE_NOFNC; +cpu_unit.flags &= ~val; +return SCPE_OK; +} + +/* Set/show register blocks */ + +t_stat cpu_set_rblks (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 invmask, lnt, i, j; +t_stat r; + +if (QCPU_5X0) /* 5X0 fixed */ + return SCPE_NOFNC; +if (cptr == NULL) + return SCPE_ARG; +invmask = PSW2_GETRP (cpu_tab[cpu_model].psw2_mbz); +if (QCPU_S89) + invmask |= 0x10; +lnt = (int32) get_uint (cptr, 10, RF_NBLK, &r); +if ((r != SCPE_OK) || (lnt == 0) || (lnt & invmask)) + return SCPE_ARG; +cpu_reset (&cpu_dev); +rf_bmax = lnt; +for (i = rf_bmax; i < RF_NBLK; i++) { /* zero unused */ + for (j = 0; j < RF_NUM; j++) + rf[(i * RF_NUM) + j] = 0; + } +return SCPE_OK; +} + +t_stat cpu_show_rblks (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "register blocks=%d", rf_bmax); +return SCPE_OK; +} + +/* Set current register file pointers for SCP */ + +void set_rf_display (uint32 *rfbase) +{ +extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr); +REG *rptr; +uint32 i; + +rptr = find_reg ("R0", NULL, &cpu_dev); +if (rptr == NULL) return; +for (i = 0; i < RF_NUM; i++, rptr++) + rptr->loc = (void *) (rfbase + i); +return; +} + +/* Front panael alarm */ + +t_stat cpu_set_alarm (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +cons_alarm_enb = val; +return SCPE_OK; +} + +t_stat cpu_show_alarm (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fputs (cons_alarm_enb? "alarm enabled\n": "alarm disabled\n", st); +return SCPE_OK; +} + +t_stat cpu_svc (UNIT *uptr) +{ +if (cons_alarm && cons_alarm_enb) + sim_putchar ('\a'); +return SCPE_OK; +} + +/* Address converter and display */ + +/* Virtual address translation */ + +t_stat cpu_show_addr (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +t_stat r; +char *cptr = (char *) desc; +uint32 ad, bpa, dlnt, virt; +static const char *lnt_str[] = { + "byte", + "halfword", + "word", + "doubleword", + }; +extern uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa); + +if ((val < 0) || (val > DW)) + return SCPE_IERR; +virt = (sim_switches & SWMASK ('V'))? 1: 0; +if (cptr) { + ad = (uint32) get_uint (cptr, 16, virt? VAMASK: PAMASK22, &r); + if (r == SCPE_OK) { + if (sim_switches & SWMASK ('B')) + dlnt = 0; + else if (sim_switches & SWMASK ('H')) + dlnt = 1; + else if (sim_switches & SWMASK ('D')) + dlnt = 3; + else dlnt = 2; + bpa = ad << val; + if (virt && map_reloc (bpa, VNT, &bpa)) + fprintf (of, "Virtual address %-X: memory management error\n"); + else fprintf (of, "%s %s %-X: physical %s %-X\n", + ((virt)? "Virtual": "Physical"), lnt_str[val], ad, lnt_str[dlnt], bpa >> dlnt); + return SCPE_OK; + } + } +fprintf (of, "Invalid argument\n"); +return SCPE_OK; +} + +/* Record history */ + +void inst_hist (uint32 ir, uint32 pc, uint32 tp) +{ +uint32 rn = I_GETRN (ir); + +hst_p = (hst_p + 1); /* next entry */ +if (hst_p >= hst_lnt) + hst_p = 0; +hst[hst_p].typ_cc_pc = (CC << PSW1_V_CC) | pc | tp; +hst[hst_p].ir = ir; +hst[hst_p].rn = R[rn]; +hst[hst_p].rn1 = R[rn|1]; +return; +} + +/* Set history */ + +t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i, lnt; +t_stat r; + +if (cptr == NULL) { + for (i = 0; i < hst_lnt; i++) + hst[i].typ_cc_pc = 0; + hst_p = 0; + return SCPE_OK; + } +lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); +if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) + return SCPE_ARG; +hst_p = 0; +if (hst_lnt) { + free (hst); + hst_lnt = 0; + hst = NULL; + } +if (lnt) { + hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); + if (hst == NULL) + return SCPE_MEM; + hst_lnt = lnt; + } +return SCPE_OK; +} + +/* Print one instruction */ + +void cpu_fprint_one_inst (FILE *st, uint32 tcp, uint32 ir, uint32 rn, uint32 rn1, + uint32 ea, uint32 opnd, uint32 opnd1) +{ +t_value sim_val; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); + +if (tcp & (H_INST|H_ITRP)) { /* instr or trap? */ + uint32 op = I_GETOP (ir); + uint32 cc = PSW1_GETCC (tcp); + uint32 pc = tcp & PAMASK20; + uint8 fl = anlz_tab[op]; + + fprintf (st, "%c %05X %X %08X %08X ", /* standard fields */ + ((tcp & H_INST)? ' ': 'T'), pc, cc, rn, rn1); + if (tcp & H_ABRT) /* aborted? */ + fputs ("aborted ", st); + else { + if (fl & CC4) /* immediate? */ + fprintf (st, "%05X ", ea); + else if ((fl >> 2) != DW) /* byte/half/word? */ + fprintf (st, "%05X %08X ", ea >> 2, opnd); + else fprintf (st, "%05X %08X %08X ", ea >> 2, opnd, opnd1); + } + sim_val = ir; + if ((fprint_sym (st, pc, &sim_val, NULL, SWMASK ('M'))) > 0) + fprintf (st, "(undefined) %08X", ir); + fputc ('\n', st); /* end line */ + } +return; +} + +/* Show history */ + +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 k, di, lnt; +t_stat r; +char *cptr = (char *) desc; +InstHistory *h; + +if (hst_lnt == 0) /* enabled? */ + return SCPE_NOFNC; +if (cptr) { + lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); + if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; + } +else lnt = hst_lnt; +di = hst_p - lnt; /* work forward */ +if (di < 0) di = di + hst_lnt; +fprintf (st, " PC CC Rn Rn|1 EA operand operand1 IR\n\n"); +for (k = 0; k < lnt; k++) { /* print specified */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + if (h->typ_cc_pc) /* instruction? */ + cpu_fprint_one_inst (st, h->typ_cc_pc, h->ir, h->rn, h->rn1, h->ea, h->op, h->op1); + } /* end for */ +return SCPE_OK; +} diff --git a/sigma/sigma_defs.h b/sigma/sigma_defs.h new file mode 100644 index 00000000..5c6951ee --- /dev/null +++ b/sigma/sigma_defs.h @@ -0,0 +1,478 @@ +/* sigma_defs.h: XDS Sigma simulator definitions + + Copyright (c) 2007-2010, Robert 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. + + The author gratefullly acknowledges the help of George Plue, who provided + answers to many puzzling questions about how the Sigma series worked. + + 22-May-10 RMS Added check for 64b definitions +*/ + +#ifndef _SIGMA_DEFS_H_ +#define _SIGMA_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ + +#if defined(USE_INT64) || defined(USE_ADDR64) +#error "Sigma 32b does not support 64b values!" +#endif + +/* Simulator stops */ + +#define STOP_INVIOC 1 /* invalid IO config */ +#define STOP_IBKPT 2 /* breakpoint */ +#define STOP_ASTOP 3 /* address stop */ +#define STOP_WAITNOINT 4 /* WAIT, no intr */ +#define STOP_INVPSD 5 /* invalid PSD */ +#define STOP_ROLLBACK 6 /* >= here, rollback PC */ +#define STOP_EXULIM 6 /* EXU loop */ +#define STOP_ILLEG 7 /* illegal instr */ +#define STOP_ILLTRP 8 /* illegal trap inst */ +#define STOP_ILLVEC 9 /* illegal vector */ +#define STOP_TRPT 10 /* trap inside int/trap */ +#define STOP_MAX 15 /* <= here for all stops */ + +/* Timers */ + +#define TMR_RTC 0 /* clocks */ + +/* Architectural constants */ + +#define PASIZE17 17 /* phys addr width, S5-8 */ +#define PASIZE20 20 /* phys addr width, 5X0 */ +#define PASIZE22 22 /* phys addr width, S9 */ +#define PAMASK17 ((1u << PASIZE17) - 1) +#define BPAMASK17 ((1u << (PASIZE17 + 2)) - 1) +#define PAMASK20 ((1u << PASIZE20) - 1) +#define BPAMASK20 ((1u << (PASIZE20 + 2)) - 1) +#define PAMASK22 ((1u << PASIZE22) - 1) +#define BPAMASK22 ((1u << (PASIZE22 + 2)) - 1) +#define MAXMEMSIZE (1u << PASIZE20) /* maximum memory */ +#define MEMSIZE (cpu_unit.capac) +#define MEM_IS_NXM(x) ((x) >= MEMSIZE) +#define BPA_IS_NXM(x) (((x) >> 2) >= MEMSIZE) +#define VASIZE 17 /* virtual addr width */ +#define VAMASK ((1u << VASIZE) - 1) /* virtual addr mask */ +#define BVAMASK ((1u << (VASIZE + 2)) - 1) /* byte virtual addr mask */ +#define RF_NUM 16 /* number of registers */ +#define RF_NBLK 32 /* max number reg blocks */ +#define RF_DFLT 4 /* default reg blocks */ + +/* CPU models, options, and variable data */ + +#define CPUF_STR (1u << (UNIT_V_UF + 0)) /* byte string */ +#define CPUF_DEC (1u << (UNIT_V_UF + 1)) /* decimal */ +#define CPUF_FP (1u << (UNIT_V_UF + 2)) /* floating point */ +#define CPUF_MAP (1u << (UNIT_V_UF + 3)) /* memory map */ +#define CPUF_WLK (1u << (UNIT_V_UF + 4)) /* write lock protect */ +#define CPUF_LAMS (1u << (UNIT_V_UF + 5)) /* LAS/LMS */ +#define CPUF_ALLOPT (CPUF_STR|CPUF_DEC|CPUF_FP|CPUF_MAP|CPUF_WLK|CPUF_LAMS) +#define CPUF_MSIZE (1u << (UNIT_V_UF + 6)) /* dummy for memory */ + +#define CPU_V_S5 0 +#define CPU_V_S6 1 +#define CPU_V_S7 2 +#define CPU_V_S8 3 /* not supported */ +#define CPU_V_S9 4 /* not supported */ +#define CPU_V_550 5 /* not supported */ +#define CPU_V_560 6 /* not supported */ +#define CPU_S5 (1u << CPU_V_S5) +#define CPU_S6 (1u << CPU_V_S6) +#define CPU_S7 (1u << CPU_V_S7) +#define CPU_S7B (1u << CPU_V_S7B) +#define CPU_S8 (1u << CPU_V_S8) +#define CPU_S9 (1u << CPU_V_S9) +#define CPU_550 (1u << CPU_V_550) +#define CPU_560 (1u << CPU_V_560) + +#define QCPU_S5 (cpu_model == CPU_V_S5) +#define QCPU_S9 (cpu_model == CPU_V_S9) +#define QCPU_5X0 ((1u << cpu_model) & (CPU_550|CPU_560)) +#define QCPU_S567 ((1u << cpu_model) & (CPU_S5|CPU_S6|CPU_S7)) +#define QCPU_S89 ((1u << cpu_model) & (CPU_S8|CPU_S9)) +#define QCPU_S89_5X0 ((1u << cpu_model) & (CPU_S8|CPU_S9|CPU_550|CPU_560)) +#define QCPU_BIGM ((1u << cpu_model) & (CPU_S9|CPU_550|CPU_560)) + +#define CPU_MUNIT_SIZE (1u << 15) /* mem unit size */ + +typedef struct { + uint32 psw1_mbz; /* PSW1 mbz */ + uint32 psw2_mbz; /* PSW2 mbz */ + uint32 mmc_cm_map1; /* MMC mode 1 cmask */ + uint32 pamask; /* physical addr mask */ + uint32 eigrp_max; /* max num ext int groups */ + uint32 chan_max; /* max num channels */ + uint32 iocc; /* IO instr CC bits */ + uint32 std; /* required options */ + uint32 opt; /* variable options */ + } cpu_var_t; + +/* Instruction format */ + +#define INST_V_IND 31 /* indirect */ +#define INST_IND (1u << INST_V_IND) +#define INST_V_OP 24 /* opcode */ +#define INST_M_OP 0x7F +#define INST_V_RN 20 /* register */ +#define INST_M_RN 0xF +#define INST_V_XR 17 /* index */ +#define INST_M_XR 0x7 +#define INST_V_ADDR 0 /* 17b addr */ +#define INST_M_ADDR 0x1FFFF +#define INST_V_LIT 0 /* 20b literal or addr */ +#define INST_M_LIT 0xFFFFF +#define TST_IND(x) ((x) & INST_IND) +#define I_GETOP(x) (((x) >> INST_V_OP) & INST_M_OP) +#define I_GETRN(x) (((x) >> INST_V_RN) & INST_M_RN) +#define I_GETXR(x) (((x) >> INST_V_XR) & INST_M_XR) +#define I_GETADDR(x) (((x) >> INST_V_ADDR) & INST_M_ADDR) +#define I_GETADDR20(x) (((x) >> INST_V_ADDR) & PAMASK20) +#define I_GETLIT(x) (((x) >> INST_V_LIT) & INST_M_LIT) +#define IRB(x) (1u << (31 - (x))) + +/* Shift instructions */ + +#define SHF_V_SOP 8 /* shift operation */ +#define SHF_M_SOP 0x7 +#define SHF_V_SC 0 /* shift count */ +#define SHF_M_SC 0x7F +#define SCSIGN 0x40 +#define SHF_GETSOP(x) (((x) >> SHF_V_SOP) & SHF_M_SOP) +#define SHF_GETSC(x) (((x) >> SHF_V_SC) & SHF_M_SC) + +/* String instructions */ + +#define S_V_MCNT 24 /* string mask/count */ +#define S_M_MCNT 0xFF +#define S_MCNT (S_M_MCNT << S_V_MCNT) +#define S_GETMCNT(x) (((x) >> S_V_MCNT) & S_M_MCNT) +#define S_ADDRINC (S_MCNT + 1) + +/* Data types */ + +#define WMASK 0xFFFFFFFF /* word */ +#define WSIGN 0x80000000 /* word sign */ +#define LITMASK (INST_M_LIT) /* literal */ +#define LITSIGN 0x80000 /* literal sign */ +#define HMASK 0xFFFF /* halfword mask */ +#define HSIGN 0x8000 /* halfword sign */ +#define BMASK 0xFF /* byte */ +#define BSIGN 0x80 /* byte sign */ +#define RNMASK (INST_M_RN) /* reg lit */ +#define RNSIGN 0x08 /* reg lit sign */ + +#define FP_V_SIGN 31 /* sign */ +#define FP_SIGN (1u << FP_V_SIGN) +#define FP_V_EXP 24 /* exponent */ +#define FP_M_EXP 0x7F +#define FP_BIAS 0x40 /* exponent bias */ +#define FP_V_FRHI 0 /* high fraction */ +#define FP_M_FRHI 0x00FFFFFF +#define FP_NORM 0x00F00000 +#define FP_M_FRLO 0xFFFFFFFF /* low fraction */ +#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & 1) +#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) +#define FP_GETFRHI(x) (((x) >> FP_V_FRHI) & FP_M_FRHI) +#define FP_GETFRLO(x) ((x) & FP_M_FRLO) + +/* PSW1 fields */ + +#define PSW1_V_CC 28 /* cond codes */ +#define PSW1_M_CC 0xF +#define CC1 0x8 +#define CC2 0x4 +#define CC3 0x2 +#define CC4 0x1 +#define PSW1_V_FR 27 /* fp mode controls */ +#define PSW1_V_FS 26 +#define PSW1_V_FZ 25 +#define PSW1_V_FN 24 +#define PSW1_V_FPC 24 /* as a group */ +#define PSW1_M_FPC 0xF +#define PSW1_FPC (PSW1_M_FPC << PSW1_V_FPC) +#define PSW1_V_MS 23 /* master/slave */ +#define PSW1_V_MM 22 /* memory map */ +#define PSW1_V_DM 21 /* decimal trap */ +#define PSW1_V_AM 20 /* arithmetic trap */ +#define PSW1_V_AS 19 /* EBCDIC/ASCII, S9 */ +#define PSW1_V_XA 15 /* ext addr flag, S9 */ +#define PSW1_V_PC 0 /* PC */ +#define PSW1_M_PC (VAMASK) +#define PSW1_FR (1u << PSW1_V_FR) +#define PSW1_FS (1u << PSW1_V_FS) +#define PSW1_FZ (1u << PSW1_V_FZ) +#define PSW1_FN (1u << PSW1_V_FN) +#define PSW1_MS (1u << PSW1_V_MS) +#define PSW1_MM (1u << PSW1_V_MM) +#define PSW1_DM (1u << PSW1_V_DM) +#define PSW1_AM (1u << PSW1_V_AM) +#define PSW1_AS (1u << PSW1_V_AS) +#define PSW1_XA (1u << PSW1_V_XA) +#define PSW1_CCMASK (PSW1_M_CC << PSW1_V_CC) +#define PSW1_PCMASK (PSW1_M_PC << PSW1_V_PC) +#define PSW1_GETCC(x) (((x) >> PSW1_V_CC) & PSW1_M_CC) +#define PSW1_GETPC(x) (((x) >> PSW1_V_PC) & PSW1_M_PC) +#define PSW1_DFLT 0 + +/* PSW2 fields */ + +#define PSW2_V_WLK 28 /* write key */ +#define PSW2_M_WLK 0xF +#define PSW2_V_CI 26 /* counter int inhibit */ +#define PSW2_V_II 25 /* IO int inhibit */ +#define PSW2_V_EI 24 /* external int inhibit */ +#define PSW2_V_INH (PSW2_V_EI) /* inhibits as a group */ +#define PSW2_M_INH 0x7 +#define PSW2_V_MA9 23 /* mode altered, S9 */ +#define PSW2_V_EA 16 /* ext addr, S9 */ +#define PSW2_M_EA 0x3F +#define PSW2_EA (PSW2_M_EA << PSW2_V_EA) +#define PSW2_V_TSF 8 /* trapped status, S9 */ +#define PSW2_M_TSF 0xFF +#define PSW2_TSF (PSW2_M_TSF << PSW2_V_TSF) +#define PSW2_V_RP 4 /* register block ptr */ +#define PSW2_M_RP5B 0x1F +#define PSW2_M_RP4B 0xF +#define PSW2_RP ((QCPU_S567? PSW2_M_RP5B: PSW2_M_RP4B) << PSW2_V_RP) +#define PSW2_V_RA 3 /* reg altered, 9,5X0 */ +#define PSW2_V_MA5X0 2 /* mode altered, 5X0 */ +#define PSW2_CI (1u << PSW2_V_CI) +#define PSW2_II (1u << PSW2_V_II) +#define PSW2_EI (1u << PSW2_V_EI) +#define PSW2_ALLINH (PSW2_CI|PSW2_II|PSW2_EI) /* all inhibits */ +#define PSW2_MA9 (1u << PSW2_V_MA9) +#define PSW2_RA (1u << PSW2_V_RA) +#define PSW2_MA5X0 (1u << PSW2_V_MA5X0) +#define PSW2_WLKMASK (PSW2_M_WLK << PSW2_V_WLK) +#define PSW2_RPMASK (PSW2_M_RP << PSW2_V_RP) +#define PSW2_GETINH(x) (((x) >> PSW2_V_INH) & PSW2_M_INH); +#define PSW2_GETWLK(x) (((x) >> PSW2_V_WLK) & PSW2_M_WLK) +#define PSW2_GETRP(x) (((x) & PSW2_RP) >> PSW2_V_RP) +#define PSW2_DFLT 0 + +/* Stack pointers */ + +#define SP_V_TS 31 /* space trap enable */ +#define SP_TS (1u << SP_V_TS) +#define SP_V_SPC 16 /* space */ +#define SP_M_SPC 0x7FFF +#define SP_V_TW 15 /* words trap enable */ +#define SP_TW (1u << SP_V_TW) +#define SP_V_WDS 0 /* words */ +#define SP_M_WDS 0x7FFF +#define SP_GETSPC(x) (((x) >> SP_V_SPC) & SP_M_SPC) +#define SP_GETWDS(x) (((x) >> SP_V_WDS) & SP_M_WDS) + +/* System stack pointer (5X0 only) */ + +#define SSP_TOS 0 /* system stack */ +#define SSP_SWC 1 /* space/word count */ +#define SSP_DFLT_PSW1 2 /* default PSD */ +#define SSP_DFLT_PSW2 3 +#define SSP_FR_LNT 28 /* frame length */ +#define SSP_FR_RN 0 /* registers */ +#define SSP_FR_PSW1 24 /* PSD */ +#define SSP_FR_PSW2 25 +#define SSP_FR_PSW4 27 + +/* The Sigma series had word addressable memory, but byte addressable + data. Virtual addresses in the simulator are BYTE addresses, and + these definitions are in terms of a byte address (word << 2). */ + +#define VA_NUM_PAG (1 << (VASIZE - (BVA_V_PAG - 2))) +#define PA_NUM_PAG (1 << (PASIZE22 - (BVA_V_PAG - 2))) +#define BVA_V_OFF 0 /* offset */ +#define BVA_M_OFF 0x7FF +#define BVA_V_PAG 11 /* page */ +#define BVA_M_PAG 0xFF +#define BVA_GETOFF(x) (((x) >> BVA_V_OFF) & BVA_M_OFF) +#define BVA_GETPAG(x) (((x) >> BVA_V_PAG) & BVA_M_PAG) +#define BPA_V_PAG (BVA_V_PAG) /* phys page */ +#define BPA_M_PAG 0x1FFF +#define BPA_GETPAG(x) (((x) >> BPA_V_PAG) & BPA_M_PAG) + +/* Memory maps */ + +#define MMC_V_CNT 24 /* count */ +#define MMC_M_CNT 0xFF +#define MMC_CNT (MMC_M_CNT << MMC_V_CNT) +#define MMC_V_CS 9 /* start of page */ +/* /* map 1: 2b locks, per model */ +#define MMC_M_CS2 0xFC /* map 2: access controls */ +#define MMC_M_CS3 0x7FE /* map 3: 4b locks */ +#define MMC_M_CS4 0xFF /* map 4: 8b relocation */ +#define MMC_M_CS5 0xFF /* map 5: 13b relocation */ +#define MMC_GETCNT(x) (((x) >> MMC_V_CNT) & MMC_M_CNT) +#define MMC_L_CS1 (VA_NUM_PAG) /* map lengths */ +#define MMC_L_CS2 (VA_NUM_PAG) +#define MMC_L_CS3 (PA_NUM_PAG) +#define MMC_L_CS4 (VA_NUM_PAG) +#define MMC_L_CS5 (VA_NUM_PAG) + +/* Trap codes */ + +#define TR_V_FL 17 /* trap flag */ +#define TR_FL (1u << TR_V_FL) +#define TR_V_PDF 16 /* proc detected fault */ +#define TR_PDF (1u << TR_V_FL) +#define TR_V_CC 12 /* or'd to CC/addr offset */ +#define TR_M_CC 0xF +#define TR_V_VEC 0 /* trap address */ +#define TR_M_VEC 0xFFF +#define TR_GETVEC(x) (((x) >> TR_V_VEC) & TR_M_VEC) +#define TR_GETCC(x) (((x) >> TR_V_CC) & TR_M_CC) + +#define TR_NXI (TR_FL|0x8040) /* non-existent inst */ +#define TR_NXM (TR_FL|0x4040) /* non-existent memory */ +#define TR_PRV (TR_FL|0x2040) /* privileged inst */ +#define TR_MPR (TR_FL|0x1040) /* mem protect violation */ +#define TR_WLK (TR_FL|0x3040) /* write lock (5x0 only) */ +#define TR_UNI (TR_FL|0x0041) /* unimplemented inst */ +#define TR_PSH (TR_FL|0x0042) /* pushdown overflow */ +#define TR_FIX (TR_FL|0x0043) /* fixed point arith */ +#define TR_FLT (TR_FL|0x0044) /* floating point arith */ +#define TR_DEC (TR_FL|0x0045) /* decimal arithmetic */ +#define TR_WAT (TR_FL|0x0046) /* watchdog timer */ +#define TR_47 (TR_FL|0x0047) /* 5X0 - WD trap */ +#define TR_C1(x) (TR_FL|0x0048|((x) << TR_V_CC)) /* call instruction */ +#define TR_C2(x) (TR_FL|0x0049|((x) << TR_V_CC)) /* call instruction */ +#define TR_C3(x) (TR_FL|0x004A|((x) << TR_V_CC)) /* call instruction */ +#define TR_C4(x) (TR_FL|0x004B|((x) << TR_V_CC)) /* call instruction */ +#define TR_NESTED (TR_FL|TR_PDF|0xF04D) /* 9,5X0 - fault in inv/trap */ +#define TR_INVTRP (TR_FL|TR_PDF|0xC04D) /* 9,5X0 - inv int/trap inst */ +#define TR_INVRPT (TR_FL|TR_PDF|0x804D) /* 9 - inv new RP in trap */ +#define TR_INVSSP (TR_FL|TR_PDF|0x404D) /* 5X0 - inv SSP for PLS */ +#define TR_INVMMC (TR_FL|TR_PDF|0x204D) /* 9,5X0 - inv MMC config */ +#define TR_INVREG (TR_FL|0x104D) /* 9,5x0 - inv reg num */ +#define TR_INVRPN (TR_FL|TR_PDF|0x004D) /* 9 - inv new RP, non-trap */ + +/* Effective address and memory access routines interface + + The access types are defined to make the following equation work: + + trap if ((access_type != 0) && (access_control >= access_type)) + + The length codes are defined so that length in bytes = 1 << length_code */ + +#define PH 0x0 /* physical */ +#define VW 0x1 /* write */ +#define VI 0x2 /* instruction */ +#define VR 0x3 /* read */ +#define VNT 0x4 /* no traps */ + +#define BY 0x0 /* byte */ +#define HW 0x1 /* halfword */ +#define WD 0x2 /* word */ +#define DW 0x3 /* doubleword */ + +/* Interrupt groups - the Sigma's have flexibly configured interrupt groups + of various widths that map non-uniformly to control register bits */ + +typedef struct { + uint32 psw2_inh; /* PSW2 inhibit */ + uint32 nbits; /* number of bits */ + uint32 vecbase; /* vector base */ + uint32 rwgroup; /* RWdirect group */ + uint32 regbit; /* RWdirect reg bit */ + } int_grp_t; + +#define INTG_MAX 17 /* max # int groups */ +#define EIGRP_DFLT 1 /* dflt # ei groups */ +#define INTG_OVR 0 /* override group */ +#define INTG_CTR 1 /* counter group */ +#define INTG_IO 2 /* I/O group */ +#define INTGIO_IO 0x2 /* I/O interrupt */ +#define INTGIO_PANEL 0x1 /* panel interrupt */ +#define INTG_E2 3 /* ext group 2 */ +#define INTG_E3 4 /* ext group 3 */ + +#define INT_V_GRP 4 /* interrupt group */ +#define INT_M_GRP 0x1F +#define INT_V_BIT 0 /* interrupt bit */ +#define INT_M_BIT 0xF +#define INT_GETGRP(x) (((x) >> INT_V_GRP) & INT_M_GRP) +#define INT_GETBIT(x) (((x) >> INT_V_BIT) & INT_M_BIT) +#define INTV(x,y) (((x) << INT_V_GRP) | ((y) << INT_V_BIT)) +#define NO_INT (INTV (INTG_MAX, 0)) + +#define VEC_C1P 0x52 /* clock pulse vectors */ +#define VEC_C4P 0x55 +#define VEC_C1Z 0x58 /* clock zero vector */ + +/* Integer data operations and condition codes */ + +#define SEXT_RN_W(x) (((x) & RNSIGN)? ((x) | ~RNMASK): ((x) & RNMASK)) +#define SEXT_H_W(x) (((x) & HSIGN)? ((x) | ~HMASK): ((x) & HMASK)) +#define SEXT_LIT_W(x) (((x) & LITSIGN)? ((x) | ~LITMASK): ((x) & LITMASK)) +#define NEG_W(x) ((~(x) + 1) & WMASK) +#define NEG_D(x,y) do { y = NEG_W(y); x = (~(x) + ((y) == 0)) & WMASK; } while (0) +#define CC34_W(x) CC = (((x) & WSIGN)? \ + ((CC & ~CC3) | CC4): \ + (((x) != 0)? \ + ((CC & ~CC4) | CC3): \ + (CC & ~(CC3|CC4)))) +#define CC234_CMP(x,y) CC = (CC & CC1) | Cmp32 ((x), (y)) | \ + (((x) & (y))? CC2: 0) + +/* Instructions */ + +enum opcodes { + OP_00, OP_01, OP_LCFI, OP_03, OP_CAL1, OP_CAL2, OP_CAL3, OP_CAL4, + OP_PLW, OP_PSW, OP_PLM, OP_PSM, OP_PLS, OP_PSS, OP_LPSD, OP_XPSD, + OP_AD, OP_CD, OP_LD, OP_MSP, OP_14, OP_STD, OP_16, OP_17, + OP_SD, OP_CLM, OP_LCD, OP_LAD, OP_FSL, OP_FAL, OP_FDL, OP_FML, + OP_AI, OP_CI, OP_LI, OP_MI, OP_SF, OP_S, OP_LAS, OP_27, + OP_CVS, OP_CVA, OP_LM, OP_STM, OP_LRA, OP_LMS, OP_WAIT, OP_LRP, + OP_AW, OP_CW, OP_LW, OP_MTW, OP_LVAW, OP_STW, OP_DW, OP_MW, + OP_SW, OP_CLR, OP_LCW, OP_LAW, OP_FSS, OP_FAS, OP_FDS, OP_FMS, + OP_TTBS, OP_TBS, OP_42, OP_43, OP_ANLZ, OP_CS, OP_XW, OP_STS, + OP_EOR, OP_OR, OP_LS, OP_AND, OP_SIO, OP_TIO, OP_TDV, OP_HIO, + OP_AH, OP_CH, OP_LH, OP_MTH, OP_54, OP_STH, OP_DH, OP_MH, + OP_SH, OP_59, OP_LCH, OP_LAH, OP_5C, OP_5D, OP_5E, OP_5F, + OP_CBS, OP_MBS, OP_62, OP_EBS, OP_BDR, OP_BIR, OP_AWM, OP_EXU, + OP_BCR, OP_BCS, OP_BAL, OP_INT, OP_RD, OP_WD, OP_AIO, OP_MMC, + OP_LCF, OP_CB, OP_LB, OP_MTB, OP_STCF, OP_STB, OP_PACK, OP_UNPK, + OP_DS, OP_DA, OP_DD, OP_DM, OP_DSA, OP_DC, OP_DL, OP_DST + }; + +/* Function prototypes */ + +uint32 Ea (uint32 ir, uint32 *bva, uint32 acc, uint32 lnt); +uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc); +uint32 WriteB (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteH (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteW (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc); +uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc); +uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc); +uint32 ReadPB (uint32 ba, uint32 *dat); +uint32 WritePB (uint32 ba, uint32 dat); +uint32 ReadPW (uint32 pa, uint32 *dat); +uint32 WritePW (uint32 pa, uint32 dat); +uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt); + +#endif \ No newline at end of file diff --git a/sigma/sigma_dk.c b/sigma/sigma_dk.c new file mode 100644 index 00000000..e732465b --- /dev/null +++ b/sigma/sigma_dk.c @@ -0,0 +1,470 @@ +/* sigma_dk.c: 7250/7251-7252 cartridge disk simulator + + Copyright (c) 2007-2008, Robert 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. + + dk 7250/7251-7252 cartridge disk + + Transfers are always done a sector at a time. +*/ + +#include "sigma_io_defs.h" +#include + +#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_HWLK (1u << UNIT_V_HWLK) +#define UNIT_WPRT (UNIT_HWLK|UNIT_RO) /* write prot */ +#define UTRK u3 /* current track */ + +/* Constants */ + +#define DK_NUMDR 8 /* drives/ctlr */ +#define DK_WDSC 90 /* words/sector */ +#define DK_SCTK 16 /* sectors/track */ +#define DK_TKUN 408 /* tracks/unit */ +#define DK_WDUN (DK_WDSC*DK_SCTK*DK_TKUN) /* words/unit */ + +/* Address bytes */ + +#define DKA_V_TK 4 /* track offset */ +#define DKA_M_TK 0x1FF +#define DKA_V_SC 0 /* sector offset */ +#define DKA_M_SC 0xF +#define DKA_GETTK(x) (((x) >> DKA_V_TK) & DKA_M_TK) +#define DKA_GETSC(x) (((x) >> DKA_V_SC) & DKA_M_SC) + +/* Status byte 3 is current sector */ + +#define DKS_NBY 3 + +/* Device state */ + +#define DKS_INIT 0x101 +#define DKS_END 0x102 +#define DKS_WRITE 0x01 +#define DKS_READ 0x02 +#define DKS_SEEK 0x03 +#define DKS_SEEK2 0x103 +#define DKS_SENSE 0x04 +#define DKS_CHECK 0x05 +#define DKS_RDEES 0x12 +#define DKS_TEST 0x13 + +/* Device status */ + +#define DKV_OVR 0x80 /* overrun - NI */ +#define DKV_BADS 0x20 /* bad track */ +#define DKV_WPE 0x10 + +#define GET_PSC(x) ((int32) fmod (sim_gtime() / ((double) (x * DK_WDSC)), \ + ((double) DK_SCTK))) + +uint32 dk_cmd = 0; /* state */ +uint32 dk_flags = 0; /* status flags */ +uint32 dk_ad = 0; /* disk address */ +uint32 dk_time = 5; /* inter-word time */ +uint32 dk_stime = 20; /* inter-track time */ +uint32 dk_stopioe = 1; /* stop on I/O error */ + +extern uint32 chan_ctl_time; + +uint32 dk_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dk_tio_status (uint32 un); +uint32 dk_tdv_status (uint32 un); +t_stat dk_chan_err (uint32 st); +t_stat dk_svc (UNIT *uptr); +t_stat dk_reset (DEVICE *dptr); +t_bool dk_inv_ad (uint32 *da); +t_bool dk_inc_ad (void); +t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); + +/* DK data structures + + dk_dev DK device descriptor + dk_unit DK unit descriptor + dk_reg DK register list +*/ + +dib_t dk_dib = { DVA_DK, &dk_disp }; + +UNIT dk_unit[] = { + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) } + }; + +REG dk_reg[] = { + { HRDATA (CMD, dk_cmd, 9) }, + { HRDATA (FLAGS, dk_flags, 8) }, + { HRDATA (ADDR, dk_ad, 8) }, + { DRDATA (TIME, dk_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dk_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOPIOE, dk_stopioe, 0) }, + { HRDATA (DEVNO, dk_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB dk_mod[] = { + { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE dk_dev = { + "DK", dk_unit, dk_reg, dk_mod, + DK_NUMDR, 16, 22, 1, 16, 32, + NULL, NULL, &dk_reset, + NULL, NULL, NULL, + &dk_dib, DEV_DISABLE + }; + +/* DK: IO dispatch routine */ + +uint32 dk_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 i; +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr; + +if ((un >= DK_NUMDR) || /* inv unit num? */ + (dk_unit[un].flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = dk_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + dk_cmd = DKS_INIT; /* start dev thread */ + sim_activate (&dk_unit[un], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = dk_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = dk_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (dk_dib.dva); /* clr int */ + *dvst = dk_tio_status (un); /* get status */ + if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */ + for (i = 0; i < DK_NUMDR; i++) { /* find busy unit */ + uptr = &dk_unit[i]; + if (sim_is_active (uptr)) { /* active? */ + sim_cancel (uptr); /* stop */ + chan_uen (dk_dib.dva); /* uend */ + } /* end if active */ + } /* end for */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (dk_dib.dva); /* clr int */ + *dvst = dk_tdv_status (un); /* status like TDV */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat dk_svc (UNIT *uptr) +{ +uint32 i, sc, da, wd, wd1, cmd, c[3]; +uint32 *fbuf = (uint32 *) uptr->filebuf; +int32 t, dc; +uint32 st; + +switch (dk_cmd) { + + case DKS_INIT: /* init state */ + st = chan_get_cmd (dk_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + if ((cmd == 0) || /* invalid cmd? */ + ((cmd > DKS_CHECK) && (cmd != DKS_RDEES) && (cmd != DKS_TEST))) { + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + dk_flags = 0; /* clear status */ + dk_cmd = cmd & 0x17; /* next state */ + if ((cmd == DKS_SEEK) || /* fast cmd? */ + (cmd == DKS_SENSE) || + (cmd == DKS_TEST)) + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = DKA_GETSC (dk_ad); /* new sector */ + t = sc - GET_PSC (dk_time); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + DK_SCTK; + sim_activate (uptr, t * dk_time * DK_WDSC); /* schedule op */ + } + return SCPE_OK; + + case DKS_END: /* end state */ + st = chan_end (dk_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + dk_cmd = DKS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + + case DKS_SEEK: /* seek */ + c[0] = c[1] = 0; + for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dk_dib.dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + } + dk_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */ + if (((i != 2) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* care? */ + return SCPE_OK; + dc = DKA_GETTK (dk_ad); /* desired track */ + t = abs (uptr->UTRK - dc); /* get track diff */ + if (t == 0) + t = 1; + sim_activate (uptr, t * dk_stime); + uptr->UTRK = dc; /* put on track */ + dk_cmd = DKS_SEEK2; + return SCPE_OK; + + case DKS_SEEK2: /* seek complete */ + if (uptr->UTRK >= DK_TKUN) { + dk_flags |= DKV_BADS; + chan_uen (dk_dib.dva); + return SCPE_OK; + } + break; /* seek done */ + + case DKS_SENSE: /* sense */ + c[0] = ((dk_ad >> 8) & 0x7F) | ((uptr->flags & UNIT_RO)? 0x80: 0); + c[1] = dk_ad & 0xFF; /* address */ + c[2] = GET_PSC (dk_time); /* curr sector */ + for (i = 0, st = 0; (i < DKS_NBY) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dk_dib.dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + } + if (((i != DKS_NBY) || (st != CHS_ZBC)) && + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* length error? */ + return SCPE_OK; + break; + + case DKS_WRITE: /* write */ + if (uptr->flags & UNIT_RO) { /* write locked? */ + dk_flags |= DKV_WPE; /* set status */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < DK_WDSC; da++, i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemW (dk_dib.dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + } + else wd = 0; + fbuf[da] = wd; /* store in buffer */ + if (da >= uptr->hwmark) /* update length */ + uptr->hwmark = da + 1; + } + if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Must be done by bytes to get precise miscompare */ + + case DKS_CHECK: /* write check */ + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < (DK_WDSC * 4)) && (st != CHS_ZBC); ) { + st = chan_RdMemB (dk_dib.dva, &wd); /* read byte */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + dk_inc_ad (); /* da increments */ + chan_set_chf (dk_dib.dva, CHF_XMDE); /* set xmt err flag */ + chan_uen (dk_dib.dva); /* force uend */ + return SCPE_OK; + } + da = da + ((++i % 4) == 0); /* every 4th byte */ + } + if (dk_end_sec (uptr, i, DK_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + + case DKS_READ: /* read */ + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < DK_WDSC) && (st != CHS_ZBC); da++, i++) { + st = chan_WrMemW (dk_dib.dva, fbuf[da]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + } + if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + } + +dk_cmd = DKS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end disk - reschedule, return TRUE + case 2 - more to transfer, end disk - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +if (st != CHS_ZBC) { /* end record? */ + if (dk_inc_ad ()) /* inc addr, ovf? */ + chan_uen (dk_dib.dva); /* uend */ + else sim_activate (uptr, dk_time * 16); /* no, next sector */ + return TRUE; + } +dk_inc_ad (); /* just incr addr */ +if ((lnt != exp) && /* length error? */ + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* do we care? */ + return TRUE; +return FALSE; /* cmd done */ +} + +/* DK status routine */ + +uint32 dk_tio_status (uint32 un) +{ +uint32 i; + +for (i = 0; i < DK_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&dk_unit[i])) /* active? */ + return (DVS_AUTO | DVS_CBUSY | (CC2 << DVT_V_CC) | + ((i == un)? DVS_DBUSY: 0)); + } +return DVS_AUTO; +} + +uint32 dk_tdv_status (uint32 un) +{ +return dk_flags | (dk_inv_ad (NULL)? DKV_BADS: 0); +} + +/* Validate disk address */ + +t_bool dk_inv_ad (uint32 *da) +{ +uint32 tk = DKA_GETTK (dk_ad); +uint32 sc = DKA_GETSC (dk_ad); + +if (tk >= DK_TKUN) /* badtrk? */ + return TRUE; +if (da) /* return word addr */ + *da = ((tk * DK_SCTK) + sc) * DK_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool dk_inc_ad (void) +{ +uint32 tk = DKA_GETTK (dk_ad); +uint32 sc = DKA_GETSC (dk_ad); + +sc = sc + 1; /* sector++ */ +if (sc >= DK_SCTK) { /* overflow? */ + sc = 0; /* wrap sector */ + tk = tk + 1; /* track++ */ + } +dk_ad = ((tk << DKA_V_TK) | /* rebuild dk_ad */ + (sc << DKA_V_SC)); +if (tk >= DK_TKUN) /* invalid addr? */ + return TRUE; +return FALSE; +} + +/* Channel error */ + +t_stat dk_chan_err (uint32 st) +{ +chan_uen (dk_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat dk_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < DK_NUMDR; i++) { + sim_cancel (&dk_unit[i]); /* stop dev thread */ + dk_unit[i].UTRK = 0; + } +dk_cmd = 0; +dk_flags = 0; +dk_ad = 0; +chan_reset_dev (dk_dib.dva); /* clr int, active */ +return SCPE_OK; +} diff --git a/sigma/sigma_doc.doc b/sigma/sigma_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..0cfb805c4d2bd5fe73bd0967e8f8b2610a545fd7 GIT binary patch literal 90624 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 G0{ + +#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_HWLK (1u << UNIT_V_HWLK) +#define UNIT_WPRT (UNIT_HWLK|UNIT_RO) /* write prot */ +#define UNIT_V_AUTO (UNIT_V_UF + 1) /* autosize */ +#define UNIT_AUTO (1u << UNIT_V_AUTO) +#define UNIT_V_DTYPE (UNIT_V_UF + 2) /* drive type */ +#define UNIT_M_DTYPE 0x7 +#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) +#define UDA u3 /* disk addr */ +#define UCMD u4 /* current command */ +#define UCTX u5 /* ctrl/ctx index */ +#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) + +/* Constants */ + +#define DP_NUMCTL 2 /* number of controllers */ +#define DP_C7270 0 /* 7270 ctrl */ +#define DP_C3281 1 /* 3281 ctrl */ +#define DP_NUMDR_7270 8 /* drives/ctrl */ +#define DP_NUMDR_3281 15 +#define DP_CONT DP_NUMDR_3281 /* ctrl's drive # */ +#define DP_WDSC 256 /* words/sector */ +#define DP_BYHD 8 /* byte/header */ +#define DP_NUMDR ((uint32) ((ctx->dp_ctype == DP_C7270)? DP_NUMDR_7270: DP_NUMDR_3281)) +#define DP_SEEK (DP_CONT + 1) + +/* Address bytes */ + +#define DPA_V_CY 16 /* cylinder offset */ +#define DPA_M_CY 0x3FF +#define DPA_V_HD 8 /* head offset */ +#define DPA_M_HD 0x1F +#define DPA_V_SC 0 /* sector offset */ +#define DPA_M_SC 0x1F +#define DPA_GETCY(x) (((x) >> DPA_V_CY) & DPA_M_CY) +#define DPA_GETHD(x) (((x) >> DPA_V_HD) & DPA_M_HD) +#define DPA_GETSC(x) (((x) >> DPA_V_SC) & DPA_M_SC) + +/* Sense order */ + +#define DPS_NBY_7270 10 +#define DPS_NBY_3281 16 +#define DPS_NBY ((uint32) ((ctx->dp_ctype == DP_C7270)? DPS_NBY_7270: DPS_NBY_3281)) + +/* Test mode */ + +#define DPT_NBY_7270 1 /* bytes/test mode spec */ +#define DPT_NBY_3281 2 +#define DPT_NBY ((uint32) ((ctx->dp_ctype == DP_C7270)? DPT_NBY_7270: DPT_NBY_3281)) + +/* Commands */ + +#define DPS_INIT 0x100 +#define DPS_END 0x101 +#define DPS_WRITE 0x01 +#define DPS_READ 0x02 +#define DPS_SEEK 0x03 +#define DPS_SEEKI 0x83 +#define DPS_SENSE 0x04 +#define DPS_CHECK 0x05 +#define DPS_RSRV 0x07 +#define DPS_WHDR 0x09 +#define DPS_RHDR 0x0A +#define DPS_CRIOF 0x0F +#define DPS_RDEES 0x12 +#define DPS_TEST 0x13 +#define DPS_RLS 0x17 +#define DPS_CRION 0x1F +#define DPS_RLSA 0x23 +#define DPS_RECAL 0x33 +#define DPS_RECALI 0xB3 + +/* Seek completion states */ + +#define DSC_SEEK 0x00 /* seeking */ +#define DSC_SEEKI 0x80 /* seeking, then int */ +#define DSC_SEEKW 0x01 /* waiting to int */ + +/* Device status - note that these are device independent */ + +#define DPF_V_WCHK 0 +#define DPF_V_DPE 1 +#define DPF_V_SNZ 2 +#define DPF_V_EOC 3 +#define DPF_V_IVA 4 +#define DPF_V_PGE 5 +#define DPF_V_WPE 6 +#define DPF_V_AIM 7 +#define DPF_WCHK (1u << DPF_V_WCHK) /* wrt chk error */ +#define DPF_DPE (1u << DPF_V_DPE) /* data error */ +#define DPF_SNZ (1u << DPF_V_SNZ) /* sec# != 0 */ +#define DPF_EOC (1u << DPF_V_EOC) /* end cylinder */ +#define DPF_IVA (1u << DPF_V_IVA) /* invalid addr */ +#define DPF_PGE (1u << DPF_V_PGE) /* prog error */ +#define DPF_WPE (1u << DPF_V_WPE) /* wrt prot err */ +#define DPF_AIM (1u << DPF_V_AIM) /* arm in motion */ +#define DPF_V_DIFF 16 +#define DPF_M_DIFF 0xFFFFu +#define DPF_DIFF (DPF_M_DIFF << DPF_V_DIFF) + +/* Drive types */ + +/* These controllers support many different disk drive types: + + type #sectors/ #surfaces/ #cylinders/ + surface cylinder drive + + 7242 6 20 204 + 7261 11 20 204 + 7271 6 20 408 + 3288 17 5 823 =67MB + 7275 11 19 411 =88MB + 7276 11 19 815 =176MB + 3283 17 18 815 + + In theory, each drive can be a different type. The size field in + each unit selects the drive capacity for each drive and thus the + drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE. +*/ + +#define DP_SZ(x) ((DPCY_##x) * (DPHD_##x) * (DPSC_##x) * DP_WDSC) +#define DP_ENT(x,y) (DP_##x), (DPCY_##x), (DPHD_##x), (DPSC_##x), (DP_C##y), (DPSZ_##x) + +#define DP_7242 0 +#define DPCY_7242 204 +#define DPHD_7242 20 +#define DPSC_7242 6 +#define DPSZ_7242 DP_SZ(7242) + +#define DP_7261 1 +#define DPCY_7261 204 +#define DPHD_7261 20 +#define DPSC_7261 11 +#define DPSZ_7261 DP_SZ(7261) + +#define DP_7271 2 +#define DPCY_7271 408 +#define DPHD_7271 20 +#define DPSC_7271 6 +#define DPSZ_7271 DP_SZ(7271) + +#define DP_3288 3 +#define DPCY_3288 822 +#define DPHD_3288 5 +#define DPSC_3288 17 +#define DPSZ_3288 DP_SZ(3288) + +#define DP_7275 4 +#define DPCY_7275 411 +#define DPHD_7275 19 +#define DPSC_7275 11 +#define DPSZ_7275 DP_SZ(7275) + +#define DP_7276 5 +#define DPCY_7276 815 +#define DPHD_7276 19 +#define DPSC_7276 11 +#define DPSZ_7276 DP_SZ(7276) + +#define DP_3283 6 +#define DPCY_3283 815 +#define DPHD_3283 19 +#define DPSC_3283 17 +#define DPSZ_3283 DP_SZ(3283) + +#define GET_PSC(x,s) ((int32) fmod (sim_gtime() / ((double) (x * DP_WDSC)), \ + ((double) (s)))) + +typedef struct { + uint32 dp_ctype; /* controller type */ + uint32 dp_flags; /* status flags */ + uint32 dp_ski; /* seek interrupts */ + uint32 dp_time; /* inter-word time */ + uint32 dp_stime; /* inter-track time */ + uint32 dp_stopioe; /* stop on I/O error */ + uint32 dp_test; /* test mode */ + } DP_CTX; + +typedef struct { + uint32 dtype; /* drive type */ + uint32 cy; /* cylinders */ + uint32 hd; /* heads */ + uint32 sc; /* sectors */ + uint32 ctype; /* controller */ + uint32 capac; /* capacity */ + } DP_TYPE; + +typedef struct { + uint32 byte; /* offset in array */ + uint32 mask; /* test mask */ + uint32 fpos; /* from position */ + uint32 tpos; /* to position */ + } DP_SNSTAB; + +static uint32 dp_buf[DP_WDSC]; + +extern uint32 chan_ctl_time; + +uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dpb_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dp_disp (uint32 cidx, uint32 op, uint32 dva, uint32 *dvst); +uint32 dp_tio_status (uint32 cidx, uint32 un); +uint32 dp_tdv_status (uint32 cidx, uint32 un); +uint32 dp_aio_status (uint32 cidx, uint32 un); +void dp_set_sense (UNIT *uptr, uint32 *c); +t_stat dp_chan_err (uint32 dva, uint32 st); +t_stat dp_svc (UNIT *uptr); +t_stat dps_svc (UNIT *uptr); +t_stat dp_reset (DEVICE *dptr); +t_bool dp_inv_ad (UNIT *uptr, uint32 *da); +t_bool dp_inc_ad (UNIT *uptr); +t_stat dp_read (UNIT *uptr, uint32 da); +t_stat dp_write (UNIT *uptr, uint32 da); +t_stat dp_ioerr (UNIT *uptr); +t_bool dp_test_mode (uint32 cidx); +t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); +int32 dp_clr_int (uint32 cidx); +void dp_set_ski (uint32 cidx, uint32 un); +void dp_clr_ski (uint32 cidx, uint32 un); +t_stat dp_attach (UNIT *uptr, char *cptr); +t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dp_set_ctl (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, void *desc); + +static DP_TYPE dp_tab[] = { + { DP_ENT (7242, 7270) }, + { DP_ENT (7261, 3281) }, + { DP_ENT (7271, 7270) }, + { DP_ENT (3288, 3281) }, + { DP_ENT (7275, 3281) }, + { DP_ENT (7276, 3281) }, + { DP_ENT (3283, 3281) }, + { 0, 0, 0, 0, 0, 0 }, + }; + +static DP_SNSTAB dp_sense_7270[] = { + { 8, DPF_WCHK, DPF_V_WCHK, 6 }, + { 8, DPF_SNZ, DPF_V_SNZ, 2 }, + { 9, 0x01000000, 24, 0 }, + { 0, 0, 0, 0 } + }; + +static DP_SNSTAB dp_sense_3281[] = { + { 8, DPF_WCHK, DPF_V_WCHK, 7 }, + { 8, DPF_EOC, DPF_V_EOC, 3}, + { 8, DPF_AIM, DPF_V_AIM, 2}, + { 14, 0xFF000000, 24, 0 }, + { 15, 0x00FF0000, 16, 0 }, + { 0, 0, 0, 0 } + }; + +/* Command table, indexed by command */ + +#define C_7270 (1u << DP_C7270) +#define C_3281 (1u << DP_C3281) +#define C_B (C_7270|C_3281) +#define C_F (1u << 2) /* fast */ +#define C_C (1u << 3) /* ctrl cmd */ + +static uint8 dp_cmd[256] = { + 0, C_B, C_B, C_B, C_B|C_F, C_B, 0, C_3281|C_F, + 0, C_B, C_B, 0, 0, 0, 0, C_3281|C_F|C_C, + 0, 0, C_B, C_B|C_F, 0, 0, 0, C_3281|C_F, + 0, 0, 0, 0, 0, 0, 0, C_3281|C_F|C_C, + 0, 0, 0, C_7270|C_F, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, C_B, 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, C_B, 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, C_3281, 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 + }; + +/* DP data structures + + dp_dev DP device descriptor + dp_unit DP unit descriptor + dp_reg DP register list +*/ + +dib_t dp_dib[] = { + { DVA_DPA, &dpa_disp }, + { DVA_DPB, &dpb_disp } + }; + +DP_CTX dp_ctx[] = { + { DP_C7270 }, + { DP_C3281 } + }; + +UNIT dpa_unit[] = { + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + }; + +UNIT dpb_unit[] = { + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + }; + +REG dpa_reg[] = { + { HRDATA (CTYPE, dp_ctx[0].dp_ctype, 1), REG_HRO }, + { HRDATA (FLAGS, dp_ctx[0].dp_flags, 8) }, + { GRDATA (DIFF, dp_ctx[0].dp_flags, 16, 16, 16) }, + { HRDATA (SKI, dp_ctx[0].dp_ski, 16) }, + { HRDATA (TEST, dp_ctx[0].dp_test, 16) }, + { URDATA (ADDR, dpa_unit[0].UDA, 16, 32, 0, DP_NUMDR_3281, 0) }, + { URDATA (CMD, dpa_unit[0].UCMD, 16, 10, 0, DP_NUMDR_3281, 0) }, + { DRDATA (TIME, dp_ctx[0].dp_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dp_ctx[0].dp_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOP_IOE, dp_ctx[0].dp_stopioe, 0) }, + { HRDATA (DEVNO, dp_dib[0].dva, 12), REG_HRO }, + { NULL } + }; + +REG dpb_reg[] = { + { HRDATA (CTYPE, dp_ctx[1].dp_ctype, 1), REG_HRO }, + { HRDATA (FLAGS, dp_ctx[1].dp_flags, 8) }, + { GRDATA (DIFF, dp_ctx[1].dp_flags, 16, 16, 16) }, + { HRDATA (SKI, dp_ctx[1].dp_ski, 16) }, + { HRDATA (TEST, dp_ctx[1].dp_test, 16) }, + { URDATA (ADDR, dpa_unit[1].UDA, 16, 32, 0, DP_NUMDR_3281, 0) }, + { URDATA (CMD, dpa_unit[1].UCMD, 16, 10, 0, DP_NUMDR_3281, 0) }, + { DRDATA (TIME, dp_ctx[1].dp_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dp_ctx[1].dp_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOP_IOE, dp_ctx[1].dp_stopioe, 0) }, + { HRDATA (DEVNO, dp_dib[1].dva, 12), REG_HRO }, + { NULL } + }; + +MTAB dp_mod[] = { + { MTAB_XTD|MTAB_VDV, DP_C7270, "C7270", "C7270", + &dp_set_ctl, &dp_show_ctl, NULL }, + { MTAB_XTD|MTAB_VDV, DP_C3281, "C3281", "C3281", + &dp_set_ctl, &dp_show_ctl, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7242 << UNIT_V_DTYPE) + UNIT_ATT, + "7242", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7261 << UNIT_V_DTYPE) + UNIT_ATT, + "7261", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7271 << UNIT_V_DTYPE) + UNIT_ATT, + "7271", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE) + UNIT_ATT, + "3288", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7275 << UNIT_V_DTYPE) + UNIT_ATT, + "7275", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7276 << UNIT_V_DTYPE) + UNIT_ATT, + "7276", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_3283 << UNIT_V_DTYPE) + UNIT_ATT, + "3283", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7242 << UNIT_V_DTYPE), + "7242", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7261 << UNIT_V_DTYPE), + "7261", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7271 << UNIT_V_DTYPE), + "7271", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE), + "3288", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7275 << UNIT_V_DTYPE), + "7275", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7276 << UNIT_V_DTYPE), + "7276", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3283 << UNIT_V_DTYPE), + "3283", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7242 << UNIT_V_DTYPE), + NULL, "7242", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7261 << UNIT_V_DTYPE), + NULL, "7261", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7271 << UNIT_V_DTYPE), + NULL, "7271", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_3288 << UNIT_V_DTYPE), + NULL, "3288", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7275 << UNIT_V_DTYPE), + NULL, "7275", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7276 << UNIT_V_DTYPE), + NULL, "7276", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7276 << UNIT_V_DTYPE), + NULL, "3282", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_3283 << UNIT_V_DTYPE), + NULL, "3283", &dp_set_size }, + { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE dp_dev[] = { + { + "DPA", dpa_unit, dpa_reg, dp_mod, + (2 * DP_NUMDR_3281) + 1, 16, 28, 1, 16, 32, + NULL, NULL, &dp_reset, + &io_boot, &dp_attach, NULL, + &dp_dib[0], DEV_DISABLE + }, + { + "DPB", dpb_unit, dpb_reg, dp_mod, + (2 * DP_NUMDR_3281) + 1, 16, 28, 1, 16, 32, + NULL, NULL, &dp_reset, + &io_boot, &dp_attach, NULL, + &dp_dib[1], DEV_DISABLE + } + }; + +/* DP: IO dispatch routine */ + +uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +return dp_disp (0, op, dva, dvst); +} + +uint32 dpb_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +return dp_disp (1, op, dva, dvst); +} + +uint32 dp_disp (uint32 cidx, uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 un = DVA_GETUNIT (dva); +UNIT *dp_unit = dp_dev[cidx].units; +UNIT *uptr = dp_unit + un; +int32 iu; +uint32 i; +DP_CTX *ctx; + +if (cidx >= DP_NUMCTL) /* inv ctrl num? */ + return DVT_NODEV; +ctx = &dp_ctx[cidx]; +if ((un >= DP_NUMDR) || /* inv unit num? */ + ((uptr->flags & UNIT_DIS) && /* disabled unit? */ + ((un != 0xF) || (ctx->dp_ctype != C_3281)))) /* not 3281 unit F? */ + return DVT_NODEV; + +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = dp_tio_status (cidx, un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + uptr->UCMD = DPS_INIT; /* start dev thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = dp_tio_status (cidx, un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = dp_tdv_status (cidx, un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = dp_tio_status (cidx, un); /* return status */ + if (un != 0xF) { /* not controller */ + if ((int32) un == chan_chk_chi (dva)) /* halt active ctlr int? */ + chan_clr_chi (dva); /* clear ctlr int */ + if (sim_is_active (uptr)) { /* chan active? */ + sim_cancel (uptr); /* stop unit */ + chan_uen (dva); /* uend */ + } + dp_clr_ski (cidx, un); /* clear seek int */ + sim_cancel (uptr + DP_SEEK); /* cancel seek compl */ + } + else { + for (i = 0; i < DP_NUMDR; i++) { /* do every unit */ + if (sim_is_active (&dp_unit[i])) { /* chan active? */ + sim_cancel (&dp_unit[i]); /* cancel */ + chan_uen (dva); /* uend */ + } + dp_clr_ski (cidx, i); /* clear seek int */ + sim_cancel (&dp_unit[i] + DP_SEEK); /* cancel seek compl */ + } + chan_clr_chi (dva); /* clear chan int */ + } + break; + + case OP_AIO: /* acknowledge int */ + iu = dp_clr_int (cidx); /* clear int */ + *dvst = dp_aio_status (cidx, iu) | /* get status */ + (iu << DVT_V_UN); + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat dp_svc (UNIT *uptr) +{ +uint32 i, da, wd, wd1, c[DPS_NBY_3281]; +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; +uint32 dtype = GET_DTYPE (uptr->flags); +UNIT *dp_unit = dp_dev[cidx].units; +uint32 un = uptr - dp_unit; +DP_CTX *ctx = &dp_ctx[cidx]; +int32 t, dc; +uint32 st, cmd, sc; +t_stat r; + +if (uptr->UCMD == DPS_INIT) { /* init state? */ + st = chan_get_cmd (dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + ctx->dp_flags = 0; /* clear status */ + if (!(dp_cmd[cmd] & (1u << ctx->dp_ctype))) { /* cmd valid for dev? */ + ctx->dp_flags |= DPF_PGE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if ((un == 0xF) && /* to controller? */ + !(dp_cmd[cmd] & C_C)) { /* not valid? */ + ctx->dp_flags |= DPF_PGE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + uptr->UCMD = cmd; /* save state */ + if (dp_cmd[cmd] & C_F) /* fast command? */ + sim_activate_abs (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = DPA_GETSC (uptr->UDA); /* new sector */ + t = sc - GET_PSC (ctx->dp_time, dp_tab[dtype].sc); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + dp_tab[dtype].sc; + sim_activate_abs (uptr, t * ctx->dp_time * DP_WDSC); /* schedule op */ + } + sim_cancel (uptr + DP_SEEK); /* cancel rest of seek */ + return SCPE_OK; + } +else if (uptr->UCMD == DPS_END) { /* end state? */ + st = chan_end (dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + if (st == CHS_CCH) { /* command chain? */ + uptr->UCMD = DPS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + } + +da = 0; +dc = 0; +switch (uptr->UCMD) { + + case DPS_SEEK: /* seek */ + case DPS_SEEKI: + for (i = 0; i < 4; i++) + c[i] = 0; + for (i = 0, st = 0; (i < 4) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + } + da = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; + if (c[0] & 0xFC) /* hi 6b non-zero? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + if (((i != 4) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (dva, CHF_LNTE)) { /* care? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + return SCPE_OK; + } + if (i < 4) { /* at least 4? */ + chan_uen (dva); + return SCPE_OK; + } + dc = DPA_GETCY (da); /* desired cyl */ + case DPS_RECAL: + case DPS_RECALI: + t = DPA_GETCY (uptr->UDA) - dc; /* get cyl diff */ + ctx->dp_flags = (ctx->dp_flags & ~DPF_DIFF) | + ((t & DPF_M_DIFF) << DPF_V_DIFF); /* save difference */ + if (t == 0) + t = 1; + else t = abs (t); + uptr->UDA = da; /* save addr */ + sim_activate (uptr + DP_SEEK, t * ctx->dp_stime); + dp_unit[un + DP_SEEK].UCMD = /* sched seek */ + (chan_tst_cmf (dva, CMF_CCH)? DSC_SEEK: uptr->UCMD & 0x80); + break; /* sched end */ + + case DPS_SENSE: /* sense */ + for (i = 0; i < DPS_NBY_3281; i++) + c[i] = 0; + c[0] = (uptr->UDA >> 24) & 0xFF; + c[1] = (uptr->UDA >> 16) & 0xFF; + c[2] = (uptr->UDA >> 8) & 0xFF; + c[3] = uptr->UDA & 0xFF; + c[4] = GET_PSC (ctx->dp_time, dp_tab[dtype].sc) | /* curr sector */ + ((sim_is_active (uptr) && ((uptr->UCMD & 0x7F) == DPS_SEEK))? 0x80: 0); + if (ctx->dp_ctype == DP_C3281) { + c[5] = c[7] = un; + c[10] = (ctx->dp_ski >> 8) & 0xFF; + c[11] = ctx->dp_ski & 0xFF; + } + dp_set_sense (uptr, &c[0]); + for (i = 0, st = 0; (i < DPS_NBY) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + } + if ((i != DPS_NBY) || (st != CHS_ZBC)) { /* length error? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */ + return SCPE_OK; + } + break; + + case DPS_WRITE: /* write */ + if (uptr->flags & UNIT_RO) { /* write locked? */ + ctx->dp_flags |= DPF_WPE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < DP_WDSC; i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemW (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + else wd = 0; + dp_buf[i] = wd; /* store in buffer */ + } + if (r = dp_write (uptr, da)) /* write buf, err? */ + return r; + if (dp_end_sec (uptr, DP_WDSC, DP_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Write header "writes" eight bytes per sector and throws them in the bit bucket */ + + case DPS_WHDR: + if (uptr->flags & UNIT_RO) { /* write locked? */ + ctx->dp_flags |= DPF_WPE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (DPA_GETSC (uptr->UDA) != 0) { + ctx->dp_flags |= DPF_SNZ; + chan_uen (dva); + return SCPE_OK; + } + for (i = 0, st = 0; (i < 8) && (st != CHS_ZBC); i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemB (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + } + if (dp_end_sec (uptr, i, 8, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + +/* Write check must be done by bytes to get precise miscompare */ + + case DPS_CHECK: /* write check */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (r = dp_read (uptr, da)) /* read buf, error? */ + return r; + for (i = 0, st = 0; (i < (DP_WDSC * 4)) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dva, &wd); /* read byte */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + wd1 = (dp_buf[i >> 2] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + dp_inc_ad (uptr); /* da increments */ + ctx->dp_flags |= DPF_WCHK; /* set status */ + chan_uen (dva); /* force uend */ + return SCPE_OK; + } + } + if (dp_end_sec (uptr, i, DP_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + + case DPS_READ: /* read */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (r = dp_read (uptr, da)) /* read buf, error? */ + return r; + for (i = 0, st = 0; (i < DP_WDSC) && (st != CHS_ZBC); i++) { + st = chan_WrMemW (dva, dp_buf[i]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + if (dp_end_sec (uptr, i, DP_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Read header reads 8 bytes per sector */ + + case DPS_RHDR: /* read header */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + c[0] = c[5] = c[6] = c[7] = 0; + wd = DPA_GETCY (uptr->UDA); + c[1] = (wd >> 8) & 0xFF; + c[2] = wd & 0xFF; + c[3] = DPA_GETHD (uptr->UDA); + c[4] = DPA_GETSC (uptr->UDA); + for (i = 0, st = 0; (i < 8) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dva, c[i]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + if (dp_end_sec (uptr, i, 8, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Test mode is not really implemented */ + + case DPS_TEST: /* test mode */ + if (!dp_test_mode (cidx)) /* enter test mode */ + return SCPE_OK; + break; + + case DPS_RSRV: /* reserve */ + case DPS_RLS: /* release */ + case DPS_RLSA: /* release */ + break; /* nop */ + } + +uptr->UCMD = DPS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Seek completion service */ + +t_stat dps_svc (UNIT *uptr) +{ +uint32 cidx = uptr->UCTX; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +uint32 un = uptr - dp_unit - DP_SEEK; +uint32 dtype = GET_DTYPE (dp_unit[un].flags); + +if (uptr->UCMD != DSC_SEEK) { /* int? */ + if (chan_chk_chi (dp_dib[cidx].dva) >= 0) { /* ctl int pending? */ + sim_activate (uptr, ctx->dp_time * dp_tab[dtype].sc); + uptr->UCMD = DSC_SEEKW; + } + else dp_set_ski (cidx, un); + } +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end cylinder - reschedule, return TRUE + case 2 - more to transfer, end cylinder - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; +uint32 dtype = GET_DTYPE (uptr->flags); +DP_CTX *ctx = &dp_ctx[cidx]; + +if (st != CHS_ZBC) { /* end record? */ + if (dp_inc_ad (uptr)) { /* inc addr, cross cyl? */ + ctx->dp_flags |= (DPF_IVA | DPF_EOC); + chan_uen (dva); /* uend */ + } + else sim_activate (uptr, ctx->dp_time * 16); /* no, next sector */ + return TRUE; + } +dp_inc_ad (uptr); /* just incr addr */ +if (lnt != exp) { /* length error at end? */ + if (exp == 8) /* hdr op? */ + ctx->dp_flags |= DPF_PGE; /* set PGE */ + if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */ + return TRUE; + } +return FALSE; /* cmd done */ +} + +/* DP status routine */ + +uint32 dp_tio_status (uint32 cidx, uint32 un) +{ +uint32 i; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; + +for (i = 0; i < DP_NUMDR; i++) { + if (sim_is_active (&dp_unit[i])) + return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC)); + } +for (i = 0; i < DP_NUMDR; i++) { + if (sim_is_active (&dp_unit[i + DP_SEEK]) && + (dp_unit[i + DP_SEEK].UCMD != DSC_SEEKW)) + return (DVS_AUTO|DVS_DBUSY|(CC2 << DVT_V_CC)); + } +return DVS_AUTO; +} + +uint32 dp_tdv_status (uint32 cidx, uint32 un) +{ +uint32 st; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +t_bool on_cyl; + +st = 0; +on_cyl = !sim_is_active (&dp_unit[un + DP_SEEK]) || + (dp_unit[un + DP_SEEK].UCMD == DSC_SEEKW); +if (dp_ctx[cidx].dp_ctype == DP_C7270) + st = ((dp_ctx[cidx].dp_flags & DPF_IVA)? 0x20: 0) | + (on_cyl? 0x04: 0); +else st = ((dp_ctx[cidx].dp_flags & DPF_PGE)? 0x20: 0) | + ((dp_ctx[cidx].dp_flags & DPF_WPE)? 0x08: 0); +return st; +} + +uint32 dp_aio_status (uint32 cidx, uint32 un) +{ +uint32 st; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +t_bool on_cyl; + +st = 0; +on_cyl = !sim_is_active (&dp_unit[un + DP_SEEK]) || + (dp_unit[un + DP_SEEK].UCMD == DSC_SEEKW); +if ((dp_ctx[cidx].dp_ctype == DP_C7270) && on_cyl) + st |= 0x04; +if (chan_chk_chi (dp_dib[cidx].dva) < 0) + st |= 0x08; +return st; +} + +/* Set sense status */ + +void dp_set_sense (UNIT *uptr, uint32 *c) +{ +uint32 cidx = uptr->UCTX; +UNIT *sptr = uptr + DP_SEEK; +DP_CTX *ctx = &dp_ctx[cidx]; +uint8 data; +DP_SNSTAB *tptr; + +if (sim_is_active (sptr) && + (sptr->UCMD != DSC_SEEKW)) + ctx->dp_flags |= DPF_AIM; +else ctx->dp_flags &= ~DPF_AIM; +if (ctx->dp_ctype == DP_C7270) + tptr = dp_sense_7270; +else tptr = dp_sense_3281; +while (tptr->byte != 0) { + if (ctx->dp_flags & tptr->mask) { + data = (uint8) ((ctx->dp_flags & tptr->mask) >> tptr->fpos); + c[tptr->byte] |= (data << tptr->tpos); + } + } +return; +} + +/* Validate disk address */ + +t_bool dp_inv_ad (UNIT *uptr, uint32 *da) +{ +uint32 dtype = GET_DTYPE (uptr->flags); +uint32 cy = DPA_GETCY (uptr->UDA); +uint32 hd = DPA_GETHD (uptr->UDA); +uint32 sc = DPA_GETSC (uptr->UDA); + +if ((cy >= dp_tab[dtype].cy) || + (hd >= dp_tab[dtype].hd) || + (sc >= dp_tab[dtype].sc)) + return TRUE; +if (da) /* return word addr */ + *da = ((((cy * dp_tab[dtype].hd) + hd) * dp_tab[dtype].sc) + sc) * DP_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool dp_inc_ad (UNIT *uptr) +{ +uint32 dtype = GET_DTYPE (uptr->flags); +uint32 cy = DPA_GETCY (uptr->UDA); +uint32 hd = DPA_GETHD (uptr->UDA); +uint32 sc = DPA_GETSC (uptr->UDA); + +sc = sc + 1; /* sector++ */ +if (sc >= dp_tab[dtype].sc) { /* overflow? */ + sc = 0; /* wrap sector */ + hd = hd + 1; /* head++ */ + if (hd >= dp_tab[dtype].hd) /* overflow? */ + hd = 0; /* wrap heads */ + } +uptr->UDA = (cy << DPA_V_CY) | (hd << DPA_V_HD) | (sc << DPA_V_SC); +if ((hd == 0) && (sc == 0)) + return TRUE; +return FALSE; +} + +/* Read and write sector */ + +t_stat dp_read (UNIT *uptr, uint32 da) +{ +int32 err, awc; + +err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET); +if (err == 0) { + awc = fxread (dp_buf, sizeof (uint32), DP_WDSC, uptr->fileref); + err = ferror (uptr->fileref); + for (; awc < DP_WDSC; awc++) /* fill buf */ + dp_buf[awc] = 0; + } +if (err != 0) + return dp_ioerr (uptr); +return SCPE_OK; +} + +t_stat dp_write (UNIT *uptr, uint32 da) +{ +int32 err; + +err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET); +if (err == 0) { + fxwrite (dp_buf, sizeof (uint32), DP_WDSC, uptr->fileref); + err = ferror (uptr->fileref); + } +if (err != 0) + return dp_ioerr (uptr); +return SCPE_OK; +} + +t_stat dp_ioerr (UNIT *uptr) +{ +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; + +perror ("DP I/O error"); +clearerr (uptr->fileref); +dp_ctx[cidx].dp_flags |= DPF_DPE; /* set DPE flag */ +chan_set_chf (dva, CHF_XMDE); +chan_uen (dva); /* force uend */ +return SCPE_IOERR; +} + +/* Test mode */ + +t_bool dp_test_mode (uint32 cidx) +{ +DP_CTX *ctx = &dp_ctx[cidx]; +uint32 dva = dp_dib[cidx].dva; +uint32 i, st, wd; + +ctx->dp_test = 0; +for (i = 0, st = 0; i < DPT_NBY; i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemB (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { + dp_chan_err (dva, st); + return FALSE; + } + } + else wd = 0; + ctx->dp_test |= (wd & 0xFF) << (i * 8); + } +return TRUE; +} + +/* Channel error */ + +t_stat dp_chan_err (uint32 dva, uint32 st) +{ +chan_uen (dva); /* uend */ +if (st < CHS_ERR) return st; +return SCPE_OK; +} + +/* Clear controller/device interrupt */ + +int32 dp_clr_int (uint32 cidx) +{ +int32 iu; +DP_CTX *ctx = &dp_ctx[cidx]; + +if ((iu = chan_clr_chi (dp_dib[cidx].dva)) >= 0) { /* chan int? clear */ + if (ctx->dp_ski != 0) /* more int? */ + chan_set_dvi (dp_dib[cidx].dva); /* set INP */ + return iu; + } +for (iu = 0; iu < (int32) DP_NUMDR; iu++) { /* seek int? */ + if (ctx->dp_ski & (1u << iu)) { + dp_clr_ski (cidx, iu); /* clear */ + return iu; + } + } +return 0; +} + +/* Set seek interrupt */ + +void dp_set_ski (uint32 cidx, uint32 un) +{ +dp_ctx[cidx].dp_ski |= (1u << un); +chan_set_dvi (dp_dib[cidx].dva); /* set INP */ +return; +} + +/* Clear seek interrupt */ + +void dp_clr_ski (uint32 cidx, uint32 un) +{ +dp_ctx[cidx].dp_ski &= ~(1u << un); /* clear */ +if (dp_ctx[cidx].dp_ski != 0) /* more int? */ + chan_set_dvi (dp_dib[cidx].dva); /* set INP */ +else if (chan_chk_chi (dp_dib[cidx].dva) < 0) /* any int? */ + chan_clr_chi (dp_dib[cidx].dva); /* clr INP */ +return; +} + +/* Reset routine */ + +t_stat dp_reset (DEVICE *dptr) +{ +uint32 i; +uint32 cidx = dptr - dp_dev; +UNIT *dp_unit; +DP_CTX *ctx; + +if (cidx >= DP_NUMCTL) + return SCPE_IERR; +dp_unit = dptr->units; +ctx = &dp_ctx[cidx]; +for (i = 0; i < DP_NUMDR; i++) { + sim_cancel (&dp_unit[i]); /* stop dev thread */ + dp_unit[i].UDA = 0; + dp_unit[i].UCMD = 0; + dp_unit[i].UCTX = cidx; + } +ctx->dp_flags = 0; +ctx->dp_ski = 0; +ctx->dp_test = 0; +chan_reset_dev (dp_dib[cidx].dva); /* clr int, active */ +return SCPE_OK; +} + +/* Device attach */ + +t_stat dp_attach (UNIT *uptr, char *cptr) +{ +uint32 i, p; +t_stat r; + +uptr->capac = dp_tab[GET_DTYPE (uptr->flags)].capac; +r = attach_unit (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) /* error? */ + return r; +if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ + return SCPE_OK; +p = sim_fsize (uptr->fileref); +for (i = 0; dp_tab[i].sc != 0; i++) { + if (p <= (dp_tab[i].capac * (uint32) sizeof (int32))) { + uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); + uptr->capac = dp_tab[i].capac; + return SCPE_OK; + } + } +return SCPE_OK; +} + +/* Set drive type command validation routine */ + +t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 dtype = GET_DTYPE (val); +uint32 cidx = uptr->UCTX; + +if (cidx >= DP_NUMCTL) /* valid ctrl idx? */ + return SCPE_IERR; +if (uptr->flags & UNIT_ATT) /* unattached? */ + return SCPE_ALATT; +if (dp_tab[dtype].ctype != dp_ctx[cidx].dp_ctype) /* valid for curr ctrl? */ + return SCPE_NOFNC; +uptr->capac = dp_tab[dtype].capac; +return SCPE_OK; +} + +/* Set controller type command validation routine */ + +t_stat dp_set_ctl (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 i, cidx = uptr->UCTX; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; + +if ((cidx >= DP_NUMCTL) || (val >= DP_NUMCTL)) /* valid ctrl idx? */ + return SCPE_IERR; +if (val == dp_ctx[cidx].dp_ctype) + return SCPE_OK; +for (i = 0; i < DP_NUMDR; i++) { /* all units detached? */ + if (dp_unit[i].flags & UNIT_ATT) + return SCPE_ALATT; + } +for (i = 0; i < DP_NUMDR; i++) { + if (val == DP_C7270) { /* changing to 7270? */ + dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) | + (DP_7271 << UNIT_V_DTYPE); + dp_unit[i].capac = DPSZ_7271; + if (i >= DP_NUMDR_7270) + dp_unit[i].flags = (dp_unit[i].flags | UNIT_DIS) & ~UNIT_DISABLE; + } + else { + dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) | + (DP_7275 << UNIT_V_DTYPE); + dp_unit[i].capac = DPSZ_7275; + if (i >= DP_NUMDR_7270) + dp_unit[i].flags = dp_unit[i].flags | UNIT_DISABLE; + } + } +return SCPE_OK; +} + +t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +uint32 cidx = uptr->UCTX; + +if (cidx >= DP_NUMCTL) /* valid ctrl idx? */ + return SCPE_IERR; +if (dp_ctx[cidx].dp_ctype == DP_C7270) + fprintf (st, "7270 controller"); +else fprintf (st, "3281 controller"); +return SCPE_OK; +} diff --git a/sigma/sigma_fp.c b/sigma/sigma_fp.c new file mode 100644 index 00000000..a82f6516 --- /dev/null +++ b/sigma/sigma_fp.c @@ -0,0 +1,421 @@ +/* sigma_fp.c: XDS Sigma floating point simulator + + Copyright (c) 2007-2008, Robert 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 "sigma_defs.h" + +#define UFP_V_GUARD 4 +#define UFP_NORM (FP_NORM << UFP_V_GUARD) +#define UFP_CARRY (UFP_NORM << 4) +#define UFP_FRHI (UFP_CARRY|UFP_NORM|FP_M_FRHI) +#define UFP_FRLO 0xFFFFFFFF + +/* Double precision fraction add/subtract/compare */ +/* Note: UFP_ADD (s, r, r) will not work!!! */ + +#define UFP_ADD(s1,s2,d) do { \ + d.l = (s1.l + s2.l) & UFP_FRLO; \ + d.h = (s1.h + s2.h + (d.l < s2.l)) & UFP_FRHI; \ + } while (0) + +#define UFP_SUB(s1,s2,d) do { \ + d.h = (s1.h - s2.h - (s1.l < s2.l)) & UFP_FRHI; \ + d.l = (s1.l - s2.l) & UFP_FRLO; \ + } while (0) + +#define UFP_GE(s1,s2) ((s1.h > s2.h) || \ + ((s1.h == s2.h) && (s1.l >= s2.l))) + +/* Variable and constant shifts; for constants, 0 < k < 32 */ + +#define UFP_RSH_V(v,s) do { \ + if ((s) < 32) { \ + v.l = ((v.l >> (s)) | \ + ( v.h << (32 - (s)))) & UFP_FRLO; \ + v.h = v.h >> (s); \ + } \ + else if ((s) < 64) { \ + v.l = v.h >> ((s) - 32); \ + v.h = 0; \ + } \ + else v.l = v.h = 0; \ + } while (0) + +#define UFP_RSH_K(v,s) do { \ + v.l = ((v.l >> (s)) | \ + (v.h << (32 - (s)))) & UFP_FRLO; \ + v.h = v.h >> (s); \ + } while (0) + +#define UFP_LSH_K(v,s) do { \ + v.h = ((v.h << (s)) | \ + (v.l >> (32 - (s)))) & UFP_FRHI; \ + v.l = (v.l << (s)) & UFP_FRLO; \ + } while (0) + +#define UFP_RSH_KP(v,s) do { \ + v->l = ((v->l >> (s)) | \ + (v->h << (32 - (s)))) & UFP_FRLO; \ + v->h = v->h >> (s); \ + } while (0) + +#define UFP_LSH_KP(v,s) do { \ + v->h = ((v->h << (s)) | \ + (v->l >> (32 - (s)))) & UFP_FRHI; \ + v->l = (v->l << (s)) & UFP_FRLO; \ + } while (0) + +typedef struct { + uint32 sign; + int32 exp; + uint32 h; + uint32 l; + } ufp_t; + +extern uint32 *R; +extern uint32 PSW1; +extern uint32 CC; + +void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst); +t_bool fp_clnzro (ufp_t *src, t_bool abnorm); +uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap); +uint32 fp_norm (ufp_t *src); + +uint32 fp (uint32 op, uint32 rn, uint32 bva) +{ +uint32 rh, rl, mh, ml, i, ediff, nsh; +t_bool s1nz, s2nz; +t_bool dbl = ((op & 0x20) == 0); +ufp_t fop1, fop2, t; +ufp_t res = { 0, 0, 0, 0 }; +uint32 tr; + +if (dbl) { /* double prec? */ + rh = R[rn]; /* get reg operands */ + rl = R[rn|1]; + if ((tr = ReadD (bva, &mh, &ml, VR)) != 0) /* get mem word */ + return tr; + } +else { /* single precision */ + rh = R[rn]; /* pad to double */ + rl = 0; + if ((tr = ReadW (bva, &mh, VR)) != 0) + return tr; + ml = 0; + } +fp_unpack (rh, rl, &fop1); /* unpack, test */ +fp_unpack (mh, ml, &fop2); +CC = 0; + +switch (op) { /* case on opcode */ + + case OP_FSS: /* subtract */ + case OP_FSL: + fop2.sign = fop2.sign ^ 1; /* invert mem sign */ + /* fall through */ + case OP_FAS: /* add */ + case OP_FAL: + s1nz = fp_clnzro (&fop1, TRUE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, TRUE); + if (!s1nz) /* op1 = 0? res = op2 */ + res = fop2; + else if (!s2nz) /* op2 = 0? res = op1 */ + res = fop1; + else { /* both non-zero */ + if (fop1.exp < fop2.exp) { /* exp1 < exp2? */ + t = fop2; /* swap operands */ + fop2 = fop1; + fop1 = t; + } + ediff = fop1.exp - fop2.exp; /* exp difference */ + res.sign = fop1.sign; /* result sign, exp */ + res.exp = fop1.exp; + if (ediff) { /* any difference? */ + UFP_RSH_V (fop2, ediff * 4); /* shift frac */ + if (dbl) { /* double? */ + if ((PSW1 & PSW1_FR) == 0) /* rounding off? */ + fop2.l &= ~0xF; /* no guard */ + } + else fop2.l = 0; /* single? clr lo */ + } + if (fop1.sign ^ fop2.sign) { /* eff subtract */ + if (UFP_GE (fop1, fop2)) { /* fop1 >= fop2? */ + UFP_SUB (fop1, fop2, res); /* sub fractions */ + } + else { /* fop2 > fop1 */ + UFP_SUB (fop2, fop1, res); /* rev subtract */ + res.sign = fop2.sign; /* change signs */ + } + } /* end subtract */ + else { /* eff add */ + UFP_ADD (fop1, fop2, res); /* add fractions */ + if (res.h & UFP_CARRY) { /* carry out? */ + UFP_RSH_K (res, 4); /* renormalize */ + res.exp = res.exp + 1; /* incr exp */ + } + } /* end add */ + } /* end nz operands */ + if (!dbl) /* single? clr lo */ + res.l = 0; + if ((PSW1 & PSW1_FN) == 0) { /* postnormalize? */ + if ((res.h | res.l) == 0) { /* result zero? */ + CC = CC1; /* set signif flag */ + if (PSW1 & PSW1_FS) /* trap enabled? */ + return TR_FLT; + return fp_pack (&res, rn, dbl, FALSE); /* pack up */ + } + nsh = fp_norm (&res); /* normalize */ + if ((res.exp < 0) && /* underflow? */ + !(PSW1 & PSW1_FZ) && /* !FN */ + (PSW1 & PSW1_FS) && /* FS */ + (nsh > 2)) { /* shifts > 2? */ + CC = CC1 | (res.sign? CC4: CC3); /* signif CC's */ + return TR_FLT; /* trap */ + } /* end if underflow */ + else if (nsh > 2) { /* shifts > 2? */ + CC |= CC1 | (res.sign? CC4: CC3); /* set CC1 */ + if (PSW1 & PSW1_FS) /* trap enabled? */ + return TR_FLT; + } + } /* end if postnorm */ + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + + case OP_FMS: + case OP_FML: /* floating multiply */ + s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, FALSE); + if (s1nz && s2nz) { /* both non-zero? */ + fp_norm (&fop1); /* prenormalize */ + fp_norm (&fop2); + UFP_RSH_K (fop2, 4); /* undo guard */ + res.sign = fop1.sign ^ fop2.sign; /* result sign */ + res.exp = fop1.exp + fop2.exp - FP_BIAS; /* result exp */ + if (!dbl) { /* 24b x 24b? */ + for (i = 0; i < 24; i++) { /* 24 iterations */ + if (fop2.h & 1) + res.h = res.h + fop1.h; /* add hi only */ + UFP_RSH_K (res, 1); /* shift dp res */ + fop2.h = fop2.h >> 1; + } + res.l = 0; /* single prec */ + } + else { /* some low 0's */ + for (i = 0; i < 56; i++) { /* 56 iterations */ + if (fop2.l & 1) { + UFP_ADD (res, fop1, res); + } + UFP_RSH_K (res, 1); + UFP_RSH_K (fop2, 1); + } + } + fp_norm (&res); /* normalize result */ + } + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + + case OP_FDS: + case OP_FDL: /* floating divide */ + s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, FALSE); + if (!s2nz) { /* divide by zero? */ + CC = CC2; /* set CC2 */ + return TR_FLT; /* trap */ + } + if (s1nz) { /* divd non-zero? */ + fp_norm (&fop1); /* prenormalize */ + fp_norm (&fop2); + res.sign = fop1.sign ^ fop2.sign; /* result sign */ + res.exp = fop1.exp - fop2.exp + FP_BIAS; /* result exp */ + if (!UFP_GE (fop1, fop2)) { + UFP_LSH_K (fop1, 4); /* ensure success */ + } + else res.exp = res.exp + 1; /* incr exponent */ + for (i = 0; i < (uint32)(dbl? 15: 7); i++) {/* 7/15 hex digits */ + UFP_LSH_K (res, 4); /* shift quotient */ + while (UFP_GE (fop1, fop2)) { /* while sub works */ + UFP_SUB (fop1, fop2, fop1); /* decrement */ + res.l = res.l + 1; /* add quo bit */ + } + UFP_LSH_K (fop1, 4); /* shift divd */ + } /* end hex loop */ + if (!dbl) { /* single? */ + res.h = res.l; /* move quotient */ + res.l = 0; + } + fp_norm (&res); /* normalize result */ + } + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + } /* end case */ + +return SCPE_IERR; +} + +void ShiftF (uint32 rn, uint32 stype, uint32 sc) +{ +uint32 opnd, opnd1; +ufp_t src; + +opnd = R[rn]; /* get operands */ +opnd1 = stype? R[rn|1]: 0; /* zextend single */ +fp_unpack (opnd, opnd1, &src); /* unpack */ + +CC = 0; +if (sc & SCSIGN) { /* right? */ + sc = SHF_M_SC + 1 - sc; + while (sc > 0) { /* while count */ + UFP_RSH_K (src, 4); /* shift right hex */ + if (stype) /* zero guard */ + src.l &= ~0xF; + else src.h &= ~0xF; + src.exp++; /* incr exp */ + sc--; + if (src.exp > FP_M_EXP) { /* overflow? */ + CC |= CC2; /* set CC2, stop */ + break; + } + } /* end while */ + if ((src.h | src.l) == 0) { /* result 0? */ + if (stype) /* result is true 0 */ + R[rn|1] = 0; + R[rn] = 0; + CC = 0; + return; + } + } +else { /* left */ + if ((src.h | src.l) == 0) { /* fraction 0? */ + if (stype) /* result is true 0 */ + R[rn|1] = 0; + R[rn] = 0; + CC = CC1; + return; + } + while ((sc > 0) && ((src.h & UFP_NORM) == 0)) { /* while count & !norm */ + UFP_LSH_K (src, 4); /* hex shift left */ + src.exp--; /* decr exp */ + sc--; + if (src.exp < 0) { /* underflow? */ + CC |= CC2; /* set CC2, stop */ + break; + } + } /* end while */ + if (src.h & UFP_NORM) /* normalized? */ + CC |= CC1; /* set CC1 */ + } +fp_pack (&src, rn, stype, FALSE); /* pack result */ +return; +} + +void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst) +{ +dst->sign = FP_GETSIGN (hi); /* get sign */ +if (dst->sign) /* negative? */ + NEG_D (hi, lo); /* 2's compl */ +dst->h = FP_GETFRHI (hi); /* get fraction */ +dst->l = FP_GETFRLO (lo); +dst->exp = FP_GETEXP (hi); /* get exp */ +UFP_LSH_KP (dst, 4); /* guard result */ +return; +} + +/* Test for and clean a floating point zero + abnorm defines whether to allow "abnormal" zeros */ + +t_bool fp_clnzro (ufp_t *src, t_bool abnorm) +{ +if (((src->h | src->l) == 0) && /* frac zero and */ + (!abnorm || (src->exp == 0))) { /* exp zero or !ab */ + src->sign = 0; /* true zero */ + src->exp = 0; + return FALSE; + } +return TRUE; /* non-zero */ +} + +uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap) +{ +static ufp_t fp_zero = { 0, 0, 0, 0}; +uint32 opnd, opnd1; + +if (src->h || (dbl && src->l)) { /* result != 0? */ + CC |= (src->sign? CC4: CC3); /* set CC's */ + if (rndtrap) { /* round, trap? */ + if (PSW1 & PSW1_FR) { /* round? */ + if (dbl) { /* double prec? */ + src->l = (src->l + 0x8) & UFP_FRLO; + src->h = src->h + (src->l < 0x8); + } + else src->h = src->h + 0x8; /* no, single */ + if (src->h & UFP_CARRY) { /* carry out? */ + UFP_RSH_KP (src, 4); /* renormalize */ + src->exp = src->exp + 1; + } + } /* end if round */ + if (src->exp > FP_M_EXP) { /* overflow? */ + CC |= CC2; /* flag */ + return TR_FLT; + } + else if (src->exp < 0) { /* underflow? */ + if (PSW1 & PSW1_FZ) { /* trap enabled? */ + CC |= CC1 | CC2; /* flag */ + return TR_FLT; + } + *src = fp_zero; /* result 0 */ + CC = CC1|CC2; /* special CC's */ + } + } /* end rnd trap */ + UFP_RSH_KP (src, 4); /* remove guard */ + if (!dbl) /* single? lose lower */ + src->l = 0; + if ((src->h | src->l) == 0) /* result now 0? */ + src->exp = src->sign = 0; + } +else *src = fp_zero; +opnd = ((src->exp & FP_M_EXP) << FP_V_EXP) | /* repack */ + ((src->h & FP_M_FRHI) << FP_V_FRHI); +opnd1 = src->l & FP_M_FRLO; +if (src->sign) /* negative? */ + NEG_D (opnd, opnd1); +R[rn] = opnd; /* store result */ +if (dbl && ((rn & 1) == 0)) + R[rn|1] = opnd1; +return 0; +} + +uint32 fp_norm (ufp_t *src) +{ +uint32 nsh; + +nsh = 0; +src->h &= UFP_FRHI; +if (src->h || src->l) { /* if non-zero */ + while ((src->h & UFP_NORM) == 0) { /* until normalized */ + UFP_LSH_KP (src, 4); /* hex shift left */ + src->exp--; /* decr exponent */ + nsh++; /* count shifts */ + } + } +return nsh; +} + diff --git a/sigma/sigma_io.c b/sigma/sigma_io.c new file mode 100644 index 00000000..f1193069 --- /dev/null +++ b/sigma/sigma_io.c @@ -0,0 +1,1497 @@ +/* sigma_io.c: XDS Sigma IO simulator + + Copyright (c) 2007-2008, Robert 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 "sigma_io_defs.h" + +#define VALID_DVA(c,d) \ + (((c) < chan_num) && ((d) < CHAN_N_DEV) && (chan[c].disp[d] != NULL)) + +uint32 int_hiact = NO_INT; /* hi act int */ +uint32 int_hireq = NO_INT; /* hi int req */ +uint32 chan_ctl_time = 5; +uint32 ei_bmax = EIGRP_DFLT; /* ext int grps */ +uint32 s9_snap = 0; +uint32 s9_marg = 0; +uint32 chan_num = CHAN_DFLT; /* num chan */ +uint32 s5x0_ireg[] = { 0 }; +uint16 int_arm[INTG_MAX]; /* int grps: arm */ +uint16 int_enb[INTG_MAX]; /* enable */ +uint16 int_req[INTG_MAX]; /* request */ +uint8 int_lnk[INTG_MAX] = { /* pri chain */ + INTG_OVR, INTG_CTR, INTG_IO, 0 + }; + +/* Interrupt group priority chain templates */ + +#define I_STD 0x80 + +static uint8 igrp_dflt_5x0[] = { + I_STD|INTG_OVR, I_STD|INTG_CTR, I_STD|INTG_IO, INTG_E2, + INTG_E3, INTG_E3+1, INTG_E3+2, 0 + }; + +static uint8 igrp_dflt_S56789[] = { + I_STD|INTG_OVR, I_STD|INTG_CTR, I_STD|INTG_IO, INTG_E2, + INTG_E3, INTG_E3+1, INTG_E3+2, INTG_E3+3, + INTG_E3+4, INTG_E3+5, INTG_E3+6, INTG_E3+7, + INTG_E3+9, INTG_E3+9, INTG_E3+10, INTG_E3+11, + INTG_E3+12, 0 + }; + +chan_t chan[CHAN_N_CHAN]; +uint32 (*dio_disp[DIO_N_MOD])(uint32, uint32, uint32); + +int_grp_t int_tab[INTG_MAX] = { +/* PSW inh #bits vec grp regbit */ + { 0, 6, 0x052, 0x0, 16 }, + { PSW2_CI, 4, 0x058, 0x0, 22 }, + { PSW2_II, 2, 0x05C, 0x0, 26 }, + { PSW2_EI, 16, 0x060, 0x2, 16 }, + { PSW2_EI, 16, 0x070, 0x3, 16 }, + { PSW2_EI, 16, 0x080, 0x4, 16 }, + { PSW2_EI, 16, 0x090, 0x5, 16 }, + { PSW2_EI, 16, 0x0A0, 0x6, 16 }, + { PSW2_EI, 16, 0x0B0, 0x7, 16 }, + { PSW2_EI, 16, 0x0C0, 0x8, 16 }, + { PSW2_EI, 16, 0x0D0, 0x9, 16 }, + { PSW2_EI, 16, 0x0E0, 0xA, 16 }, + { PSW2_EI, 16, 0x0F0, 0xB, 16 }, + { PSW2_EI, 16, 0x100, 0xC, 16 }, + { PSW2_EI, 16, 0x110, 0xD, 16 }, + { PSW2_EI, 16, 0x120, 0xE, 16 }, + { PSW2_EI, 16, 0x130, 0xF, 16 } + }; + +extern uint32 *R; +extern uint32 PSW1, PSW2; +extern uint32 CC, SSW; +extern uint32 stop_op; +extern uint32 cpu_model; +extern uint32 cons_alarm, cons_pcf; +extern UNIT cpu_unit; +extern cpu_var_t cpu_tab[]; +extern DEVICE *sim_devices[]; +extern FILE *sim_log; + +void io_eval_ioint (void); +t_bool io_init_inst (uint32 ad, uint32 rn, uint32 ch, uint32 dev, uint32 r0); +uint32 io_set_status (uint32 rn, uint32 ch, uint32 dev, uint32 dvst, t_bool tdv); +uint32 io_rwd_m0 (uint32 op, uint32 rn, uint32 ad); +uint32 io_rwd_m1 (uint32 op, uint32 rn, uint32 ad); +t_stat io_set_eiblks (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat io_show_eiblks (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat int_reset (DEVICE *dptr); +t_stat chan_reset (DEVICE *dptr); +uint32 chan_new_cmd (uint32 ch, uint32 dev, uint32 clc); +void io_set_eimax (uint32 max); +uint32 chan_proc_prolog (uint32 dva, uint32 *ch, uint32 *dev); +uint32 chan_proc_epilog (uint32 dva, int32 cnt); + +extern uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2); + +/* IO data structures + + io_dev IO device descriptor + io_unit IO unit + io_reg IO register list + io_mod IO modifier list +*/ + +dib_t int_dib = { 0, NULL, 1, io_rwd_m1 }; + +UNIT int_unit = { UDATA (NULL, 0, 0) }; + +REG int_reg[] = { + { HRDATA (IHIACT, int_hiact, 9) }, + { HRDATA (IHIREQ, int_hireq, 9) }, + { BRDATA (IREQ, int_req, 16, 16, INTG_MAX) }, + { BRDATA (IENB, int_enb, 16, 16, INTG_MAX) }, + { BRDATA (IARM, int_arm, 16, 16, INTG_MAX) }, + { BRDATA (ILNK, int_lnk, 10, 8, INTG_MAX), REG_HRO }, + { DRDATA (EIBLKS, ei_bmax, 4), REG_HRO }, + { HRDATA (S9_SNAP, s9_snap, 32) }, + { HRDATA (S9_MARG, s9_marg, 32) }, + { BRDATA (S5X0_IREG, s5x0_ireg, 16, 32, 32) }, + { NULL } + }; + +MTAB int_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "EIBLKS", "EIBLKS", + &io_set_eiblks, &io_show_eiblks }, + { 0 } + }; + +DEVICE int_dev = { + "INT", &int_unit, int_reg, int_mod, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &int_reset, + NULL, NULL, NULL, + &int_dib, 0 + }; + +/* Channel data structures */ + +UNIT chan_unit[] = { + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) } + }; + +REG chana_reg[] = { + { BRDATA (CLC, chan[0].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[0].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[0].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[0].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[0].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[0].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[0].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[0].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanb_reg[] = { + { BRDATA (CLC, chan[1].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[1].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[1].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[1].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[1].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[1].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[1].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[1].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanc_reg[] = { + { BRDATA (CLC, chan[2].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[2].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[2].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[2].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[2].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[2].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[2].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[2].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chand_reg[] = { + { BRDATA (CLC, chan[3].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[3].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[3].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[3].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[3].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[3].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[3].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[3].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chane_reg[] = { + { BRDATA (CLC, chan[4].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[4].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[4].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[4].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[4].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[4].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[4].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[4].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanf_reg[] = { + { BRDATA (CLC, chan[5].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[5].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[5].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[5].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[5].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[5].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[5].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[5].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chang_reg[] = { + { BRDATA (CLC, chan[6].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[6].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[6].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[6].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[6].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[6].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[6].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[6].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanh_reg[] = { + { BRDATA (CLC, chan[7].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[7].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[7].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[7].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[7].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[7].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[7].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[7].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +DEVICE chan_dev[] = { + { + "CHANA", &chan_unit[0], chana_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_MIOP, 0 + }, + { + "CHANB", &chan_unit[1], chanb_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_MIOP, 0 + }, + { + "CHANC", &chan_unit[2], chanc_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP, 0 + }, + { + "CHAND", &chan_unit[3], chand_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP, 0 + }, + { + "CHANE", &chan_unit[4], chane_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANF", &chan_unit[5], chanf_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANG", &chan_unit[6], chang_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANH", &chan_unit[7], chanh_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + } + }; + + +/* Read direct */ + +uint32 io_rwd (uint32 op, uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 mode = DIO_GETMOD (ad); /* mode */ + +if (dio_disp[mode] != NULL) /* if defined */ + return dio_disp[mode] (op, rn, ad); /* dispatch */ +return (stop_op)? STOP_ILLEG: 0; /* ill inst */ +} + +/* Start IO */ + +uint32 io_sio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, R[0])) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +if (chan[ch].chf[dev] & CHF_INP) { /* int pending? */ + chan[ch].disp[dev] (OP_TIO, ad, &dvst); /* get status */ + CC |= (CC2 | io_set_status (rn, ch, dev, dvst, 0)); /* set status */ + return 0; + } +st = chan[ch].disp[dev] (OP_SIO, ad, &dvst); /* start I/O */ +CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ +if (CC & cpu_tab[cpu_model].iocc) /* error? */ + return 0; +chan[ch].chf[dev] = 0; /* clear flags */ +chan[ch].chi[dev] = 0; /* clear intrs */ +chan[ch].chsf[dev] |= CHSF_ACT; /* set chan active */ +chan_new_cmd (ch, dev, R[0]); /* new command */ +return st; +} + +/* Test IO */ + +uint32 io_tio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +st = chan[ch].disp[dev] (OP_TIO, ad, &dvst); /* test status */ +CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ +return st; +} + +/* Test device status */ + +uint32 io_tdv (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +st = chan[ch].disp[dev] (OP_TDV, ad, &dvst); /* test status */ +CC |= io_set_status (rn, ch, dev, dvst, 1); /* set status */ +return st; +} + +/* Halt IO */ + +uint32 io_hio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, subop, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; +ad = bva >> 2; +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +subop = (ad >> 13) & 0x7; +if (subop) { /* extended fnc? */ + if (!QCPU_S89_5X0 || (subop > 3)) /* S9, 5X0 only */ + return (stop_op? STOP_ILLEG: 0); + if (ch >= chan_num) { /* valid channel? */ + CC |= CC1|CC2; + return 0; + } + switch (subop) { + + case 1: /* reset channel */ + chan_reset (&chan_dev[ch]); + break; + + case 2: case 3: /* poll processor */ + if (rn) /* NI */ + R[rn] = 0; + break; + } + } +else { /* normal HIO */ + if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } + st = chan[ch].disp[dev] (OP_HIO, ad, &dvst); /* halt IO */ + CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ + } +return st; +} + +/* Acknowledge interrupt (ignores device address) */ + +uint32 io_aio (uint32 rn, uint32 bva) +{ +uint32 i, j, dva, dvst; +uint32 st; + +if (DVA_GETCHAN (bva >> 2) != 0) /* non std I/O addr? */ + return (stop_op? STOP_ILLEG: 0); +CC = CC & ~cpu_tab[cpu_model].iocc; /* clear CC's */ +for (i = 0; i < chan_num; i++) { /* loop thru chan */ + for (j = 0; j < CHAN_N_DEV; j++) { /* loop thru dev */ + if (chan[i].chf[j] & CHF_INP) { /* intr pending? */ + if (chan[i].disp[j] == NULL) { /* false interrupt? */ + chan[i].chf[j] &= ~CHF_INP; /* clear intr */ + continue; + } + dva = (i << DVA_V_CHAN) | /* chan number */ + ((chan[i].chsf[j] & CHSF_MU)? /* device number */ + ((j << DVA_V_DEVMU) | DVA_MU): + (j << DVA_V_DEVSU)); + st = chan[i].disp[j] (OP_AIO, dva, &dvst); /* get AIO status */ + dva |= DVT_GETUN (dvst); /* finish dev addr */ + if (rn) /* want status? */ + R[rn] = (DVT_GETDVS (dvst) << 24) | /* device status */ + ((uint32) ((chan[i].chf[j] & (CHF_LNTE|CHF_XMDE)) | + CHI_GETINT (chan[i].chi[j])) << 16) | dva; + if (chan[i].chi[j] & CHI_UEN) /* unusual end? */ + CC |= CC2; /* set CC2 */ + return st; + } + } /* end for dev */ + } /* end for chan */ +CC |= CC1|CC2; /* no recognition */ +return 0; +} + +/* Initiate I/O instruction */ + +t_bool io_init_inst (uint32 rn, uint32 ad, uint32 ch, uint32 dev, uint32 r0) +{ +uint32 loc20; + +if (ch >= chan_num) /* bad chan? */ + return FALSE; +loc20 = ((ad & 0xFF) << 24) | /* <0:7> = dev ad */ + ((rn & 1) | (rn? 3: 0) << 22) | /* <8:9> = reg ind */ + (r0 & (cpu_tab[cpu_model].pamask >> 1)); /* <14/16:31> = r0 */ +WritePW (0x20, loc20); +return (chan[ch].disp[dev] != NULL)? TRUE: FALSE; +} + +/* Set status for I/O instruction */ + +uint32 io_set_status (uint32 rn, uint32 ch, uint32 dev, uint32 dvst, t_bool tdv) +{ +uint32 mrgst; +uint32 odd = rn & 1; + +if ((rn != 0) && !(dvst & DVT_NOST)) { /* return status? */ + if (tdv) + mrgst = (DVT_GETDVS (dvst) << 8) | (chan[ch].chf[dev] & 0xFF); + else mrgst = ((DVT_GETDVS(dvst) << 8) & ~CHF_ALL) | (chan[ch].chf[dev] & CHF_ALL); + R[rn] = chan[ch].clc[dev]; /* even reg */ + if (!odd) /* even pair? */ + WritePW (0x20, R[rn]); /* write to 20 */ + R[rn|1] = (mrgst << 16) | chan[ch].bc[dev]; /* odd reg */ + WritePW (0x20 + odd, R[rn|1]); /* write to 20/21 */ + } +return DVT_GETCC (dvst); +} + +/* Channel support routines */ + +/* Get new command */ + +uint32 chan_get_cmd (uint32 dva, uint32 *cmd) +{ +uint32 ch, dev; +t_stat st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +*cmd = chan[ch].cmd[dev]; /* return cmd */ +return 0; +} + +/* Channel end */ + +uint32 chan_end (uint32 dva) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_ICE) /* int on chan end? */ + chan_set_chi (dva, CHI_END); +if ((chan[ch].cmf[dev] & CMF_CCH) && /* command chain? */ + !chan_new_cmd (ch, dev, chan[ch].clc[dev] + 1)) /* next command? */ + return CHS_CCH; +else chan[ch].chsf[dev] &= ~CHSF_ACT; /* channel inactive */ +return 0; +} + +/* Channel error */ + +uint32 chan_set_chf (uint32 dva, uint32 fl) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +fl &= ~CHF_INP; /* ignore int pend */ +chan[ch].chf[dev] |= fl; +if ((fl & CHF_LNTE) && /* length error */ + ((chan[ch].cmf[dev] & CMF_SIL) || /* suppressed? */ + !(chan[ch].cmf[dev] & CMF_HTE))) /* or don't stop? */ + fl &= ~CHF_LNTE; /* ignore it */ +if ((fl & CHF_XMDE) && /* data error? */ + !(chan[ch].cmf[dev] & CMF_HTE)) /* don't stop? */ + fl &= ~CHF_XMDE; /* ignore it */ +if ((fl & CHF_XMME) && /* memory error? */ + !(chan[ch].cmf[dev] & CMF_HTE)) /* don't stop? */ + fl &= ~CHF_XMME; /* ignore it */ +if (fl) /* fatal error? */ + return chan_uen (dva); /* unusual end */ +return 0; +} + +/* Channel test command flags */ + +t_bool chan_tst_cmf (uint32 dva, uint32 fl) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (VALID_DVA (ch, dev) && /* valid? */ + (chan[ch].cmf[dev] & fl)) + return TRUE; +return FALSE; +} + +/* Channel unusual end */ + +uint32 chan_uen (uint32 dva) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +if (chan[ch].cmf[dev] & CMF_IUE) /* int on uend? */ + chan_set_chi (dva, CHI_UEN); +chan[ch].chf[dev] |= CHF_UEN; /* flag uend */ +chan[ch].chsf[dev] &= ~CHSF_ACT; +return CHS_INACTV; /* done */ +} + +/* Channel read processes */ + +uint32 chan_RdMemB (uint32 dva, uint32 *dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_SKP) /* skip? */ + *dat = 0; +else if (ReadPB (chan[ch].ba[dev], dat)) { /* read data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 1); /* adjust counts */ +} + +uint32 chan_RdMemW (uint32 dva, uint32 *dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_SKP) /* skip? */ + *dat = 0; +else if ((chan[ch].bc[dev] < 4) || /* unaligned? */ + ((chan[ch].ba[dev] & 0x3) != 0)) { + uint32 i, wd; + for (i = 0, *dat = 0, wd = 0; i < 4; i++) { /* up to 4 bytes */ + st = chan_RdMemB (dva, &wd); /* get byte */ + *dat |= ((wd & 0xFF) << (24 - (i * 8))); /* pack */ + if (st != 0) /* stop if error */ + return st; + } + return 0; + } +else if (ReadPW (chan[ch].ba[dev] >> 2, dat)) { /* read word, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 4); /* adjust counts */ +} + +/* Channel write processes */ + +uint32 chan_WrMemB (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePB (chan[ch].ba[dev], dat)) { /* write data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 1); /* adjust counts */ +} + +uint32 chan_WrMemBR (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePB (chan[ch].ba[dev], dat)) { /* write data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, -1); /* adjust counts */ +} + +uint32 chan_WrMemW (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if ((chan[ch].bc[dev] < 4) || /* unaligned? */ + ((chan[ch].ba[dev] & 0x3) != 0)) { + uint32 i, wd; + for (i = 0; i < 4; i++) { /* up to 4 bytes */ + wd = (dat >> (24 - (i * 8))) & 0xFF; /* get byte */ + if ((st = chan_WrMemB (dva, wd)) != 0) /* write */ + return st; /* stop if error */ + } + return 0; + } +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePW (chan[ch].ba[dev] >> 2, dat)) { /* write word, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 4); /* adjust counts */ +} + +/* Channel process common code */ + +uint32 chan_proc_prolog (uint32 dva, uint32 *ch, uint32 *dev) +{ +*ch = DVA_GETCHAN (dva); /* get chan, dev */ +*dev = DVA_GETDEV (dva); +if (!VALID_DVA (*ch, *dev)) /* valid? */ + return SCPE_IERR; +if ((chan[*ch].chsf[*dev] & CHSF_ACT) == 0) /* active? */ + return CHS_INACTV; +return 0; +} + +uint32 chan_proc_epilog (uint32 dva, int32 cnt) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +chan[ch].ba[dev] = (chan[ch].ba[dev] + cnt) & CHBA_MASK; +chan[ch].bc[dev] = (chan[ch].bc[dev] - abs (cnt)) & CHBC_MASK; +if (chan[ch].bc[dev] != 0) /* more to do? */ + return 0; +if (chan[ch].cmf[dev] & CMF_IZC) /* int on zero?*/ + chan_set_chi (dva, CHI_ZBC); +if (chan[ch].cmf[dev] & CMF_DCH) { /* data chaining? */ + if (chan_new_cmd (ch, dev, chan[ch].clc[dev] + 1)) + return CHS_ZBC; + return 0; + } +return CHS_ZBC; +} + +/* New channel command */ + +uint32 chan_new_cmd (uint32 ch, uint32 dev, uint32 clc) +{ +uint32 i, ccw1, ccw2, cmd; + +for (i = 0; i < 2; i++) { /* max twice */ + clc = clc & (cpu_tab[cpu_model].pamask >> 1); /* mask clc */ + chan[ch].clc[dev] = clc; /* and save */ + if (ReadPW (clc << 1, &ccw1)) { /* get ccw1, nxm? */ + chan[ch].chf[dev] |= CHF_IOME; /* memory error */ + chan[ch].chsf[dev] &= ~CHSF_ACT; /* stop channel */ + return CHS_INACTV; + } + ReadPW ((clc << 1) + 1, &ccw2); /* get ccw2 */ + cmd = CCW1_GETCMD (ccw1); /* get chan cmd */ + if ((cmd & 0xF) == CMD_TIC) /* transfer? */ + clc = ccw1; /* try again */ + else { + chan[ch].cmd[dev] = cmd; /* decompose CCW */ + chan[ch].ba[dev] = CCW1_GETBA (ccw1); + chan[ch].cmf[dev] = CCW2_GETCMF (ccw2); + chan[ch].bc[dev] = CCW2_GETBC (ccw2); + return 0; + } + } +chan[ch].chf[dev] |= CHF_IOCE; /* control error */ +chan[ch].chsf[dev] &= ~CHSF_ACT; /* stop channel */ +return CHS_INACTV; +} + +/* Set, clear, test channel interrupt */ + +void chan_set_chi (uint32 dva, uint32 fl) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); +uint32 un = DVA_GETUNIT (dva); /* get unit */ + +chan[ch].chf[dev] |= CHF_INP; /* int pending */ +chan[ch].chi[dev] = (chan[ch].chi[dev] & CHI_FLAGS) | /* update status */ + fl | CHI_CTL | un; /* save unit */ +return; +} + +int32 chan_clr_chi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); +uint32 old_chi = chan[ch].chi[dev]; + +chan[ch].chf[dev] &= ~CHF_INP; /* clr int pending */ +chan[ch].chi[dev] &= CHI_FLAGS; /* clr ctl int */ +if (old_chi & CHI_CTL) + return CHI_GETUN (old_chi); +else return -1; +} + +int32 chan_chk_chi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +if (chan[ch].chi[dev] & CHI_CTL) /* ctl int pending? */ + return CHI_GETUN (chan[ch].chi[dev]); +else return -1; +} + +/* Set device interrupt */ + +void chan_set_dvi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +chan[ch].chf[dev] |= CHF_INP; /* int pending */ +return; +} + +/* Called by device reset to reset channel registers */ + +t_stat chan_reset_dev (uint32 dva) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +chan[ch].chf[dev] &= ~CHF_INP; /* clear intr */ +chan[ch].chsf[dev] &= ~CHSF_ACT; /* clear active */ +return SCPE_OK; +} + +/* Find highest priority pending interrupt + Question: must an interrupt be armed to be recognized? + Answer: yes; req'arm = 11 signifies waiting state */ + +uint32 io_eval_int (void) +{ +uint32 i, j, t, curr, mask, newi; + +if (int_arm[INTG_IO] & INTGIO_IO) /* I/O armed? */ + io_eval_ioint (); /* eval I/O interrupt */ +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + t = int_req[curr] & int_arm[curr] & int_enb[curr]; /* req, armed, enb */ + if ((t != 0) && /* any waiting req? */ + ((PSW2 & int_tab[curr].psw2_inh) == 0)) { /* group not inh? */ + for (j = 0; j < int_tab[curr].nbits; j++) { /* loop thru reqs */ + mask = 1u << (int_tab[curr].nbits - j - 1); + if (t & mask) { /* request active? */ + newi = INTV (curr, j); /* get int number */ + if (newi < int_hiact) /* higher priority? */ + return newi; /* new highest actv */ + return NO_INT; /* no pending intr */ + } + } + printf ("%%int eval consistency error = %X\r\n", t); + int_req[curr] = 0; /* "impossible" */ + } + if (curr == INT_GETGRP (int_hiact)) /* at active group? */ + return NO_INT; /* no pending intr */ + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return NO_INT; /* no pending intr */ + } +printf ("%%int eval consistency error, list end not found\r\n"); +return NO_INT; +} + +/* See if any interrupt is possible (used by WAIT) */ + +t_bool io_poss_int (void) +{ +uint32 i, curr; + +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + if (((int_arm[curr] & int_enb[curr]) != 0) && + ((PSW2 & int_tab[curr].psw2_inh) == 0)) /* group not inh? */ + return TRUE; /* int can occur */ + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return FALSE; /* no int possible */ + } +printf ("%%int possible consistency error, list end not found\r\n"); +return FALSE; +} + +/* Evaluate I/O interrupts */ + +void io_eval_ioint (void) +{ +uint32 i, j; + +for (i = 0; i < chan_num; i++) { /* loop thru chan */ + for (j = 0; j < CHAN_N_DEV; j++) { /* loop thru dev */ + if (chan[i].chf[j] & CHF_INP) { /* intr pending? */ + int_req[INTG_IO] |= INTGIO_IO; /* set I/O intr */ + return; + } /* end if int pend */ + } /* end for dev */ + } /* end for chan */ +return; +} + +/* Find highest priority active interrupt + Question: is an inhibited or disabled interrupt recognized? + Answer: yes; req'arm = 10 signifies active state */ + +uint32 io_actv_int (void) +{ +uint32 i, j, t, curr, mask; + +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + if ((t = int_req[curr] & ~int_arm[curr]) != 0) { /* req active? */ + for (j = 0; j < int_tab[curr].nbits; j++) { /* loop thru reqs */ + mask = 1u << (int_tab[curr].nbits - j - 1); + if (t & mask) /* req active? */ + return INTV (curr, j); /* return int num */ + } + printf ("%%int actv consistency error = %X\r\n", t); + int_req[curr] = 0; /* "impossible" */ + } + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return NO_INT; /* no pending interupt */ + } +printf ("%%int actv consistency error, list end not found\r\n"); +return NO_INT; +} + +/* Acknowledge interrupt and get vector */ + +uint32 io_ackn_int (uint32 hireq) +{ +uint32 grp, bit, mask; + +if (hireq >= NO_INT) /* none pending? */ + return 0; +grp = INT_GETGRP (hireq); /* get grp, bit */ +bit = INT_GETBIT (hireq); +if (bit >= int_tab[grp].nbits) { /* validate bit */ + printf ("%%int ack consistency error, hireq=%X\r\n", hireq); + return 0; + } +mask = 1u << (int_tab[grp].nbits - bit - 1); +int_arm[grp] &= ~mask; /* clear armed */ +int_hiact = hireq; /* now active */ +int_hireq = io_eval_int (); /* paranoia */ +if (int_hireq != NO_INT) + printf ("%%int ack consistency error, post iack req=%X\r\n", int_hireq); +return int_tab[grp].vecbase + bit; +} + +/* Release interrupt and set new armed/disarmed state */ + +extern uint32 io_rels_int (uint32 hiact, t_bool arm) +{ +uint32 grp, bit, mask; + +if (hiact < NO_INT) { /* intr active? */ + grp = INT_GETGRP (hiact); /* get grp, bit */ + bit = INT_GETBIT (hiact); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + printf ("%%int release consistency error, hiact=%X\r\n", hiact); + return 0; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + int_req[grp] &= ~mask; /* clear req */ + if (arm) /* rearm? */ + int_arm[grp] |= mask; + else int_arm[grp] &= ~mask; + } +int_hiact = io_actv_int (); /* new highest actv */ +return io_eval_int (); /* new request */ +} + +/* Set panel interrupt */ + +t_stat io_set_pint (void) +{ +int_req[INTG_IO] |= INTGIO_PANEL; +return SCPE_OK; +} + +/* Set or clear interrupt status flags */ + +void io_sclr_req (uint32 inum, uint32 val) +{ +uint32 grp, bit, mask; + +if (inum < NO_INT) { /* valid? */ + grp = INT_GETGRP (inum); /* get grp, bit */ + bit = INT_GETBIT (inum); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + printf ("%%intreq set/clear consistency error, inum=%X\r\n", inum); + return; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + if (val) { /* set req? */ + if (int_arm[grp] & mask) /* must be armed */ + int_req[grp] |= mask; + } + else int_req[grp] &= ~mask; /* clr req */ + } +return; +} + +void io_sclr_arm (uint32 inum, uint32 val) +{ +uint32 grp, bit, mask; + +if (inum < NO_INT) { /* valid? */ + grp = INT_GETGRP (inum); /* get grp, bit */ + bit = INT_GETBIT (inum); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + printf ("%%intarm set/clear consistency error, inum=%X\r\n", inum); + return; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + if (val) /* set or clr arm */ + int_arm[grp] |= mask; + else int_arm[grp] &= ~mask; + } +return; +} + +/* Read/write direct mode 0 - processor miscellaneous */ + +uint32 io_rwd_m0 (uint32 op, uint32 rn, uint32 ad) +{ +uint32 wd; +uint32 fnc = DIO_GET0FNC (ad); +uint32 dat = rn? R[rn]: 0; + +if (op == OP_RD) { /* read direct? */ + if (fnc == 0x000) { /* copy SSW to SC */ + CC = SSW; + } + else if (fnc == 0x010) { /* read mem fault */ + if (rn) + R[rn] = 0; + CC = SSW; + } + else if (QCPU_S89_5X0 && (fnc == 0x040)) { /* S89, 5X0 only */ + if (rn) /* read inhibits */ + R[rn] = PSW2_GETINH (PSW2); + } + else if (QCPU_S89 && (fnc == 0x045)) { /* S89 only */ + if (rn) + R[rn] = s9_marg & 0x00C00000 | /* <8,9> = margins */ + (QCPU_S9? 0x00100000: 0x00200000); /* S8 sets 10, S9 11 */ + } + else if (QCPU_S89 && (fnc == 0x049)) { /* S89 only */ + if (rn) /* read snapshot */ + R[rn] = s9_snap; + } + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x100)) { /* 5X0 only */ + ReadPW (fnc & 0x1F, &wd); /* read low mem */ + if (rn) + R[rn] = wd; + } + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x300)) { /* 5X0 only */ + if (rn) /* read int reg */ + R[rn] = s5x0_ireg[fnc & 0x1F]; + } + else return (stop_op)? STOP_ILLEG: 0; + } +else { /* write direct */ + if (QCPU_5X0 && (fnc == 0x000)) /* 5X0 only */ + SSW = dat & 0xF; /* write SSW */ + else if (QCPU_5X0 && (fnc == 0x002)) /* 5X0 only */ + return TR_47; /* trap to 47 */ + else if ((fnc & 0xFF0) == 0x020) /* bit clear inh */ + PSW2 &= ~((ad & PSW2_M_INH) << PSW2_V_INH); + else if ((fnc & 0xFF0) == 0x030) /* bit set inh */ + PSW2 |= ((ad & PSW2_M_INH) << PSW2_V_INH); + else if (fnc == 0x040) /* alarm off */ + cons_alarm = 0; + else if (fnc == 0x041) /* alarm on */ + cons_alarm = 1; + else if (fnc == 0x042) { /* toggle freq */ + cons_alarm = 0; + cons_pcf ^= 1; + } + else if (fnc == 0x044) ; /* S5 reset IIOP */ + else if (QCPU_S89 && (fnc == 0x045)) /* S89 only */ + s9_marg = dat; /* write margins */ + else if (QCPU_S89_5X0 && (fnc == 0x046)) /* S89, 5X0 only */ + PSW2 &= ~(PSW2_MA9|PSW2_MA5X0); /* clr mode altered */ + else if (QCPU_S9 && (fnc == 0x047)) /* S9 set mode alt */ + PSW2 |= PSW2_MA9; + else if (QCPU_5X0 && (fnc == 0x047)) /* 5X0 set mode alt */ + PSW2 |= PSW2_MA5X0; + else if (QCPU_S89 && (fnc == 0x049)) /* S9 only */ + s9_snap = dat; /* write snapshot */ + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x100)) /* 5X0 only */ + WritePW (fnc & 0x1F, dat); /* write low mem */ + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x300)) /* 5X0 only */ + s5x0_ireg[fnc & 0x1F] = dat; /* write int reg */ + else return (stop_op)? STOP_ILLEG: 0; + } +return 0; +} + +/* Read/write direct mode 1 - interrupt flags + This is the only routine that has to map between architecturally + defined interrupts groups and the internal representation. */ + +uint32 io_rwd_m1 (uint32 op, uint32 rn, uint32 ad) +{ +uint32 i, beg, end, mask, sc; +uint32 grp = DIO_GET1GRP (ad); +uint32 fnc = DIO_GET1FNC (ad); + +if (grp == 0) { /* overrides? */ + beg = INTG_OVR; + end = INTG_IO; + } +else if (grp == 1) /* group 1? */ + return 0; /* not there */ +else beg = end = grp + 1; + +if (op == OP_RD) { /* read direct? */ + if (!QCPU_S89_5X0) /* S89, 5X0 only */ + return (stop_op? STOP_ILLEG: 0); + if (rn == 0) /* want result? */ + return 0; + R[rn] = 0; /* clear reg */ + } +for (i = beg; i <= end; i++) { /* loop thru grps */ + mask = (1u << int_tab[i].nbits) - 1; + sc = 32 - int_tab[i].regbit - int_tab[i].nbits; + if (op == OP_RD) { /* read direct? */ + if (fnc & 0x1) + R[rn] |= ((mask & int_arm[i]) << sc); + if (fnc & 0x2) + R[rn] |= ((mask & int_req[i]) << sc); + if (fnc & 0x4) + R[rn] |= ((mask & int_enb[i]) << sc); + } + else { /* write direct */ + mask = (R[rn] >> sc) & mask; + switch (fnc) { + + case 0x0: /* armed||wait->act */ + if (QCPU_S89_5X0) { + int_req[i] |= (mask & int_arm[i]); + int_arm[i] &= mask; + } + else return (stop_op? STOP_ILLEG: 0); + break; + + case 0x1: /* disarm, clr req */ + int_arm[i] &= ~mask; + int_req[i] &= ~mask; + break; + + case 0x2: /* arm, enb, clr req */ + int_arm[i] |= mask; + int_enb[i] |= mask; + int_req[i] &= ~mask; + break; + + case 0x3: /* arm, dsb, clr req */ + int_arm[i] |= mask; + int_enb[i] &= ~mask; + int_req[i] &= ~mask; + break; + + case 0x4: /* enable */ + int_enb[i] |= mask; + break; + + case 0x5: /* disable */ + int_enb[i] &= ~mask; + break; + + case 0x6: /* direct set enb */ + int_enb[i] = mask; + break; + + case 0x7: /* armed->waiting */ + int_req[i] |= (mask & int_arm[i]); + } + } + } +return 0; +} + +/* Reset routines */ + +t_stat int_reset (DEVICE *dptr) +{ +uint32 i; + +if (int_lnk[0] == 0) /* int chain not set up? */ + io_set_eimax (ei_bmax); +for (i = 0; i < INTG_MAX; i++) { + int_arm[i] = 0; + int_enb[i] = 0; + int_req[i] = 0; + } +int_hiact = NO_INT; +int_hireq = NO_INT; +return SCPE_OK; +} + +t_stat chan_reset (DEVICE *dptr) +{ +uint32 ch = dptr - &chan_dev[0]; +uint32 i, j; +DEVICE *devp; + +if (ch >= CHAN_N_CHAN) + return SCPE_IERR; +for (i = 0; i < CHAN_N_DEV; i++) { + chan[ch].clc[i] = 0; + chan[ch].cmd[i] = 0; + chan[ch].cmf[i] = 0; + chan[ch].ba[i] = 0; + chan[ch].bc[i] = 0; + chan[ch].chf[i] = 0; + chan[ch].chi[i] = 0; + chan[ch].chsf[i] &= ~CHSF_ACT; + for (j = 0; (devp = sim_devices[j]) != NULL; j++) { /* loop thru dev */ + if (devp->ctxt != NULL) { + dib_t *dibp = (dib_t *) devp->ctxt; + if ((DVA_GETCHAN (dibp->dva) == ch) && (devp->reset)) + devp->reset (devp); + } + } + } +return SCPE_OK; +} + +/* Universal boot routine */ + +static uint32 boot_rom[] = { + 0x00000000, 0x00000000, 0x020000A8, 0x0E000058, + 0x00000011, 0x00000000, 0x32000024, 0xCC000025, + 0xCD000025, 0x69C00028, 0x00000000, 0x00000000 + }; + +t_stat io_boot (int32 u, DEVICE *dptr) +{ +uint32 i; +dib_t *dibp = (dib_t *) dptr->ctxt; + +for (i = 0; i < MEMSIZE; i++) /* boot clrs mem */ + WritePW (i, 0); +if ((dibp == NULL) || + ((u != 0) && + ((dibp->dva & DVA_MU) == 0))) + return SCPE_ARG; +for (i = 0; i < BOOT_LNT; i++) + WritePW (BOOT_SA + i, boot_rom[i]); +WritePW (BOOT_DEV, dibp->dva | u); +cpu_new_PSD (1, BOOT_PC, 0); +return SCPE_OK; +} + +/* I/O table initialization routine */ + +t_stat io_init (void) +{ +uint32 i, j, ch, dev, dio; +DEVICE *dptr; +dib_t *dibp; + +for (i = 0; i < CHAN_N_CHAN; i++) { + for (j = 0; j < CHAN_N_DEV; j++) { + chan[i].chsf[j] &= ~CHSF_MU; + chan[i].disp[j] = NULL; + } + } +dio_disp[0] = &io_rwd_m0; +for (i = 1; i < DIO_N_MOD; i++) + dio_disp[i] = NULL; + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + if ((dibp = (dib_t *) dptr->ctxt) != NULL) { + ch = DVA_GETCHAN (dibp->dva); + dev = DVA_GETDEV (dibp->dva); + dio = dibp->dio; + if ((ch >= chan_num) || + (dev >= CHAN_N_DEV) || + (dio >= DIO_N_MOD)) { + printf ("%s: invalid device address, chan = %d, dev = %X, dio = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva), dio); + if (sim_log) + fprintf (sim_log, "%s: invalid device address, chan = %d, dev = %X, dio = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva), dio); + return SCPE_STOP; + } + if ((dibp->disp != NULL) && (chan[ch].disp[dev] != NULL)) { + printf ("%s: device address conflict, chan = %d, dev = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva)); + if (sim_log) + fprintf (sim_log, "%s: device address conflict, chan = %d, dev = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva)); + return SCPE_STOP; + } + if ((dibp->dio_disp != NULL) && (dio_disp[dio] != NULL)) { + printf ("%s: direct I/O address conflict, dio = %X\n", + sim_dname (dptr), dio); + if (sim_log) + fprintf (sim_log, "%s: direct I/O address conflict, dio = %X\n", + sim_dname (dptr), dio); + return SCPE_STOP; + } + if (dibp->disp) + chan[ch].disp[dev] = dibp->disp; + if (dibp->dio_disp) + dio_disp[dio] = dibp->dio_disp; + if (dibp->dva & DVA_MU) + chan[ch].chsf[dev] |= CHSF_MU; + } + } +return SCPE_OK; +} + +/* Set/show external interrupt blocks */ + +t_stat io_set_eiblks (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 lnt; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; +lnt = (int32) get_uint (cptr, 10, cpu_tab[cpu_model].eigrp_max, &r); +if ((r != SCPE_OK) || (lnt == 0)) + return SCPE_ARG; +int_reset (&int_dev); +io_set_eimax (lnt); +return SCPE_OK; +} + +t_stat io_show_eiblks (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "eiblks=%d", ei_bmax); +return SCPE_OK; +} + +/* Change the number of external I/O blocks, and restore the default + chain configuration */ + +void io_set_eimax (uint32 max) +{ +uint32 i, curr, ngrp; +uint8 *dflt_p; + +ei_bmax = max; +if (QCPU_5X0) + dflt_p = igrp_dflt_5x0; +else dflt_p = igrp_dflt_S56789; +curr = dflt_p[0] & ~I_STD; +for (i = 1, ngrp = 0; dflt_p[i] != 0; i++) { + if (dflt_p[i] & I_STD) { + int_lnk[curr] = dflt_p[i] & ~I_STD; + curr = int_lnk[curr]; + } + else if (ngrp < ei_bmax) { + int_lnk[curr] = dflt_p[i]; + curr = int_lnk[curr]; + ngrp++; + } + else int_lnk[curr] = 0; + } +return; +} + +/* Set or show number of channels */ + +t_stat io_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i, num; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; +num = (int32) get_uint (cptr, 10, cpu_tab[cpu_model].chan_max, &r); +if ((r != SCPE_OK) || (num == 0)) + return SCPE_ARG; +chan_num = num; +for (i = 0; i < CHAN_N_CHAN; i++) { + if (i < num) + chan_dev[i].flags &= ~DEV_DIS; + else chan_dev[i].flags |= DEV_DIS; + chan_reset (&chan_dev[i]); + } +return SCPE_OK; +} + +t_stat io_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "channels=%d", chan_num); +return SCPE_OK; +} + +/* Set or show device channel assignment */ + +t_stat io_set_dvc (UNIT* uptr, int32 val, char *cptr, void *desc) +{ +int32 num; +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +if ((cptr == NULL) || (*cptr == 0) || (*(cptr + 1) != 0)) + return SCPE_ARG; +num = *cptr - 'A'; +if ((num < 0) || (num >= (int32) chan_num)) + return SCPE_ARG; +dibp->dva = (dibp->dva & ~DVA_CHAN) | (num << DVA_V_CHAN); +return SCPE_OK; +} + +t_stat io_show_dvc (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +fprintf (st, "channel=%c", DVA_GETCHAN (dibp->dva) + 'A'); +return SCPE_OK; +} + +/* Set or show device address */ + +t_stat io_set_dva (UNIT* uptr, int32 val, char *cptr, void *desc) +{ +int32 num; +DEVICE *dptr; +dib_t *dibp; +t_stat r; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +if (cptr == NULL) + return SCPE_ARG; +num = (int32) get_uint (cptr, 16, CHAN_N_DEV, &r); +if (r != SCPE_OK) + return SCPE_ARG; +if (dibp->dva & DVA_MU) + dibp->dva = (dibp->dva & ~DVA_DEVMU) | ((num & DVA_M_DEVMU) << DVA_V_DEVMU); +else dibp->dva = (dibp->dva & ~DVA_DEVSU) | ((num & DVA_M_DEVSU) << DVA_V_DEVSU); +return SCPE_OK; +} + +t_stat io_show_dva (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +fprintf (st, "address=%02X", DVA_GETDEV (dibp->dva)); +return SCPE_OK; +} + +/* Show channel state */ + +t_stat io_show_cst (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; +uint32 ch, dva; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +ch = DVA_GETCHAN (dibp->dva); +dva = DVA_GETDEV (dibp->dva); +fprintf (st, "Status for device %s, channel=%02X, address=%02X:\n", + sim_dname(dptr), ch, dva); +fprintf (st, "CLC:\t%06X\nBA:\t%06X\nBC:\t%04X\nCMD:\t%02X\n", + chan[ch].clc[dva], chan[ch].ba[dva], + chan[ch].bc[dva], chan[ch].cmd[dva]); +fprintf (st, "CMF:\t%02X\nCHF\t%04X\nCHI:\t%02X\nCHSF:\t%02X\n", + chan[ch].cmf[dva], chan[ch].chf[dva], + chan[ch].chi[dva], chan[ch].chsf[dva]); +return SCPE_OK; +} diff --git a/sigma/sigma_io_defs.h b/sigma/sigma_io_defs.h new file mode 100644 index 00000000..a44c4f91 --- /dev/null +++ b/sigma/sigma_io_defs.h @@ -0,0 +1,276 @@ +/* sigma_io_defs.h: XDS Sigma I/O device simulator definitions + + Copyright (c) 2007-2008, Robert 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 _SIGMA_IO_DEFS_H_ +#define _SIGMA_IO_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ +#include "sigma_defs.h" + +/* Channel constants */ + +#define CHAN_N_CHAN 8 /* max # channels */ +#define CHAN_DFLT 4 /* default # chan */ +#define CHAN_N_DEV 32 /* max dev per chan */ +#define CHAN_V_IOPT (DEV_V_UF + 0) /* channel type */ +#define CHAN_MIOP (0 << CHAN_V_IOPT) +#define CHAN_SIOP (1 << CHAN_V_IOPT) + +/* I/O device definition block */ + +typedef struct { + uint32 dva; /* dev addr (chan+dev) */ + uint32 (*disp)(uint32 op, uint32 dva, uint32 *dvst); + uint32 dio; /* dev addr (direct IO) */ + uint32 (*dio_disp)(uint32 op, uint32 rn, uint32 dva); + } dib_t; + +/* Channel data structure */ + +typedef struct { + uint32 clc[CHAN_N_DEV]; /* location counter */ + uint32 ba[CHAN_N_DEV]; /* mem addr */ + uint16 bc[CHAN_N_DEV]; /* byte count */ + uint8 cmd[CHAN_N_DEV]; /* command */ + uint8 cmf[CHAN_N_DEV]; /* command flags */ + uint16 chf[CHAN_N_DEV]; /* channel flags */ + uint8 chi[CHAN_N_DEV]; /* interrupts */ + uint8 chsf[CHAN_N_DEV]; /* simulator flags */ + uint32 (*disp[CHAN_N_DEV])(uint32 op, uint32 dva, uint32 *dvst); + } chan_t; + +/* Channel command words */ + +#define CCW1_V_CMD 24 /* command */ +#define CCW1_M_CMD 0xFF +#define CCW1_V_BA 0 +#define CCW1_M_BA ((cpu_tab[cpu_model].pamask << 2) | 0x3) +#define CHBA_MASK (CCW1_M_BA << CCW1_V_BA) +#define CCW2_V_CMF 24 /* cmd flags */ +#define CCW2_M_CMF 0xFF +#define CCW2_V_BC 0 +#define CCW2_M_BC 0xFFFF +#define CHBC_MASK (CCW2_M_BC << CCW2_V_BC) +#define CCW1_GETCMD(x) (((x) >> CCW1_V_CMD) & CCW1_M_CMD) +#define CCW1_GETBA(x) (((x) >> CCW1_V_BA) & CCW1_M_BA) +#define CCW2_GETCMF(x) (((x) >> CCW2_V_CMF) & CCW2_M_CMF) +#define CCW2_GETBC(x) (((x) >> CCW2_V_BC) & CCW2_M_BC) + +/* Channel commands */ + +#define CMD_TIC 0x8 /* transfer */ + +/* Channel command flags */ + +#define CMF_DCH 0x80 /* data chain */ +#define CMF_IZC 0x40 /* int on zero cnt */ +#define CMF_CCH 0x20 /* command chain */ +#define CMF_ICE 0x10 /* int on chan end */ +#define CMF_HTE 0x08 /* hlt on xmit err */ +#define CMF_IUE 0x04 /* int on uend */ +#define CMF_SIL 0x02 /* suppress lnt err */ +#define CMF_SKP 0x01 /* skip */ + +/* Channel flags */ + +#define CHF_INP 0x8000 /* int pending */ +#define CHF_UEN 0x0400 /* unusual end */ +#define CHF_LNTE 0x0080 /* length error */ +#define CHF_XMDE 0x0040 /* xmit data error */ +#define CHF_XMME 0x0020 /* xmit mem error */ +#define CHF_XMAE 0x0010 /* xmit addr error */ +#define CHF_IOME 0x0008 /* IOP mem error */ +#define CHF_IOCE 0x0004 /* IOP ctrl error */ +#define CHF_IOHE 0x0002 /* IOP halted */ +#define CHF_ALL (CHF_INP|CHF_UEN|0xFF) + +/* Channel interrupts */ + +#define CHI_F_SHF 1 /* flag shift */ +#define CHI_CTL (0x40 << CHI_F_SHF) /* ctl int (fake) */ +#define CHI_ZBC (0x20 << CHI_F_SHF) /* zero by cnt int */ +#define CHI_END (0x10 << CHI_F_SHF) /* channel end int */ +#define CHI_UEN (0x08 << CHI_F_SHF) /* unusual end int */ +#define CHI_FLAGS (CHI_ZBC|CHI_END|CHI_UEN) +#define CHI_V_UN 0 +#define CHI_M_UN 0xF +#define CHI_GETUN(x) (((x) >> CHI_V_UN) & CHI_M_UN) +#define CHI_GETINT(x) (((x) & CHI_FLAGS) >> CHI_F_SHF) + +/* Internal simulator flags */ + +#define CHSF_ACT 0x0001 /* channel active */ +#define CHSF_MU 0x0002 /* multi-unit dev */ + +/* Dispatch routine status return value */ + +#define DVT_V_UN 24 /* unit addr (AIO only) */ +#define DVT_M_UN 0xF +#define DVT_V_CC 16 /* cond codes */ +#define DVT_M_CC 0xF +#define DVT_V_DVS 0 /* device status */ +#define DVT_M_DVS 0xFF +#define DVS_V_DST 5 /* device status */ +#define DVS_M_DST 0x3 +#define DVS_DST (DVS_M_DST << DVS_V_DST) +#define DVS_DOFFL (0x1 << DVS_V_DST) +#define DVS_DBUSY (0x3 << DVS_V_DST) +#define DVS_AUTO 0x10 /* manual/automatic */ +#define DVS_V_CST 1 /* ctrl status */ +#define DVS_M_CST 0x3 +#define DVS_CBUSY (0x3 << DVS_V_CST) +#define DVS_CST (DVS_M_CST << DVS_V_CST) +#define DVT_GETUN(x) (((x) >> DVT_V_UN) & DVT_M_UN) +#define DVT_GETCC(x) (((x) >> DVT_V_CC) & DVT_M_CC) +#define DVT_GETDVS(x) (((x) >> DVT_V_DVS) & DVT_M_DVS) +#define DVT_NOST (CC1 << DVT_V_CC) /* no status */ +#define DVT_NODEV ((CC1|CC2) < DVT_V_CC) /* no device */ + +/* Read and write direct address format */ + +#define DIO_V_MOD 12 /* mode */ +#define DIO_M_MOD 0xF +#define DIO_V_0FNC 0 /* mode 0 func */ +#define DIO_M_0FNC 0xFFF +#define DIO_V_1FNC 8 /* mode 1 int func */ +#define DIO_M_1FNC 0x7 +#define DIO_V_1GRP 0 /* int group */ +#define DIO_M_1GRP 0xF +#define DIO_GETMOD(x) (((x) >> DIO_V_MOD) & DIO_M_MOD) +#define DIO_GET0FNC(x) (((x) >> DIO_V_0FNC) & DIO_M_0FNC) +#define DIO_GET1FNC(x) (((x) >> DIO_V_1FNC) & DIO_M_1FNC) +#define DIO_GET1GRP(x) (((x) >> DIO_V_1GRP) & DIO_M_1GRP) +#define DIO_N_MOD (DIO_M_MOD + 1) /* # DIO "modes" */ + +/* I/O instruction address format */ + +#define DVA_V_CHAN 8 /* channel */ +#define DVA_M_CHAN (CHAN_N_CHAN - 1) +#define DVA_CHAN (DVA_M_CHAN << DVA_V_CHAN) +#define DVA_V_DEVSU 0 /* dev, 1 unit */ +#define DVA_M_DEVSU 0x7F +#define DVA_DEVSU (DVA_M_DEVSU << DVA_V_DEVSU) +#define DVA_MU 0x80 /* multi-unit flg */ +#define DVA_V_DEVMU 4 /* dev, multi */ +#define DVA_M_DEVMU 0x7 +#define DVA_DEVMU (DVA_M_DEVMU << DVA_V_DEVMU) +#define DVA_V_UNIT 0 /* unit number */ +#define DVA_M_UNIT 0xF +#define DVA_GETCHAN(x) (((x) >> DVA_V_CHAN) & DVA_M_CHAN) +#define DVA_GETDEV(x) (((x) & DVA_MU)? \ + (((x) >> DVA_V_DEVMU) & DVA_M_DEVMU): \ + (((x) >> DVA_V_DEVSU) & DVA_M_DEVSU)) +#define DVA_GETUNIT(x) (((x) & DVA_MU)? \ + (((x) >> DVA_V_UNIT) & DVA_M_UNIT): 0) + +/* Default I/O device addresses */ + +#define DVA_TT 0x001 +#define DVA_LP 0x002 +#define DVA_CR 0x003 +#define DVA_CP 0x004 +#define DVA_PT 0x005 +#define DVA_MUX 0x006 +#define DIO_MUX 0x3 +#define DVA_MT 0x080 +#define DVA_RAD 0x180 +#define DVA_DK 0x190 +#define DVA_DPA 0x280 +#define DVA_DPB 0x380 + +/* Channel routine status codes */ + +#define CHS_ERR 0x4000 /* any error */ +#define CHS_INF 0x8000 /* information */ +#define CHS_IFERR(x) (((x) != 0) && ((x) < CHS_INF)) + +#define CHS_INACTV (CHS_ERR + 0) +#define CHS_NXM (CHS_ERR + 1) +#define CHS_SEQ (CHS_ERR + 2) + +#define CHS_ZBC (CHS_INF + 1) /* zero byte count */ +#define CHS_CCH (CHS_INF + 2) /* command chain */ + +/* Boot ROM */ + +#define BOOT_SA 0x20 +#define BOOT_LNT 12 +#define BOOT_DEV 0x25 +#define BOOT_PC 0x26 + +/* Internal real-time scheduler */ + +#define RTC_C1 0 +#define RTC_C2 1 +#define RTC_C3 2 +#define RTC_C4 3 +#define RTC_NUM_CNTRS 4 +#define RTC_TTI (RTC_NUM_CNTRS + 0) +#define RTC_COC (RTC_NUM_CNTRS + 1) +#define RTC_ALARM (RTC_NUM_CNTRS + 2) +#define RTC_NUM_EVNTS (RTC_NUM_CNTRS + 3) + +#define RTC_HZ_OFF 0 +#define RTC_HZ_500 1 +#define RTC_HZ_50 2 +#define RTC_HZ_60 3 +#define RTC_HZ_100 4 +#define RTC_HZ_2 5 +#define RTC_NUM_HZ 6 + +/* Function prototypes */ + +uint32 chan_get_cmd (uint32 dva, uint32 *cmd); +uint32 chan_set_chf (uint32 dva, uint32 fl); +t_bool chan_tst_cmf (uint32 dva, uint32 fl); +void chan_set_chi (uint32 dva, uint32 fl); +void chan_set_dvi (uint32 dva); +int32 chan_clr_chi (uint32 dva); +int32 chan_chk_chi (uint32 dva); +uint32 chan_end (uint32 dva); +uint32 chan_uen (uint32 dva); +uint32 chan_RdMemB (uint32 dva, uint32 *dat); +uint32 chan_WrMemB (uint32 dva, uint32 dat); +uint32 chan_WrMemBR (uint32 dva, uint32 dat); +uint32 chan_RdMemW (uint32 dva, uint32 *dat); +uint32 chan_WrMemW (uint32 dva, uint32 dat); +t_stat chan_reset_dev (uint32 dva); +void io_sclr_req (uint32 inum, uint32 val); +void io_sclr_arm (uint32 inum, uint32 val); +t_stat io_set_dvc (UNIT* uptr, int32 val, char *cptr, void *desc); +t_stat io_show_dvc (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_set_dva (UNIT* uptr, int32 val, char *cptr, void *desc); +t_stat io_show_dva (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_show_cst (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_boot (int32 u, DEVICE *dptr); + +/* Internal real-time event scheduler */ + +t_stat rtc_set_tps (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rtc_show_tps (FILE *of, UNIT *uptr, int32 val, void *desc); +t_stat rtc_register (uint32 tm, uint32 idx, UNIT *uptr); + +#endif \ No newline at end of file diff --git a/sigma/sigma_lp.c b/sigma/sigma_lp.c new file mode 100644 index 00000000..70261e4d --- /dev/null +++ b/sigma/sigma_lp.c @@ -0,0 +1,529 @@ +/* sigma_lp.c: Sigma 7440/7450 line printer + + Copyright (c) 2007-2008, Robert 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. + + lp 7440/7445 or 7450 line printer +*/ + +#include "sigma_io_defs.h" + +/* Device definitions */ + +#define CCT_LNT 256 /* carriage ctl max */ +#define BUF_LNT4 132 /* line lengths */ +#define BUF_LNT5 128 + +#define LP_7440 0 /* models */ +#define LP_7450 1 + +/* Device states */ + +#define LPS_INIT 0x101 +#define LPS_END 0x102 +#define LPS_PRI 0x1 +#define LPS_FMT 0x3 +#define LPS_FMTP 0x5 +#define LPS_INT 0x40 + +/* Device status */ + +#define LPDV_ODD 0x40 /* odd */ +#define LPDV_TOF 0x10 /* top of form */ +#define LPDV_MOV 0x08 /* paper moving */ +#define LPDV_V_RUN 2 /* runaway CCT */ +#define LPDV_RUN (1u << LPDV_V_RUN) +#define LPDV_WT2 0x02 /* waiting for 2nd */ + +/* Format characters */ + +#define FMT_INH 0x60 +#define FMT_SPC 0xC0 +#define FMT_SKP 0xF0 + +#define FMT_MSPC4 15 /* max space cmd */ +#define FMT_MSPC5 7 +#define SPC_MASK ((lp_model == LP_7440)? FMT_MSPC4: FMT_MSPC5) +#define FMT_MCH4 7 /* max CCT channel */ +#define FMT_MCH5 1 +#define CCH_MASK ((lp_model == LP_7440)? FMT_MCH5: FMT_MCH4) + +#define CH_BOF 0 /* CCT bot of form */ +#define CH_TOF 1 /* CCT top of form */ + +#define CHP(ch,val) ((val) & (1 << (ch))) + +uint32 lp_cmd = 0; +uint32 lp_stopioe = 1; +uint32 lp_cctp = 0; /* CCT position */ +uint32 lp_cctl = 1; /* CCT length */ +uint32 lp_lastcmd = 0; /* last command */ +uint32 lp_pass = 0; /* 7450 print pass */ +uint32 lp_inh = 0; /* space inhibit */ +uint32 lp_run = 0; /* CCT runaway */ +uint32 lp_model = LP_7440; +uint8 lp_buf[BUF_LNT4]; /* print buffer */ +uint8 lp_cct[CCT_LNT] = { 0xFF }; /* carriage ctl tape */ +uint8 lp_to_ascii[64] = { + ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', '`', '.', '<', '(', '+', '|', + '&', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', '!', '$', '*', ')', ';', '~', + '-', '/', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '^', ',', '%', '_', '>', '?', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', '#', '@', '\'', '=', '"' + }; + +extern uint32 chan_ctl_time; + +uint32 lp_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 lp_tio_status (void); +uint32 lp_tdv_status (void); +t_stat lp_chan_err (uint32 st); +t_stat lp_svc (UNIT *uptr); +t_stat lp_reset (DEVICE *dptr); +t_stat lp_attach (UNIT *uptr, char *cptr); +t_stat lp_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat lp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat lp_load_cct (UNIT *uptr, int32 val, char *cptr, void *desc); +uint32 lp_fmt (UNIT *uptr); +uint32 lp_skip (UNIT *uptr, uint32 ch); +uint32 lp_space (UNIT *uptr, uint32 lines, t_bool skp); +uint32 lp_print (UNIT *uptr); + +/* LP data structures + + lp_dev LP device descriptor + lp_unit LP unit descriptors + lp_reg LP register list + lp_mod LP modifiers list +*/ + +dib_t lp_dib = { DVA_LP, lp_disp, 0, NULL }; + +UNIT lp_unit = { UDATA (&lp_svc, UNIT_ATTABLE+UNIT_SEQ, 0), SERIAL_OUT_WAIT }; + +REG lp_reg[] = { + { HRDATA (CMD, lp_cmd, 9) }, + { BRDATA (BUF, lp_buf, 16, 7, BUF_LNT4) }, + { FLDATA (PASS, lp_pass, 0) }, + { FLDATA (INH, lp_inh, 0) }, + { FLDATA (RUNAWAY, lp_run, LPDV_V_RUN) }, + { BRDATA (CCT, lp_cct, 8, 8, CCT_LNT) }, + { DRDATA (CCTP, lp_cctp, 8), PV_LEFT }, + { DRDATA (CCTL, lp_cctl, 8), PV_LEFT + REG_HRO + REG_NZ }, + { DRDATA (POS, lp_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, lp_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, lp_stopioe, 0) }, + { HRDATA (LASTC, lp_lastcmd, 8), REG_HIDDEN }, + { FLDATA (MODEL, lp_model, 0), REG_HRO }, + { HRDATA (DEVNO, lp_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB lp_mod[] = { + { MTAB_XTD | MTAB_VDV, LP_7440, NULL, "7440", + &lp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, LP_7450, NULL, "7450", + &lp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &lp_showtype, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "CCT", + &lp_load_cct, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE lp_dev = { + "LP", &lp_unit, lp_reg, lp_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &lp_reset, + NULL, &lp_attach, NULL, + &lp_dib, 0 + }; + +/* Line printer: IO dispatch routine */ + +uint32 lp_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = lp_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + lp_cmd = LPS_INIT; /* start dev thread */ + sim_activate (&lp_unit, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = lp_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = lp_tdv_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (lp_dib.dva); /* clear int */ + *dvst = lp_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&lp_unit); /* stop dev thread */ + chan_uen (lp_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (lp_dib.dva); /* clear int */ + *dvst = lp_lastcmd & LPS_INT; /* int requested */ + lp_lastcmd = 0; + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Service routine */ + +t_stat lp_svc (UNIT *uptr) +{ +uint32 cmd; +uint32 st; + +switch (lp_cmd) { /* case on state */ + + case LPS_INIT: /* I/O init */ + st = chan_get_cmd (lp_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return lp_chan_err (st); + lp_inh = 0; /* clear inhibit, */ + lp_run = 0; /* runaway */ + lp_cmd = lp_lastcmd = cmd; /* save command */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case LPS_FMT: + case LPS_FMT|LPS_INT: /* format only */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_fmt (uptr); /* format */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + if ((lp_model == LP_7440) && /* 7440? lnt chk */ + (st != CHS_ZBC) && + chan_set_chf (lp_dib.dva, CHF_LNTE)) /* not ignored? */ + return lp_chan_err (SCPE_OK); /* force uend */ + lp_cmd = LPS_END; /* actual print */ + break; + + case LPS_FMTP: + case LPS_FMTP|LPS_INT: /* format and print */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_fmt (uptr); /* format */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + if (st == CHS_ZBC) { /* command done? */ + if ((lp_model == LP_7440) && /* 7440? lnt err */ + chan_set_chf (lp_dib.dva, CHF_LNTE)) /* not ignored? */ + return lp_chan_err (SCPE_OK); + } + else { /* more to do */ + st = lp_print (uptr); /* print */ + if (CHS_IFERR (st)) /* error */ + return lp_chan_err (st); + } + break; + + case LPS_PRI: + case LPS_PRI|LPS_INT: /* print only */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_print (uptr); /* print */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + break; + + case LPS_END: /* command done */ + if ((lp_lastcmd & LPS_INT) && !lp_pass) /* int requested? */ + chan_set_chi (lp_dib.dva, 0); + st = chan_end (lp_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return lp_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + lp_cmd = LPS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + default: /* invalid cmd */ + chan_uen (lp_dib.dva); /* uend */ + break; + } + +return SCPE_OK; +} + +/* Format routine */ + +uint32 lp_fmt (UNIT *uptr) +{ +uint32 c, i; +uint32 st; + +st = chan_RdMemB (lp_dib.dva, &c); /* get char */ +if (CHS_IFERR (st)) /* channel error? */ + return st; /* caller handles */ +if (lp_pass) /* only on pass 1 */ + return 0; +if ((c & 0x7F) == FMT_INH) /* inhibit? */ + lp_inh = 1; +else if ((c & ~(((lp_model == LP_7450)? 0x20: 0) | SPC_MASK)) == FMT_SPC) { + c = c & SPC_MASK; /* space? */ + for (i = 1; i <= c; i++) { /* look for BOF */ + if (CHP (CH_BOF, lp_cct[(lp_cctp + i) % lp_cctl])) + return lp_skip (uptr, CH_TOF); /* found, TOF */ + } + return lp_space (uptr, c, FALSE); /* space */ + } +else if ((c & ~CCH_MASK) == FMT_SKP) /* skip? */ + return lp_skip (uptr, c & CCH_MASK); /* skip to chan */ +return 0; +} + +/* Skip to channel */ + +uint32 lp_skip (UNIT *uptr, uint32 ch) +{ +uint32 i; + +for (i = 1; i < (lp_cctl + 1); i++) { /* sweep thru CCT */ + if (CHP (ch, lp_cct[(lp_cctp + i) % lp_cctl])) /* channel punched? */ + return lp_space (uptr, i, TRUE); /* space to chan */ + } +lp_run = LPDV_RUN; /* runaway CCT */ +return lp_space (uptr, lp_cctl, TRUE); /* space max */ +} + +/* Space routine */ + +uint32 lp_space (UNIT *uptr, uint32 cnt, t_bool skp) +{ +uint32 i; + +lp_cctp = (lp_cctp + cnt) % lp_cctl; /* adv cct, mod lnt */ +if (skp && CHP (CH_TOF, lp_cct[lp_cctp])) /* skip, TOF? */ + fputs ("\f", uptr->fileref); /* ff */ + else { /* space */ + for (i = 0; i < cnt; i++) + fputc ('\n', uptr->fileref); + } +uptr->pos = ftell (uptr->fileref); /* update position */ +if (ferror (uptr->fileref)) { /* error? */ + perror ("Line printer I/O error"); + clearerr (uptr->fileref); + chan_set_chf (lp_dib.dva, CHF_XMDE); + return SCPE_IOERR; + } +return 0; +} + +/* Print routine */ + +uint32 lp_print (UNIT *uptr) +{ +uint32 i, bp, c; +uint32 max = (lp_model == LP_7440)? BUF_LNT4: BUF_LNT5; +uint32 st; + +if (lp_pass == 0) { /* pass 1? clr buf */ + for (i = 0; i < BUF_LNT4; i++) lp_buf[i] = ' '; + } +for (bp = 0, st = 0; (bp < max) && !st; bp++) { /* fill buffer */ + st = chan_RdMemB (lp_dib.dva, &c); /* get char */ + if (CHS_IFERR (st)) /* channel error? */ + return st; /* caller handles */ + if ((lp_model == LP_7440) || /* 7440 or */ + ((bp & 1) == lp_pass)) /* correct pass? */ + lp_buf[bp] = lp_to_ascii[c & 0x3F]; + } +if ((lp_model == LP_7440) || lp_pass) { /* ready to print? */ + lp_pass = 0; + for (i = BUF_LNT4; (i > 0) && (lp_buf[i - 1] == ' '); i--) ; /* trim */ + if (i) /* write line */ + sim_fwrite (lp_buf, 1, i, uptr->fileref); + fputc (lp_inh? '\r': '\n', uptr->fileref); /* cr or nl */ + uptr->pos = ftell (uptr->fileref); /* update position */ + if (ferror (uptr->fileref)) { /* error? */ + perror ("Line printer I/O error"); + clearerr (uptr->fileref); + chan_set_chf (lp_dib.dva, CHF_XMDE); + return SCPE_IOERR; + } + if ((lp_model == LP_7440) && /* 7440? */ + ((bp != BUF_LNT4) || (st != CHS_ZBC)) && /* check lnt err */ + chan_set_chf (lp_dib.dva, CHF_LNTE)) + return CHS_INACTV; /* stop if asked */ + } +else lp_pass = 1; /* 7450 pass 2 */ +lp_cmd = LPS_END; /* end state */ +return 0; +} + +/* LP status routine */ + +uint32 lp_tio_status (void) +{ +uint32 st; + +st = (lp_unit.flags & UNIT_ATT)? DVS_AUTO: 0; /* auto? */ +if (sim_is_active (&lp_unit)) /* busy? */ + st |= (DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC)); +return st; +} + +uint32 lp_tdv_status (void) +{ +uint32 st; + +st = lp_run; /* runaway flag */ +if ((lp_unit.flags & UNIT_ATT) == 0) /* fault? */ + st |= (CC2 << DVT_V_CC); +if (lp_cmd == LPS_END) /* end state? */ + st |= LPDV_MOV; /* printing */ +if (lp_pass && (lp_model == LP_7450)) { /* 7450 pass 2? */ + st |= LPDV_ODD; /* odd state */ + if (lp_cmd == LPS_INIT) /* wait for cmd? */ + st |= LPDV_WT2; + } +return st; +} + +/* Channel error */ + +t_stat lp_chan_err (uint32 st) +{ +sim_cancel (&lp_unit); /* stop dev thread */ +chan_uen (lp_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat lp_reset (DEVICE *dptr) +{ +sim_cancel (&lp_unit); /* stop dev thread */ +lp_cmd = 0; +lp_lastcmd = 0; +lp_pass = 0; +lp_inh = 0; +lp_run = 0; +chan_reset_dev (lp_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Attach routine */ + +t_stat lp_attach (UNIT *uptr, char *cptr) +{ +lp_cctp = 0; /* clear cct ptr */ +lp_pass = 0; +return attach_unit (uptr, cptr); +} + +/* Set carriage control tape */ + +t_stat lp_load_cct (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 col, rpt, ptr, mask; +uint8 cctbuf[CCT_LNT]; +t_stat r; +char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; +FILE *cfile; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG; +if ((cfile = fopen (cptr, "r")) == NULL) + return SCPE_OPENERR; +ptr = 0; +for ( ; (cptr = fgets (cbuf, CBUFSIZE, cfile)) != NULL; ) { + mask = 0; + if (*cptr == '(') { /* repeat count? */ + cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ + rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */ + if (r != SCPE_OK) + return SCPE_FMT; + } + else rpt = 1; + while (*cptr != 0) { /* get col no's */ + cptr = get_glyph (cptr, gbuf, ','); /* get next field */ + col = get_uint (gbuf, 10, FMT_MCH4, &r); /* column number */ + if (r != SCPE_OK) + return SCPE_FMT; + mask = mask | (1 << col); /* set bit */ + } + for ( ; rpt > 0; rpt--) { /* store vals */ + if (ptr >= CCT_LNT) + return SCPE_FMT; + cctbuf[ptr++] = mask; + } + } +if (ptr == 0) + return SCPE_FMT; +lp_cctl = ptr; +lp_cctp = 0; +for (rpt = 0; rpt < lp_cctl; rpt++) + lp_cct[rpt] = cctbuf[rpt]; +return SCPE_OK; +} + +/* Set controller type */ + +t_stat lp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +lp_model = val; +lp_reset (&lp_dev); +return SCPE_OK; +} + +/* Show controller type */ + +t_stat lp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, lp_model? "7450": "7440"); +return SCPE_OK; +} diff --git a/sigma/sigma_map.c b/sigma/sigma_map.c new file mode 100644 index 00000000..898de7bb --- /dev/null +++ b/sigma/sigma_map.c @@ -0,0 +1,591 @@ +/* sigma_map.c: XDS Sigma memory access routines + + Copyright (c) 2007, Robert 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 "sigma_defs.h" + +#define BVA_REG (RF_NUM << 2) +#define BPAMASK ((cpu_tab[cpu_model].pamask << 2) | 0x3) +#define NUM_MUNITS (MAXMEMSIZE / CPU_MUNIT_SIZE) + +/* Sigma 8-9 memory status words */ + +#define S89_SR0_BADLMS 0x00800000 /* bad LMS */ +#define S89_SR0_RD (S89_SR0_BADLMS) +#define S89_SR0_V_PORTS 12 + +#define S89_SR1_FIXED 0x50C40000 /* always 1 */ +#define S89_SR1_M_MEMU 0xF /* mem unit */ +#define S89_SR1_V_MEMU 24 +#define S89_SR1_MARG 0x00F80000 /* margin write */ +#define S89_SR1_MAROFF 2 /* offset to read */ + +/* 5X0 memory status words */ + +#define S5X0_SR0_FIXED 0x40000000 +#define S5X0_SR0_BADLMS 0x00000004 /* bad LMS */ +#define S5X0_SR0_RD (S5X0_SR0_BADLMS) +#define S5X0_SR0_V_PORTS 21 + +#define S5X0_SR1_FIXED 0xB0000000 /* fixed */ +#define S5X0_SR1_M_MEMU 0x7 /* mem unit */ +#define S5X0_SR1_V_MEMU 25 +#define S5X0_SR1_V_SA 18 /* start addr */ + +#define S8 + +typedef struct { + uint32 width; /* item width */ + uint32 dmask; /* data mask */ + uint32 cmask; /* control start mask */ + uint32 lnt; /* array length */ + uint32 opt; /* option control */ + } mmc_ctl_t; + +uint16 mmc_rel[VA_NUM_PAG]; +uint8 mmc_acc[VA_NUM_PAG]; +uint8 mmc_wlk[PA_NUM_PAG]; + +uint32 mem_sr0[NUM_MUNITS]; +uint32 mem_sr1[NUM_MUNITS]; + +mmc_ctl_t mmc_tab[8] = { + { 0, 0, 0, 0 }, + { 2, 0x003, 0, MMC_L_CS1, CPUF_WLK }, /* map 1: 2b locks */ + { 2, 0x003, MMC_M_CS2, MMC_L_CS2, CPUF_MAP }, /* map 2: 2b access ctls */ + { 4, 0x00F, MMC_M_CS3, MMC_L_CS3, CPUF_WLK }, /* map 3: 4b locks */ + { 8, 0x0FF, MMC_M_CS4, MMC_L_CS4, CPUF_MAP }, /* map 4: 8b relocation */ + { 16, 0x7FF, MMC_M_CS5, MMC_L_CS5, CPUF_MAP }, /* map 5: 16b relocation */ + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 } + }; + +extern uint32 *R; +extern uint32 *M; +extern uint32 PSW1, PSW2, PSW4; +extern uint32 CC, PSW2_WLK; +extern uint32 stop_op; +extern uint32 cpu_model; +extern uint32 chan_num; +extern UNIT cpu_unit; +extern cpu_var_t cpu_tab[]; + +uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa); +uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr); +t_stat map_reset (DEVICE *dptr); +uint32 map_las (uint32 rn, uint32 bva); + +/* Map data structures + + map_dev map device descriptor + map_unit map units + map_reg map register list +*/ + +UNIT map_unit = { UDATA (NULL, 0, 0) }; + +REG map_reg[] = { + { BRDATA (REL, mmc_rel, 16, 13, VA_NUM_PAG) }, + { BRDATA (ACC, mmc_acc, 16, 2, VA_NUM_PAG) }, + { BRDATA (WLK, mmc_wlk, 16, 4, PA_NUM_PAG) }, + { BRDATA (SR0, mem_sr0, 16, 32, NUM_MUNITS) }, + { BRDATA (SR1, mem_sr1, 16, 32, NUM_MUNITS) }, + { NULL } + }; + +DEVICE map_dev = { + "MAP", &map_unit, map_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &map_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* Read and write virtual routines - per length */ + +uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, sc, tr; + +sc = 24 - ((bva & 3) << 3); +if (bva < BVA_REG) /* register access */ + *dat = (R[bva >> 2] >> sc) & BMASK; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = (M[bpa >> 2] >> sc) & BMASK; + } /* end else memory */ +return 0; +} + +uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + if (bva & 2) + *dat = R[bva >> 2] & HMASK; + else *dat = (R[bva >> 2] >> 16) & HMASK; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + if (bva & 2) + *dat = M[bpa >> 2] & HMASK; + else *dat = (M[bpa >> 2] >> 16) & HMASK; + } /* end else memory */ +return 0; +} + +uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) /* register access */ + *dat = R[bva >> 2]; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = M[bpa >> 2]; + } /* end else memory */ +return 0; +} + +uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + *dat = R[(bva >> 2) & ~1]; /* force alignment */ + *dat1 = R[(bva >> 2) | 1]; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = M[(bpa >> 2) & ~1]; /* force alignment */ + *dat1 = M[(bpa >> 2) | 1]; + } /* end else memory */ + +return 0; +} + +uint32 WriteB (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, sc, tr; + +sc = 24 - ((bva & 3) << 3); +if (bva < BVA_REG) /* register access */ + R[bva >> 2] = (R[bva >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc); +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[bpa >> 2] = (M[bpa >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc); + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteH (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + if (bva & 2) + R[bva >> 2] = (R[bva >> 2] & ~HMASK) | (dat & HMASK); + else R[bva >> 2] = (R[bva >> 2] & HMASK) | ((dat & HMASK) << 16); + } /* end if register */ +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + if (bva & 2) + M[bpa >> 2] = (M[bpa >> 2] & ~HMASK) | (dat & HMASK); + else M[bpa >> 2] = (M[bpa >> 2] & HMASK) | ((dat & HMASK) << 16); + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteW (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) /* register access */ + R[bva >> 2] = dat & WMASK; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[bpa >> 2] = dat & WMASK; + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + R[(bva >> 2) & ~1] = dat & WMASK; /* force alignment */ + R[(bva >> 2) | 1] = dat1 & WMASK; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[(bpa >> 2) & ~1] = dat & WMASK; /* force alignment */ + M[(bpa >> 2) | 1] = dat1 & WMASK; + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +/* General virtual read for instruction history */ + +uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt) +{ +switch (lnt) { /* case on length */ + + case BY: /* byte */ + return ReadB (bva, dat, acc); + + case HW: /* halfword */ + return ReadH (bva, dat, acc); + + case WD: /* word */ + return ReadW (bva, dat, acc); + + case DW: /* doubleword first */ + return ReadD (bva, dat, dat1, acc); + } /* end case length */ + +return SCPE_IERR; +} + +/* Specialized virtual read and write word routines - + treats all addresses as memory addresses */ + +uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa; +uint32 tr; + +if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; +*dat = M[bpa >> 2] & WMASK; +return 0; +} + +uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa; +uint32 tr; + +if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; +M[bpa >> 2] = dat & WMASK; +return 0; +} + +/* Relocation routine */ + +uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa) +{ +if ((acc != 0) && (PSW1 & PSW1_MM)) { /* virt, map on? */ + uint32 vpag = BVA_GETPAG (bva); /* virt page num */ + *bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK; + if (((PSW1 & PSW1_MS) || /* slave mode? */ + (PSW2 & (PSW2_MA9|PSW2_MA5X0))) && /* master prot? */ + (mmc_acc[vpag] >= acc)) /* access viol? */ + return map_viol (bva, *bpa, TR_MPR); + } +else *bpa = bva; /* no, physical */ +if ((acc == VW) && PSW2_WLK) { /* write check? */ + uint32 ppag = BPA_GETPAG (*bpa); /* phys page num */ + if (PSW2_WLK && mmc_wlk[ppag] && /* lock, key != 0 */ + (PSW2_WLK != mmc_wlk[ppag])) /* lock != key? */ + return map_viol (bva, *bpa, TR_WLK); + } +if (BPA_IS_NXM (*bpa)) /* memory exist? */ + return TR_NXM; /* don't set TSF */ +return 0; +} + +/* Memory management error */ + +uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr) +{ +uint32 vpag = BVA_GETPAG (bva); /* virt page num */ + +if (QCPU_S9) /* Sigma 9? */ + PSW2 = (PSW2 & ~PSW2_TSF) | (vpag << PSW2_V_TSF); /* save address */ +PSW4 = bva >> 2; /* 5X0 address */ +if ((tr == TR_WLK) && !QCPU_5X0) /* wlock on S5-9? */ + tr = TR_MPR; /* mem prot trap */ +if (BPA_IS_NXM (bpa)) /* also check NXM */ + tr |= TR_NXM; /* on MPR or WLK */ +return tr; +} + +/* Physical byte access routines */ + +uint32 ReadPB (uint32 ba, uint32 *wd) +{ +uint32 sc; + +ba = ba & BPAMASK; +if (BPA_IS_NXM (ba)) + return TR_NXM; +sc = 24 - ((ba & 3) << 3); +*wd = (M[ba >> 2] >> sc) & BMASK; +return 0; +} + +uint32 WritePB (uint32 ba, uint32 wd) +{ +uint32 sc; + +ba = ba & BPAMASK; +if (BPA_IS_NXM (ba)) + return TR_NXM; +sc = 24 - ((ba & 3) << 3); +M[ba >> 2] = (M[ba >> 2] & ~(BMASK << sc)) | ((wd & BMASK) << sc); +return 0; +} + +/* Physical word access routines */ + +uint32 ReadPW (uint32 pa, uint32 *wd) +{ +pa = pa & cpu_tab[cpu_model].pamask; +if (MEM_IS_NXM (pa)) + return TR_NXM; +*wd = M[pa]; +return 0; +} + +uint32 WritePW (uint32 pa, uint32 wd) +{ +pa = pa & cpu_tab[cpu_model].pamask; +if (MEM_IS_NXM (pa)) + return TR_NXM; +M[pa] = wd; +return 0; +} + +/* LRA - load real address (extended memory systems only) */ + +uint32 map_lra (uint32 rn, uint32 IR) +{ +uint32 lnt, bva, bpa, vpag, ppag; +uint32 tr; + +lnt = CC >> 2; /* length */ +CC = 0; /* clear */ +if ((tr = Ea (IR, &bva, VR, lnt)) != 0) { /* get eff addr */ + if (tr == TR_NXM) /* NXM trap? */ + CC = CC1|CC2; + R[rn] = bva >> 2; /* fails */ + } +else if (bva < BVA_REG) { /* reg ref? */ + CC = CC1|CC2; + R[rn] = bva >> 2; /* fails */ + } +else { + vpag = BVA_GETPAG (bva); /* virt page num */ + bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK; + ppag = BPA_GETPAG (bpa); /* phys page num */ + if (MEM_IS_NXM (bpa)) /* NXM? */ + CC = CC1|CC2; + R[rn] = (QCPU_S9? (mmc_wlk[ppag] << 24): 0) | /* result */ + (bpa >> lnt); + CC |= mmc_acc[vpag]; /* access prot */ + } +return 0; +} + +/* MMC - load memory map control */ + +uint32 map_mmc (uint32 rn, uint32 map) +{ +uint32 tr; +uint32 wd, i, map_width, maps_per_word, map_cmask, cs; + +map_width = mmc_tab[map].width; /* width in bits */ +maps_per_word = 32 / map_width; +if (map != 1) /* maps 2-7? */ + map_cmask = mmc_tab[map].cmask; /* std ctl mask */ +else map_cmask = cpu_tab[cpu_model].mmc_cm_map1; /* model based */ +if ((map_width == 0) || /* validate map */ + ((cpu_unit.flags & mmc_tab[map].opt) == 0) || + ((map == 3) && !QCPU_5X0) || + ((map == 5) && !QCPU_BIGM)) { + if (QCPU_S89_5X0) /* S89, 5X0 trap */ + return TR_INVMMC; + return stop_op? STOP_ILLEG: 0; + } +do { + cs = (R[rn|1] >> MMC_V_CS) & map_cmask; /* ptr into map */ + if ((tr = ReadW ((R[rn] << 2) & BVAMASK, &wd, VR)) != 0) + return tr; + for (i = 0; i < maps_per_word; i++) { /* loop thru word */ + wd = ((wd << map_width) | (wd >> (32 - map_width))) & WMASK; + switch (map) { + + case 1: case 3: /* write locks */ + mmc_wlk[cs] = wd & mmc_tab[map].dmask; + break; + + case 2: /* access ctls */ + mmc_acc[cs] = wd & mmc_tab[map].dmask; + break; + + case 4: case 5: /* relocation */ + mmc_rel[cs] = wd & mmc_tab[map].dmask; + break; + }; + cs = (cs + 1) % mmc_tab[map].lnt; /* incr mod lnt */ + } /* end for */ + R[rn] = (R[rn] + 1) & WMASK; /* incr mem ptr */ + R[rn|1] = (R[rn|1] & ~(MMC_CNT | (map_cmask << MMC_V_CS))) | + (((MMC_GETCNT (R[rn|1]) - 1) & MMC_M_CNT) << MMC_V_CNT) | + ((cs & map_cmask) << MMC_V_CS); + } while (MMC_GETCNT (R[rn|1]) != 0); +return SCPE_OK; +} + +/* LAS instruction (reused by LMS), without condition code settings */ + +uint32 map_las (uint32 rn, uint32 bva) +{ +uint32 opnd, tr; + +if ((bva < (RF_NUM << 2)) && QCPU_5X0) /* on 5X0, reg */ + ReadW (bva, &opnd, VR); /* refs ignored */ +else { /* go to mem */ + if ((tr = ReadMemVW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if ((tr = WriteMemVW (bva, opnd | WSIGN, VW)) != 0) /* set bit */ + return tr; + } +R[rn] = opnd; /* store */ +return 0; +} + +/* Load memory status */ + +uint32 map_lms (uint32 rn, uint32 bva) +{ +uint32 tr, wd, low, ppag; +uint32 memu = (bva >> 2) / CPU_MUNIT_SIZE; + +if (CC == 0) /* LAS */ + return map_las (rn, bva); +if (CC == 1) { /* read no par */ + if ((tr = ReadW (bva, &wd, PH)) != 0) + return tr; + R[rn] = wd; + for (CC = CC3; wd != 0; CC ^= CC3) { /* calc odd par */ + low = wd & -((int32) wd); + wd = wd & ~low; + } + return 0; + } + +ppag = BPA_GETPAG (bva); /* phys page num */ +wd = mem_sr0[memu]; /* save sr0 */ +if (QCPU_S89) + switch (CC) { /* Sigma 8-9 */ + case 0x2: /* read bad par */ + if ((tr = ReadW (bva, &wd, VR)) != 0) + return tr; + R[rn] = wd; + break; + case 0x7: /* set margins */ + mem_sr1[memu] = S89_SR1_FIXED | + ((memu & S89_SR1_M_MEMU) << S89_SR1_V_MEMU) | + ((R[rn] & S89_SR1_MARG) >> S89_SR1_MAROFF); + break; + case 0xB: /* read sr0, clr */ + mem_sr0[memu] = mem_sr1[memu] = 0; + case 0x8: /* read sr0 */ + R[rn] = (wd & S89_SR0_RD) | + (((1u << (chan_num + 1)) - 1) << (S89_SR0_V_PORTS - (chan_num + 1))); + break; + case 0x9: /* read sr1 */ + R[rn] = mem_sr1[memu]; + break; + case 0xA: case 0xE: /* read sr2 */ + R[rn] = 0; + break; + case 0xF: /* clear word */ + return WriteW (bva, 0, VW); + break; + default: + mem_sr0[memu] |= S89_SR0_BADLMS; + break; + } +else switch (CC) { /* 5X0 */ + case 0x2: /* clear word */ + return WriteW (bva, 0, VW); + case 0x6: /* read wlk */ + R[rn] = (mmc_wlk[ppag & ~1] << 4) | mmc_wlk[ppag | 1]; + break; + case 0x7: /* write wlk */ + mmc_wlk[ppag & ~1] = (R[rn] >> 4) & 0xF; + mmc_wlk[ppag | 1] = R[rn] & 0xF; + break; + case 0xC: /* read sr0, clr */ + mem_sr0[memu] = 0; + case 0x8: /* read sr0 */ + R[rn] = S5X0_SR0_FIXED | (wd & S5X0_SR0_RD) | + (((1u << (chan_num + 1)) - 1) << (S5X0_SR0_V_PORTS - (chan_num + 1))); + break; + case 0xA: /* read sr1 */ + R[rn] = S5X0_SR1_FIXED | + ((memu & S5X0_SR1_M_MEMU) << S5X0_SR1_V_MEMU) | + (memu << S5X0_SR1_V_SA); + break; + case 0xE: /* trash mem */ + return WriteW (bva, R[rn] & ~0xFF, VW); + default: + mem_sr0[memu] |= S5X0_SR0_BADLMS; + break; + } +return 0; +} + +/* Device reset */ + +t_stat map_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < VA_NUM_PAG; i++) { /* clear mmc arrays */ + mmc_rel[i] = 0; + mmc_acc[i] = 0; + } +for (i = 0; i < PA_NUM_PAG; i++) + mmc_wlk[i] = 0; +return SCPE_OK; +} diff --git a/sigma/sigma_mt.c b/sigma/sigma_mt.c new file mode 100644 index 00000000..7e3e9f35 --- /dev/null +++ b/sigma/sigma_mt.c @@ -0,0 +1,645 @@ +/* sigma_mt.c: Sigma 732X 9-track magnetic tape + + Copyright (c) 2007-2008, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + mt 7320 and 7322/7323 magnetic tape + + Magnetic tapes are represented as a series of variable records + of the form: + + 32b byte count + byte 0 + byte 1 + : + byte n-2 + byte n-1 + 32 byte count + + If the byte count is odd, the record is padded with an extra byte + of junk. File marks are represented by a byte count of 0. +*/ + +#include "sigma_io_defs.h" +#include "sim_tape.h" + +/* Device definitions */ + +#define MT_NUMDR 8 /* #drives */ +#define MT_REW (MT_NUMDR) /* rewind threads */ +#define UST u3 /* unit status */ +#define UCMD u4 /* unit command */ +#define MT_MAXFR (1 << 16) /* max record lnt */ + +/* Unit commands */ + +#define MCM_INIT 0x100 +#define MCM_END 0x101 +#define MCM_WRITE 0x01 +#define MCM_READ 0x02 +#define MCM_SETC 0x03 +#define MCM_SENSE 0x04 +#define MCM_RDBK 0x0C +#define MCM_RWI 0x13 +#define MCM_RWU 0x23 +#define MCM_REW 0x33 +#define MCM_SFWR 0x43 +#define MCM_SBKR 0x4B +#define MCM_SFWF 0x53 +#define MCM_SBKF 0x5B +#define MCM_ERS 0x63 +#define MCM_WTM 0x73 + +/* Command flags */ + +#define O_ATT 0x01 /* req attached */ +#define O_WRE 0x02 /* req write enb */ +#define O_REV 0x04 /* reverse oper */ +#define O_NMT 0x10 /* no motion */ + +/* Device status in UST, ^ = dynamic */ + +#define MTDV_OVR 0x80 /* overrun - NI */ +#define MTDV_WRE 0x40 /* write enabled^ */ +#define MTDV_WLE 0x20 /* write lock err */ +#define MTDV_EOF 0x10 /* end of file */ +#define MTDV_DTE 0x08 /* data error */ +#define MTDV_BOT 0x04 /* begin of tape */ +#define MTDV_EOT 0x02 /* end of tape^ */ +#define MTDV_REW 0x01 /* rewinding^ */ + +#define MTAI_MASK (MTDV_OVR|MTDV_WLE|MTDV_EOF|MTDV_DTE) +#define MTAI_V_INT 6 +#define MTAI_INT (1u << MTAI_V_INT) + +uint32 mt_stopioe = 1; +int32 mt_rwtime = 10000; /* rewind latency */ +int32 mt_ctime = 100; /* command latency */ +int32 mt_time = 10; /* record latency */ +uint32 mt_rwi = 0; /* rewind interrupts */ +t_mtrlnt mt_bptr; +t_mtrlnt mt_blim; +uint8 mt_xb[MT_MAXFR]; /* transfer buffer */ +uint8 mt_op[128] = { + 0, O_ATT|O_WRE, O_ATT, O_NMT, O_NMT, 0, 0, 0, /* wr, rd, set, sense */ + 0, 0, 0, 0, O_ATT|O_REV, 0, 0, 0, /* rd rev */ + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind & int */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind offline */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* space fwd rec */ + 0, 0, 0, O_ATT|O_REV, 0, 0, 0, 0, /* space bk rec */ + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* space fwd file */ + 0, 0, 0, O_ATT|O_REV, 0, 0, 0, 0, /* space bk file */ + 0, 0, 0, O_NMT, 0, 0, 0, 0, /* set erase */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT|O_WRE, 0, 0, 0, 0, /* write tmk */ + 0, 0, 0, 0, 0, 0, 0, 0 + }; + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 mt_tio_status (uint32 un); +uint32 mt_tdv_status (uint32 un); +t_stat mt_chan_err (uint32 st); +t_stat mtu_svc (UNIT *uptr); +t_stat mtr_svc (UNIT *uptr); +t_stat mt_reset (DEVICE *dptr); +t_stat mt_attach (UNIT *uptr, char *cptr); +t_stat mt_detach (UNIT *uptr); +t_stat mt_flush_buf (uptr); +t_stat mt_map_err (UNIT *uptr, t_stat r); +int32 mt_clr_int (uint32 dva); +void mt_set_rwi (uint32 un); +void mt_clr_rwi (uint32 un); + +/* MT data structures + + mt_dev MT device descriptor + mt_unit MT unit descriptors + mt_reg MT register list + mt_mod MT modifiers list +*/ + +dib_t mt_dib = { DVA_MT, mt_disp }; + +/* First 'n' units are tape drives; second 'n' are rewind threads */ + +UNIT mt_unit[] = { + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) } + }; + +REG mt_reg[] = { + { BRDATA (BUF, mt_xb, 16, 8, MT_MAXFR) }, + { DRDATA (BPTR, mt_bptr, 17) }, + { DRDATA (BLNT, mt_blim, 17) }, + { HRDATA (RWINT, mt_rwi, MT_NUMDR) }, + { DRDATA (TIME, mt_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (CTIME, mt_ctime, 24), PV_LEFT+REG_NZ }, + { DRDATA (RWTIME, mt_rwtime, 24), PV_LEFT+REG_NZ }, + { URDATA (UST, mt_unit[0].UST, 16, 8, 0, MT_NUMDR, 0) }, + { URDATA (UCMD, mt_unit[0].UCMD, 16, 8, 0, 2 * MT_NUMDR, 0) }, + { URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0, + MT_NUMDR, PV_LEFT | REG_RO) }, + { FLDATA (STOP_IOE, mt_stopioe, 0) }, + { HRDATA (DEVNO, mt_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB mt_mod[] = { + { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", + &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, + { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", + &sim_tape_set_capac, &sim_tape_show_capac, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE mt_dev = { + "MT", mt_unit, mt_reg, mt_mod, + MT_NUMDR * 2, 10, T_ADDR_W, 1, 16, 8, + NULL, NULL, &mt_reset, + &io_boot, &mt_attach, &mt_detach, + &mt_dib, DEV_DISABLE + }; + +/* Magtape: IO dispatch routine */ + +uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr = &mt_unit[un]; + +if ((un >= MT_NUMDR) || /* inv unit num? */ + (uptr-> flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = mt_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + uptr->UCMD = MCM_INIT; /* start dev thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = mt_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = mt_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = mt_tio_status (un); /* get status */ + if ((int32) un == chan_chk_chi (dva)) /* halt active ctlr int? */ + chan_clr_chi (dva); /* clear ctlr int */ + if (sim_is_active (uptr)) { /* chan active? */ + sim_cancel (uptr); /* stop unit */ + chan_uen (dva); /* uend */ + } + mt_clr_rwi (un); /* clear rewind int */ + sim_cancel (uptr + MT_REW); /* cancel rewind */ + break; + + case OP_AIO: /* acknowledge int */ + un = mt_clr_int (mt_dib.dva); /* clr int, get unit */ + *dvst = (mt_tdv_status (un) & MTAI_MASK) | /* device status */ + (un & MTAI_INT) | /* device int flag */ + ((un & DVA_M_UNIT) << DVT_V_UN); /* unit number */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat mtu_svc (UNIT *uptr) +{ +uint32 cmd = uptr->UCMD; +uint32 un = uptr - mt_unit; +uint32 c; +uint32 st; +int32 t; +t_mtrlnt tbc; +t_stat r; + +if (cmd == MCM_INIT) { /* init state */ + if ((t = sim_is_active (uptr + MT_REW)) != 0) { /* rewinding? */ + sim_activate (uptr, t); /* retry later */ + return SCPE_OK; + } + st = chan_get_cmd (mt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((cmd & 0x80) || /* invalid cmd? */ + (mt_op[cmd] == 0)) { + uptr->UCMD = MCM_END; /* end state */ + sim_activate (uptr, chan_ctl_time); /* resched ctlr */ + return SCPE_OK; + } + else { /* valid cmd */ + if ((mt_op[cmd] & O_REV) && /* reverse op */ + (mt_unit[un].UST & MTDV_BOT)) { /* at load point? */ + chan_uen (mt_dib.dva); /* channel end */ + return SCPE_OK; + } + uptr->UCMD = cmd; /* unit state */ + if (!(mt_op[cmd] & O_NMT)) /* motion? */ + uptr->UST = 0; /* clear status */ + } + mt_blim = 0; /* no buffer yet */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + return SCPE_OK; /* done */ + } + +if (cmd == MCM_END) { /* end state */ + st = chan_end (mt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + uptr->UCMD = MCM_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + else uptr->UCMD = 0; /* ctlr idle */ + return SCPE_OK; /* done */ + } + +if ((mt_op[cmd] & O_ATT) && /* op req att and */ + ((uptr->flags & UNIT_ATT) == 0)) { /* not attached? */ + sim_activate (uptr, mt_ctime); /* retry */ + return mt_stopioe? SCPE_UNATT: SCPE_OK; + } +if ((mt_op[cmd] & O_WRE) && /* write op and */ + sim_tape_wrp (uptr)) { /* write protected? */ + uptr->UST |= MTDV_WLE; /* set status */ + chan_uen (mt_dib.dva); /* unusual end */ + return SCPE_OK; + } + +r = SCPE_OK; +switch (cmd) { /* case on command */ + + case MCM_SFWR: /* space forward */ + if (r = sim_tape_sprecf (uptr, &tbc)) /* spc rec fwd, err? */ + r = mt_map_err (uptr, r); /* map error */ + break; + + case MCM_SBKR: /* space reverse */ + if (r = sim_tape_sprecr (uptr, &tbc)) /* spc rec rev, err? */ + r = mt_map_err (uptr, r); /* map error */ + break; + + case MCM_SFWF: /* space fwd file */ + while ((r = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; + if (r != MTSE_TMK) /* stopped by tmk? */ + r = mt_map_err (uptr, r); /* no, map error */ + else r = SCPE_OK; + break; + + case MCM_SBKF: /* space rev file */ + while ((r = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; + if (r != MTSE_TMK) /* stopped by tmk? */ + r = mt_map_err (uptr, r); /* no, map error */ + else r = SCPE_OK; + break; + + case MCM_WTM: /* write eof */ + if (r = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + r = mt_map_err (uptr, r); /* map error */ + uptr->UST |= MTDV_EOF; /* set eof */ + break; + + case MCM_RWU: /* rewind unload */ + r = detach_unit (uptr); + break; + + case MCM_REW: /* rewind */ + case MCM_RWI: /* rewind and int */ + if (r = sim_tape_rewind (uptr)) /* rewind */ + r = mt_map_err (uptr, r); /* map error */ + mt_unit[un + MT_REW].UCMD = uptr->UCMD; /* copy command */ + sim_activate (uptr + MT_REW, mt_rwtime); /* sched compl */ + break; + + case MCM_READ: /* read */ + if (mt_blim == 0) { /* first read? */ + r = sim_tape_rdrecf (uptr, mt_xb, &mt_blim, MT_MAXFR); + if (r != MTSE_OK) { /* tape error? */ + r = mt_map_err (uptr, r); /* map error */ + break; + } + mt_bptr = 0; /* init rec ptr */ + } + c = mt_xb[mt_bptr++]; /* get char */ + st = chan_WrMemB (mt_dib.dva, c); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((st != CHS_ZBC) && (mt_bptr != mt_blim)) { /* not done? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + if (((st == CHS_ZBC) ^ (mt_bptr == mt_blim)) && /* length err? */ + chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ + return SCPE_OK; /* finished */ + break; /* normal end */ + + case MCM_RDBK: /* read reverse */ + if (mt_blim == 0) { /* first read? */ + r = sim_tape_rdrecr (uptr, mt_xb, &mt_blim, MT_MAXFR); + if (r != MTSE_OK) { /* tape error? */ + r = mt_map_err (uptr, r); /* map error */ + break; + } + mt_bptr = mt_blim; /* init rec ptr */ + } + c = mt_xb[--mt_bptr]; /* get char */ + st = chan_WrMemBR (mt_dib.dva, c); /* write mem rev */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((st != CHS_ZBC) && (mt_bptr != 0)) { /* not done? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + if (((st == CHS_ZBC) ^ (mt_bptr == 0)) && /* length err? */ + chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ + return SCPE_OK; /* finished */ + break; /* normal end */ + + case MCM_WRITE: /* write */ + st = chan_RdMemB (mt_dib.dva, &c); /* read char */ + if (CHS_IFERR (st)) { /* channel error? */ + mt_flush_buf (uptr); /* flush buffer */ + return mt_chan_err (st); + } + mt_xb[mt_blim++] = c; /* store in buffer */ + if (st != CHS_ZBC) { /* end record? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + r = mt_flush_buf (uptr); /* flush buffer */ + break; + } + +if (r != SCPE_OK) /* error? abort */ + return CHS_IFERR(r)? SCPE_OK: r; +uptr->UCMD = MCM_END; /* end state */ +sim_activate (uptr, mt_ctime); /* sched ctlr */ +return SCPE_OK; +} + +/* Rewind completion - set BOT, interrupt if desired */ + +t_stat mtr_svc (UNIT *uptr) +{ +uint32 un = uptr - mt_unit - MT_REW; + +mt_unit[un].UST |= MTDV_BOT; /* set BOT */ +if (uptr->UCMD == MCM_RWI) /* int wanted? */ + mt_set_rwi (un); /* interrupt */ +return SCPE_OK; +} + +t_stat mt_flush_buf (UNIT *uptr) +{ +t_stat st; + +if (mt_blim == 0) /* any output? */ + return SCPE_OK; +if (st = sim_tape_wrrecf (uptr, mt_xb, mt_blim)) /* write, err? */ + return mt_map_err (uptr, st); /* map error */ +return SCPE_OK; +} + +/* Map tape error status - returns chan error or SCP status */ + +t_stat mt_map_err (UNIT *uptr, t_stat st) +{ +int32 u = uptr - mt_dev.units; + +switch (st) { + + case MTSE_FMT: /* illegal fmt */ + case MTSE_UNATT: /* not attached */ + case MTSE_WRP: /* write protect */ + chan_set_chf (mt_dib.dva, CHF_XMME); + case MTSE_OK: /* no error */ + chan_uen (mt_dib.dva); /* uend */ + return SCPE_IERR; + + case MTSE_TMK: /* end of file */ + uptr->UST |= MTDV_EOF; /* set eof flag */ + chan_uen (mt_dib.dva); /* uend */ + return CHS_INACTV; + + case MTSE_IOERR: /* IO error */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + chan_set_chf (mt_dib.dva, CHF_XMDE); + chan_uen (mt_dib.dva); /* force uend */ + return SCPE_IOERR; + + case MTSE_INVRL: /* invalid rec lnt */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + chan_set_chf (mt_dib.dva, CHF_XMDE); + chan_uen (mt_dib.dva); /* force uend */ + return SCPE_MTRLNT; + + case MTSE_RECE: /* record in error */ + case MTSE_EOM: /* end of medium */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + return chan_set_chf (mt_dib.dva, CHF_XMDE); /* possible error */ + + case MTSE_BOT: /* reverse into BOT */ + uptr->UST |= MTDV_BOT; /* set BOT */ + chan_uen (mt_dib.dva); /* uend */ + return CHS_INACTV; + } /* end switch */ + +return SCPE_OK; +} + +/* MT status routine */ + +uint32 mt_tio_status (uint32 un) +{ +uint32 i, st; +UNIT *uptr = &mt_unit[un]; + +st = (uptr->flags & UNIT_ATT)? DVS_AUTO: 0; /* AUTO */ +if (sim_is_active (uptr) || /* unit busy */ + sim_is_active (uptr + MT_REW)) /* or rewinding? */ + st |= DVS_DBUSY; +for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&mt_unit[i])) { /* active? */ + st |= (DVS_CBUSY | (CC2 << DVT_V_CC)); /* ctrl is busy */ + } + } +return st; +} + +uint32 mt_tdv_status (uint32 un) +{ +uint32 st; +UNIT *uptr = &mt_unit[un]; + +if (uptr->flags & UNIT_ATT) { /* attached? */ + st = uptr->UST; /* unit stat */ + if (sim_tape_eot (uptr)) /* at EOT? */ + st |= MTDV_EOT; + if (!sim_tape_wrp (uptr)) /* not wlock? */ + st |= MTDV_WRE; + } +else st = (CC2 << DVT_V_CC); +if (sim_is_active (uptr + MT_REW)) /* unit rewinding? */ + st |= (MTDV_REW | (CC2 << DVT_V_CC)); +return st; +} + + +/* Channel error */ + +t_stat mt_chan_err (uint32 st) +{ +chan_uen (mt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Clear controller/device interrupt, return active unit */ + +int32 mt_clr_int (uint32 dva) +{ +int32 iu; + +if ((iu = chan_clr_chi (dva)) >= 0) { /* chan int? clear */ + if (mt_rwi != 0) /* dev ints? */ + chan_set_dvi (dva); /* set them */ + return iu; + } +for (iu = 0; iu < MT_NUMDR; iu++) { /* rewind int? */ + if (mt_rwi & (1u << iu)) { + mt_clr_rwi ((uint32) iu); + return (iu | MTAI_INT); + } + } +return 0; +} + +/* Set rewind interrupt */ + +void mt_set_rwi (uint32 un) +{ +mt_rwi |= (1u << un); +chan_set_dvi (mt_dib.dva); /* set INP */ +return; +} + +/* Clear rewind interrupt */ + +void mt_clr_rwi (uint32 un) +{ +mt_rwi &= ~(1u << un); /* clear */ +if (mt_rwi != 0) /* more? */ + chan_set_dvi (mt_dib.dva); +else if (chan_chk_chi (mt_dib.dva) < 0) /* any int? */ + chan_clr_chi (mt_dib.dva); /* clr INP */ +return; +} + +/* Reset routine */ + +t_stat mt_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < MT_NUMDR; i++) { + sim_cancel (&mt_unit[i]); /* stop unit */ + sim_cancel (&mt_unit[i + MT_REW]); /* stop rewind */ + mt_unit[i].UST = 0; + mt_unit[i].UCMD = 0; + } +mt_rwi = 0; +mt_bptr = 0; +mt_blim = 0; +chan_reset_dev (mt_dib.dva); /* clr int, active */ +for (i = 0; i < MT_MAXFR; i++) + mt_xb[i] = 0; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat mt_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = sim_tape_attach (uptr, cptr); +if (r != SCPE_OK) return r; +uptr->UST = MTDV_BOT; +return r; +} + +/* Detach routine */ + +t_stat mt_detach (UNIT* uptr) +{ +uint32 un = uptr - mt_dev.units; + +uptr->UST = 0; +sim_cancel (uptr + MT_REW); +return sim_tape_detach (uptr); +} \ No newline at end of file diff --git a/sigma/sigma_pt.c b/sigma/sigma_pt.c new file mode 100644 index 00000000..f5507f6b --- /dev/null +++ b/sigma/sigma_pt.c @@ -0,0 +1,297 @@ +/* sigma_pt.c: Sigma 7060 paper tape reader/punch + + Copyright (c) 2007-2008, Robert 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. + + pt 7060 paper-tape reader/punch +*/ + +#include "sigma_io_defs.h" + +/* Device definitions */ + +#define PTR 0 +#define PTP 1 + +/* Device states */ + +#define PTS_INIT 0x101 +#define PTS_END 0x102 +#define PTS_WRITE 0x1 +#define PTS_READ 0x2 +#define PTS_READI 0x82 + +/* Device status */ + +#define PTDV_PMAN 0x20 +#define PTDV_RMAN 0x10 + +uint32 pt_cmd = 0; +uint32 ptr_nzc = 0; +uint32 ptr_stopioe = 1; +uint32 ptp_stopioe = 1; + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 pt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 pt_tio_status (void); +uint32 pt_tdv_status (void); +t_stat pt_chan_err (uint32 st); +t_stat pt_svc (UNIT *uptr); +t_stat pt_reset (DEVICE *dptr); +t_stat pt_attach (UNIT *uptr, char *cptr); + +/* PT data structures + + pt_dev PT device descriptor + pt_unit PT unit descriptors + pt_reg PT register list + pt_mod PT modifiers list +*/ + +dib_t pt_dib = { DVA_PT, pt_disp }; + +UNIT pt_unit[] = { + { UDATA (&pt_svc, UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE, 0), SERIAL_IN_WAIT }, + { UDATA (&pt_svc, UNIT_ATTABLE+UNIT_SEQ, 0), SERIAL_OUT_WAIT } + }; + +REG pt_reg[] = { + { HRDATA (CMD, pt_cmd, 9) }, + { FLDATA (NZC, ptr_nzc,0) }, + { DRDATA (RPOS, pt_unit[PTR].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (RTIME, pt_unit[PTR].wait, 24), PV_LEFT }, + { FLDATA (RSTOP_IOE, ptr_stopioe, 0) }, + { DRDATA (PPOS, pt_unit[PTP].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (PTIME, pt_unit[PTP].wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (PSTOP_IOE, ptp_stopioe, 0) }, + { HRDATA (DEVNO, pt_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB pt_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE pt_dev = { + "PT", pt_unit, pt_reg, pt_mod, + 2, 10, 31, 1, 16, 8, + NULL, NULL, &pt_reset, + &io_boot, &pt_attach, NULL, + &pt_dib, DEV_DISABLE + }; + +/* Reader/punch: IO dispatch routine */ + +uint32 pt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = pt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + pt_cmd = PTS_INIT; /* start dev thread */ + sim_activate (&pt_unit[PTR], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = pt_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = pt_tdv_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (pt_dib.dva); /* clr int*/ + *dvst = pt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&pt_unit[PTR]); /* stop dev thread */ + chan_uen (pt_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (pt_dib.dva); /* clr int*/ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Service routine */ + +t_stat pt_svc (UNIT *uptr) +{ +int32 c; +uint32 cmd; +uint32 st; + +switch (pt_cmd) { /* case on state */ + + case PTS_INIT: /* I/O init */ + st = chan_get_cmd (pt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if ((cmd == PTS_WRITE) || /* valid command? */ + ((cmd & 0x7F) == PTS_READ)) + pt_cmd = cmd; /* next state */ + else pt_cmd = PTS_END; /* no, end state */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case PTS_READ: + case PTS_READI: + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return ptr_stopioe? SCPE_UNATT: SCPE_OK; + if ((c = getc (uptr->fileref)) == EOF) { /* read char */ + if (feof (uptr->fileref)) { /* end of file? */ + chan_set_chf (pt_dib.dva, CHF_LNTE); /* length error */ + pt_cmd = PTS_END; /* end state */ + break; + } + else { /* real error */ + perror ("PTR I/O error"); + clearerr (uptr->fileref); + chan_set_chf (pt_dib.dva, CHF_XMDE); /* data error */ + return pt_chan_err (SCPE_IOERR); /* force uend */ + } + } + uptr->pos = uptr->pos + 1; + if (c != 0) /* leader done? */ + ptr_nzc = 1; /* set flag */ + if ((pt_cmd == PTS_READI) || ptr_nzc) { + st = chan_WrMemB (pt_dib.dva, c); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (st == CHS_ZBC) /* bc == 0? */ + pt_cmd = PTS_END; /* end state */ + } + break; + + case PTS_WRITE: /* write */ + sim_activate (uptr, pt_unit[PTP].wait); /* continue thread */ + if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* not attached? */ + return ptp_stopioe? SCPE_UNATT: SCPE_OK; + st = chan_RdMemB (pt_dib.dva, &c); /* read from channel */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (putc (c, pt_unit[PTP].fileref) == EOF) { + perror ("PTP I/O error"); + clearerr (pt_unit[PTP].fileref); + chan_set_chf (pt_dib.dva, CHF_XMDE); /* data error */ + return pt_chan_err (SCPE_IOERR); /* force uend */ + } + pt_unit[PTP].pos = pt_unit[PTP].pos + 1; + if (st == CHS_ZBC) /* bc == 0? */ + pt_cmd = PTS_END; /* end state */ + break; + + case PTS_END: /* command done */ + st = chan_end (pt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + pt_cmd = PTS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + } + +return SCPE_OK; +} + +/* PT status routine */ + +uint32 pt_tio_status (void) +{ +uint32 st; + +if (((pt_unit[PTR].flags & UNIT_ATT) == 0) || /* rdr not att? */ + ((pt_unit[PTP].flags & UNIT_ATT) == 0)) /* pun not att? */ + st = 0; +else st = DVS_AUTO; /* otherwise ok */ +if (sim_is_active (&pt_unit[PTR])) /* dev busy? */ + st |= (DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC)); +return st; +} + +uint32 pt_tdv_status (void) +{ +uint32 st; + +st = 0; +if ((pt_unit[PTR].flags & UNIT_ATT) == 0) /* rdr not att? */ + st |= PTDV_RMAN; +if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* pun not att? */ + st |= PTDV_PMAN; +return st; +} + +/* Channel error */ + +t_stat pt_chan_err (uint32 st) +{ +sim_cancel (&pt_unit[PTR]); /* stop dev thread */ +chan_uen (pt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat pt_reset (DEVICE *dptr) +{ +sim_cancel (&pt_unit[PTR]); /* stop dev thread */ +pt_cmd = 0; +chan_reset_dev (pt_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Attach routine */ + +t_stat pt_attach (UNIT *uptr, char *cptr) +{ +t_stat st; + +st = attach_unit (uptr, cptr); +if ((uptr == &pt_unit[PTR]) && (st == SCPE_OK)) + ptr_nzc = 0; +return st; +} \ No newline at end of file diff --git a/sigma/sigma_rad.c b/sigma/sigma_rad.c new file mode 100644 index 00000000..8ecdbd71 --- /dev/null +++ b/sigma/sigma_rad.c @@ -0,0 +1,532 @@ +/* sigma_rad.c: Sigma 7211/7212 or 7231/7232 fixed head disk simulator + + Copyright (c) 2007-2008, Robert 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. + + rad 7211/7212 or 7231/7232 fixed head disk + + The RAD is a head-per-track disk. To minimize overhead, the entire RAD + is buffered in memory. + + Transfers are always done a sector at a time. +*/ + +#include "sigma_io_defs.h" +#include + +/* Constants */ + +#define RAD_7212 0 /* ctlr type */ +#define RAD_7232 1 +#define RAD_NUMDR 4 /* drives/ctlr */ +#define RAD_WDSC 256 /* words/sector */ +#define RAD_WDMASK (RAD_WDSC - 1) +#define RAD_SCTK1 82 /* sectors/track */ +#define RAD_SCTK3 12 +#define RAD_TKUN1 64 /* tracks/unit */ +#define RAD_TKUN3 512 +#define RAD_WDUNDF (RAD_WDSC*RAD_SCTK1*RAD_TKUN1) /* dflt words/unit */ +#define RAD_WDUN (RAD_WDSC*rad_tab[rad_model].sctk*rad_tab[rad_model].tkun) +#define RAD_N_WLK 16 /* num wlk switches */ + +/* Address bytes */ + +#define RADA_V_TK1 7 /* track offset */ +#define RADA_M_TK1 0xFF +#define RADA_V_SC1 0 /* sector offset */ +#define RADA_M_SC1 0x7F +#define RADA_V_TK3 4 +#define RADA_M_TK3 0x3FF +#define RADA_V_SC3 0 +#define RADA_M_SC3 0xF +#define RADA_GETTK(x) (((x) >> rad_tab[rad_model].tk_v) & rad_tab[rad_model].tk_m) +#define RADA_GETSC(x) (((x) >> rad_tab[rad_model].sc_v) & rad_tab[rad_model].sc_m) + +/* Address bad flag */ + +#define RADA_INV 0x80 + +/* Status byte 3 is current sector */ +/* Status byte 4 (7212 only) is failing sector */ + +#define RADS_NBY1 4 /* num status bytes */ +#define RADS_NBY3 3 + +/* Device state */ + +#define RADS_INIT 0x101 +#define RADS_END 0x102 +#define RADS_WRITE 0x01 +#define RADS_READ 0x02 +#define RADS_SEEK 0x03 +#define RADS_SENSE 0x04 +#define RADS_CHECK 0x05 +#define RADS_RDEES 0x12 + +/* Device status */ + +#define RADV_OVR 0x80 /* overrun - NI */ +#define RADV_BADS 0x20 /* bad sector */ +#define RADV_WPE 0x10 + +#define GET_PSC(x) ((int32) fmod (sim_gtime() / ((double) (x * RAD_WDSC)), \ + ((double) rad_tab[rad_model].sctk))) + +/* Model table */ + +typedef struct { + uint32 tk_v; /* track extract */ + uint32 tk_m; + uint32 sc_v; /* sector extract */ + uint32 sc_m; + uint32 sctk; /* sectors/track */ + uint32 tkun; /* tracks/unit */ + uint32 nbys; /* bytes of status */ + } rad_t; + +static rad_t rad_tab[] = { + { RADA_V_TK1, RADA_M_TK1, RADA_V_SC1, RADA_M_SC1, RAD_SCTK1, RAD_TKUN1, RADS_NBY1 }, + { RADA_V_TK3, RADA_M_TK3, RADA_V_SC3, RADA_M_SC3, RAD_SCTK3, RAD_TKUN3, RADS_NBY3 } + }; + +uint32 rad_model = RAD_7212; /* model */ +uint32 rad_cmd = 0; /* state */ +uint32 rad_flags = 0; /* status flags */ +uint32 rad_ad = 0; /* rad address */ +uint32 rad_wlk = 0; /* write lock */ +uint32 rad_time = 2; /* inter-word time */ + +extern uint32 chan_ctl_time; + +uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 rad_tio_status (uint32 un); +uint32 rad_tdv_status (uint32 un); +t_stat rad_chan_err (uint32 st); +t_stat rad_svc (UNIT *uptr); +t_stat rad_reset (DEVICE *dptr); +t_stat rad_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); +t_bool rad_inv_ad (uint32 *da); +t_bool rad_inc_ad (void); +t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); + +/* RAD data structures + + rad_dev RAD device descriptor + rad_unit RAD unit descriptor + rad_reg RAD register list +*/ + +dib_t rad_dib = { DVA_RAD, &rad_disp }; + +UNIT rad_unit[] = { + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) } + }; + +REG rad_reg[] = { + { HRDATA (CMD, rad_cmd, 9) }, + { HRDATA (FLAGS, rad_flags, 8) }, + { HRDATA (ADDR, rad_ad, 15) }, + { HRDATA (WLK, rad_wlk, RAD_N_WLK) }, + { DRDATA (TIME, rad_time, 24), PV_LEFT }, + { FLDATA (MODEL, rad_model, 0), REG_HRO }, + { HRDATA (DEVNO, rad_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB rad_mod[] = { + { MTAB_XTD | MTAB_VDV, RAD_7212, NULL, "7211", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7212, NULL, "7212", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7232, NULL, "7231", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7232, NULL, "7232", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &rad_showtype, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE rad_dev = { + "RAD", rad_unit, rad_reg, rad_mod, + RAD_NUMDR, 16, 21, 1, 16, 32, + NULL, NULL, &rad_reset, + &io_boot, NULL, NULL, + &rad_dib, DEV_DISABLE + }; + +/* RAD: IO dispatch routine */ + +uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 i; +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr; + +if ((un >= RAD_NUMDR) || /* inv unit num? */ + (rad_unit[un].flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = rad_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + rad_cmd = RADS_INIT; /* start dev thread */ + sim_activate (&rad_unit[un], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = rad_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = rad_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (rad_dib.dva); /* clr int*/ + *dvst = rad_tio_status (un); /* get status */ + if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */ + for (i = 0; i < RAD_NUMDR; i++) { /* find busy unit */ + uptr = &rad_unit[i]; + if (sim_is_active (uptr)) { /* active? */ + sim_cancel (uptr); /* stop */ + chan_uen (rad_dib.dva); /* uend */ + } /* end if active */ + } /* end for */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (rad_dib.dva); /* clr int */ + *dvst = rad_tdv_status (0); /* status like TDV */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service - this code assumes the entire disk is buffered */ + +t_stat rad_svc (UNIT *uptr) +{ +uint32 i, sc, da, cmd, wd, wd1, c[4], gp; +uint32 *fbuf = (uint32 *) uptr->filebuf; +uint32 st; +int32 t; + +switch (rad_cmd) { + + case RADS_INIT: /* init state */ + st = chan_get_cmd (rad_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + if ((cmd == 0) || /* invalid cmd? */ + ((cmd > RADS_CHECK) && (cmd != RADS_RDEES))) { + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + rad_flags = 0; /* clear status */ + rad_cmd = cmd & 0x7; /* next state */ + if ((cmd == RADS_SEEK) || (cmd == RADS_SENSE)) /* seek or sense? */ + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = RADA_GETSC (rad_ad); /* new sector */ + t = sc - GET_PSC (rad_time); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + rad_tab[rad_model].sctk; + sim_activate (uptr, t * rad_time * RAD_WDSC); /* schedule op */ + } + return SCPE_OK; + + case RADS_END: /* end state */ + st = chan_end (rad_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + rad_cmd = RADS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + + case RADS_SEEK: /* seek */ + c[0] = c[1] = 0; + for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (rad_dib.dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + } + rad_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */ + if (((i != 2) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* care? */ + return SCPE_OK; + break; + + case RADS_SENSE: /* sense */ + c[0] = ((rad_ad >> 8) & 0x7F) | (rad_inv_ad (NULL)? RADA_INV: 0); + c[1] = rad_ad & 0xFF; /* address */ + c[2] = GET_PSC (rad_time); /* curr sector */ + c[3] = 0; + for (i = 0, st = 0; (i < rad_tab[rad_model].nbys) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (rad_dib.dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + } + if (((i != rad_tab[rad_model].nbys) || (st != CHS_ZBC)) && + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* length error? */ + return SCPE_OK; + break; + + case RADS_WRITE: /* write */ + gp = (RADA_GETSC (rad_ad) * RAD_N_WLK) / /* write lock group */ + rad_tab[rad_model].tkun; + if ((rad_wlk >> gp) & 1) { /* write lock set? */ + rad_flags |= RADV_WPE; /* set status */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } /* fall through */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < RAD_WDSC; da++, i++) { /* write */ + if (st != CHS_ZBC) { /* chan active? */ + st = chan_RdMemW (rad_dib.dva, &wd); /* get data */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + } + else wd = 0; + fbuf[da] = wd; /* store in buffer */ + if (da >= uptr->hwmark) /* update length */ + uptr->hwmark = da + 1; + } + if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */ + return SCPE_OK; + break; + +/* Must be done by bytes to get precise miscompare */ + + case RADS_CHECK: /* write check */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < (RAD_WDSC * 4)) && (st != CHS_ZBC); ) { + st = chan_RdMemB (rad_dib.dva, &wd); /* read sector */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + rad_inc_ad (); /* da increments */ + chan_set_chf (rad_dib.dva, CHF_XMDE); /* set xmt err flag */ + chan_uen (rad_dib.dva); /* force uend */ + return SCPE_OK; + } + da = da + ((++i % 4) == 0); /* every 4th byte */ + } + if (rad_end_sec (uptr, i, RAD_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; + break; + + case RADS_READ: /* read */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < RAD_WDSC) && (st != CHS_ZBC); da++, i++) { + st = chan_WrMemW (rad_dib.dva, fbuf[da]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + } + if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */ + return SCPE_OK; + break; + } + +rad_cmd = RADS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end disk - reschedule, return TRUE + case 2 - more to transfer, end disk - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +if (st != CHS_ZBC) { /* end record? */ + if (rad_inc_ad ()) /* inc addr, ovf? */ + chan_uen (rad_dib.dva); /* uend */ + else sim_activate (uptr, rad_time * 16); /* no, next sector */ + return TRUE; + } +rad_inc_ad (); /* just incr addr */ +if ((lnt != exp) && /* length error? */ + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* do we care? */ + return TRUE; +return FALSE; /* cmd done */ +} + +/* RAD status routine */ + +uint32 rad_tio_status (uint32 un) +{ +uint32 i, st; + +st = DVS_AUTO; /* flags */ +if (sim_is_active (&rad_unit[un])) /* active => busy */ + st |= DVS_DBUSY; +else if ((rad_unit[un].flags & UNIT_ATT) == 0) /* not att => offl */ + st |= DVS_DOFFL; +for (i = 0; i < RAD_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&rad_unit[i])) { /* active? */ + st |= (DVS_CBUSY |(CC2 << DVT_V_CC)); /* ctrl is busy */ + return st; + } + } +return st; +} + +uint32 rad_tdv_status (uint32 un) +{ +uint32 st; + +st = rad_flags; +if (rad_inv_ad (NULL)) /* bad address? */ + st |= RADV_BADS; +return st; +} + +/* Validate disk address */ + +t_bool rad_inv_ad (uint32 *da) +{ +uint32 tk = RADA_GETTK (rad_ad); +uint32 sc = RADA_GETSC (rad_ad); + +if ((tk >= rad_tab[rad_model].tkun) || /* bad sec or trk? */ + (sc >= rad_tab[rad_model].sctk)) { + return TRUE; + } +if (da) /* return word addr */ + *da = ((tk * rad_tab[rad_model].sctk) + sc) * RAD_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool rad_inc_ad (void) +{ +uint32 tk = RADA_GETTK (rad_ad); +uint32 sc = RADA_GETSC (rad_ad); + +sc = sc + 1; /* sector++ */ +if (sc >= rad_tab[rad_model].sctk) { /* overflow? */ + sc = 0; /* wrap sector */ + tk = tk + 1; /* track++ */ + } +rad_ad = ((tk << rad_tab[rad_model].tk_v) | /* rebuild rad_ad */ + (sc << rad_tab[rad_model].sc_v)); +if (tk >= rad_tab[rad_model].tkun) /* overflow? */ + return TRUE; +return FALSE; +} + +/* Channel error */ + +t_stat rad_chan_err (uint32 st) +{ +chan_uen (rad_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat rad_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < RAD_NUMDR; i++) + sim_cancel (&rad_unit[i]); /* stop dev thread */ +rad_cmd = 0; +rad_flags = 0; +rad_ad = 0; +chan_reset_dev (rad_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Set controller type */ + +t_stat rad_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 i; + +for (i = 0; i < RAD_NUMDR; i++) { /* all units unatt? */ + if (rad_unit[i].flags & UNIT_ATT) + return SCPE_ALATT; + } +rad_model = val; /* update model */ +rad_reset (&rad_dev); /* reset */ +for (i = 0; i < RAD_NUMDR; i++) /* update capacity */ + rad_unit[i].capac = RAD_WDUN; +return SCPE_OK; +} + +/* Show controller type */ + +t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, (rad_model == RAD_7212)? "7211/7212": "7231/7232"); +return SCPE_OK; +} diff --git a/sigma/sigma_rtc.c b/sigma/sigma_rtc.c new file mode 100644 index 00000000..34982fa3 --- /dev/null +++ b/sigma/sigma_rtc.c @@ -0,0 +1,267 @@ +/* sigma_rtc.c: Sigma clocks + + Copyright (c) 2007, Robert 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. + + rtc clocks + + The real-time clock includes an internal scheduler for events which need to + be driven at multiples of the clock frequency, such as console and multiplexor + polling. Other devices can "register" with the clock module to receive service + callbacks at a timed interval. This replaces the standard SimH event queue + mechanism for real-time synchronous events. +*/ + +#include "sigma_io_defs.h" + +#define RTC_HZ_BASE 500 +#define RTC_TICKS_DFLT 500 + +/* Timed events data structures */ + +uint8 rtc_indx[RTC_NUM_EVNTS]; /* index into rtc_tab */ +uint8 rtc_cntr[RTC_NUM_EVNTS]; /* timer ticks left */ +uint8 rtc_xtra[RTC_NUM_EVNTS]; /* extra counter */ +UNIT *rtc_usrv[RTC_NUM_EVNTS]; /* unit servers */ + +/* Real-time clock counter frequencies */ + +uint16 rtc_tps[RTC_NUM_CNTRS] = { + RTC_HZ_OFF, RTC_HZ_OFF, RTC_HZ_500, RTC_HZ_500 + }; + +/* Frequency descriptors. The base clock runs at 500Hz. To get submultiples, + an event uses a tick counter. If the frequency is not an even submultiple, the + event can specify an "extra" counter. Every "extra" ticks of the event counter, + the event counter is increased by one. Thus, 60Hz counts as 8-8-9, providing + 3 clock ticks for every 25 base timer ticks. */ + +typedef struct { + uint32 hz; + uint32 cntr_reset; + uint32 xtra_reset; + } rtcdef_t; + +static rtcdef_t rtc_tab[RTC_NUM_HZ] = { + { 0, 0, 0 }, + { 500, 1, 0 }, + { 50, 10, 0 }, + { 60, 8, 3 }, + { 100, 5, 0 }, + { 2, 250, 0 }, + }; + +t_stat rtc_svc (UNIT *uptr); +t_stat rtc_cntr_svc (UNIT *uptr); +t_stat rtc_reset (DEVICE *dptr); +t_stat rtc_show_events (FILE *of, UNIT *uptr, int32 val, void *desc); + +/* Clock data structures + + rtc_dev RTC device descriptor + rtc_unit RTC unit + rtc_reg RTC register list +*/ + +UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), RTC_TICKS_DFLT }; + +UNIT rtc_cntr_unit[RTC_NUM_CNTRS] = { + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) } + }; + +REG rtc_reg[] = { + { BRDATA (TPS, rtc_tps, 10, 10, RTC_NUM_CNTRS), REG_HRO }, + { BRDATA (INDX, rtc_indx, 10, 4, RTC_NUM_EVNTS), REG_HRO }, + { BRDATA (CNTR, rtc_cntr, 10, 6, RTC_NUM_EVNTS), REG_HRO }, + { BRDATA (XTRA, rtc_xtra, 10, 6, RTC_NUM_EVNTS), REG_HRO }, + { NULL } + }; + +MTAB rtc_mod[] = { + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C1, "C1", "C1", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C2, "C2", "C2", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C3, "C3", "C3", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C4, "C4", NULL, + NULL, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "EVENTS", NULL, + NULL, &rtc_show_events, NULL }, + { 0 } + }; + +DEVICE rtc_dev = { + "RTC", &rtc_unit, rtc_reg, rtc_mod, + 1, 16, 8, 1, 16, 8, + NULL, NULL, &rtc_reset, + NULL, NULL, NULL + }; + +/* Master timer service routine */ + +t_stat rtc_svc (UNIT *uptr) +{ +uint32 i, idx; +int32 t; +t_stat st; + +t = sim_rtcn_calb (RTC_HZ_BASE, TMR_RTC); /* calibrate clock */ +sim_activate (uptr, t); /* reactivate unit */ +for (i = 0; i < RTC_NUM_EVNTS; i++) { /* loop thru events */ + if (rtc_cntr[i] != 0) { /* event active? */ + rtc_cntr[i] = rtc_cntr[i] - 1; /* decrement */ + if (rtc_cntr[i] == 0) { /* expired? */ + idx = rtc_indx[i]; + rtc_cntr[i] = rtc_tab[idx].cntr_reset; /* reset counter */ + if (rtc_xtra[i] != 0) { /* fudge factor? */ + rtc_xtra[i] = rtc_xtra[i] - 1; /* decr fudge cntr */ + if (rtc_xtra[i] == 0) { /* expired? */ + rtc_cntr[i]++; /* extra tick */ + rtc_xtra[i] = rtc_tab[idx].xtra_reset; /* reset fudge cntr */ + } /* end fudge = 0 */ + } /* end fudge active */ + if ((rtc_usrv[i] == NULL) || /* registered? */ + (rtc_usrv[i]->action == NULL)) + return SCPE_IERR; /* should be */ + st = rtc_usrv[i]->action (rtc_usrv[i]); /* callback */ + if (st != SCPE_OK) /* error */ + return st; + } /* end cntr = 0 */ + } /* end event active */ + } /* end event loop */ +return SCPE_OK; +} + +/* Callback for a system timer */ + +t_stat rtc_cntr_svc (UNIT *uptr) +{ +uint32 cn = uptr - rtc_cntr_unit; + +io_sclr_req (INTV (INTG_OVR, cn), 1); /* set cntr intr */ +return SCPE_OK; +} + +/* Register a timer */ + +t_stat rtc_register (uint32 tm, uint32 idx, UNIT *uptr) +{ +if ((tm >= RTC_NUM_EVNTS) || /* validate params */ + (idx >= RTC_NUM_HZ) || + (uptr == NULL) || + (uptr->action == NULL)) + return SCPE_IERR; +rtc_usrv[tm] = uptr; +rtc_indx[tm] = idx; +rtc_cntr[tm] = rtc_tab[idx].cntr_reset; /* init event */ +rtc_xtra[tm] = rtc_tab[idx].xtra_reset; +return SCPE_OK; +} + +/* Set timer ticks */ + +t_stat rtc_set_tps (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 newval, i; +t_stat r; + +if (val >= RTC_NUM_EVNTS) /* validate params */ + return SCPE_IERR; +if (cptr == NULL) /* must have arg */ + return SCPE_ARG; +newval = get_uint (cptr, 10, 10000, &r); +if ((r != SCPE_OK) || /* error? */ + ((newval == 0) && (val >= 2))) /* can't turn off 3,4 */ + return SCPE_ARG; +for (i = 0; i < RTC_NUM_HZ; i++) { /* loop thru freqs */ + if (newval == rtc_tab[i].hz) { /* found freq? */ + rtc_tps[val] = i; + rtc_indx[val] = i; /* save event vals */ + rtc_cntr[val] = rtc_tab[i].cntr_reset; + rtc_xtra[val] = rtc_tab[i].xtra_reset; + return SCPE_OK; + } + } +return SCPE_ARG; +} + +/* Show timer ticks */ + +t_stat rtc_show_tps (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +uint32 idx; + +if (val >= RTC_NUM_EVNTS) + return SCPE_IERR; +idx = rtc_tps[val]; /* ptr to clk defs */ +if (rtc_tab[idx].hz == 0) + fprintf (of, "off\n"); +else fprintf (of, "%dHz\n", rtc_tab[idx].hz); +return SCPE_OK; +} + + +/* Reset routine */ + +t_stat rtc_reset (DEVICE *dptr) +{ +uint32 i; + +sim_rtcn_init (rtc_unit.wait, TMR_RTC); /* init base clock */ +sim_activate_abs (&rtc_unit, rtc_unit.wait); /* activate unit */ + +for (i = 0; i < RTC_NUM_EVNTS; i++) { /* clear counters */ + if (i < RTC_NUM_CNTRS) { + rtc_cntr[i] = 0; + rtc_xtra[i] = 0; + rtc_indx[i] = 0; + rtc_usrv[i] = NULL; + if (rtc_register (i, rtc_tps[i], &rtc_cntr_unit[i]) != SCPE_OK) + return SCPE_IERR; + } + else if ((rtc_usrv[i] != NULL) && + (rtc_register (i, rtc_indx[i], rtc_usrv[i]) != SCPE_OK)) + return SCPE_IERR; + } +return SCPE_OK; +} + +/* Show events */ + +t_stat rtc_show_events (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +uint32 i; + +fprintf (of, "Event Status Frequency Ticks Extra\n"); +for (i = 0; i < RTC_NUM_EVNTS; i++) { + if (rtc_cntr[i]) + fprintf (of, " %d on %3dHz %3d %d\n", + i, rtc_tab[rtc_indx[i]].hz, rtc_cntr[i], rtc_xtra[i]); + else fprintf (of, " %d off\n", i); + } +return SCPE_OK; +} \ No newline at end of file diff --git a/sigma/sigma_sys.c b/sigma/sigma_sys.c new file mode 100644 index 00000000..53aeb6dd --- /dev/null +++ b/sigma/sigma_sys.c @@ -0,0 +1,613 @@ +/* sigma_sys.c: Sigma system interface + + Copyright (c) 2007-2008, Robert 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 "sigma_defs.h" +#include + +#define FMTASC(x) ((x) < 0x20)? "<%02X>": "%c", (x) + +extern DEVICE cpu_dev; +extern DEVICE map_dev; +extern DEVICE int_dev; +extern DEVICE chan_dev[]; +extern DEVICE rtc_dev; +extern DEVICE tt_dev; +extern DEVICE pt_dev; +extern DEVICE lp_dev; +extern DEVICE rad_dev; +extern DEVICE dk_dev; +extern DEVICE dp_dev[]; +extern DEVICE mt_dev; +extern DEVICE mux_dev, muxl_dev; +extern REG cpu_reg[]; +extern uint32 *M; +extern UNIT cpu_unit; + +t_stat fprint_sym_m (FILE *of, uint32 inst); +t_stat parse_sym_m (char *cptr, t_value *val); +void fprint_ebcdic (FILE *of, uint32 c); + +/* SCP data structures and interface routines + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words 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[] = "XDS Sigma"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 1; + +DEVICE *sim_devices[] = { + &cpu_dev, + &map_dev, + &int_dev, + &chan_dev[0], + &chan_dev[1], + &chan_dev[2], + &chan_dev[3], + &chan_dev[4], + &chan_dev[5], + &chan_dev[6], + &chan_dev[7], + &rtc_dev, /* must be first */ + &tt_dev, + &pt_dev, + &lp_dev, + &mt_dev, + &rad_dev, + &dk_dev, + &dp_dev[0], + &dp_dev[1], + &mux_dev, + &muxl_dev, + NULL + }; + +const char *sim_stop_messages[] = { + "Unknown error", + "Invalid I/O configuration", + "Breakpoint", + "Address stop", + "Wait, interrupts off", + "Invalid PSD", + "Nested EXU's exceed limit", + "Undefined instruction", + "Illegal trap or interrupt instruction", + "Invalid interrupt vector", + "Nested traps", + }; + +/* Character conversion tables (from Sigma 7 manual) */ + +uint8 ascii_to_ebcdic[128] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x06, 0x07, /* 00 - 1F */ + 0x08, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 - 3F */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 - 5F */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xB4, 0xB1, 0xB5, 0x6A, 0x6D, + 0x4A, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60- 7F */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xB2, 0x4F, 0xB3, 0x5F, 0xFF + }; + +uint8 ebcdic_to_ascii[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x06, 0x07, /* 00 - 1F */ + 0x08, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20 - 3F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 40 - 5F */ + 0x00, 0x00, '`', '.', '<', '(', '+', '|', + '&', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, '!', '$', '*', ')', ';', '~', + '-', '/', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 - 7F */ + 0x00, 0x00, '^', ',', '%', '_', '>', '?', + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, ':', '#', '@', '\'', '=', '"', + 0x00, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 80 - 9F */ + 'h', 'i', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 's', 't', 'u', 'v', 'w', 'x', /* A0 - BF */ + 'y', 'z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, '\\', '{', '}', '[', ']', 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* C0 - DF */ + 'H', 'I', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 'S', 'T', 'U', 'V', 'W', 'X', /* E0 - FF */ + 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, + }; + +/* Binary loader */ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +return SCPE_NOFNC; +} + +/* Symbol and format tables */ + +#define IC_V_CL 17 /* class */ +#define IC_M_CL 0x1F +#define IC_V_RN 16 /* takes rn */ +#define IC_RN (1u << IC_V_RN) +#define IC_V_IND 15 /* takes ind */ +#define IC_IND (1u << IC_V_IND) +#define IC_V_XR 13 /* takes xr */ +#define IC_M_XR 0x3 +#define IC_NONE 0 +#define IC_XR 1 +#define IC_CTL 2 +#define IC_V_AW 7 /* addr width */ +#define IC_M_AW 0x3F +#define IC_V_AP 2 /* addr position */ +#define IC_M_AP 0x1F +#define IC_V_SGN 1 /* sign allowed */ +#define IC_SGN (1u << IC_V_SGN) +#define IC_V_AOP 0 /* addr optional */ +#define IC_AOP (1u << IC_V_AOP) + +#define ID1_07 0 /* decode 1-7 */ +#define ID1_11 1 /* decode 1-11 */ +#define IDSHFT 2 /* shift */ +#define IDSHFF 3 /* shift floating */ +#define IDMMCX 4 /* MMC ext */ + +#define I_C(c,r,i,w,s,x,sn,ao) \ + (((c) << IC_V_CL) | ((r) << IC_V_RN) | ((i) << IC_V_IND)|\ + ((w) << IC_V_AW) | ((s) << IC_V_AP) | ((x) << IC_V_XR) |\ + ((sn) << IC_V_SGN) | ((ao) << IC_V_AOP)) + +/* decode R I wd ps x sn ao */ +#define IC_MRF I_C(ID1_07,1,1,17, 0,1, 0, 0) /* mem ref */ +#define IC_IMM I_C(ID1_07,1,0,20, 0,0, 1, 0) /* immediate */ +#define IC_LCFI I_C(ID1_07,0,0, 8, 0,2, 0, 0) /* LCFI */ +#define IC_LFI I_C(ID1_11,0,0, 4, 0,0, 0, 0) /* LFI */ +#define IC_LCI I_C(ID1_11,0,0, 4, 4,0, 0, 0) /* LCI */ +#define IC_SHFT I_C(IDSHFT,1,0, 7, 0,1, 1, 0) /* shift */ +#define IC_SHFF I_C(IDSHFF,1,0, 7, 0,1, 1, 0) /* floating shift */ +#define IC_MNOR I_C(ID1_07,0,1,17, 0,1, 0, 0) /* mem ref, no reg */ +#define IC_MNOX I_C(ID1_11,0,1,17, 0,1, 0, 0) /* mef ref ext */ +#define IC_NOP I_C(ID1_07,1,0, 0, 0,0, 0, 0) /* no operand */ +#define IC_NOPX I_C(ID1_11,1,0, 0, 0,0, 0, 0) /* no operand ext */ +#define IC_MMC I_C(ID1_07,1,1, 3,17,0, 0, 0) /* MMC */ +#define IC_MMCX I_C(IDMMCX,1,0, 0, 0,0, 0, 0) /* MMC extended */ +#define IC_MNRI I_C(ID1_11,0,0, 0, 0,0, 0, 0) /* no operands */ +#define IC_MNRO I_C(ID1_07,0,1,17, 0,1, 0, 1) /* mem ref, addr opt */ + +#define IC_GETCL(x) (((x) >> IC_V_CL) & IC_M_CL) +#define IC_GETXR(x) (((x) >> IC_V_XR) & IC_M_XR) +#define IC_GETAW(x) (((x) >> IC_V_AW) & IC_M_AW) +#define IC_GETAP(x) (((x) >> IC_V_AP) & IC_M_AP) + +static const uint32 masks[] = { + 0x7F000000, 0x7FF00000, 0x7F000700, 0x7F000100, + 0x7F0E0000 + }; + +/* Opcode tables - extended mnemonics must precede standard mnemonics */ + +static const uint32 opc_val[] = { + 0x02100000, IC_LFI, 0x02200000, IC_LCI, 0x70100000, IC_MNOX, 0x70200000, IC_MNOX, + 0x25000000, IC_SHFT, 0x25000100, IC_SHFT, 0x25000200, IC_SHFT, 0x25000000, IC_SHFT, + 0x25000400, IC_SHFT, 0x25000500, IC_SHFT, 0x25000600, IC_SHFT, 0x25000700, IC_SHFT, + 0x24000000, IC_SHFT, 0x24000100, IC_SHFT, + 0x68000000, IC_MNOX, 0x68100000, IC_MNOX, 0x68200000, IC_MNOX, 0x68300000, IC_MNOX, + 0x68400000, IC_MNOX, 0x68800000, IC_MNOX, + 0x69000000, IC_MNOX, 0x69100000, IC_MNOX, 0x69200000, IC_MNOX, 0x69300000, IC_MNOX, + 0x69400000, IC_MNOX, 0x69800000, IC_MNOX, + 0x6F020000, IC_MMCX, 0x6F040000, IC_MMCX, 0x6F060000, IC_MMCX, 0x6F080000, IC_MMCX, + 0x6F080000, IC_MMCX, 0x02000000, IC_MNRI, + + 0x02000000, IC_LCFI, + 0x04000000, IC_MRF, 0x05000000, IC_MRF, 0x06000000, IC_MRF, 0x07000000, IC_MRF, + 0x08000000, IC_MRF, 0x09000000, IC_MRF, 0x0A000000, IC_MRF, 0x0B000000, IC_MRF, + 0x0C000000, IC_MRF, 0x0D000000, IC_NOP, 0x0E000000, IC_MRF, 0x0F000000, IC_MRF, + 0x10000000, IC_MRF, 0x11000000, IC_MRF, 0x12000000, IC_MRF, 0x13000000, IC_MRF, + 0x15000000, IC_MRF, + 0x18000000, IC_MRF, 0x19000000, IC_MRF, 0x1A000000, IC_MRF, 0x1B000000, IC_MRF, + 0x1C000000, IC_MRF, 0x1D000000, IC_MRF, 0x1E000000, IC_MRF, 0x1F000000, IC_MRF, + 0x20000000, IC_IMM, 0x21000000, IC_IMM, 0x22000000, IC_IMM, 0x23000000, IC_IMM, + 0x24000000, IC_MRF, 0x25000000, IC_MRF, 0x26000000, IC_MRF, + 0x28000000, IC_MRF, 0x29000000, IC_MRF, 0x2A000000, IC_MRF, 0x2B000000, IC_MRF, + 0x2C000000, IC_MRF, 0x2D000000, IC_MRF, 0x2E000000, IC_MNRO, 0x2F000000, IC_MRF, + 0x30000000, IC_MRF, 0x31000000, IC_MRF, 0x32000000, IC_MRF, 0x33000000, IC_MRF, + 0x34000000, IC_MRF, 0x35000000, IC_MRF, 0x36000000, IC_MRF, 0x37000000, IC_MRF, + 0x38000000, IC_MRF, 0x39000000, IC_MRF, 0x3A000000, IC_MRF, 0x3B000000, IC_MRF, + 0x3C000000, IC_MRF, 0x3D000000, IC_MRF, 0x3E000000, IC_MRF, 0x3F000000, IC_MRF, + 0x40000000, IC_IMM, 0x41000000, IC_IMM, + 0x44000000, IC_MRF, 0x45000000, IC_MRF, 0x46000000, IC_MRF, 0x47000000, IC_MRF, + 0x48000000, IC_MRF, 0x49000000, IC_MRF, 0x4A000000, IC_MRF, 0x4B000000, IC_MRF, + 0x4C000000, IC_MRF, 0x4D000000, IC_MRF, 0x4E000000, IC_MRF, 0x4F000000, IC_MRF, + 0x50000000, IC_MRF, 0x51000000, IC_MRF, 0x52000000, IC_MRF, 0x53000000, IC_MRF, + 0x55000000, IC_MRF, 0x56000000, IC_MRF, 0x57000000, IC_MRF, + 0x58000000, IC_MRF, 0x5A000000, IC_MRF, 0x5B000000, IC_MRF, + + 0x60000000, IC_IMM, 0x61000000, IC_IMM, 0x63000000, IC_IMM, + 0x64000000, IC_MRF, 0x65000000, IC_MRF, 0x66000000, IC_MRF, 0x67000000, IC_MNOR, + 0x68000000, IC_MRF, 0x69000000, IC_MRF, 0x6A000000, IC_MRF, 0x6B000000, IC_MRF, + 0x6C000000, IC_MRF, 0x6D000000, IC_MRF, 0x6E000000, IC_MRF, 0x6F000000, IC_MMC, + 0x70000000, IC_MRF, 0x71000000, IC_MRF, 0x72000000, IC_MRF, 0x73000000, IC_MRF, + 0x74000000, IC_MNOR, 0x75000000, IC_MRF, 0x76000000, IC_MRF, 0x77000000, IC_MRF, + 0x78000000, IC_MRF, 0x79000000, IC_MRF, 0x7A000000, IC_MRF, 0x7B000000, IC_MRF, + 0x7C000000, IC_MNOR, 0x7D000000, IC_MRF, 0x7E000000, IC_MRF, 0x7F000000, IC_MRF, + 0xFFFFFFFF, 0 + }; + +static const char *opcode[] = { + "LFI", "LCI", "LF", "LC", /* extended mmenomics */ + "SLS", "SLD", "SCS", "SCD", + "SAS", "SAD", "SSS", "SSD", + "SFS", "SFL", + "B", "BGE", "BLE", "BE", + "BNOV", "BNC", + "BNVR", "BL", "BG", "BNE", + "BOV", "BC", + "LLOCKS", "LPC", "LLOCKSE", "LMAP", + "LMAPRE", "NOP", + + "LCFI", /* 00 */ + "CAL1", "CAL2", "CAL3", "CAL4", + "PLW", "PSW", "PLM", "PSM", + "PLS", "PSS", "LPSD", "XPSD", + "AD", "CD", "LD", "MSP", /* 10 */ + "STD", + "SD", "CLM", "LCD", "LAD", + "FSL", "FAL", "FDL", "FML", + "AI", "CI", "LI", "MI", /* 20 */ + "SF", "S", "LAS", + "CVS", "CVA", "LM", "STM", + "LRA", "LMS", "WAIT", "LRP", + "AW", "CW", "LW", "MTW", /* 30 */ + "LVAW", "STW", "DW", "MW", + "SW", "CLR", "LCW", "LAW", + "FSS", "FAS", "FDS", "FMS", + "TTBS", "TBS", /* 40 */ + "ANLZ", "CS", "XW", "STS", + "EOR", "OR", "LS", "AND", + "SIO", "TIO", "TDV", "HIO", + "AH", "CH", "LH", "MTH", /* 50 */ + "STH", "DH", "MH", + "SH", "LCH", "LAH", + + "CBS", "MBS", "EBS", /* 60 */ + "BDR", "BIR", "AWM", "EXU", + "BCR", "BCS", "BAL", "INT", + "RD", "WD", "AIO", "MMC", + "LCF", "CB", "LB", "MTB", /* 70 */ + "STCF", "STB", "PACK", "UNPK", + "DS", "DA", "DD", "DM", + "DSA", "DC", "DL", "DST", + NULL + }; + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *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) +{ +uint32 inst, sc, rdx, c; +DEVICE *dptr; + +inst = val[0]; /* get inst */ +if (uptr == NULL) /* anon = CPU */ + uptr = &cpu_unit; +else if (uptr != &cpu_unit) /* CPU only */ + return SCPE_ARG; +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) + return SCPE_IERR; +if (sw & SWMASK ('D')) /* get radix */ + rdx = 10; +else if (sw & SWMASK ('O')) + rdx = 8; +else if (sw & SWMASK ('X')) + rdx = 16; +else rdx = dptr->dradix; + +if (sw & SWMASK ('C')) { /* char format? */ + for (sc = 0; sc < 32; sc = sc + 8) { /* print string */ + c = (inst >> (24 - sc)) & BMASK; + if (sw & SWMASK ('A')) + fprintf (of, FMTASC (c & 0x7F)); + else fprint_ebcdic (of, c); + } + return 0; /* return # chars */ + } +if (sw & SWMASK ('A')) { /* ASCII? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & 0x7F; + fprintf (of, "%c", FMTASC (c)); + return 0; + } +if (sw & SWMASK ('E')) { /* EBCDIC? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & BMASK; + fprint_ebcdic (of, c); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & BMASK; + fprintf (of, "%02X", c); + return 0; + } +if (sw & SWMASK ('H')) { /* halfword? */ + c = ((addr & 1)? inst: inst >> 16) & HMASK; + fprintf (of, "%04X", c); + return 0; + } +if ((sw & SWMASK ('M')) && /* inst format? */ + !fprint_sym_m (of, inst)) /* decode inst */ + return 0; + +fprint_val (of, inst, rdx, 32, PV_RZRO); +return 0; +} + +/* Instruction decode */ + +t_stat fprint_sym_m (FILE *of, uint32 inst) +{ +uint32 i, j; + +for (i = 0; opc_val[i] < 0xFFFFFFFF; i = i + 2) { /* loop thru ops */ + j = IC_GETCL (opc_val[i + 1]); /* get class */ + if (opc_val[i] == (inst & masks[j])) { /* match? */ + uint32 fl = opc_val[i + 1]; /* get format */ + uint32 aw = IC_GETAW (fl); + uint32 ap = IC_GETAP (fl); + uint32 xr = IC_GETXR (fl); + uint32 rn = I_GETRN (inst); /* get fields */ + uint32 xn = I_GETXR (inst); + uint32 mask = (1u << aw) - 1; + uint32 ad = (inst >> ap) & mask; + + fprintf (of, "%s", opcode[i >> 1]); /* opcode */ + if (fl & IC_RN) /* rn? */ + fprintf (of, ",%d", rn); + if (TST_IND (inst) || aw || xr) { /* anything else? */ + fputs (TST_IND (inst)? " *": " ", of); /* space{*} */ + if (aw) { /* any value? */ + if ((fl & IC_SGN) && /* signed and */ + (ad & (1u << (aw - 1)))) /* negative? */ + fprintf (of, "-%X", (mask + 1) - ad); + else fprintf (of, "%X", ad); + if ((xr == IC_XR) && xn) /* any index? */ + fprintf (of, ",%d", xn); + else if (xr == IC_CTL) /* or control? */ + fprintf (of, ",%X", rn); + } + } + return SCPE_OK; + } + } +return SCPE_ARG; +} + +void fprint_ebcdic (FILE *of, uint32 c) +{ +uint32 cv = ebcdic_to_ascii[c]; +if ((cv < 0040) || (cv >= 0177)) + fprintf (of, "<%02X>", c); +else fputc (cv, of); +return; +} + +/* 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) +{ +t_value num; +uint32 i, sc, rdx, c; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) /* anon = CPU */ + uptr = &cpu_unit; +else if (uptr != &cpu_unit) /* CPU only */ + return SCPE_ARG; +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) + return SCPE_IERR; +if (sw & SWMASK ('D')) /* get radix */ + rdx = 10; +else if (sw & SWMASK ('O')) + rdx = 8; +else if (sw & SWMASK ('X')) + rdx = 16; +else rdx = dptr->dradix; + +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* chars? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + for (i = 0; i < 4; i++) { + if (cptr[i] == 0) + break; + sc = 24 - (i * 8); + c = (sw & SWMASK ('A'))? + cptr[i] & 0x7F: + ascii_to_ebcdic[cptr[i]]; + val[0] = (val[0] & ~(BMASK << sc)) | (c << sc); + } + return 0; + } +if ((sw & SWMASK ('A')) || ((*cptr == '#') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (cptr[0] << sc); + return 0; + } +if ((sw & SWMASK ('E')) || ((*cptr == '\'') && cptr++)) { /* EBCDIC char? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (ascii_to_ebcdic[cptr[0]] << sc); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + num = get_uint (cptr, rdx, BMASK, &r); /* get byte */ + if (r != SCPE_OK) + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (num << sc); + return 0; + } +if (sw & SWMASK ('H')) { /* halfword? */ + num = get_uint (cptr, rdx, HMASK, &r); /* get half word */ + if (r != SCPE_OK) + return SCPE_ARG; + sc = addr & 1? 0: 16; + val[0] = (val[0] & ~(HMASK << sc)) | (num << sc); + return 0; + } +if (!parse_sym_m (cptr, val)) + return 0; + +val[0] = get_uint (cptr, rdx, WMASK, &r); /* get number */ +if (r != SCPE_OK) + return r; +return 0; +} + +t_stat parse_sym_m (char *cptr, t_value *val) +{ +uint32 i, sgn; +t_stat r; +char *sep; +char gbuf[CBUFSIZE]; + +cptr = get_glyph (cptr, gbuf, 0); /* get opcode+reg*/ +if (sep = strchr (gbuf, ',')) /* , in middle? */ + *sep++ = 0; /* split strings */ +for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */ + if (strcmp (opcode[i], gbuf) == 0) { /* string match? */ + uint32 rn, xn, ad; + uint32 k = i << 1; /* index to opval */ + uint32 fl = opc_val[k + 1]; + uint32 aw = IC_GETAW (fl); + uint32 ap = IC_GETAP (fl); + uint32 xr = IC_GETXR (fl); + uint32 mask = (1u << aw) - 1; + + val[0] = opc_val[k]; + if (fl & IC_RN) { /* need rn? */ + if (sep == NULL) + return SCPE_ARG; + rn = get_uint (sep, 10, INST_M_RN, &r); + if (r != SCPE_OK) + return SCPE_ARG; + val[0] |= rn << INST_V_RN; + } + else if (sep) /* rn & not wanted */ + return SCPE_ARG; + if (aw) { /* more? */ + if (*cptr == 0) + return (fl & IC_AOP)? SCPE_OK: SCPE_ARG; + if ((fl & IC_IND) && (*cptr == '*')) { /* indirect? */ + val[0] |= INST_IND; + cptr++; + } + if ((fl & IC_SGN) && /* signed val? */ + strchr ("+-", *cptr) && /* with sign? */ + (*cptr++ == '-')) /* and minus? */ + sgn = 1; + else sgn = 0; /* else + */ + cptr = get_glyph (cptr, gbuf, 0); /* get rest */ + if (sep = strchr (gbuf, ',')) /* , in middle? */ + *sep++ = 0; /* split strings */ + ad = get_uint (gbuf, 16, mask, &r); + if (r != SCPE_OK) + return r; + if (sgn && ad) /* negative, nz? */ + ad = (mask + 1) - ad; /* complement */ + val[0] |= (ad << ap); + if ((xr == IC_XR) && sep) { /* index? */ + xn = get_uint (sep, 10, 7, &r); + if (r != SCPE_OK) + return r; + val[0] |= (xn << INST_V_XR); + } + else if (xr == IC_CTL) { /* control? */ + if (sep == NULL) + return SCPE_ARG; + xn = get_uint (gbuf, 16, INST_M_RN, &r); + if (r != SCPE_OK) + return r; + val[0] |= (xn << INST_V_RN); + } + else if (sep) + return SCPE_ARG; + } + if (*cptr != 0) + return SCPE_ARG; + return SCPE_OK; + } + } +return SCPE_ARG; +} diff --git a/sigma/sigma_tt.c b/sigma/sigma_tt.c new file mode 100644 index 00000000..97d32d3c --- /dev/null +++ b/sigma/sigma_tt.c @@ -0,0 +1,331 @@ +/* sigma_tt.c: Sigma 7012 console teletype + + Copyright (c) 2007-2008, Robert 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. + + tt 7012 console + + The 7012 has the following special cases on input and output: + + CR input, mapped to NEWLINE and echoes CR-LF + ^H input, mapped to EOM and not echoed + HT input or output, simulates tabbing with fixed 8 character stops +*/ + +#include "sigma_io_defs.h" +#include + +/* Device definitions */ + +#define TTI 0 +#define TTO 1 + +/* Device states */ + +#define TTS_IDLE 0x0 +#define TTS_INIT 0x1 +#define TTS_END 0x2 +#define TTS_WRITE 0x5 +#define TTS_READ 0x6 +#define TTS_READS 0x86 + +/* EBCDIC special characters for input */ + +#define E_EOM 0x08 /* end of medium */ +#define E_HT 0x05 /* tab */ +#define E_NL 0x15 /* new line */ + +uint32 tt_cmd = TTS_IDLE; +uint32 tti_tps = RTC_HZ_100; +uint32 tti_panel = 020; /* panel int char */ +uint32 tto_pos = 0; /* char position */ + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 tt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 tt_tio_status (void); +t_stat tt_chan_err (uint32 st); +t_stat tti_rtc_svc (uint32 tm); +t_stat tti_svc (UNIT *uptr); +t_stat tto_svc (UNIT *uptr); +t_stat tt_reset (DEVICE *dptr); +t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); +void tto_echo (int32 c); + +extern t_stat io_set_pint (void); + +/* TT data structures + + tt_dev TT device descriptor + tt_unit TT unit descriptors + tt_reg TT register list + tt_mod TT modifiers list +*/ + +dib_t tt_dib = { DVA_TT, tt_disp }; + +UNIT tt_unit[] = { + { UDATA (&tti_svc, TT_MODE_UC, 0), 0 }, + { UDATA (&tto_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT } + }; + +REG tt_reg[] = { + { HRDATA (CMD, tt_cmd, 9) }, + { DRDATA (KPOS, tt_unit[TTI].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (KTPS, tti_tps, 8), REG_HRO }, + { DRDATA (TPOS, tt_unit[TTO].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, + { HRDATA (PANEL, tti_panel, 8) }, + { HRDATA (DEVNO, tt_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB tt_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", &tt_set_mode }, + { TT_MODE, TT_MODE_7P, "7p", "7P", &tt_set_mode }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_TTI, "POLL", "POLL", + &rtc_set_tps, &rtc_show_tps, (void *) &tti_tps }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE tt_dev = { + "TT", tt_unit, tt_reg, tt_mod, + 2, 10, 31, 1, 16, 8, + NULL, NULL, &tt_reset, + NULL, NULL, NULL, + &tt_dib, 0 + }; + +/* Terminal: IO dispatch routine */ + +uint32 tt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = tt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + tt_cmd = TTS_INIT; /* start dev thread */ + sim_activate (&tt_unit[TTO], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = tt_tio_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (tt_dib.dva); /* clr int*/ + *dvst = tt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&tt_unit[TTO]); /* stop dev thread */ + tt_cmd = TTS_IDLE; + chan_uen (tt_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (tt_dib.dva); /* clr int*/ + case OP_TDV: /* test status */ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Timed input service routine - runs continuously + Only accepts input in TTS_READx state */ + +t_stat tti_svc (UNIT *uptr) +{ +int32 c, ebcdic; +uint32 st; + +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or err? */ + return c; +if (c & SCPE_BREAK) { /* break? */ + if (tt_cmd == TTS_WRITE) { /* during write? */ + tt_cmd = TTS_IDLE; + sim_cancel (&tt_unit[TTO]); /* cancel write */ + chan_uen (tt_dib.dva); /* uend */ + } + return SCPE_OK; + } +c = c & 0x7F; +if (c == tti_panel) /* panel interrupt? */ + return io_set_pint (); +uptr->pos = uptr->pos + 1; /* incr count */ +if (c == '\r') /* map CR to NL */ + c = '\n'; +if (c == 0x7F) /* map ^H back */ + c = 0x08; +c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); /* input conversion */ +ebcdic = ascii_to_ebcdic[c]; /* then to EBCDIC */ +tto_echo (c); /* echo character */ +if ((tt_cmd & 0x7F) == TTS_READ) { /* waiting for input? */ + st = chan_WrMemB (tt_dib.dva, ebcdic); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if ((st == CHS_ZBC) || (ebcdic == E_EOM) || /* channel end? */ + ((tt_cmd == TTS_READS) && ((ebcdic == E_HT) || (ebcdic == E_NL)))) { + tt_cmd = TTS_END; /* new state */ + sim_activate (&tt_unit[TTO], chan_ctl_time); /* start dev thread */ + } + } +return SCPE_OK; +} + +/* Output service routine - also acts as overall device thread + Because of possible retry, channel status and converted character + must be preserved across calls. */ + +t_stat tto_svc (UNIT *uptr) +{ +int32 c, cmd; +uint32 st; + +switch (tt_cmd) { /* case on state */ + + case TTS_INIT: /* I/O init */ + st = chan_get_cmd (tt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if ((cmd == TTS_WRITE) || /* valid command? */ + ((cmd & 0x7F) == TTS_READ)) + tt_cmd = cmd; /* next state */ + else tt_cmd = TTS_END; /* no, end state */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case TTS_WRITE: /* char output */ + st = chan_RdMemB (tt_dib.dva, &c); /* get char */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + c = ebcdic_to_ascii[c & 0xFF]; /* convert to ASCII */ + tto_echo (c); /* echo character */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if (st == CHS_ZBC) /* st = zbc? */ + tt_cmd = TTS_END; /* next is end */ + else tt_cmd = TTS_WRITE; /* next is write */ + break; + + case TTS_END: /* command done */ + st = chan_end (tt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + tt_cmd = TTS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + else tt_cmd = TTS_IDLE; /* all done */ + break; + } + +return SCPE_OK; +} + +/* Actual tty output routines; simulates horizontal tabs */ + +void tto_echo (int32 c) +{ +uint32 cnt; + +cnt = 1; +if (c == '\r') + tto_pos = 0; +else if (c == '\n') { + tto_pos = 0; + sim_putchar ('\r'); + tt_unit[TTO].pos = tt_unit[TTO].pos + 1; + } +else if (c == '\t') { + c = ' '; + cnt = 8 - (tto_pos % 8); + } +else c = sim_tt_outcvt (c, TT_GET_MODE (tt_unit[TTO].flags)); +if (c >= 0) { + while (cnt-- > 0) { + sim_putchar (c); + tto_pos++; + tt_unit[TTO].pos = tt_unit[TTO].pos + 1; + } + } +return; +} + +/* TTY status routine */ + +uint32 tt_tio_status (void) +{ +if (tt_cmd == TTS_IDLE) + return DVS_AUTO; +return (CC2 << DVT_V_CC) | DVS_DBUSY | DVS_CBUSY | DVS_AUTO; +} + +/* Channel error */ + +t_stat tt_chan_err (uint32 st) +{ +tt_cmd = TTS_IDLE; +sim_cancel (&tt_unit[TTO]); /* stop dev thread */ +chan_uen (tt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat tt_reset (DEVICE *dptr) +{ +rtc_register (RTC_TTI, tti_tps, &tt_unit[TTI]); /* register timer */ +sim_cancel (&tt_unit[TTO]); /* stop dev thread */ +tt_cmd = TTS_IDLE; /* idle */ +chan_reset_dev (tt_dib.dva); /* clr int, active */ +tto_pos = 0; +return SCPE_OK; +} + +/* Make mode flags uniform */ + +t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tt_unit[TTO].flags = (tt_unit[TTO].flags & ~TT_MODE) | val; +if (val == TT_MODE_7P) + val = TT_MODE_7B; +tt_unit[TTI].flags = (tt_unit[TTI].flags & ~TT_MODE) | val; +return SCPE_OK; +} diff --git a/sim_rev.h b/sim_rev.h index 8d7a623b..e82247d9 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -28,15 +28,15 @@ #define _SIM_REV_H_ 0 #define SIM_MAJOR 3 -#define SIM_MINOR 8 -#define SIM_PATCH 2 +#define SIM_MINOR 9 +#define SIM_PATCH 0 #define SIM_DELTA 0 -/* V3.8 revision history +/* V3.9 revision history patch date module(s) and fix(es) - 2 tbd scp.c: + 0 xx-yyy-1 scp.c: - added *nix READLINE support (Mark Pizzolato) - fixed handling of DO with no arguments (Dave Bryan) - clarified some help messages (Mark Pizzolato) @@ -53,7 +53,64 @@ patch date module(s) and fix(es) - made option negotiation more reliable (Mark Pizzolato) h316_cpu.c: - - fixed bugs in MPY, DIV introduced in 3.8-1 + - fixed bugs in MPY, DIV introduced in 3.8-1 (from Theo Engel) + - fixed bugs in double precision, normalization, SC (from Adrian Wise) + - fixed XR behavior (from Adrian Wise) + + hp2100 all peripherals (Dave Bryan): + - Changed I/O signal handlers for newly revised signal model + + hp2100_cpu.c (Dave Bryan): + - Revised DMA for new multi-card paradigm + - Consolidated DMA reset routines + - DMA channels renamed from 0,1 to 1,2 to match documentation + - Changed I/O instructions, handlers, and DMA for revised signal model + - Changed I/O dispatch table to use DIB pointers + - Removed DMA latency counter + - Fixed DMA requests to enable stealing every cycle + - Fixed DMA priority for channel 1 over channel 2 + - Corrected comments for "cpu_set_idle" + - Fixed I/O return status bug for DMA cycles + - Failed I/O cycles now stop on failing instruction + + hp2100_cpu.h: + - Changed declarations for VMS compiler + + hp2100_cpu0.c (Dave Bryan): + - Removed DS note regarding PIF card (is now implemented) + + hp2100_cpu6.c (Dave Bryan): + - DMA channels renamed from 0,1 to 1,2 to match documentation + + hp2100_defs.h (Dave Bryan): + - DMA channels renamed from 0,1 to 1,2 to match documentation + - Revised I/O signal enum values for concurrent signals + - Revised I/O macros for new signal handling + + hp2100_ds.c (Dave Bryan): + - Corrected status returns for disabled drive, auto-seek + beyond drive limits, Request Sector Address and Wakeup + with invalid or offline unit + - Address verification reenabled if auto-seek during + Read Without Verify + + hp2100_fp1.c (Dave Bryan): + - Completed the comments for divide; no code changes + + hp2100_ipl.c (Dave Bryan): + - Revised for new multi-card paradigm + - A failed STC may now be retried + + hp2100_lps.c (Dave Bryan): + - Corrected 12566B (DIAG mode) jumper settings + - Revised detection of CLC at last DMA cycle + + hp2100_mt.c (Dave Bryan): + - Fixed error in command scan in mtcio ioIOO handler + + hp2100_sys.c (Dave Bryan): + - DMA channels renamed from 0,1 to 1,2 to match documentation + - Changed DIB access for revised signal model i1401_cd.c: - fixed read stacker operation in column binary mode @@ -71,6 +128,12 @@ patch date module(s) and fix(es) - fixed backspace over tapemark not to set EOR (Van Snyder) - added no rewind option (Van Snyder) + pdp11_defs.h: + - fixed priority of PIRQ vs IO; added INT_INTERNALn + + pdp11_io.c: + - fixed Qbus interrupts to treat all IO devices as BR4 + pdp11_rk.c: - fixed bug in read header (Walter F Mueller) @@ -90,7 +153,7 @@ patch date module(s) and fix(es) - fixed debug output of tape file positions when they are 64b - added more debug output after positioning operations - added textual display of the command being performed - (All of the above from Mark Pizzolato) + (all of the above from Mark Pizzolato) - fixed comments about register addresses pdp11_ts.c: @@ -103,12 +166,25 @@ patch date module(s) and fix(es) pdp8_sys.c: - added link to FPP + pdp8_td.c: + - fixed SDLC to clear AC (from Dave Gesswein) + vax_cpu.c: - revised idle design (from Mark Pizzolato) - fixed bug in SET CPU IDLE + - fixed failure to clear PSL in BPT, XFC vax_cpu1.c: - revised idle design (from Mark Pizzolato) + - added VEC_QMODE test in interrupt handler + + vax_fpa.c + - fixed integer overflow bug in EMODx (from Camiel Vanderhoeven) + - fixed POLYx normalizing before add mask bug (from Camiel Vanderhoeven) + + vax_octa.c + - fixed integer overflow bug in EMODH (from Camiel Vanderhoeven) + - fixed POLYH normalizing before add mask bug (from Camiel Vanderhoeven) vax_syscm.c: - fixed t_addr printouts for 64b big-endian systems @@ -123,6 +199,11 @@ patch date module(s) and fix(es) vax780_stddev.c - added REBOOT support (from Mark Pizzolato) + vaxmod_def.h + - moved all Qbus devices to BR4; deleted RP definitions + + +/* V3.8 revision history 1 08-Feb-09 scp.c: - revised RESTORE unit logic for consistency @@ -132,6 +213,7 @@ patch date module(s) and fix(es) - decommitted MTAB_VAL - fixed implementation of MTAB_NC - fixed warnings in help printouts + - fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) sim_tape.c: - fixed signed/unsigned warning in sim_tape_set_fmt (Dave Bryan) diff --git a/sim_timer.c b/sim_timer.c index 2a364cdf..fbf5acf3 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -590,7 +590,7 @@ return (sim_idle_rate_ms != 0); t_bool sim_idle (uint32 tmr, t_bool sin_cyc) { -static uint32 cyc_ms; +static uint32 cyc_ms = 0; uint32 w_ms, w_idle, act_ms; int32 act_cyc; @@ -601,7 +601,7 @@ if ((sim_clock_queue == NULL) || /* clock queue empty? */ sim_interval = sim_interval - 1; return FALSE; } -if (!cyc_ms) +if (cyc_ms == 0) /* not computed yet? */ cyc_ms = (rtc_currd[tmr] * rtc_hz[tmr]) / 1000; /* cycles per msec */ if ((sim_idle_rate_ms == 0) || (cyc_ms == 0)) { /* not possible? */ if (sin_cyc) @@ -620,8 +620,8 @@ act_cyc = act_ms * cyc_ms; if (act_ms < w_ms) /* awakened early? */ act_cyc += (cyc_ms * sim_idle_rate_ms) / 2; /* account for half an interval's worth of cycles */ if (sim_interval > act_cyc) - sim_interval = sim_interval - act_cyc; -else sim_interval = 0; + sim_interval = sim_interval - act_cyc; /* count down sim_interval */ +else sim_interval = 0; /* or fire immediately */ return TRUE; } From fabdf73beda5d028bdf2538884941806e72bc5eb Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 19 Mar 2012 16:07:36 -0700 Subject: [PATCH 012/112] Compiler cleanup after v3.9-0 merge --- 0readme_39.txt | 9 ++------- ALTAIR/altair_cpu.c | 2 +- H316/h316_dp.c | 3 ++- H316/h316_fhd.c | 3 ++- H316/h316_mt.c | 3 ++- I1620/i1620_cd.c | 6 +++--- I1620/i1620_pt.c | 2 +- I1620/i1620_sys.c | 3 ++- I7094/i7094_cd.c | 2 +- I7094/i7094_io.c | 2 +- I7094/i7094_mt.c | 2 +- Interdata/id_fd.c | 3 +++ PDP11/pdp11_cpu.c | 2 +- PDP11/pdp11_hk.c | 2 +- PDP11/pdp11_io.c | 3 ++- PDP11/pdp11_rh.c | 3 ++- PDP11/pdp11_rl.c | 2 +- PDP11/pdp11_rq.c | 2 +- PDP11/pdp11_tq.c | 2 +- PDP11/pdp11_ts.c | 2 +- PDP11/pdp11_vh.c | 2 +- PDP18B/pdp18b_fpp.c | 6 +++++- S3/s3_cd.c | 4 ++-- S3/s3_cpu.c | 2 +- S3/s3_lp.c | 2 +- S3/s3_sys.c | 2 +- SDS/sds_io.c | 5 +++-- SDS/sds_sys.c | 3 ++- sim_disk.c | 2 +- swtp/swtp_cpu.c | 2 +- 30 files changed, 49 insertions(+), 39 deletions(-) diff --git a/0readme_39.txt b/0readme_39.txt index d3c8fbc0..cfb5b874 100644 --- a/0readme_39.txt +++ b/0readme_39.txt @@ -1,13 +1,8 @@ Notes For V3.9 -The makefile now works for Linux and most Unix's. However, for Solaris -and MacOS, you must first export the OSTYPE environment variable: - -> export OSTYPE -> make - -Otherwise, you will get build errors. +The makefile now works for all *nix platforms and with cygwin and MinGW32 +on Windows. 1. New Features diff --git a/ALTAIR/altair_cpu.c b/ALTAIR/altair_cpu.c index 4a837c8b..3e97664f 100644 --- a/ALTAIR/altair_cpu.c +++ b/ALTAIR/altair_cpu.c @@ -107,7 +107,7 @@ int32 chip = 0; /* 0 = 8080 chip, 1 = z8 int32 PCX; /* External view of PC */ extern int32 sim_int_char; -extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ;/* breakpoint info */ /* function prototypes */ diff --git a/H316/h316_dp.c b/H316/h316_dp.c index 0a8df9af..63023cba 100644 --- a/H316/h316_dp.c +++ b/H316/h316_dp.c @@ -215,7 +215,8 @@ static struct drvtyp dp_tab[] = { { DP_DRV (4720) } }; -extern int32 dev_int, dev_enb, chan_req; +extern int32 dev_int, dev_enb; +extern uint32 chan_req; extern int32 stop_inst; extern uint32 dma_ad[DMA_MAX]; extern int32 sim_switches; diff --git a/H316/h316_fhd.c b/H316/h316_fhd.c index df2c9aac..afadcb3b 100644 --- a/H316/h316_fhd.c +++ b/H316/h316_fhd.c @@ -72,7 +72,8 @@ #define OTA_CW1 1 /* expecting CW1 */ #define OTA_CW2 2 /* expecting CW2 */ -extern int32 dev_int, dev_enb, chan_req; +extern int32 dev_int, dev_enb; +extern uint32 chan_req; extern int32 stop_inst; extern uint32 dma_ad[DMA_MAX]; diff --git a/H316/h316_mt.c b/H316/h316_mt.c index 5ca516f4..3004a3df 100644 --- a/H316/h316_mt.c +++ b/H316/h316_mt.c @@ -82,7 +82,8 @@ #define STA_BOT 0000002 /* beg of tape */ #define STA_EOT 0000001 /* end of tape */ -extern int32 dev_int, dev_enb, chan_req; +extern int32 dev_int, dev_enb; +extern uint32 chan_req; extern int32 stop_inst; uint32 mt_buf = 0; /* data buffer */ diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c index d7e7cb7a..39783df8 100644 --- a/I1620/i1620_cd.c +++ b/I1620/i1620_cd.c @@ -43,7 +43,7 @@ extern uint8 M[MAXMEMSIZE]; extern uint8 ind[NUM_IND]; extern UNIT cpu_unit; -extern int32 io_stop; +extern uint32 io_stop; char cdr_buf[CD_LEN + 2]; char cdp_buf[CD_LEN + 2]; @@ -332,8 +332,8 @@ return SCPE_OK; t_stat cdr_boot (int32 unitno, DEVICE *dptr) { t_stat r; -int32 old_io_stop; -extern int32 saved_PC; +uint32 old_io_stop; +extern uint32 saved_PC; old_io_stop = io_stop; io_stop = 1; diff --git a/I1620/i1620_pt.c b/I1620/i1620_pt.c index dff4ac06..89b6dbd4 100644 --- a/I1620/i1620_pt.c +++ b/I1620/i1620_pt.c @@ -363,7 +363,7 @@ const static uint8 boot_rom[] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int32 i; -extern int32 saved_PC; +extern uint32 saved_PC; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; diff --git a/I1620/i1620_sys.c b/I1620/i1620_sys.c index aba91488..cf0fb94c 100644 --- a/I1620/i1620_sys.c +++ b/I1620/i1620_sys.c @@ -124,7 +124,8 @@ t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { int32 col, rpt, ptr, mask, cctbuf[CCT_LNT]; t_stat r; -extern int32 cct_lnt, cct_ptr, cct[CCT_LNT]; +extern int32 cct_lnt, cct_ptr; +extern uint32 cct[CCT_LNT]; char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; if ((*cptr != 0) || (flag != 0)) diff --git a/I7094/i7094_cd.c b/I7094/i7094_cd.c index 88a15ebe..8235ef36 100644 --- a/I7094/i7094_cd.c +++ b/I7094/i7094_cd.c @@ -87,7 +87,7 @@ t_stat cd_attach (UNIT *uptr, char *cptr); t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); char colbin_to_bcd (uint32 cb); -extern uint32 sim_switches; +extern int32 sim_switches; extern uint32 PC; extern uint32 ind_ioc; extern char bcd_to_ascii_a[64]; diff --git a/I7094/i7094_io.c b/I7094/i7094_io.c index 655e7b7f..00851951 100644 --- a/I7094/i7094_io.c +++ b/I7094/i7094_io.c @@ -86,7 +86,7 @@ extern DEVICE mt_dev[NUM_CHAN]; extern DEVICE drm_dev; extern DEVICE dsk_dev; extern DEVICE com_dev; -extern int32 sim_brk_summ; +extern uint32 sim_brk_summ; t_stat ch_reset (DEVICE *dptr); t_stat ch6_svc (UNIT *uptr); diff --git a/I7094/i7094_mt.c b/I7094/i7094_mt.c index 18c34942..c06eb5ac 100644 --- a/I7094/i7094_mt.c +++ b/I7094/i7094_mt.c @@ -72,7 +72,7 @@ extern uint32 PC; extern uint32 cpu_model; extern uint32 ind_ioc; extern FILE *sim_deb; -extern char *sel_name[]; +extern const char *sel_name[]; t_stat mt_chsel (uint32 ch, uint32 sel, uint32 unit); t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 flags); diff --git a/Interdata/id_fd.c b/Interdata/id_fd.c index 12654c9c..461b54ab 100644 --- a/Interdata/id_fd.c +++ b/Interdata/id_fd.c @@ -75,6 +75,9 @@ #define STA_WRP 0x80 /* *write prot */ #define STA_DEF 0x40 /* def track NI */ +#ifdef STA_DEL /* Some platforms define a conflicting symbol here */ +#undef STA_DEL +#endif #define STA_DEL 0x20 /* del record */ #define STA_ERR 0x10 /* error */ #define STA_IDL 0x02 /* idle */ diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 670a37ca..850b0ffe 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -304,7 +304,7 @@ t_addr cpu_memsize = INIMEMSIZE; /* last mem addr */ extern int32 CPUERR, MAINT; extern int32 sim_interval; extern int32 sim_int_char; -extern uint32 sim_switches; +extern int32 sim_switches; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern t_bool sim_idle_enab; extern DEVICE *sim_devices[]; diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index 0e25886a..f2bb1015 100644 --- a/PDP11/pdp11_hk.c +++ b/PDP11/pdp11_hk.c @@ -60,7 +60,7 @@ #else /* PDP-11 version */ #include "pdp11_defs.h" -extern int32 cpu_opt; +extern uint32 cpu_opt; #endif extern uint16 *M; diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index 1e687530..f8c98240 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -52,7 +52,8 @@ extern uint16 *M; extern int32 int_req[IPL_HLVL]; extern int32 ub_map[UBM_LNT_LW]; -extern int32 cpu_opt, cpu_bme; +extern uint32 cpu_opt; +extern int32 cpu_bme; extern int32 trap_req, ipl; extern int32 cpu_log; extern int32 autcon_enb; diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c index 8e632683..3256c8a6 100644 --- a/PDP11/pdp11_rh.c +++ b/PDP11/pdp11_rh.c @@ -158,7 +158,8 @@ typedef struct { MBACTX massbus[MBA_NUM]; -extern int32 cpu_opt, cpu_bme; +extern uint32 cpu_opt; +extern int32 cpu_bme; extern uint16 *M; extern int32 int_req[IPL_HLVL]; extern t_addr cpu_memsize; diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 9c97888d..1e77512c 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -530,7 +530,7 @@ max 17ms for 1 track seek w/head switch rlmp2 = rlmp1 = rlmp; if (DEBUG_PRS (rl_dev)) fprintf (sim_deb, ">>RL GSTA: rlds=%06o drv=%ld\n", - rlmp, uptr - rl_dev.units); + rlmp, (long)(uptr - rl_dev.units)); rl_set_done (0); /* done */ break; default: /* data transfer */ diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index c7b8cc70..8ecd715d 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -99,7 +99,7 @@ extern int32 fault_PC; #define RQ_XTIME 500 #define OLDPC MMR2 extern int32 MMR2; -extern int32 cpu_opt; +extern uint32 cpu_opt; #endif #if !defined (RQ_NUMCT) diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index b993f349..c4b8fbe8 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -83,7 +83,7 @@ #include "pdp11_defs.h" #define INIT_TYPE TQ5_TYPE #define INIT_CAP TQ5_CAP -extern int32 cpu_opt; +extern uint32 cpu_opt; #endif #include "pdp11_uqssp.h" diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index 01a5b0fe..0d5ff9c9 100644 --- a/PDP11/pdp11_ts.c +++ b/PDP11/pdp11_ts.c @@ -96,7 +96,7 @@ #else /* PDP-11 version */ #include "pdp11_defs.h" #define TS_DIS DEV_DIS /* off by default */ -extern int32 cpu_opt; +extern uint32 cpu_opt; #endif #include "sim_tape.h" diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index da8e472a..e6153f22 100644 --- a/PDP11/pdp11_vh.c +++ b/PDP11/pdp11_vh.c @@ -79,7 +79,7 @@ extern int32 int_req[IPL_HLVL]; #if defined (VM_PDP11) #include "pdp11_defs.h" extern int32 int_req[IPL_HLVL]; -extern int32 cpu_opt; +extern uint32 cpu_opt; #endif #include "sim_sock.h" diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index 1a22c4c2..a55510e9 100644 --- a/PDP18B/pdp18b_fpp.c +++ b/PDP18B/pdp18b_fpp.c @@ -143,7 +143,11 @@ static UFP fmb; /* FMB */ static UFP fmq; /* FMQ - hi,lo only */ extern int32 M[MAXMEMSIZE]; -extern int32 pcq[PCQ_SIZE]; +#if defined (PDP15) +extern int32 pcq[PCQ_SIZE]; /* PC queue */ +#else +extern int16 pcq[PCQ_SIZE]; /* PC queue */ +#endif extern int32 pcq_p; extern int32 PC; extern int32 trap_pending, usmd; diff --git a/S3/s3_cd.c b/S3/s3_cd.c index 5221c775..99041df5 100644 --- a/S3/s3_cd.c +++ b/S3/s3_cd.c @@ -40,8 +40,8 @@ #include extern uint8 M[]; -extern char ebcdic_to_ascii[256]; -extern char ascii_to_ebcdic[256]; +extern unsigned char ebcdic_to_ascii[]; +extern unsigned char ascii_to_ebcdic[]; int32 s1sel, s2sel; char rbuf[CBUFSIZE]; /* > CDR_WIDTH */ t_stat cdr_svc (UNIT *uptr); diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c index 0574d15b..6b9890b2 100644 --- a/S3/s3_cpu.c +++ b/S3/s3_cpu.c @@ -381,7 +381,7 @@ int32 debug_reg = 0; /* set for debug/trace * int32 debug_flag = 0; /* 1 when trace.log open */ FILE *trace; extern int32 sim_int_char; -extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ;/* breakpoint info */ 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); diff --git a/S3/s3_lp.c b/S3/s3_lp.c index cf21a127..6c085115 100644 --- a/S3/s3_lp.c +++ b/S3/s3_lp.c @@ -41,7 +41,7 @@ t_stat lpt_attach (UNIT *uptr, char *cptr); t_stat write_line (int32 ilnt, int32 mod); t_stat space (int32 lines, int32 lflag); t_stat carriage_control (int32 action, int32 mod); -extern unsigned char ebcdic_to_ascii[256]; +extern unsigned char ebcdic_to_ascii[]; #define UNIT_V_PCHAIN (UNIT_V_UF + 0) #define UNIT_M_PCHAIN 03 diff --git a/S3/s3_sys.c b/S3/s3_sys.c index 0fa2c1ee..d4123a6b 100644 --- a/S3/s3_sys.c +++ b/S3/s3_sys.c @@ -41,7 +41,7 @@ extern UNIT cpu_unit; extern REG cpu_reg[]; extern unsigned char M[]; extern int32 saved_PC, IAR[]; -extern char ebcdic_to_ascii[256]; +extern unsigned char ebcdic_to_ascii[]; char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype); int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val, diff --git a/SDS/sds_io.c b/SDS/sds_io.c index 241d7ce7..c7f87b48 100644 --- a/SDS/sds_io.c +++ b/SDS/sds_io.c @@ -79,9 +79,10 @@ extern uint32 int_req; /* int req */ extern uint32 xfr_req; /* xfer req */ extern uint32 alert; /* pin/pot alert */ extern uint32 X, EM2, EM3, OV, ion, bpt; -extern uint32 nml_mode, usr_mode, rtc_pie; +extern uint32 nml_mode, usr_mode; +extern int32 rtc_pie; extern int32 stop_invins, stop_invdev, stop_inviop; -extern int32 mon_usr_trap; +extern uint32 mon_usr_trap; extern UNIT cpu_unit; extern FILE *sim_log; extern DEVICE *sim_devices[]; diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index cd87ea82..f46f4d82 100644 --- a/SDS/sds_sys.c +++ b/SDS/sds_sys.c @@ -154,7 +154,8 @@ t_stat sim_load_cct (FILE *fileref) { int32 col, rpt, ptr, mask, cctbuf[CCT_LNT]; t_stat r; -extern int32 lpt_ccl, lpt_ccp, lpt_cct[CCT_LNT]; +extern int32 lpt_ccl, lpt_ccp; +extern uint8 lpt_cct[CCT_LNT]; char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE]; ptr = 0; diff --git a/sim_disk.c b/sim_disk.c index 8e3090c4..99f9d088 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -344,7 +344,7 @@ if (uptr->capac) { fprintf (st, "capacity=%dM%s", (uint32) (uptr->capac / ((t_addr) 1000000)), cap_units); else if (uptr->capac >= (t_addr) 1000) fprintf (st, "capacity=%dK%s", (uint32) (uptr->capac / ((t_addr) 1000)), cap_units); - else fprintf (st, "capacity=%d%S", (uint32) uptr->capac, cap_units); + else fprintf (st, "capacity=%d%s", (uint32) uptr->capac, cap_units); } else fprintf (st, "undefined capacity"); return SCPE_OK; diff --git a/swtp/swtp_cpu.c b/swtp/swtp_cpu.c index e01f1d7e..e3c69ede 100644 --- a/swtp/swtp_cpu.c +++ b/swtp/swtp_cpu.c @@ -109,7 +109,7 @@ int32 int_req = 0; /* Interrupt request */ int32 mem_fault = 0; /* memory fault flag */ extern int32 sim_int_char; -extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ;/* breakpoint info */ /* function prototypes */ From 1945465a5e96d3c64d61a283358abd191669cbf6 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 20 Mar 2012 08:54:44 -0700 Subject: [PATCH 013/112] Revised makefile to build with gcc 3.x as well as different 4.x versions and to dynamically determine the availability of desired features and to report the GCC version at build time. --- makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/makefile b/makefile index 1da49155..aaea003f 100644 --- a/makefile +++ b/makefile @@ -248,6 +248,7 @@ else #Win32 Environments (via MinGW32) GCC = gcc GCC_Path := $(dir $(shell where gcc.exe)) + GCC_VERSION = $(word 3,$(shell $(GCC) --version)) ifeq (pthreads,$(shell if exist ..\windows-build\pthreads\Pre-built.2\include\pthread.h echo pthreads)) PTHREADS_CCDEFS = -DUSE_READER_THREAD -DPTW32_STATIC_LIB -I../windows-build/pthreads/Pre-built.2/include ifeq (,$(NOASYNCH)) @@ -326,6 +327,7 @@ ifneq (3,$(GCC_MAJOR_VERSION)) CFLAGS_O += -Wno-unused-result endif endif +BUILD_FEATURES := $(BUILD_FEATURES). GCC Version: $(GCC_VERSION) $(info ***) $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with:) $(info *** $(BUILD_FEATURES).) From 93f14f76fbf380a439cdedc1a8aa14c3f1eed8ed Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 20 Mar 2012 11:13:17 -0700 Subject: [PATCH 014/112] Compile cleanups --- Ibm1130/ibm1130_cr.c | 2 +- swtp/swtp_dsk.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Ibm1130/ibm1130_cr.c b/Ibm1130/ibm1130_cr.c index 6d262da4..62230842 100644 --- a/Ibm1130/ibm1130_cr.c +++ b/Ibm1130/ibm1130_cr.c @@ -944,7 +944,7 @@ t_stat load_cr_boot (int drvno, int switches) #ifdef GUI_SUPPORT remark_cmd(msg); #else - printf("", msg); + printf("%s", msg); #endif } diff --git a/swtp/swtp_dsk.c b/swtp/swtp_dsk.c index b41943ef..9c8c7d38 100644 --- a/swtp/swtp_dsk.c +++ b/swtp/swtp_dsk.c @@ -408,7 +408,7 @@ int32 fdccmd(int32 io, int32 data) #endif break; default: - printf("Unknown FDC command %02X\n\r", data); + printf("Unknown FDC command %02XH\n\r", data); } } else { /* read status from fdc */ val = cur_flg[cur_dsk]; /* set return value */ From 3ccd66d54623985fc13b7fe47b457c364a07e069 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 20 Mar 2012 11:16:00 -0700 Subject: [PATCH 015/112] Cleanup potential fault in eth_close if eth_close is called with a NULL argument. --- sim_ether.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sim_ether.c b/sim_ether.c index 78cf7fc4..0b4dcfec 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1713,12 +1713,13 @@ t_stat eth_close(ETH_DEV* dev) { char* msg = "Eth: closed %s\r\n"; pcap_t *pcap; -int pcap_fd = dev->fd_handle; +int pcap_fd; /* make sure device exists */ if (!dev) return SCPE_UNATT; /* close the device */ +pcap_fd = dev->fd_handle; /* save handle to possibly close later */ pcap = (pcap_t *)dev->handle; dev->handle = NULL; dev->fd_handle = 0; From 2b43b358a8da95f6a47881f09fabbad9911d3270 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 20 Mar 2012 11:16:41 -0700 Subject: [PATCH 016/112] Fix SHOW SHOW command to separate the SHOW options which are device specific and unit specific --- scp.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/scp.c b/scp.c index 1da280dc..59344e72 100644 --- a/scp.c +++ b/scp.c @@ -2159,21 +2159,39 @@ return SCPE_OK; t_stat show_dev_show_commands (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { -int32 any, enb; +int32 any = 0; MTAB *mptr; -any = enb = 0; if (dptr->modifiers) { + any = 0; for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { if ((!mptr->disp) || (!mptr->pstring)) continue; + if (('\0' == *mptr->pstring) || + (0 == (mptr->mask & MTAB_XTD)) || + (0 == (mptr->mask & MTAB_VDV))) /* Device Option */ + continue; if (any++) fprintf (st, ", %s", mptr->pstring); else fprintf (st, "sh{ow} %s\t%s", sim_dname (dptr), mptr->pstring); } + if (any) + fprintf (st, "\n"); + any = 0; + for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { + if ((!mptr->disp) || (!mptr->pstring)) + continue; + if (('\0' == *mptr->pstring) || + (0 == (mptr->mask & MTAB_XTD)) || + (0 == (mptr->mask & MTAB_VUN))) /* Unit Option */ + continue; + if (any++) + fprintf (st, ", %s", mptr->pstring); + else fprintf (st, "sh{ow} %sn\t%s", sim_dname (dptr), mptr->pstring); + } + if (any) + fprintf (st, "\n"); } -if (any) - fprintf (st, "\n"); return SCPE_OK; } From cf280ad8f77b5d446d47741755893e56689a5a88 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 20 Mar 2012 18:55:45 -0700 Subject: [PATCH 017/112] Completing merge of v3.9-0-rc1 compile cleanups --- AltairZ80/altairz80_cpu.c | 5 +- AltairZ80/altairz80_sio.c | 4 +- AltairZ80/i8272.c | 4 +- AltairZ80/mfdc.c | 8 +- AltairZ80/vfdhd.c | 4 +- AltairZ80/wd179x.c | 12 +- PDP11/pdp11_rl.c | 16 +- PDP11/pdp11_rx.c | 2 +- PDP11/pdp11_ry.c | 2 +- Visual Studio Projects/PDP18B.vcproj | 326 --------------------------- Visual Studio Projects/Simh.sln | 6 - descrip.mms | 5 +- scp.c | 13 +- 13 files changed, 37 insertions(+), 370 deletions(-) delete mode 100644 Visual Studio Projects/PDP18B.vcproj diff --git a/AltairZ80/altairz80_cpu.c b/AltairZ80/altairz80_cpu.c index 7b4e7a5c..e645b7c3 100644 --- a/AltairZ80/altairz80_cpu.c +++ b/AltairZ80/altairz80_cpu.c @@ -1774,7 +1774,8 @@ void PutByteDMA(const uint32 Addr, const uint32 Value) { static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) { extern t_bool sim_brk_pend[SIM_BKPT_N_SPC]; extern t_addr sim_brk_ploc[SIM_BKPT_N_SPC]; - extern char *sim_brk_act; + extern int32 sim_do_depth; + extern char *sim_brk_act[]; BRKTAB *bp; if ((bp = sim_brk_fnd (loc)) && /* entry in table? */ (btyp & bp -> typ) && /* type match? */ @@ -1782,7 +1783,7 @@ static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) { (--(bp -> cnt) <= 0)) { /* count reach 0? */ bp -> cnt = 0; /* reset count */ sim_brk_ploc[0] = loc; /* save location */ - sim_brk_act = bp -> act; /* set up actions */ + sim_brk_act[sim_do_depth] = bp -> act; /* set up actions */ sim_brk_pend[0] = TRUE; /* don't do twice */ return TRUE; } diff --git a/AltairZ80/altairz80_sio.c b/AltairZ80/altairz80_sio.c index 94a35f81..fb76b774 100644 --- a/AltairZ80/altairz80_sio.c +++ b/AltairZ80/altairz80_sio.c @@ -132,7 +132,7 @@ static t_stat sio_attach(UNIT *uptr, char *cptr); static t_stat sio_detach(UNIT *uptr); static t_stat ptr_reset(DEVICE *dptr); static t_stat ptp_reset(DEVICE *dptr); -static t_stat toBool(char tf, int *result); +static t_stat toBool(char tf, int32 *result); static t_stat sio_dev_set_port(UNIT *uptr, int32 value, char *cptr, void *desc); static t_stat sio_dev_show_port(FILE *st, UNIT *uptr, int32 val, void *desc); static t_stat sio_dev_set_interrupton(UNIT *uptr, int32 value, char *cptr, void *desc); @@ -859,7 +859,7 @@ int32 sio1d(const int32 port, const int32 io, const int32 data) { return result; } -static t_stat toBool(char tf, int *result) { +static t_stat toBool(char tf, int32 *result) { if (tf == 'T') { *result = TRUE; return SCPE_OK; diff --git a/AltairZ80/i8272.c b/AltairZ80/i8272.c index b02fa450..bf7451da 100644 --- a/AltairZ80/i8272.c +++ b/AltairZ80/i8272.c @@ -476,8 +476,8 @@ static char *messages[0x20] = { uint8 I8272_Write(const uint32 Addr, uint8 cData) { I8272_DRIVE_INFO *pDrive; - unsigned int flags = 0; - unsigned int readlen; + uint32 flags = 0; + uint32 readlen; uint8 disk_read = 0; int32 i; diff --git a/AltairZ80/mfdc.c b/AltairZ80/mfdc.c index e697660d..7438039c 100644 --- a/AltairZ80/mfdc.c +++ b/AltairZ80/mfdc.c @@ -417,8 +417,8 @@ static uint8 MFDC_Read(const uint32 Addr) if(mfdc_info->datacount == 0) { unsigned int i, checksum; unsigned long sec_offset; - unsigned int flags; - unsigned int readlen; + uint32 flags; + uint32 readlen; /* Clear out unused portion of sector. */ memset(&sdata.u.unused[0], 0x00, 10); @@ -516,8 +516,8 @@ static uint8 MFDC_Read(const uint32 Addr) static uint8 MFDC_Write(const uint32 Addr, uint8 cData) { unsigned int sec_offset; - unsigned int flags = 0; - unsigned int writelen; + uint32 flags = 0; + uint32 writelen; MFDC_DRIVE_INFO *pDrive; pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; diff --git a/AltairZ80/vfdhd.c b/AltairZ80/vfdhd.c index bc03ed44..a8879cb0 100644 --- a/AltairZ80/vfdhd.c +++ b/AltairZ80/vfdhd.c @@ -534,7 +534,7 @@ static void VFDHD_Command(void) if(vfdhd_info->read == 1) { /* Perform a Read operation */ unsigned int i, checksum; - unsigned int readlen; + uint32 readlen; sim_debug(RD_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector); @@ -601,7 +601,7 @@ static void VFDHD_Command(void) } } else { /* Perform a Write operation */ - unsigned int writelen; + uint32 writelen; sim_debug(WR_DATA_MSG, &vfdhd_dev, "VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d\n", PCX, vfdhd_info->sel_drive, pDrive->track, vfdhd_info->head, vfdhd_info->sector); diff --git a/AltairZ80/wd179x.c b/AltairZ80/wd179x.c index 034d7e80..f3992603 100644 --- a/AltairZ80/wd179x.c +++ b/AltairZ80/wd179x.c @@ -444,8 +444,8 @@ uint8 WD179X_Read(const uint32 Addr) { uint8 cData; WD179X_DRIVE_INFO *pDrive; - unsigned int flags = 0; - unsigned int readlen; + uint32 flags = 0; + uint32 readlen; int status; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { @@ -571,8 +571,8 @@ static uint8 Do1793Command(uint8 cCommand) { uint8 result = 0; WD179X_DRIVE_INFO *pDrive; - unsigned int flags = 0; - unsigned int readlen; + uint32 flags = 0; + uint32 readlen; int status; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { @@ -952,8 +952,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) { WD179X_DRIVE_INFO *pDrive; /* uint8 disk_read = 0; */ - unsigned int flags = 0; - unsigned int writelen; + uint32 flags = 0; + uint32 writelen; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { return 0xFF; diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 1e77512c..ef338bf5 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -253,14 +253,14 @@ t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); static void rlv_maint (void); t_stat rl_detach (UNIT *uptr); t_stat rl_set_cover (UNIT *, int32, char *, void *); -t_stat rl_show_cover (FILE *, UNIT *, int, void *); +t_stat rl_show_cover (FILE *, UNIT *, int32, void *); t_stat rl_set_load (UNIT *, int32, char *, void *); -t_stat rl_show_load (FILE *, UNIT *, int, void *); -t_stat rl_show_dstate (FILE *, UNIT *, int, void *); +t_stat rl_show_load (FILE *, UNIT *, int32, void *); +t_stat rl_show_dstate (FILE *, UNIT *, int32, void *); #if defined (VM_PDP11) t_stat rl_set_ctrl (UNIT *uptr, int32 val, char *cptr, void *desc); #endif -t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int val, void *desc); +t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc); /* RL11 data structures @@ -1043,7 +1043,7 @@ t_stat rl_set_cover (UNIT *uptr, int32 val, char *cptr, void *desc) return (SCPE_OK); } -t_stat rl_show_cover (FILE *st, UNIT *uptr, int val, void *desc) +t_stat rl_show_cover (FILE *st, UNIT *uptr, int32 val, void *desc) { fprintf (st, "cover %s", (uptr->STAT & RLDS_CVO) ? "open" : "closed"); return (SCPE_OK); @@ -1072,14 +1072,14 @@ t_stat rl_set_load (UNIT *uptr, int32 val, char *cptr, void *desc) return (SCPE_OK); } -t_stat rl_show_load (FILE *st, UNIT *uptr, int val, void *desc) +t_stat rl_show_load (FILE *st, UNIT *uptr, int32 val, void *desc) { fprintf (st, "load %s", ((uptr->STAT & RLDS_M_STATE) != RLDS_LOAD) ? "set" : "reset"); return (SCPE_OK); } -t_stat rl_show_dstate (FILE *st, UNIT *uptr, int val, void *desc) +t_stat rl_show_dstate (FILE *st, UNIT *uptr, int32 val, void *desc) { int32 cnt; @@ -1121,7 +1121,7 @@ t_stat rl_set_ctrl (UNIT *uptr, int32 val, char *cptr, void *desc) #endif /* SHOW RL will display the controller type */ -t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int val, void *desc) +t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) { char *s = "RLV12"; diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index 67335d22..f4267b61 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -130,7 +130,7 @@ t_stat rx_wr (int32 data, int32 PA, int32 access); t_stat rx_svc (UNIT *uptr); t_stat rx_reset (DEVICE *dptr); t_stat rx_boot (int32 unitno, DEVICE *dptr); -void rx_done (int esr_flags, int new_ecode); +void rx_done (int32 esr_flags, int32 new_ecode); /* RX11 data structures diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index 7310cf80..47b51975 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -161,7 +161,7 @@ t_stat ry_wr (int32 data, int32 PA, int32 access); t_stat ry_svc (UNIT *uptr); t_stat ry_reset (DEVICE *dptr); t_stat ry_boot (int32 unitno, DEVICE *dptr); -void ry_done (int esr_flags, int new_ecode); +void ry_done (int32 esr_flags, int32 new_ecode); t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ry_attach (UNIT *uptr, char *cptr); diff --git a/Visual Studio Projects/PDP18B.vcproj b/Visual Studio Projects/PDP18B.vcproj deleted file mode 100644 index 236714c9..00000000 --- a/Visual Studio Projects/PDP18B.vcproj +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln index c855bee0..9eb34c1c 100644 --- a/Visual Studio Projects/Simh.sln +++ b/Visual Studio Projects/Simh.sln @@ -43,8 +43,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "I1620", "I1620.vcproj", "{0 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IBM1130", "IBM1130.vcproj", "{D593C954-5115-4D15-ABDB-01B66006FF6F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP18B", "PDP18B.vcproj", "{0A3FD54C-E497-4B2D-AD32-D83EAF996D59}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP15", "PDP15.vcproj", "{44C07AA4-6D56-45ED-8393-18A23E76B758}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP9", "PDP9.vcproj", "{9D589BCA-9E10-4FFA-B43F-DDFA91C1C098}" @@ -143,10 +141,6 @@ Global {D593C954-5115-4D15-ABDB-01B66006FF6F}.Debug|Win32.Build.0 = Debug|Win32 {D593C954-5115-4D15-ABDB-01B66006FF6F}.Release|Win32.ActiveCfg = Release|Win32 {D593C954-5115-4D15-ABDB-01B66006FF6F}.Release|Win32.Build.0 = Release|Win32 - {0A3FD54C-E497-4B2D-AD32-D83EAF996D59}.Debug|Win32.ActiveCfg = Debug|Win32 - {0A3FD54C-E497-4B2D-AD32-D83EAF996D59}.Debug|Win32.Build.0 = Debug|Win32 - {0A3FD54C-E497-4B2D-AD32-D83EAF996D59}.Release|Win32.ActiveCfg = Release|Win32 - {0A3FD54C-E497-4B2D-AD32-D83EAF996D59}.Release|Win32.Build.0 = Release|Win32 {44C07AA4-6D56-45ED-8393-18A23E76B758}.Debug|Win32.ActiveCfg = Debug|Win32 {44C07AA4-6D56-45ED-8393-18A23E76B758}.Debug|Win32.Build.0 = Debug|Win32 {44C07AA4-6D56-45ED-8393-18A23E76B758}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/descrip.mms b/descrip.mms index 27407ab5..7fd0c78a 100644 --- a/descrip.mms +++ b/descrip.mms @@ -250,7 +250,7 @@ ALTAIRZ80_SOURCE1 = $(ALTAIRZ80_DIR)ALTAIRZ80_CPU.C,$(ALTAIRZ80_DIR)ALTAIRZ80_CP $(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.C,$(ALTAIRZ80_DIR)ALTAIRZ80_NET.C,\ $(ALTAIRZ80_DIR)FLASHWRITER2.C,$(ALTAIRZ80_DIR)I86_DECODE.C,\ $(ALTAIRZ80_DIR)I86_OPS.C,$(ALTAIRZ80_DIR)I86_PRIM_OPS.C,\ - $(ALTAIRZ80_DIR)I8272.C,$(ALTAIRZ80_DIR)INSNSA.C,$(ALTAIRZ80_DIR)INSNSD.C,\ + $(ALTAIRZ80_DIR)I8272.C,$(ALTAIRZ80_DIR)INSNSD.C,\ $(ALTAIRZ80_DIR)MFDC.C,$(ALTAIRZ80_DIR)N8VEM.C,$(ALTAIRZ80_DIR)VFDHD.C ALTAIRZ80_LIB2 = $(LIB_DIR)ALTAIRZ80L2-$(ARCH).OLB ALTAIRZ80_SOURCE2 = $(ALTAIRZ80_DIR)S100_DISK1A.C,$(ALTAIRZ80_DIR)S100_DISK2.C,\ @@ -488,8 +488,7 @@ PDP10_SOURCE = $(PDP10_DIR)PDP10_FE.C,\ $(PDP10_DIR)PDP10_RP.C,$(PDP10_DIR)PDP10_SYS.C,\ $(PDP10_DIR)PDP10_TIM.C,$(PDP10_DIR)PDP10_TU.C,\ $(PDP11_DIR)PDP11_PT.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_XU.C,\ - $(PDP11_DIR)PDP11_CR.C + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_CR.C PDP10_OPTIONS = /INCL=($(SIMH_DIR),$(PDP10_DIR),$(PDP11_DIR))\ /DEF=($(CC_DEFS),"USE_INT64=1","VM_PDP10=1"$(PCAP_DEFS)) diff --git a/scp.c b/scp.c index 59344e72..eac6523a 100644 --- a/scp.c +++ b/scp.c @@ -438,7 +438,7 @@ FILE *sim_deb = NULL; /* debug file */ FILEREF *sim_deb_ref = NULL; /* debug file file reference */ static FILE *sim_gotofile; /* the currently open do file */ static int32 sim_do_echo = 0; /* the echo status of the currently open do file */ -static int32 sim_do_depth = 0; +int32 sim_do_depth = 0; static int32 sim_on_check[MAX_DO_NEST_LVL+1]; static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1]; @@ -4599,8 +4599,7 @@ return pptr; SCHTAB *get_search (char *cptr, int32 radix, SCHTAB *schptr) { -int32 c; -size_t logop, cmpop; +int32 c, logop, cmpop; t_value logval, cmpval; char *sptr, *tptr; const char logstr[] = "|&^", cmpstr[] = "=!><"; @@ -4610,14 +4609,14 @@ if (*cptr == 0) /* check for clause */ return NULL; for (logop = cmpop = -1; c = *cptr++; ) { /* loop thru clauses */ if (sptr = strchr (logstr, c)) { /* check for mask */ - logop = sptr - logstr; + logop = (int32)(sptr - logstr); logval = strtotv (cptr, &tptr, radix); if (cptr == tptr) return NULL; cptr = tptr; } else if (sptr = strchr (cmpstr, c)) { /* check for boolop */ - cmpop = sptr - cmpstr; + cmpop = (int32)(sptr - cmpstr); if (*cptr == '=') { cmpop = cmpop + strlen (cmpstr); cptr++; @@ -4630,11 +4629,11 @@ for (logop = cmpop = -1; c = *cptr++; ) { /* loop thru clauses */ else return NULL; } /* end for */ if (logop >= 0) { - schptr->logic = (int32)logop; + schptr->logic = logop; schptr->mask = logval; } if (cmpop >= 0) { - schptr->boolop = (int32)cmpop; + schptr->boolop = cmpop; schptr->comp = cmpval; } return schptr; From 663b25818bd7143b477fc4c1e2358cebb7b38e6f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 20 Mar 2012 18:57:02 -0700 Subject: [PATCH 018/112] Fix potential memory leak in error path reported by Michael Bloom --- PDP11/pdp11_xq.c | 5 ++++- PDP11/pdp11_xu.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index f3b3ce1f..e9a05ae4 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -2582,7 +2582,10 @@ t_stat xq_attach(UNIT* uptr, char* cptr) strcpy(tptr, cptr); xq->var->etherface = (ETH_DEV *) malloc(sizeof(ETH_DEV)); - if (!xq->var->etherface) return SCPE_MEM; + if (!xq->var->etherface) { + free(tptr); + return SCPE_MEM; + } status = eth_open(xq->var->etherface, cptr, xq->dev, DBG_ETH); if (status != SCPE_OK) { diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index 05bccaed..28dc50e0 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -1571,7 +1571,10 @@ t_stat xu_attach(UNIT* uptr, char* cptr) strcpy(tptr, cptr); xu->var->etherface = (ETH_DEV *) malloc(sizeof(ETH_DEV)); - if (!xu->var->etherface) return SCPE_MEM; + if (!xu->var->etherface) { + free(tptr); + return SCPE_MEM; + } status = eth_open(xu->var->etherface, cptr, xu->dev, DBG_ETH); if (status != SCPE_OK) { From 45246a33395f197a87339998f01bbad8df2448ec Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 21 Mar 2012 06:14:01 -0700 Subject: [PATCH 019/112] Updated HP2100 from Dave Bryan --- HP2100/hp2100_baci.c | 58 +- HP2100/hp2100_bugfixes.txt | 389 +++- HP2100/hp2100_cpu.c | 38 +- HP2100/hp2100_cpu0.c | 1 + HP2100/hp2100_cpu4.c | 7 +- HP2100/hp2100_cpu5.c | 6 +- HP2100/hp2100_cpu7.c | 5 +- HP2100/hp2100_defs.h | 32 +- HP2100/hp2100_di.c | 1927 ++++++++++++++++++ HP2100/hp2100_di.h | 296 +++ HP2100/hp2100_di_da.c | 2127 ++++++++++++++++++++ HP2100/hp2100_diag.txt | 621 +++++- HP2100/hp2100_dp.c | 47 +- HP2100/hp2100_dq.c | 13 +- HP2100/hp2100_dr.c | 13 +- HP2100/hp2100_ds.c | 2686 ++++++++++++-------------- HP2100/hp2100_fp1.c | 5 +- HP2100/hp2100_ipl.c | 16 +- HP2100/hp2100_lps.c | 8 +- HP2100/hp2100_lpt.c | 8 +- HP2100/hp2100_mpx.c | 60 +- HP2100/hp2100_ms.c | 25 +- HP2100/hp2100_mt.c | 15 +- HP2100/hp2100_mux.c | 44 +- HP2100/hp2100_pif.c | 19 +- HP2100/hp2100_stddev.c | 27 +- HP2100/hp2100_sys.c | 86 +- HP2100/hp_disclib.c | 2407 +++++++++++++++++++++++ HP2100/hp_disclib.h | 380 ++++ Visual Studio Projects/HP2100.vcproj | 20 + descrip.mms | 4 +- makefile | 3 +- 32 files changed, 9699 insertions(+), 1694 deletions(-) create mode 100644 HP2100/hp2100_di.c create mode 100644 HP2100/hp2100_di.h create mode 100644 HP2100/hp2100_di_da.c create mode 100644 HP2100/hp_disclib.c create mode 100644 HP2100/hp_disclib.h diff --git a/HP2100/hp2100_baci.c b/HP2100/hp2100_baci.c index ac695f6a..063705a6 100644 --- a/HP2100/hp2100_baci.c +++ b/HP2100/hp2100_baci.c @@ -1,6 +1,6 @@ /* hp2100_baci.c: HP 12966A buffered asynchronous communications interface simulator - Copyright (c) 2007-2011, J. David Bryan + Copyright (c) 2007-2012, J. David Bryan 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 @@ BACI 12966A BACI card + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines @@ -358,12 +359,6 @@ t_bool baci_enq_seen = FALSE; /* ENQ seen flag */ uint32 baci_enq_cntr = 0; /* ENQ seen counter */ -/* Terminal multiplexer library interface */ - -TMLN baci_ldsc = { 0 }; /* line descriptor */ -TMXR baci_desc = { 1, 0, 0, &baci_ldsc }; /* device descriptor */ - - /* BACI local routines */ static int32 service_time (uint32 control_word); @@ -387,12 +382,14 @@ t_stat baci_detach (UNIT *uptr); /* BACI data structures + baci_ldsc BACI terminal multiplexer line descriptor + baci_desc BACI terminal multiplexer device descriptor baci_dib BACI device information block - baci_dev BACI device descriptor baci_unit BACI unit list baci_reg BACI register list baci_mod BACI modifier list baci_deb BACI debug list + baci_dev BACI device descriptor Two units are used: one to handle character I/O via the Telnet library, and another to poll for connections and input. The character I/O service routine @@ -405,10 +402,13 @@ t_stat baci_detach (UNIT *uptr); ten millisecond period. */ -DIB baci_dib = { &baci_io, BACI, 0 }; - DEVICE baci_dev; +TMLN baci_ldsc = { 0 }; /* line descriptor */ +TMXR baci_desc = { 1, 0, 0, &baci_ldsc }; /* device descriptor */ + +DIB baci_dib = { &baci_io, BACI, 0 }; + UNIT baci_unit[] = { { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */ { UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */ @@ -444,11 +444,12 @@ REG baci_reg[] = { { FLDATA (ENQFLAG, baci_enq_seen, 0), REG_HRO }, { DRDATA (ENQCNTR, baci_enq_cntr, 16), REG_HRO }, - { FLDATA (LKO, baci.lockout, 0) }, - { FLDATA (CTL, baci.control, 0) }, - { FLDATA (FLG, baci.flag, 0) }, - { FLDATA (FBF, baci.flagbuf, 0) }, - { FLDATA (SRQ, baci.srq, 0) }, + { FLDATA (LKO, baci.lockout, 0) }, + { FLDATA (CTL, baci.control, 0) }, + { FLDATA (FLG, baci.flag, 0) }, + { FLDATA (FBF, baci.flagbuf, 0) }, + { FLDATA (SRQ, baci.srq, 0) }, + { ORDATA (SC, baci_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, baci_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -470,7 +471,8 @@ MTAB baci_mod[] = { { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &baci_desc }, { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &baci_desc }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &baci_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &baci_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &baci_dev }, { 0 } }; @@ -500,7 +502,7 @@ DEVICE baci_dev = { &baci_attach, /* attach routine */ &baci_detach, /* detach routine */ &baci_dib, /* device information block */ - DEV_NET | DEV_DEBUG | DEV_DISABLE, /* device flags */ + DEV_DEBUG | DEV_DISABLE, /* device flags */ 0, /* debug control flags */ baci_deb, /* debug flag name table */ NULL, /* memory size change routine */ @@ -786,8 +788,8 @@ return stat_data; transmit mode enables the output of the FIFO to be unloaded into the transmitter holding register (THR). Characters received or transmitted pass through the receiver register (RR) or transmitter register (TR), - respectively. They are not strictly necessary in terminal (Telnet) - transactions but are critical to diagnostic operations. + respectively. They are not strictly necessary in terminal transactions but + are critical to diagnostic operations. The UART signals an overrun if a complete character is received while the RHR still contains the previous character. The BACI does not use this signal, @@ -854,7 +856,7 @@ while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UA "ENQ count = %d\n", baci_enq_cntr); } - else { /* character is not an ENQ */ + else { /* character is not ENQ or not fast timing */ baci_enq_cntr = 0; /* reset ENQ counter */ if (is_attached) { /* attached to network? */ @@ -980,12 +982,16 @@ return status; characters. If characters are available, the terminal I/O service routine is scheduled. It starts when the socket is attached and stops when the socket is detached. + + As there is only one line, we only poll for a new connection when the line is + disconnected. */ t_stat baci_poll_svc (UNIT *uptr) { -if (baci_term.flags & UNIT_ATT) { /* attached to network? */ - if (tmxr_poll_conn (&baci_desc) >= 0) /* new connection established? */ +if (baci_term.flags & UNIT_ATT) { /* attached to line? */ + if ((baci_ldsc.conn == 0) && /* line not connected? */ + (tmxr_poll_conn (&baci_desc) >= 0)) /* and new connection established? */ baci_ldsc.rcve = 1; /* enable line to receive */ tmxr_poll_rx (&baci_desc); /* poll for input */ @@ -1205,9 +1211,9 @@ return; /* Calculate service time from baud rate. - Service times are based on 1580 instructions per second, which is the 1000 - E-Series execution speed. The "external clock" rate uses the 9600 baud rate, - as most real terminals were set to their maximum rate. + Service times are based on 1580 instructions per millisecond, which is the + 1000 E-Series execution speed. The "external clock" rate uses the 9600 baud + rate, as most real terminals were set to their maximum rate. Note that the RTE driver has a race condition that will trip if the service time is less than 1500 instructions. Therefore, these times cannot be @@ -1216,6 +1222,8 @@ return; static int32 service_time (uint32 control_word) { +/* Baud Rates 0- 7 : ext., 50, 75, 110, 134.5, 150, 300, 600, */ +/* Baud Rates 8-15 : 900, 1200, 1800, 2400, 3600, 4800, 7200, 9600 */ static const int32 ticks [] = { 1646, 316000, 210667, 143636, 117472, 105333, 52667, 26333, 17556, 13667, 8778, 6583, 4389, 3292, 2194, 1646 }; diff --git a/HP2100/hp2100_bugfixes.txt b/HP2100/hp2100_bugfixes.txt index 68ef6e55..da1e22a1 100644 --- a/HP2100/hp2100_bugfixes.txt +++ b/HP2100/hp2100_bugfixes.txt @@ -1,6 +1,6 @@ HP 2100 SIMULATOR BUG FIX WRITEUPS ================================== - Last update: 2011-06-21 + Last update: 2012-03-17 1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756 @@ -4433,7 +4433,7 @@ (except for binary mode). A correct negotiation mechanism must be implemented to handle the variety of Telnet clients properly. - WORKAROUND: Modify the TNS_SKIP case in "tmxr_poll_rx" (sim_txmxr.c) to + RESOLUTION: Modify the TNS_SKIP case in "tmxr_poll_rx" (sim_txmxr.c) to skip only LF or NUL following CR. Any other character is processed as is. STATUS: Fixed in version 3.8-0. @@ -5379,7 +5379,7 @@ RESOLUTION: Modify "do_arg" (scp.c) to test "do_arg[0]" for NULL and to return SCPE_2FARG if so. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5412,7 +5412,7 @@ pending, skip instruction execution. This allows consecutive DMA cycles without intervening instruction executions if SRQ is asserted continuously. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5438,7 +5438,7 @@ inhibit DMA channel 2 if a channel 1 request is still pending after a channel 1 cycle. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5454,7 +5454,7 @@ RESOLUTION: Modify the device names (hp2100_cpu.c, hp2100_defs.h, and hp2100_sys.c) from 0 and 1 to 1 and 2 to align with HP usage. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5470,7 +5470,7 @@ RESOLUTION: Removed obsolete comments. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5487,7 +5487,7 @@ RESOLUTION: Modify hp2100_cpu.c to remove the latency counter. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5522,7 +5522,7 @@ modify all I/O device handlers to allow processing of multiple concurrent signals. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5542,7 +5542,7 @@ and modify all signal handlers accordingly. Modify all device DIBs to add card numbers to allow for multiple-device handlers. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5577,7 +5577,7 @@ DIAG mode in three instructions if the CPU is a 2114, 2115, or 2116 and in two instructions otherwise. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5608,7 +5608,7 @@ RESOLUTION: Modify "mtcio" (hp2100_mt.c) to use the count of command table entries as the loop count. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5625,7 +5625,7 @@ RESOLUTION: Modify "iplio" (hp2100_ipl.c) to add a CRS invocation counter and to report a single debug line for consecutive CRS calls. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5647,7 +5647,7 @@ the device signal handler, and modify "sim_instr" to stop instruction execution if the returned status is not SCPE_OK. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5678,7 +5678,7 @@ if the I/O cycle completes successfully, and modify "iplio" (hp2100_ipl.c) to allow for restarting of a failed I/O cycle. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5697,7 +5697,7 @@ RESOLUTION: Expanded and completed the comments in the "divide" function (hp2100_fp1.c). - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5719,7 +5719,7 @@ unloaded" condition as Not Ready and Busy, and a "disabled" condition as Not Ready only. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5767,7 +5767,7 @@ Head-Sector Compare Error (Head-Sector and Cylinder Compare Errors can only occur during sparing operations which are not supported in simulation). - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5828,7 +5828,7 @@ RESOLUTION: Modify the Read Without Verify command handler in "ds_svc_u" (hp2100_ds.c) to begin verifying if a track boundary is crossed. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5884,7 +5884,7 @@ Unavailable if so. Modify "ds_svc_u" to check that the heads are loaded on the target unit and report Status-2 if not. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. @@ -5902,4 +5902,351 @@ the status-1 field and to check for invalid units and report Unit Unavailable if so. - STATUS: Fixed in version 3.8-2. + STATUS: Fixed in version 3.9-0. + + + +232. PROBLEM: SHOW doesn't show the unit number when all but one unit are + disabled. + + VERSION: 3.8-1 + + OBSERVATION: For multi-unit devices, the SHOW command prints device + information on the first line and then prints each unit's information on + succeeding lines. For single-unit devices, the device and unit information + are combined on one line, as the device name is allowed as a synonym for + unit 0. However, if a multi-unit device has all but one unit disabled, the + SHOW command reports the remaining unit as though the device had only + one unit, implying that the enabled unit is unit 0. + + For example, HP device DQC has two units. Attaching a file to unit 1 and + disabling unit 0 produces this output for the SHOW DQC command: + + DQC, devno=24/25, 11MW, attached to file.tmp, heads loaded, write enabled + + There is no indication that the file is attached to unit 1, and indeed if + the attachment and disabled units are reversed, the command output is the + same as above. + + CAUSE: Routine "show_device" (scp.c) combines the device and unit display + when a device has only one enabled unit. This is intended to hide the + implementation detail of single-unit devices, e.g., paper tape readers, + while allowing additional permanently-disabled units to be used by the + device for scheduling. However, it should not combine the device and units + when user-disabled units exist. + + RESOLUTION: Modify "show_device" (scp.c) to count units that have been + disabled by the user instead of units that may be disabled by the user, and + to report the unit number if user-disabled units are present. Also change + the count of reported units from the number of enabled units to the sum of + the enabled and user-disabled units. + + STATUS: Fixed in version 3.9-0. + + + +233. ENHANCEMENT: Add a simulation of the ICD series of disc drives and the + 12821A Disc Interface. + + VERSION: 3.8-1 + + OBSERVATION: The ICD drives were lower-cost versions of the earlier MAC + drives that incorporated single-drive controllers in the drive chassis. + This obviated the requirement for the separate 13037 disc controller. They + were interfaced via the 12821A HP-IB Disc Interface card; this card was + also used to interface CS/80 disc and Amigo tape drives, such as the 7912 + and 7974A. + + The addition of an ICD simulation allows preparation and direct exchange of + image files with the "HPDrive" disc emulator to enable hardware CPUs to run + with emulated drives. + + RESOLUTION: Add a simulation of the 12821A Disc Interface (hp2100_di.c + and hp2100_di.h). Add the DA device to simulate the ICD disc drives and + the ICD disc loader ROM (hp2100_di_da.c). Generalize the controller code + in the DS simulation into a common disc simulation library (hp_disclib.c + and hp_disclib.h). Alter "hp2100_sys.c" and "hp2100_defs.h" to add the + device structure and default select code assignment. + + STATUS: Fixed in version 3.9-0. + + + +234. ENHANCEMENT: Revise the simulator and documentation to use the term + "select code" instead of "device number." + + VERSION: 3.8-1 + + OBSERVATION: The HP2100 simulator and documentation use the terms "device + number," "device address," and "DEVNO" to refer to the I/O addresses of the + CPU interface cards. These terms are alien to HP users; all of the CPU and + interface documentation, from the 2116 through the 1000, use the term + "select code" for this property. + + With the addition of the 12821A disc interface and associated HP-IB drives, + the terms in use are now confusing as well. The switches on the drives + that set the bus addresses are labelled, "HP-IB DEVICE ADDRESS." Other HP + disc and tape drive manuals refer to "unit addresses" or "unit numbers" to + indicate the addresses that differentiate multiple drives on a given + interface. + + It would be clearer, especially to new users, if the existing terms were + deprecated in preference to "select code" in the simulator and + documentation. + + RESOLUTION: Modify all I/O device simulators to add "SC" as an alias for + "DEVNO" in the register and modifier tables, retaining "DEVNO" to preserve + backward compatibility with existing procedures and command files. Add + MTAB_NMO to the DEVNO modifier entry so that it does not appear in EXAMINE + or SHOW lists but can still be displayed or modified if requested + explicitly. Add hp_setsc and hp_showsc functions (hp2100_sys.c) to set and + show the select code, and modify hp_setdev and hp_showdev to call hp_setsc + and hp_showsc, respectively, and to work aroung newline suppression for + MTAB_NMO entries. Modify the documentation to change device number + references to select code references. + + STATUS: Fixed in version 3.9-0. + + + +235. ENHANCEMENT: Deprecate the device name CLK in favor of TBG. + + VERSION: 3.8-1 + + OBSERVATION: The CLK device provides a simulation of the 12539C Time Base + Generator interface. This interface is universally known to HP users as + the TBG. It would be clearer for these users if the device were named TBG. + + RESOLUTION: Modify clk_dev (hp_stddev.c) to add "TBG" as the logical name. + This still allows use of the CLK name for existing command files. + + STATUS: Fixed in version 3.9-0. + + + +236. PROBLEM: The 13037 disc controller indicates a data under/overrun + incorrectly. + + VERSION: 3.8-1 + + OBSERVATION: The 13037 disc simulator monitors the data transfer during a + read or write operation. A data overrun is indicated if SRQ is still set + when a data transfer is ready, indicating that the previous transfer has + not been handled yet by DCPC. However, the interface contains a 16-word + FIFO, so an overrun should be indicated only if the FIFO is full when a + read transfer is ready or empty when a write transfer is ready. + + A read transfer writes a word to the FIFO and sets SRQ. Currently, DCPC + must remove the word and clear SRQ before the next read transfer occurs, + even though 15 empty slots still remain in the FIFO. Similarly, a write + transfer reads a word from the FIFO and sets SRQ. DCPC must supply the + next word and clear SRQ before the next write transfer occurs, even though + available words may remain in the FIFO. Effectively, the FIFO doesn't + exist, as the simulator treats it as a single-word register. + + Moreover, the SRQ generation logic does not attempt to keep the FIFO full + for a write or empty for a read. If DCPC activity on the other channel + delays the DS channel, even by one word, an overrun is indicated, even + though available space remains in the FIFO. + + CAUSE: Incomplete FIFO implementation. + + RESOLUTION: Modify the read and write data transfer logic (hp2100_ds.c) to + indicate a data overrun when the FIFO is full or empty, respectively, and + extend the SRQ logic to continue requesting DCPC transfers until the FIFO + is empty (read) or has five words present (write), as in the hardware. + + STATUS: Fixed in version 3.9-0. + + + +237. PROBLEM: The 13037 disc controller Clear command clears too much. + + VERSION: 3.8-1 + + OBSERVATION: In hardware, the Clear command issues a Controller Preset + (CPS) tag to all connected disc drives. The description of CPS says that + it clears drive faults, the drive head and sector registers, the drive + illegal head and sector address flip-flops, and the seek check, first + status, drive fault, and attention status bits. In simulation, the + "ds_clear" routine clears the drive current cylinder register and all + status bits. + + CAUSE: Incorrect implementation. + + RESOLUTION: Modify "ds_clear" (hp_disclib.c) to clear just the indicted + drive status. + + STATUS: Fixed in version 3.9-0. + + + +238. PROBLEM: The 13037 Recalibrate command clears the End-of-Cylinder flag. + + VERSION: 3.8-1 + + OBSERVATION: The 13037 disc controller provides the Recalibrate command to + recover from Cylinder Compare errors. Recalibrate does not alter the + cylinder, head, or sector address in the controller. This allows a Read to + follow the Recalibrate directly without requiring an intervening Seek. + + However, the DS simulator clears the EOC flag. This flag indicates that + the controller cylinder address must be incremented before it is used by + the read or write routines. Therefore, a Read following a Recalibrate will + begin at the wrong address if the last successful read ended after the + last sector on a track. + + CAUSE: Oversight. + + RESOLUTION: Modify the "ds_opflags" table (hp2100_ds.c) to remove the + CMF_CLREC flag from the Recalibrate entry. + + STATUS: Fixed in version 3.9-0. + + + +239. PROBLEM: The 13037 Request Status command reports Normal Completion for an + invalid unit. + + VERSION: 3.8-1 + + OBSERVATION: The Request Status command includes a unit number field to + specify the disc drive whose status is returned in the second word. The + unit number is checked for validity, and a "unit not present" status is + returned if the number is invalid. However, if the unit number is illegal + (i.e., > 10), the command sets Normal Completion status instead of Unit + Unavailable status. + + CAUSE: The status is set without checking for unit number legality. + + RESOLUTION: Modify "ds_svc_c" (hp2100_ds.c) to set Unit Unavailable status + if the supplied unit number is greater than 10. + + STATUS: Fixed in version 3.9-0. + + + +240. PROBLEM: The 13037 Cold Load Read and Seek commands do not set Seek Check + if issued while a seek is in progress. + + VERSION: 3.8-1 + + OBSERVATION: In hardware, the read, write, and recalibrate commands wait + for seek completion if they are issued while the heads are positioning. + The Cold Load Read and Seek commands do not; they issue a seek to the drive + without checking. The drive rejects a seek while the heads are in motion + and sets Seek Check status. In simulation, however, the Cold Load Read and + Seek commands wait for seek completion before seeking. + + CAUSE: Oversight. + + RESOLUTION: Modify the "ds_opflags" table (hp2100_ds.c) to remove the + CMF_UIDLE flag from the Cold Load Read and Seek entries, and modify + "ds_docmd" to check for a seek in progress when processing the Cold Load + Read and Seek commands. + + STATUS: Fixed in version 3.9-0. + + + +241. PROBLEM: A 13037 Seek command followed by Read does not set the busy flag. + + VERSION: 3.8-1 + + OBSERVATION: In hardware, a Read command (e.g.) may be issued while a seek + is in progress. The controller firmware sets the busy flag to indicate + that the command was accepted. In simulation, however, the Read command is + not started until the seek is complete, so the busy flag is clear. A + program checking the busy flag will conclude that the Read was rejected. + + CAUSE: The busy flag is set after the check for a seek in progress, and + the firmware wait is modeled by leaving the command pending on the + interface until the seek completes. + + RESOLUTION: Modify "ds_docmd" (hp2100_ds.c) to eliminate the command + holdoff and instead model the wait for seek completion by changing the unit + function from "seek completion" to "read initiation" (e.g.). + + STATUS: Fixed in version 3.9-0. + + + +242. PROBLEM: The DO -E command continues to execute commands after a VM error. + + VERSION: 3.8-1 + + OBSERVATION: According to the manual, when invoking a DO command file and + specifying the -E switch, "command processing (including nested command + invocations) will be aborted if any error is encountered." Errors that + occur as a result of commands, e.g., an invalid unit name supplied to the + ATTACH command, correctly terminate the DO command. However, errors that + occur when running the simulated CPU (e.g., a host I/O error) do not; the + error is printed on the console, but the command file continues to execute. + + CAUSE: When the -E switch is specified, the DO command processor checks + the return status from each command invoked and aborts execution of the + command file if the return is not SCPE_OK. When a RUN, GO, STEP, CONT, or + BOOT command is invoked, the run command processor calls the VM-provided + instruction execution function to start the simulation. + + When simulation is stopped, the instruction executor returns a status code + to indicate why execution has stopped. The reason might be a VM-defined + condition (e.g., execution of a "halt" instruction) or a system condition + (e.g., a host file system I/O error). The run command processor uses this + code to print an error message, but then returns SCPE_OK to the caller. As + the DO command processor never sees the error message, it continues to + execute commands. + + RESOLUTION: Modify "run_cmd" (scp.c) to return the correct status instead + of SCPE_OK. Consolidate the error printing code from "run_cmd", "main", + and "do_cmd" into a new "fprint_error" function that combines both VM stop + and command error messages. Modify the error checkers in "main" and + "do_cmd" to call "fprint_error" to avoid printing messages from "run_cmd" + twice. + + STATUS: Fixed in version 3.9-0. + + + +243. ENHANCEMENT: Modify the 13037 disc simulator to use the common disc + controller library. + + VERSION: 3.8-1 + + OBSERVATION: The 13037 (MAC) and 13365 (ICD) disc controllers are almost + identical. Altering the DS simulator to use the controller library + introduced with the DA simulator would reduce code size, ease maintenance, + and ensure that controller bug fixes propagate to both simulators. + + RESOLUTION: Modify the 13037 simulator (hp2100_ds.c) to call routines in + the common disc controller library (hp_disclib.c). + + STATUS: Fixed in version 3.9-0. + + + +244. ENHANCEMENT: Add debug printout support to the 13037 disc simulator. + + VERSION: 3.8-1 + + OBSERVATION: Debugging the disc controller behavior would be easier if the + internal state of the simulator was observable and recordable. + + RESOLUTION: Modify "hp2100_ds.c" to add debug-mode printouts. + + STATUS: Fixed in version 3.9-0. + + + +245. ENHANCEMENT: Eliminate the poll for parameters to 13037 disc commands. + + VERSION: 3.8-1 + + OBSERVATION: The DS simulator repeatedly polls the CPU interface for the + parameters to certain disc commands, such as Seek. It would be more + efficient to wait for a parameter to be output by the CPU. + + RESOLUTION: Modify "ds_io" (hp2100_ds.c) to activate the controller + service only when a parameter word has been received with an ioIOO signal. + + STATUS: Fixed in version 3.9-0. diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 0f7331b5..7ccb3c4e 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -1,6 +1,6 @@ /* hp2100_cpu.c: HP 21xx/1000 CPU simulator - Copyright (c) 1993-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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,8 @@ DMA1,DMA2 12607B/12578A/12895A direct memory access controller DCPC1,DCPC2 12897B dual channel port controller + 13-Jan-12 JDB Minor speedup in "is_mapped" + Added casts to cpu_mod, dmasio, dmapio, cpu_reset, dma_reset 07-Apr-11 JDB Fixed I/O return status bug for DMA cycles Failed I/O cycles now stop on failing instruction 28-Mar-11 JDB Tidied up signal handling @@ -729,17 +731,17 @@ REG cpu_reg[] = { Reference Handbook. */ MTAB cpu_mod[] = { - { UNIT_MODEL_MASK, UNIT_2116, "", "2116", &cpu_set_model, &cpu_show_model, "2116" }, - { UNIT_MODEL_MASK, UNIT_2115, "", "2115", &cpu_set_model, &cpu_show_model, "2115" }, - { UNIT_MODEL_MASK, UNIT_2114, "", "2114", &cpu_set_model, &cpu_show_model, "2114" }, - { UNIT_MODEL_MASK, UNIT_2100, "", "2100", &cpu_set_model, &cpu_show_model, "2100" }, - { UNIT_MODEL_MASK, UNIT_1000_E, "", "1000-E", &cpu_set_model, &cpu_show_model, "1000-E" }, - { UNIT_MODEL_MASK, UNIT_1000_E, NULL, "21MX-E", &cpu_set_model, &cpu_show_model, "1000-E" }, - { UNIT_MODEL_MASK, UNIT_1000_M, "", "1000-M", &cpu_set_model, &cpu_show_model, "1000-M" }, - { UNIT_MODEL_MASK, UNIT_1000_M, NULL, "21MX-M", &cpu_set_model, &cpu_show_model, "1000-M" }, + { UNIT_MODEL_MASK, UNIT_2116, "", "2116", &cpu_set_model, &cpu_show_model, (void *) "2116" }, + { UNIT_MODEL_MASK, UNIT_2115, "", "2115", &cpu_set_model, &cpu_show_model, (void *) "2115" }, + { UNIT_MODEL_MASK, UNIT_2114, "", "2114", &cpu_set_model, &cpu_show_model, (void *) "2114" }, + { UNIT_MODEL_MASK, UNIT_2100, "", "2100", &cpu_set_model, &cpu_show_model, (void *) "2100" }, + { UNIT_MODEL_MASK, UNIT_1000_E, "", "1000-E", &cpu_set_model, &cpu_show_model, (void *) "1000-E" }, + { UNIT_MODEL_MASK, UNIT_1000_E, NULL, "21MX-E", &cpu_set_model, &cpu_show_model, (void *) "1000-E" }, + { UNIT_MODEL_MASK, UNIT_1000_M, "", "1000-M", &cpu_set_model, &cpu_show_model, (void *) "1000-M" }, + { UNIT_MODEL_MASK, UNIT_1000_M, NULL, "21MX-M", &cpu_set_model, &cpu_show_model, (void *) "1000-M" }, #if defined (HAVE_INT64) - { UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &cpu_set_model, &cpu_show_model, "1000-F" }, + { UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &cpu_set_model, &cpu_show_model, (void *) "1000-F" }, #endif { MTAB_XTD | MTAB_VDV, 1, "IDLE", "IDLE", &cpu_set_idle, &cpu_show_idle, NULL }, @@ -2442,13 +2444,15 @@ return; static t_bool is_mapped (uint32 va) { -uint32 dms_fence = dms_sr & MST_FENCE; /* get BP fence value */ +uint32 dms_fence; if (va >= 02000) /* above the base bage? */ return TRUE; /* always mapped */ -else +else { + dms_fence = dms_sr & MST_FENCE; /* get BP fence value */ return (dms_sr & MST_FLT) ? (va < dms_fence) : /* below BP fence and lower portion mapped? */ (va >= dms_fence); /* or above BP fence and upper portion mapped? */ + } } @@ -3073,7 +3077,7 @@ return stat_data; uint32 dmasio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const CHANNEL ch = dibptr->card_index; /* DMA channel number */ +const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ uint16 data; IOSIGNAL signal; IOCYCLE working_set = signal_set; /* no SIR handler needed */ @@ -3155,7 +3159,7 @@ return stat_data; uint32 dmapio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const CHANNEL ch = dibptr->card_index; /* DMA channel number */ +const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ uint16 data; IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ @@ -3459,7 +3463,7 @@ if (M == NULL) { /* initial call after st else /* not defined */ return SCPE_IERR; /* internal error */ - M = calloc (PASIZE, sizeof (uint16)); /* alloc mem */ + M = (uint16 *) calloc (PASIZE, sizeof (uint16)); /* alloc mem */ if (M == NULL) /* alloc fail? */ return SCPE_MEM; @@ -3504,7 +3508,7 @@ return SCPE_OK; t_stat dma_reset (DEVICE *dptr) { DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ -const CHANNEL ch = dibptr->card_index; /* DMA channel number */ +const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ hp_enbdis_pair (dma_dptrs [ch], /* make specified channel */ @@ -3980,7 +3984,7 @@ switch (sel) { break; case 3: /* DS boot */ - ibl_copy (ds_rom,dev); + ibl_copy (ds_rom, dev); break; } diff --git a/HP2100/hp2100_cpu0.c b/HP2100/hp2100_cpu0.c index 2e7e6eb2..838d2883 100644 --- a/HP2100/hp2100_cpu0.c +++ b/HP2100/hp2100_cpu0.c @@ -98,6 +98,7 @@ 105521 105301 "Closed loop" (trap cell handler) 105522 105302 [unknown] [test] 105524 105304 [self test] + -- 105310 7974 boot loader ROM extension Notes: diff --git a/HP2100/hp2100_cpu4.c b/HP2100/hp2100_cpu4.c index acc39862..3da7a9d3 100644 --- a/HP2100/hp2100_cpu4.c +++ b/HP2100/hp2100_cpu4.c @@ -1,6 +1,6 @@ /* hp2100_cpu4.c: HP 1000 FPP/SIS - Copyright (c) 2006-2008, J. David Bryan + Copyright (c) 2006-2012, J. David Bryan 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 @@ CPU4 Floating Point Processor and Scientific Instruction Set + 06-Feb-12 JDB Added OPSIZE casts to fp_accum calls in .FPWR/.TPWR 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) 18-Mar-08 JDB Fixed B register return bug in /CMRT @@ -1074,7 +1075,7 @@ switch (entry) { /* decode IR<3:0> */ exponent = exponent - 1; O = 0; /* clear overflow */ - fp_accum (&op[2], (fp_f + p)); /* acc = arg */ + fp_accum (&op[2], (OPSIZE) (fp_f + p)); /* acc = arg */ while (exponent-- > 0) { O = O | fp_exec ((uint16) (0054 | p), /* square acc */ @@ -1086,7 +1087,7 @@ switch (entry) { /* decode IR<3:0> */ i = i << 1; } - op[2] = fp_accum (NULL, (fp_f + p)); /* get accum */ + op[2] = fp_accum (NULL, (OPSIZE) (fp_f + p)); /* get accum */ if (op[2].fpk[0] == 0) /* result zero? */ O = 1; /* underflow */ diff --git a/HP2100/hp2100_cpu5.c b/HP2100/hp2100_cpu5.c index 00dec44e..6285ef10 100644 --- a/HP2100/hp2100_cpu5.c +++ b/HP2100/hp2100_cpu5.c @@ -1,7 +1,7 @@ /* hp2100_cpu5.c: HP 1000 RTE-6/VM VMA and RTE-IV EMA instructions Copyright (c) 2007-2008, Holger Veit - Copyright (c) 2006-2008, J. David Bryan + Copyright (c) 2006-2011, J. David Bryan 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 @@ CPU5 RTE-6/VM and RTE-IV firmware option instructions + 28-Dec-11 JDB Eliminated unused variable in "cpu_ema_vset" 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) 30-Jul-08 JDB Redefined ABORT to pass address, moved def to hp2100_cpu.h @@ -970,7 +971,7 @@ uint32 scalars = op[3].word; /* S4 */ uint32 vectors = op[4].word; /* S5 */ uint32 k = op[5].word; /* S6 */ uint32 imax = 0; /* imax S11*/ -uint32 xidex,idext1,mseg,phys, addr, i, MA; +uint32 xidex, idext1, mseg, addr, i, MA; t_bool negflag = FALSE; for (i=0; i> 1) & MSEGMASK; /* S9 get logical start MSEG */ -phys = idext1 & 01777; /* phys start of EMA */ for (i=0; ifpk[0] & 0100000) -static void vis_abs(OP* in, uint32 opsize) +static void vis_abs(OP* in, OPSIZE opsize) { uint32 sign = GET_MSIGN(in); /* get sign */ if (sign) (void)fp_pcom(in, opsize); /* if negative, make positive */ diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index f999867b..3118e2d1 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-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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,10 +23,12 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 10-Feb-12 JDB Added hp_setsc, hp_showsc functions to support SC modifier 28-Mar-11 JDB Tidied up signal handling 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation 27-Oct-10 JDB Revised I/O signal enum values for concurrent signals Revised I/O macros for new signal handling + 09-Oct-10 JDB Added DA and DC device select code assignments 07-Sep-08 JDB Added POLL_FIRST to indicate immediate connection attempt 15-Jul-08 JDB Rearranged declarations with hp2100_cpu.h 26-Jun-08 JDB Rewrote device I/O to model backplane signals @@ -170,6 +172,8 @@ typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization #define MUXL 040 /* 12920A lower data */ #define MUXU 041 /* 12920A upper data */ #define MUXC 042 /* 12920A control */ +#define DI_DA 043 /* 12821A Disc Interface with Amigo disc devices */ +#define DI_DC 044 /* 12821A Disc Interface with CS/80 disc and tape devices */ #define OPTDEV 002 /* start of optional devices */ #define CRSDEV 006 /* start of devices that receive CRS */ @@ -178,19 +182,19 @@ typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization /* IBL assignments */ -#define IBL_V_SEL 14 /* ROM select */ +#define IBL_V_SEL 14 /* ROM select <15:14> */ #define IBL_M_SEL 03 -#define IBL_PTR 0000000 /* PTR */ -#define IBL_DP 0040000 /* disk: DP */ -#define IBL_DQ 0060000 /* disk: DQ */ -#define IBL_MS 0100000 /* option 0: MS */ -#define IBL_DS 0140000 /* option 1: DS */ -#define IBL_MAN 0010000 /* RPL/man boot */ -#define IBL_V_DEV 6 /* dev in <11:6> */ +#define IBL_PTR 0000000 /* ROM 0: 12992K paper tape reader (PTR) */ +#define IBL_DP 0040000 /* ROM 1: 12992A 7900 disc (DP) */ +#define IBL_DQ 0060000 /* ROM 1: 12992A 2883 disc (DQ) */ +#define IBL_MS 0100000 /* ROM 2: 12992D 7970 tape (MS) */ +#define IBL_DS 0140000 /* ROM 3: 12992B 7905/06/20/25 disc (DS) */ +#define IBL_MAN 0010000 /* RPL/manual boot <13:12> */ +#define IBL_V_DEV 6 /* select code <11:6> */ #define IBL_OPT 0000070 /* options in <5:3> */ -#define IBL_DP_REM 0000001 /* DP removable */ -#define IBL_DS_HEAD 0000003 /* DS head number */ -#define IBL_LNT 64 /* boot ROM length */ +#define IBL_DP_REM 0000001 /* DP removable <0:0> */ +#define IBL_DS_HEAD 0000003 /* DS head number <1:0> */ +#define IBL_LNT 64 /* boot ROM length in words */ #define IBL_MASK (IBL_LNT - 1) /* boot length mask */ #define IBL_DPC (IBL_LNT - 2) /* DMA ctrl word */ #define IBL_END (IBL_LNT - 1) /* last location */ @@ -453,10 +457,12 @@ extern void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp); extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw); extern const char *fmt_char (uint8 ch); +extern t_stat hp_setsc (UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat hp_showsc (FILE *st, UNIT *uptr, int32 val, void *desc); extern t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc); extern t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc); -/* Standard device functions */ +/* Device-specific functions */ extern int32 sync_poll (POLLMODE poll_mode); diff --git a/HP2100/hp2100_di.c b/HP2100/hp2100_di.c new file mode 100644 index 00000000..4b790ff1 --- /dev/null +++ b/HP2100/hp2100_di.c @@ -0,0 +1,1927 @@ +/* hp2100_di.c: HP 12821A HP-IB Disc Interface simulator + + Copyright (c) 2010-2012, J. David Bryan + + 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. + + DI 12821A Disc Interface + + 13-Feb-12 JDB First release + 15-Dec-11 JDB Added dummy DC device for diagnostics + 09-Oct-10 JDB Created DI simulation + + References: + - HP 12821A Disc Interface Installation and Service Manual (12821-90006, + Feb-1985) + - IEEE Standard Digital Interface for Programmable Instrumentation + (IEEE-488A-1980, Sep-1979) + + + The 12821A was a high-speed implementation of the Hewlett-Packard Interface + Bus (HP-IB, formalized as IEEE Std. 488-1978). It was used to interface + HP-IB disc and tape devices, such as the HP 7906H, 7908A, and 7974A, to the + HP 1000 running RTE-IVB and RTE-6/VM. Three device command protocols were + supported by the I/O drivers: Amigo discs by driver DVA32, CS/80 discs by + DVM33, and Amigo tapes by DVS23. + + In an RTE environment, the 12821A was the system controller. While + electrically compatible with the HP-IB specification and capable of receiving + addressing commands from the bus, the 12821A did not use the full IEEE-488 + protocol. Card talker and listener states were set by bits in a control + register, rather than by receiving talk and listen commands over the bus. + The bus address of the card could be set via DIP switches, but this feature + was only used by the diagnostic. + + The card supported packed and unpacked transfers across the bus. Up to four + devices could be connected to each card; the limit was imposed by the maximum + electrical loading on the bus compatible with the high data rate. + + The 12821A had a 16-word FIFO buffer and could sustain DCPC transfers of one + megabyte per second. Burst transfers by the CPU to fill or empty the FIFO + could run at the full bandwidth of the I/O backplane. This could hold off + lower-priority devices for 10-15 microseconds until the card slowed down to + the rate of the disc or tape. + + Card assembly 12821-60003 was revised to add a DCPC pacing option. Placing + jumper W1 in position A inhibited SRQ for one I/O cycle in six to allow a + lower-priority interface card to transfer one word. Position B allowed SRQ + to assert continuously as it did on the earlier card assembly 12821-60001. + + The simulator is logically partitioned into three sets of functions: the + interface card simulation, the HP-IB bus simulation, and the device + simulation. This is the card simulation and the card portion of the HP-IB + simulation. Separate files for the tape and disc devices contain the device + simulations and the device portions of the HP-IB simulations. + + This simulation is written to allow the definition of multiple DI cards in a + system. The RTE operating system provided separate I/O drivers for the Amigo + disc, Amigo tape, and CS/80 disc devices. As only one I/O driver could + control a given interface, separate interfaces were required if more than one + device class was installed. For example, it was not possible to install an + Amigo disc and an Amigo tape on the same interface card. + + + Implementation notes: + + 1. The simulator behaves as though card switches S1-S7 are initially closed, + providing a card bus address of 0. The address may be changed with the + SET ADDRESS=n command. Only addresses 0-7 are supported, and the + address may duplicate a device bus address without conflict, as the + address is only used during the diagnostic when devices are disconnected. + + 2. The simulator behaves as though card switch S8 is open, enabling the card + to be the system controller. This cannot be changed by the user. + + 3. The simulator behaves as though card jumper W1 (DCPC pacing) is in + position B. This cannot be changed by the user. +*/ + + + +#include "hp2100_defs.h" +#include "hp2100_di.h" + + + +/* Program constants */ + +#define SW8_SYSCTL 1 /* card is always the system controller (switch 8) */ + +#define IFC_TIMEOUT 157 /* 157 instructions = ~ 100 microseconds */ + +#define CONTROLLER 31 /* dummy unit number for DI */ + + +/* Character constants */ + +#define LF '\012' + + +/* Control Word Register */ + +#define CNTL_SRQ 0100000 /* enable service request interrupt */ +#define CNTL_IFC 0040000 /* assert IFC, enable IFC interrupt */ +#define CNTL_REN 0020000 /* assert remote enable */ +#define CNTL_IRL 0010000 /* enable input-register-loaded interrupt */ +#define CNTL_LBO 0004000 /* enable last-byte-out interrupt */ +#define CNTL_LF 0002000 /* enable line feed terminator */ +#define CNTL_EOI 0001000 /* assert end or identify */ +#define CNTL_ATN 0000400 /* assert attention */ +#define CNTL_DIAG 0000200 /* diagnostic loopback */ +#define CNTL_NRFD 0000100 /* assert not ready for data */ +#define CNTL_PPE 0000040 /* parallel poll enable */ +#define CNTL_ODD 0000020 /* odd number of bytes */ +#define CNTL_PACK 0000010 /* packed data transfer */ +#define CNTL_LSTN 0000004 /* listen */ +#define CNTL_TALK 0000002 /* talk */ +#define CNTL_CIC 0000001 /* controller in charge */ + + +/* Status Word Register */ + +#define STAT_SRQBUS 0100000 /* service request bus state */ +#define STAT_IFCBUS 0040000 /* interface clear bus state */ +#define STAT_RENBUS 0020000 /* remote enable bus state */ +#define STAT_IRL 0010000 /* input register loaded */ +#define STAT_LBO 0004000 /* last byte out */ +#define STAT_LBI 0002000 /* last byte in */ +#define STAT_EOIBUS 0001000 /* end or identify */ +#define STAT_ATNBUS 0000400 /* attention */ +#define STAT_IFC 0000200 /* interface clear seen */ +#define STAT_ODD 0000020 /* odd number of bytes */ +#define STAT_SYSCTL 0000010 /* system controller */ +#define STAT_LSTN 0000004 /* listener */ +#define STAT_TALK 0000002 /* talker */ +#define STAT_CIC 0000001 /* controller in charge */ + + +/* Data word */ + +#define DATA_LBO 0100000 /* last byte out */ +#define DATA_EOI 0001000 /* end or identify */ +#define DATA_ATN 0000400 /* attention */ + + +/* Tag word */ + +#define BUS_SHIFT 16 /* left shift count to align BUS_ATN, EOI with tag */ +#define DATA_SHIFT 8 /* left shift count to align DATA_ATN, EOI with tag */ + +#define TAG_ATN 0000200000 /* bit 16: attention */ +#define TAG_EOI 0000400000 /* bit 17: end-or-identify */ +#define TAG_EDT 0001000000 /* bit 18: end of data transfer */ +#define TAG_LBR 0002000000 /* bit 19: last byte received */ + +#define TAG_MASK (TAG_ATN | TAG_EOI | TAG_EDT | TAG_LBR) + + +/* FIFO access modes */ + +#define FIFO_EMPTY (di_card->fifo_count == 0) /* FIFO empty test */ +#define FIFO_FULL (di_card->fifo_count == FIFO_SIZE) /* FIFO full test */ + +typedef enum { + bus_access, /* per-byte access */ + cpu_access, /* per-word access */ + diag_access /* mixed access */ + } FIFO_ACCESS; + + +/* Disc interface state variables */ + +DI_STATE di [card_count]; /* per-card state */ + + +/* Disc interface global VM routines */ + +IOHANDLER di_io; +t_stat di_reset (DEVICE *dptr); + +/* Disc interface global SCP routines */ + +t_stat di_set_address (UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc); +t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc); + +/* Disc interface global bus routines */ + +t_bool di_bus_source (CARD_ID card, uint8 data); +void di_bus_control (CARD_ID card, uint32 unit, uint8 assert, uint8 deny); +void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response); + +/* Disc interface local bus routines */ + +static t_bool di_bus_accept (CARD_ID card, uint8 data); +static void di_bus_respond (CARD_ID card, uint8 cntl); +static void di_bus_poll (CARD_ID card); + +/* Disc interface local utility routines */ + +static void master_reset (CARD_ID card); +static void update_state (CARD_ID card); +static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access); +static uint16 fifo_unload (CARD_ID card, FIFO_ACCESS access); +static void fprint_bus (FILE *file, char *format, uint8 cntl); + + + +/* Dummy DC device. + + This dummy device allows the DI diagnostic to test inter-card signals. Test + 15 can only be performed if there are two DIs available. + + This device provides a second "bare" card. Normally, it is disabled and + cannot be enabled by the user. Enabling or disabling DIAG mode on the DA + device automatically enables or disables the DC device. The select code of + the DC device is fixed at 45B and cannot be changed. +*/ + +DIB dc_dib = { &di_io, DI_DC, dc }; + +REG dc_reg [] = { + { BRDATA (FIFO, di [dc].fifo, 8, 20, FIFO_SIZE), REG_CIRC }, /* needed for "qptr" */ + { NULL } + }; + +DEVICE dc_dev = { + "DC", /* device name */ + NULL, /* unit array */ + dc_reg, /* register array */ + NULL, /* modifier array */ + 0, /* number of units */ + 10, /* address radix */ + 31, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 8, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &di_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &dc_dib, /* device information block */ + DEV_DEBUG | DEV_DIS, /* device flags */ + 0, /* debug control flags */ + di_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + + + +/* DI data structures. + + *dptrs device pointers + *bus_accept device acceptor function pointers + *bus_respond device responder function pointers + + di_deb DI debug table + + The first three pointer arrays have elements that correspond one-for-one with + the supported devices. These allow the DI simulator to work with multiple + cards. The actual devices are defined in the individual device simulators. + + Note that the DC and MA devices are reserved for future use. Until one or + the other is fully implemented, a dummy DC device is provided above for use + by the diagnostic only. +*/ + +extern DEVICE da_dev; + +static DEVICE *dptrs [card_count] = { &da_dev, &dc_dev, NULL }; +static ACCEPTOR *bus_accept [card_count] = { &da_bus_accept, NULL, NULL }; +static RESPONDER *bus_respond [card_count] = { &da_bus_respond, NULL, NULL }; + + +DEBTAB di_deb [] = { + { "CPU", DEB_CPU }, + { "CMDS", DEB_CMDS }, + { "BUF", DEB_BUF }, + { "XFER", DEB_XFER }, + { "RWSC", DEB_RWSC }, + { "SERV", DEB_SERV }, + { NULL, 0 } + }; + + + +/* Disc interface global VM routines */ + + +/* I/O signal handler. + + The card has two input and two output registers. The Input Data Register and + Output Data Register are addressed when the control flip-flop is set. The + Status Word and the Control Word Register are addressed when the control + flip-flop is clear. The card has the usual control, flag buffer, flag, and + SRQ flip-flops, though flag and SRQ are decoupled to allow the full DCPC + transfer rate. + + In hardware, the presence of the card FIFO, which is necessary to obtain full + DCPC bandwidth, implies a delay between CPU actions, such as outputting the + last word in a data transfer, and device actions, such as accepting the last + word of a disc write. Four flip-flops are used to monitor FIFO status: + + - EDT (End of Data Transfer) + - LBO (Last Byte Out) + - LBI (Last Byte In) + - EOR (End of Record) + + The EDT signal indicates that the final data word of a transfer is being + written to the FIFO. The flip-flop is set by the EDT backplane signal when + the last cycle of a DCPC transfer is executing, or during programmed output + transfers when CLF does not accompany IOO in packed mode, or when bit 15 of + the data word is set in unpacked mode. It remains set until cleared by a + master reset. The output of the EDT flip-flop drives the EDT tag input of + the FIFO. + + The LBO signal indicates that the final data byte of a transfer has been + sourced to the bus. The flip-flop is set when the last byte of the entry + tagged with EDT has been unloaded from the FIFO. It is cleared by a master + reset, or when an entry not tagged with EDT is unloaded. The output of the + LBO flip-flop drives the LBO bit in the Status Word. + + The LBI signal indicates that the final byte of an input transfer has been + accepted from the bus. The flip-flop is set when a byte tagged with EOI is + received and the EOI bit in the control register is set, or a line-feed byte + is received and the LF bit in the control register is set. It is cleared by + a master reset, or when neither of these conditions is true. The input of + the LBI flip-flop also drives the LBR (last byte received) tag input of the + FIFO, and the output of the flip-flop drives the LBI bit in the Status Word. + + The EOR signal indicates that the final data word of a transfer is available + in the Input Data Register. The flip-flop is set when the last byte of the + entry tagged with LBR has been unloaded from the FIFO and written to the IDR. + It is cleared by a master reset, or when an entry not tagged with LBR is + unloaded and written to the IDR. The output of the EOR flip-flop sets the + flag flip-flop when the IDR is unloaded. + + + Implementation notes: + + 1. In hardware, the Status Word consists of individual flip-flops and status + signals that are enabled onto the I/O backplane. In simulation, the + individual status values are collected into a Status Word Register, and + the Output Data Register does not exist (output data is written directly + to the FIFO buffer). + + 2. The DIAG, T, and L control bits enable a data loopback path on the card. + An IOO issued to the card unloads a word from the FIFO and then loads the + lower byte into both bytes of the FIFO. The data word output with the + IOO instruction is not used. + + In hardware, IOO triggers the FIFO unload and reload; T and L are + required only for the loopback path. If L is not asserted, the FIFO is + loaded with 177777 due to the floating bus. If L is asserted and T is + not, the FIFO is loaded with 000000 due to pullups on the DIO lines. + In simulation, we look only for DIAG and assume that T/L are set + properly, i.e., unloaded data is reloaded. + + 3. In hardware, the SRQ and NRFD lines are open-collector and may be driven + simultaneously from several bus devices. Simulating this fully would + require keeping the state of the lines for each device, and deriving the + common bus signals from the logical AND/OR of the state values. + Fortunately, some simplifications are possible. + + The DI asserts SRQ only if control word bit 15 is 1 and bit 0 is 0. + Other bit combinations deny SRQ; as neither the Amigo nor CS/80 protocols + use SRQ and serial polls, there will be no other driver. + + In hardware, every listener drives NRFD, but in practice there is only + one listener at a time. When the card is the listener, it asserts NRFD + if the FIFO becomes full. In simulation, we assert NRFD on the bus if + NRFD is set in the control register, or we are listening and the FIFO is + full. We deny NRFD if NRFD had been set in the control register but is + no longer, or if we had been a listener but are no longer. That is, we + assume that if we have forced NRFD or set it as a listener, then no one + else will be asserting NRFD, so it's safe for us to deny NRFD when the + override is removed or we are no longer a listener. + + We also deny NRFD when a CRS is issued if NRFD had been explicitly + requested or the card had been listening. The rationale is the same: + only a listener can assert NRFD, so if we were listening, it's safe to + deny it, because only we could have set it. + + 4. In hardware, the IRL, LBO, LBI, and IFC status bits are driven by + corresponding flip-flops. In simulation, the status bits themselves hold + the equivalent states and are set and cleared as indicated. + + 5. The card state must be updated during status read (IOI) processing + because the 7974 boot ROM watches the IFC line to determine when IFC + assertion ends. + + 6. DCPC performance is optimized by recognizing that the normal cases (an + input that empties the FIFO or an output that fills the FIFO) do not + alter the card state, and so the usual update_state call may be omitted. + + 7. The gcc compiler (at least as of version 4.6.2) does not optimize + repeated use of array-of-structures accesses. Instead, it recalculates + the index each time, even though the index is a constant within the + function. To avoid this performance penalty, we use a pointer to the + selected DI_STATE structure. Note that VC++ 2008 does perform this + optimization. +*/ + + +uint32 di_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +static const char * const output_state [] = { "Control", "Data" }; +static const char * const input_state [] = { "Status", "Data" }; + +const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : ""); +const CARD_ID card = (CARD_ID) (dibptr->card_index); +DI_STATE * const di_card = &di [card]; + +uint8 assert, deny; /* new bus control states */ +uint16 data; +t_bool update_required = TRUE; /* TRUE if CLF must update card state */ + +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + di_card->flag = CLEAR; /* clear flag */ + di_card->flagbuf = CLEAR; /* and flag buffer */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [CLF] Flag cleared\n", + dptrs [card]->name); + + if (update_required) /* if card state has changed */ + update_state (card); /* then update the state */ + break; + + + case ioSTF: /* set flag flip-flop */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [STF] Flag set\n", + dptrs [card]->name); + + /* fall into ENF handler */ + + case ioENF: /* enable flag */ + di_card->flag = SET; /* set flag */ + di_card->flagbuf = SET; /* and flag buffer */ + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (di [card]); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (di [card]); + break; + + + case ioIOI: /* I/O data input */ + if (di_card->control == SET) { /* control set = data mode? */ + data = di_card->input_data_register; /* read input data register */ + di_card->status_register &= ~STAT_IRL; /* clear input register loaded status */ + + if (FIFO_EMPTY && di_card->eor == CLEAR) { /* FIFO empty and end of record not seen? */ + if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: SRQ cleared\n", + dptrs [card]->name); + + di_card->srq = CLEAR; /* clear SRQ */ + update_required = FALSE; /* card state does not change */ + } + } + + else { /* control clear = status mode */ + di_card->status_register &= /* clear the values to be computed, */ + STAT_IRL | STAT_LBO /* preserving those set elsewhere */ + | STAT_LBI | STAT_IFC; + + di_card->status_register |= /* set T/L/C status from control register */ + di_card->cntl_register /* (T/L are ORed, as MTA or MLA can also set) */ + & (CNTL_CIC | CNTL_TALK | CNTL_LSTN); + + + if (SW8_SYSCTL) /* if SW8 set, card is system controller */ + di_card->status_register |= STAT_SYSCTL; + + if (di_card->ibp == lower) /* if lower byte input is next */ + di_card->status_register |= STAT_ODD; /* then last transfer was odd */ + + di_card->status_register |= /* set bus status bits */ + (di_card->bus_cntl /* from corresponding bus control lines */ + & (BUS_SRQ | BUS_IFC | BUS_REN + | BUS_EOI | BUS_ATN)) << DATA_SHIFT; + + data = di_card->status_register; /* return the status word */ + } + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [LIx%s] %s = %06o\n", + dptrs [card]->name, hold_or_clear, + input_state [di_card->control], data); + + if (update_required && !(signal_set & ioCLF)) /* if update and CLF not present, */ + update_state (card); /* update state, else ioCLF will update */ + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* get the data value */ + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [OTx%s] %s = %06o\n", + dptrs [card]->name, hold_or_clear, + output_state [di_card->control], data); + + if (di_card->control == SET) { /* control set = data mode */ + if (signal_set & ioEDT) /* if end of DCPC transfer */ + di_card->edt = SET; /* set EDT flip-flop */ + + else if (di_card->cntl_register & CNTL_PACK) { /* packed transfer? */ + if (!(signal_set & ioCLF)) /* and CLF not given? */ + di_card->edt = SET; /* set EDT flip-flop */ + } + + else /* unpacked transfer */ + if (data & DATA_LBO) /* and last byte out? */ + di_card->edt = SET; /* set EDT flip-flop */ + + if (di_card->cntl_register & CNTL_DIAG) { /* DIAG loopback? */ + data = fifo_unload (card, diag_access); /* unload data from FIFO */ + fifo_load (card, data, diag_access); /* and load back in */ + } + + else { /* normal mode */ + fifo_load (card, data, cpu_access); /* load data word into FIFO */ + + if (FIFO_FULL && (di_card->bus_cntl & BUS_NRFD)) { /* FIFO full and listener not ready? */ + if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: SRQ cleared\n", + dptrs [card]->name); + + di_card->srq = CLEAR; /* clear SRQ */ + update_required = FALSE; /* card state does not change */ + } + } + } + + else { /* control clear = write control word */ + assert = 0; /* initialize bus control assertions */ + deny = 0; /* and denials */ + + if (!(data & CNTL_PACK)) /* unpacked mode always sets */ + di_card->ibp = di_card->obp = lower; /* byte selectors to the lower byte */ + + if (data & CNTL_TALK) { /* talking enables ATN and EOI outputs */ + if ((data & (CNTL_PPE | CNTL_CIC)) /* if parallel poll is enabled */ + == (CNTL_PPE | CNTL_CIC)) /* and card is CIC */ + assert = BUS_PPOLL; /* then conduct parallel poll */ + + else if ((di_card->cntl_register /* if PP was enabled */ + & (CNTL_PPE | CNTL_CIC)) /* but is not now */ + == (CNTL_PPE | CNTL_CIC)) + deny = BUS_PPOLL; /* then end the parallel poll */ + + else if ((data /* if packed mode */ + & (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* and card is CIC */ + == (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* then ATN control output */ + assert = BUS_ATN; /* is coupled to the bus */ + + else /* if none of the above */ + deny = BUS_ATN; /* ATN is not driven */ + } + + else /* not talking */ + deny = BUS_ATN | BUS_EOI; /* so ATN and EOI are disabled */ + + + if (data & CNTL_NRFD) /* card not ready set explicitly? */ + assert |= BUS_NRFD; /* assert NRFD on bus */ + + else if (di_card->cntl_register & CNTL_NRFD) /* NRFD was set but is not now? */ + deny |= BUS_NRFD; /* deny NRFD on bus */ + + if (FIFO_FULL) /* is FIFO full? */ + if (data & CNTL_LSTN) /* is card now listening? */ + assert |= BUS_NRFD; /* listener and full FIFO asserts NRFD */ + + else if (di_card->cntl_register & CNTL_LSTN) /* was listener but is not now? */ + deny |= BUS_NRFD; /* deny NRFD on bus */ + + + if (SW8_SYSCTL) { /* system controller drives REN and IFC */ + if (data & CNTL_REN) /* REN control */ + assert |= BUS_REN; /* output is */ + else /* coupled to */ + deny |= BUS_REN; /* the bus */ + + if (data & CNTL_IFC) { /* IFC set? */ + assert |= BUS_IFC; /* assert IFC on bus */ + + di_card->status_register = + di_card->status_register + & ~(STAT_LSTN | STAT_TALK) /* clear listen and talk status */ + | STAT_IFC; /* and set IFC status */ + + di_card->ifc_timer = /* start IFC timer by calculating */ + sim_gtime () + IFC_TIMEOUT; /* IFC stop time (100 microseconds) */ + } + } + + if ((data & (CNTL_SRQ | CNTL_CIC)) == CNTL_SRQ) /* service request and not controller? */ + assert |= BUS_SRQ; /* assert SRQ on bus */ + else /* else */ + deny |= BUS_SRQ; /* deny SRQ on bus */ + + di_card->cntl_register = data; /* save control word */ + di_bus_control (card, CONTROLLER, assert, deny); /* update bus control state */ + } + + if (update_required && !(signal_set & ioCLF)) /* if update and CLF not present, */ + update_state (card); /* update state, else ioCLF will update */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + di_card->flag = SET; /* set flag */ + di_card->flagbuf = SET; /* and flag buffer */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [POPIO] Flag set\n", + dptrs [card]->name); + break; + + + case ioCRS: /* control reset */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [CRS] Master reset\n", + dptrs [card]->name); + + di_card->status_register &= /* clear listen and talk status */ + ~(STAT_LSTN | STAT_TALK); + + deny = BUS_SRQ | BUS_REN | BUS_ATN | BUS_EOI; /* clear lines driven by control register */ + + if (di_card->cntl_register & (CNTL_NRFD | CNTL_LSTN)) /* if asserting NRFD or listening */ + deny |= BUS_NRFD; /* deny because we're clearing */ + + di_card->cntl_register = 0; /* clear control word register */ + di_card->control = CLEAR; /* clear control */ + di_card->srq = CLEAR; /* clear srq */ + + master_reset (card); /* master reset */ + + di_bus_control (card, CONTROLLER, 0, deny); /* update bus control state */ + update_state (card); /* update card state */ + break; + + + case ioCLC: /* clear control flip-flop */ + di_card->control = CLEAR; /* clear control */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) { + fprintf (sim_deb, ">>%s cmds: [CLC%s] Control cleared (configure mode)", + dptrs [card]->name, hold_or_clear); + + if (signal_set & ioCLF) /* if ioCLF given, */ + fputs (", master reset\n", sim_deb); /* then report master reset */ + else + fputc ('\n', sim_deb); + } + + if (signal_set & ioCLF) /* if ioCLF given, */ + master_reset (card); /* then do master reset */ + break; /* (ioCLF will call update_state for us) */ + + + case ioSTC: /* set control flip-flop */ + di_card->control = SET; /* set control */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [STC%s] Control set (data mode)\n", + dptrs [card]->name, hold_or_clear); + break; + + + case ioEDT: /* end data transfer */ + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [EDT] DCPC transfer ended\n", + dptrs [card]->name); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (di [card]); /* set standard PRL signal */ + setstdIRQ (di [card]); /* set standard IRQ signal */ + + setSRQ (dibptr->select_code, /* set SRQ signal from control and SRQ */ + di_card->srq == SET && di_card->control == SET); + break; + + + case ioIAK: /* interrupt acknowledge */ + di_card->flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Reset the simulator. + + During a hardware PRESET, POPIO sets the flag buffer and flag flip-flops, and + CRS clears the control flip-flop and Control Word Register. In addition, CRS + asserts a master reset on the card. + + PON is not used by the card. + + + Implementation notes: + + 1. During a power-on reset, a pointer to the FIFO simulation register is + saved to allow access to the "qptr" field during FIFO loading and + unloading. This enables the SCP to view the FIFO as a circular queue, so + that the bottom word of the FIFO is always displayed as FIFO[0], + regardless of where it is in the actual FIFO array. +*/ + +t_stat di_reset (DEVICE *dptr) +{ +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ +const CARD_ID card = (CARD_ID) (dibptr->card_index); /* card number */ + +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ + di [card].fifo_reg = find_reg ("FIFO", NULL, dptr); /* find the FIFO register entry */ + + if (di [card].fifo_reg == NULL) /* not there? */ + return SCPE_IERR; /* is a programming error! */ + else /* found it */ + di [card].fifo_reg->qptr = 0; /* reset the FIFO bottom index */ + + di [card].status_register = 0; /* clear the status word */ + + di [card].bus_cntl = 0; /* deny the HP-IB control lines */ + + di [card].listeners = 0; /* clear map of listeners */ + di [card].talker = 0; /* clear map of talker */ + di [card].poll_response = 0; /* clear map of parallel poll responses */ + + di [card].ifc_timer = 0.0; /* clear IFC timer */ + } + +IOPRESET (dibptr); /* PRESET the device */ + +return SCPE_OK; +} + + + +/* Disc interface global SCP routines */ + + +/* Set a unit's bus address. + + Bus addresses range from 0-7 and are initialized to the unit number. All + units of a device must have unique bus addresses. In addition, the card also + has a bus address, although this is only used for the diagnostic. The card + address may be the same as a unit address, as all units are disconnected + during a diagnostic run. + + The "value" parameter indicates whether the routine is setting a unit's bus + address (0) or a card's bus address (1). + + + Implementation notes: + + 1. To ensure that each address is unique, a check is made of the other units + for conflicting addresses. An "invalid argument" error is returned if + the desired address duplicates another. This means that addresses cannot + be exchanged without first assigning one of them to an unused address. + Also, an address cannot be set that duplicates the address of a disabled + unit (which cannot be displayed without enabling it). + + An alternate method would be to set the new assignments into a "shadow + array" that is set into the unit flags (and checked for validity) only + when a power-on reset is done. This does follow the disc and tape + controller hardware, which reads the HP-IB address switch settings only + at power-up. +*/ + +t_stat di_set_address (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +t_stat status; +uint32 index, new_address; +uint32 old_address = GET_BUSADR (uptr->flags); +DEVICE *dptr = (DEVICE *) desc; + +if (cptr == NULL) /* if address not given */ + return SCPE_ARG; /* report a missing argument */ + +new_address = get_uint (cptr, 10, 7, &status); /* parse the address value */ + +if (status == SCPE_OK) { /* parse OK? */ + if (value) /* setting the card address? */ + dptr->flags = dptr->flags & ~DEV_BUSADR /* store new address in the device flags */ + | SET_DIADR (new_address); + + else { /* setting a unit address */ + for (index = 0; index < dptr->numunits; index++) /* look through units */ + if (new_address != old_address /* to ensure address is unique */ + && new_address == GET_BUSADR (dptr->units [index].flags)) { + printf ("Bus address conflict: DA%d\n", index); + + if (sim_log) + fprintf (sim_log, "Bus address conflict: DA%d\n", index); + + return SCPE_NOFNC; /* a duplicate address gives an error */ + } + + uptr->flags = uptr->flags & ~UNIT_BUSADR /* address is valid; change */ + | SET_BUSADR (new_address); /* the address in the unit flags */ + } + } + +return status; /* return the result of the parse */ +} + + +/* Show a unit's bus address. + + The "value" parameter indicates whether the routine is showing a unit's bus + address (0) or a card's bus address (1). +*/ + +t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc) +{ +DEVICE *dptr = (DEVICE *) desc; + +if (value) /* card address? */ + fprintf (st, "address=%d", GET_DIADR (dptr->flags)); /* get from device flags */ +else /* unit address */ + fprintf (st, "bus=%d", GET_BUSADR (uptr->flags)); /* get from unit flags */ + +return SCPE_OK; +} + + +/* Set the bus cable connection. + + In normal use, the various tape and disc devices are connected together and + to the disc interface card by HP-IB cables. For the diagnostic, two disc + interface cards are connected by a single cable. + + The "value" parameter indicates whether the routine is connecting the + cable to devices for normal use (0) or to another card for diagnostics (1). + + + Implementation notes: + + 1. Initially, only one card and peripheral set is simulated: the ICD disc + family (DA device). For diagnostic use, a second, dummy card is enabled + (DC device). Once a second card simulation is implemented, this code + will no longer be necessary. +*/ + +t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +if (value) { /* diagnostic cable selected? */ + ((DEVICE *) desc)->flags |= DEV_DIAG; /* set diagnostic flag */ + dc_dev.flags &= ~DEV_DIS; /* enable dummy device */ + dc_dev.flags |= DEV_DIAG; /* and set its flag as well */ + } +else { /* peripheral cable selected */ + ((DEVICE *) desc)->flags &= ~DEV_DIAG; /* clear diagnostic flag */ + dc_dev.flags |= DEV_DIS; /* disable dummy device */ + dc_dev.flags &= ~DEV_DIAG; /* and clear its flag */ + } + +return SCPE_OK; +} + + +/* Show the bus cable connection. + + The "value" parameter indicates whether the cable is connected to devices for + normal use (0) or to another card for diagnostics (1). +*/ + +t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc) +{ +if (((DEVICE *) desc)->flags & DEV_DIAG) /* is cable connected for diagnostics? */ + fputs ("diagnostic cable", st); /* report it */ +else /* cable is connected for normal use */ + fputs ("HP-IB cable", st); /* report the condition */ + +return SCPE_OK; +} + + + +/* Disc interface global bus routines. + + In hardware, the HP-IB bus consists of eight control lines and eight data + lines. Signals are asserted on the control lines to establish communication + between a source and one or more acceptors. For commands, the source is + always the controller (the 12821A card), and the acceptors are all connected + devices. For data, the source is the current talker, and the acceptors are + one or more current listeners. A three-wire interlocking handshake enables + communication at the rate of the slowest of the multiple acceptors. The + controller conducts a parallel poll by asserting ATN and EOI together. + Devices whose parallel poll responses are enabled each assert one of the data + lines to indicate that service is required. + + In simulation, a disabled or detached unit logically is not connected to the + bus. The card maintains a bitmap of acceptors (all devices currently + attached), listeners (all devices currently addressed to listen), the talker + (the device currently addressed to talk), and the enabled parallel poll + responses. Changes in control line state are communicated to all acceptors + via control/respond function calls, and data is exchanged between talker and + listeners via source/acceptor function calls. Data bytes are sent to all + current listeners in bus-address order. The card conducts a parallel poll by + checking the response bitmap; devices must set and clear their poll responses + appropriately in advance of the poll. + + Not all of the HP-IB control lines are simulated. The DAV and NDAC handshake + lines are never asserted; instead, they are simulated by the bus source + function calling one or more bus acceptor functions. SRQ and REN are + asserted as directed by the system controller but are not otherwise used (no + HP disc or tape devices assert SRQ or respond to REN). IFC, ATN, EOI, and + NRFD are asserted and tested by the controller and devices. In particular, + asserting NRFD will hold off a pending data transmission until it is denied. + + The functions that simulate the HP-IB (where "*" is "di", "da", etc.) are: + + di_bus_source -- Source a data byte to the bus. Returns TRUE if the + byte was accepted (i.e., there were one or more + listeners) and FALSE if it was not. Called by the + controller to send commands to devices, and called by + the current talker to send data to the listener(s). ATN + and EOI should be set as required in the control word + before calling. + + *_bus_accept -- Accept a data byte from the bus. Returns TRUE if the + byte was accepted and FALSE if it was not. Called by + di_bus_source to handshake between source and acceptor. + If ATN is set in the control word, the byte is a + command; otherwise, it is data. If EOI is set for a + data byte, it is the last byte of a transmission. + + di_bus_control -- Set the control lines on the bus. Called by the system + controller to assert or deny REN or IFC, by the + controller to assert or deny SRQ, NRFD, or ATN and EOI + (to conduct or conclude a parallel poll), and by the + current listener to assert or deny NRFD. All connected + devices on the bus are notified of the changes. It is + not necessary to call di_bus_control for changes to ATN + and EOI that accompany a command or data byte. + + *_bus_respond -- Respond to changes in the control lines on the bus. + Called by di_bus_control to inform each connected device + of a change in control state. + + di_poll_response -- Set a device's poll response. Called by a device to + enable or disable its response to a future parallel + poll. +*/ + + +/* Source a byte to the bus. + + This routine is called to send bytes to devices on the bus connected to the + specified card. If the card is in diagnostic mode, which simulate two cards + connected by an HP-IB cable, then the byte is sent to another card in the + card cage that is also in diagnostic mode and enabled to receive. If the + card is not in diagnostic mode, then the byte is sent to all acceptors (if a + command) or to all listeners (if data) on the bus. + + An indication is returned showing whether or not there were any acceptors on + the bus. + + + Implementation notes: + + 1. If the responses from a previously conducted parallel poll are not + cleared from the FIFO before enabling the card to transmit, the card will + appear to conduct a new parallel poll because the FIFO tags cause ATN and + EOI to be asserted. This "fake" parallel poll is ignored (a real + parallel poll does not source data onto the bus). +*/ + +t_bool di_bus_source (CARD_ID card, uint8 data) +{ +CARD_ID other; +uint32 acceptors, unit; +t_bool accepted = FALSE; + +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) { + fprintf (sim_deb, ">>%s xfer: HP-IB DIO %03o available ", dptrs [card]->name, data); + fprint_bus (sim_deb, "[%s]\n", di [card].bus_cntl); + } + +if (dptrs [card]->flags & DEV_DIAG) /* diagnostic run? */ + for (other = first_card; other <= last_card; other++) { /* look through list of cards */ + if (other != card && dptrs [other] /* for the other card */ + && (dptrs [other]->flags & DEV_DIAG) /* that is configured for diagnostic */ + && (di [other].cntl_register & CNTL_LSTN)) /* and is listening */ + accepted = di_bus_accept (other, data); /* call interface acceptor for other card */ + } + +else if ((di [card].bus_cntl & BUS_PPOLL) != BUS_PPOLL) { /* normal run; not a fake poll? */ + if (di [card].cntl_register & CNTL_LSTN) /* is card a listener? */ + accepted = di_bus_accept (card, data); /* call interface acceptor for this card */ + + acceptors = di [card].acceptors; /* get map of acceptors */ + + if (!(di [card].bus_cntl & BUS_ATN) /* if a data transfer, */ + || (data & BUS_COMMAND) == BUS_ACG) /* or an addressed command, e.g., SDC */ + acceptors = di [card].listeners; /* then limit just to listeners */ + + for (unit = 0; acceptors; unit++) { /* loop through units */ + if (acceptors & 1) /* is current unit accepting? */ + accepted |= (*bus_accept [card]) (unit, data); /* call acceptor for this card */ + + acceptors = acceptors >> 1; /* move to next acceptor */ + } + } + +if (DEBUG_PRJ (dptrs [card], DEB_XFER) && !accepted) + fprintf (sim_deb, ">>%s xfer: HP-IB no acceptors\n", + dptrs [card]->name); + +return accepted; +} + + +/* Assert or deny control on the bus. + + This routine is called by the indicated unit to assert or deny the HP-IB + control lines on the bus connected to the specified card. Separate sets of + signals to assert and deny are provided. + + If the bus state after modification did not change, the routine returns with + no further action. Otherwise, if the card is in diagnostic mode, then + notification of the bus change is sent to another card in the card cage that + is also in diagnostic mode. + + If the card is not in diagnostic mode, then the set of control lines that + are changing is checked to determine whether notification is necessary. If + not, then the change is not broadcast to improve performance. However, if + notification is required, then all acceptors on the bus are informed of the + change. + + + Implementation notes: + + 1. If a signal is asserted and denied in the same call, the assertion takes + precedence. + + 2. Of the sixteen potential control line state changes, only IFC assertion + and ATN and NRFD denial must be broadcast. Asserting IFC unaddresses all + devices, and denying ATN or NRFD allows a waiting talker to source a data + byte to the bus. Devices do not act upon the remaining thirteen state + changes, and a considerable performance improvement is obtained by + omitting the notification calls. + + 3. All control line state notifications are sent in diagnostic mode, as the + responses of the other card are specifically tested by the diagnostic. + + 4. Asserting ATN and EOI will conduct a parallel poll. Devices are not + notified of the poll. Instead, the previously stored parallel poll + responses will be used. +*/ + +#define ASSERT_SET (BUS_IFC) +#define DENY_SET (BUS_ATN | BUS_NRFD) + +void di_bus_control (CARD_ID card, uint32 unit, uint8 assert, uint8 deny) +{ +CARD_ID other; +uint32 acceptors, responder; +t_bool responded; +uint8 new_state, new_assertions, new_denials; + +new_state = di [card].bus_cntl & ~deny | assert; /* set up new control state */ + +if (new_state == di [card].bus_cntl) /* if control state did not change */ + return; /* return now */ + +new_assertions = ~di [card].bus_cntl & assert; /* get changing assertions */ +new_denials = di [card].bus_cntl & deny; /* get changing denials */ + +di [card].bus_cntl = new_state; /* establish the new control state */ + +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) { + if (unit == CONTROLLER) + fprintf (sim_deb, ">>%s xfer: HP-IB card %d", dptrs [card]->name, card); + else + fprintf (sim_deb, ">>%s xfer: HP-IB address %d", + dptrs [card]->name, GET_BUSADR (dptrs [card]->units [unit].flags)); + + if (new_assertions) + fprint_bus (sim_deb, " asserted [%s]", new_assertions); + + if (new_denials) + fprint_bus (sim_deb, " denied [%s]", new_denials); + + fprint_bus (sim_deb, ", bus is [%s]\n", new_state); + } + +if ((dptrs [card]->flags & DEV_DIAG) /* diagnostic mode? */ + || (new_assertions & ASSERT_SET) /* or changed signals in the */ + || (new_denials & DENY_SET)) { /* set that must be broadcast? */ + responded = FALSE; /* assume no response */ + + if (dptrs [card]->flags & DEV_DIAG) { /* diagnostic run? */ + for (other = first_card; other <= last_card; other++) /* look through list of cards */ + if (other != card && dptrs [other] /* for the other card */ + && (dptrs [other]->flags & DEV_DIAG)) { /* that is configured for diagnostic */ + di_bus_respond (other, new_state); /* notify other card of new control state */ + responded = TRUE; /* and note that there was a responder */ + } + } + + else { /* normal run */ + update_state (card); /* update card for new control state */ + + acceptors = di [card].acceptors; /* get map of acceptors */ + responded = (acceptors != 0); /* set if there are any acceptors */ + + for (responder = 0; acceptors; responder++) { /* loop through units */ + if ((acceptors & 1) && responder != unit) /* is current unit accepting? */ + (*bus_respond [card]) (card, responder, new_state); /* call responder for this card */ + + acceptors = acceptors >> 1; /* move to next acceptor */ + } + } + + if (DEBUG_PRJ (dptrs [card], DEB_XFER) & !responded) + fprintf (sim_deb, ">>%s xfer: HP-IB no responders\n", + dptrs [card]->name); +} + +if ((new_state & BUS_PPOLL) == BUS_PPOLL) /* parallel poll requested? */ + di_bus_poll (card); /* conduct the poll */ + +return; +} + + +/* Enable or disable a unit's parallel poll response. + + The poll response for a unit connected to a specified card is set or cleared + as indicated. If a parallel poll is in progress when a poll response is set, + the poll is conducted again to reflect the new response. +*/ + +void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response) +{ +const uint32 address = GET_BUSADR (dptrs [card]->units [unit].flags); +uint32 previous_response = di [card].poll_response; + +if (response == SET) { /* enable PPR? */ + di [card].poll_response |= PPR (address); /* set response bit */ + + if ((di [card].bus_cntl & BUS_PPOLL) == BUS_PPOLL) /* is parallel poll in progress? */ + di_bus_poll (card); /* conduct with new response */ + } +else /* disable PPR */ + di [card].poll_response &= ~PPR (address); /* clear response bit */ + +if (DEBUG_PRJ (dptrs [card], DEB_XFER) + && previous_response != di [card].poll_response) + fprintf (sim_deb, ">>%s xfer: HP-IB address %d parallel poll response %s\n", + dptrs [card]->name, address, (response == SET ? "enabled" : "disabled")); + +return; +} + + + +/* Disc interface local bus routines */ + + +/* Conduct a parallel poll on the bus. + + A controller asserting ATN and EOI simultaneously on the bus is conducting a + parallel poll. In hardware, each device whose poll response is enabled + asserts one of the data lines corresponding to its bus address. The + controller terminates the poll by denying ATN and EOI. + + Setting the CIC (controller in charge) and PPE (parallel poll enable) bits in + the Control Word Register directs the disc interface to conduct a poll. + Setting PPE without CIC enables the poll response for the interface. + + In the diagnostic mode, one card is set to conduct the poll, and the other is + set to respond to it. In the normal mode, connected devices have set or + cleared their respective poll responses before this routine is called. + + + Implementation notes: + + 1. The card hardware fills the upper and lower bytes of the FIFO with the + response byte. In simulation, we use the diag_access mode to do the same + thing (diagnostic loopback also fills both bytes with the lower byte). +*/ + +static void di_bus_poll (CARD_ID card) +{ +CARD_ID other; +uint8 response; + +if ((di [card].cntl_register + & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) /* card poll response enabled? */ + response = di [card].poll_response /* add card's response */ + | PPR (GET_DIADR (dptrs [card]->flags)); /* to the devices' responses */ +else + response = di [card].poll_response; /* card disabled, so just use devices */ + +if (dptrs [card]->flags & DEV_DIAG) /* diagnostic run? */ + for (other = first_card; other <= last_card; other++) /* look through list of cards */ + if (other != card && dptrs [other] /* for another card */ + && (dptrs [other]->flags & DEV_DIAG) /* that is configured for diagnostic */ + && (di [other].cntl_register /* and has PPE asserted */ + & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) + response |= /* merge its poll response */ + PPR (GET_DIADR (dptrs [other]->flags)); + +if (response) { /* poll response indicated? */ + if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, ">>%s xfer: HP-IB parallel poll DIO %03o\n", + dptrs [card]->name, response); + + while (di [card].fifo_count != FIFO_SIZE) /* fill card FIFO with responses */ + fifo_load (card, (uint16) response, diag_access); /* (hardware feature) */ + + update_state (card); /* update card state */ + } + +return; +} + + +/* Accept a data byte from the bus. + + The indicated card accepts a byte that has been sourced to the bus. The byte + is loaded into the FIFO, and the card state is updated to reflect the load. + + Bus acceptors return TRUE to indicate if the byte was accepted. A card + always accepts a byte, so the routine always returns TRUE. +*/ + +static t_bool di_bus_accept (CARD_ID card, uint8 data) +{ +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, ">>%s xfer: HP-IB card %d accepted data %03o \n", + dptrs [card]->name, card, data); + +fifo_load (card, data, bus_access); /* load data byte into the FIFO */ +update_state (card); /* and update the card state */ +return TRUE; /* indicate the byte was accepted */ +} + + +/* Respond to the bus control lines. + + The indicated card is notified of the new control state on the bus. The + routine establishes the new bus state and updates the card state to reflect + the change. +*/ + +static void di_bus_respond (CARD_ID card, uint8 new_cntl) +{ +di [card].bus_cntl = new_cntl; /* update bus control */ +update_state (card); /* update card state */ +return; +} + + + +/* Disc interface local utility routines */ + + +/* Master reset the interface. + + This is the programmed card master reset, not the simulator reset routine. + Master reset initializes a number of flip-flops and data paths on the card. + The primary use, other than during a PRESET, is to clear the FIFO in + preparation to changing the card from a listener to a talker or vice versa. + This ensures that unneeded FIFO data is not transmitted inadvertently to the + bus or the CPU. It is also used when changing the data mode from unpacked to + packed to release the byte pointer flip-flops, which are held in the "lower + byte" position during unpacked transfers. + + In hardware, master reset: + - clears the EDT, EOR, IRL, LBO, LBI, and IFC flip-flops + - clears the Input Data Register + - clears the FIFO + - sets or clears the odd/even input and output byte pointer flip-flops, + depending on whether the P (packed transfer) bit is set in the Control + Word Register +*/ + +static void master_reset (CARD_ID card) +{ +di [card].edt = CLEAR; /* clear the EDT flip-flop */ +di [card].eor = CLEAR; /* clear the EOR flip-flop */ + +if (di [card].cntl_register & CNTL_PACK) /* if packed mode is set, */ + di [card].ibp = di [card].obp = upper; /* MR sets selectors to the upper byte */ +else /* otherwise, unpacked mode overrides */ + di [card].ibp = di [card].obp = lower; /* and sets the selectors to the lower byte */ + +di [card].status_register &= /* clear status flip-flops */ + ~(STAT_IRL | STAT_LBO | STAT_LBI | STAT_IFC); + +di [card].input_data_register = 0; /* clear the input data register */ +di [card].fifo_count = 0; /* clear the FIFO */ + +if (DEBUG_PRJ (dptrs [card], DEB_BUF)) + fprintf (sim_deb, ">>%s buf: FIFO cleared\n", + dptrs [card]->name); + +return; +} + + +/* Update the interface state. + + In hardware, certain external operations cause automatic responses by the + disc interface card. For example, when the Input Data Register is unloaded + by an LIx instruction, it is automatically reloaded with the next word from + the FIFO. Also, the card may be set to interrupt in response to the + assertion of certain bus control lines. + + In simulation, this routine must be called whenever the FIFO, card control, + or bus control state changes. It determines whether: + + 1. the next word from the FIFO should be unloaded into the IDR. If the card + is listening, and the IDR is empty, and the FIFO contains data, then a + word is unloaded and stored in the IDR, and the Input Register Loaded + status bit is set. + + 2. the next word from the FIFO should be unloaded and sourced to the bus. + If the card is talking (but not polling), and the listener is ready to + accept data, and the last byte has not been sent, and the FIFO contains + data, then a word is unloaded and sourced to the bus. This occurs + regardless of whether or not there are any listeners. + + 3. an interface clear operation has completed. If IFC is asserted, and the + current simulation time is later than the IFC expiration time, then IFC + is denied, and the timer is reset. + + 4. the card should assert NRFD to prevent FIFO overflow. If the card is + listening, and the FIFO is full, or the last byte has been received, or a + pause has been explicitly requested, then NRFD is asserted. + + 5. the SRQ flip-flop should be set or cleared. If the card is listening and + the Input Data Register has been loaded, or the card is talking and the + FIFO is not full, then SRQ is asserted to request a DCPC transfer. + + 6. the flag flip-flop should be set or cleared. If the Input Data Register + has been loaded or the Last Byte Out flip-flop is set and the + corresponding Control Word Register IRL or LBO bits are set, or the End + of Record flip-flop is set and the Input Data Register has been unloaded, + or SRQ is asserted on the bus and the corresponding Control Word Register + bit is set when the card is not the controller-in-charge, or REN or IFC + is asserted on the bus and the corresponding Control Word Register bits + are set when the card is not the system controller, then the flag is set + to request an interrupt. + + + Implementation notes: + + 1. The fifo_unload routine may set STAT_LBO, so the flag test must be done + after unloading. + + 2. The gcc compiler (at least as of version 4.6.2) does not optimize + repeated use of array-of-structures accesses. Instead, it recalculates + the index each time, even though the index is a constant within the + function. To avoid this performance penalty, we use a pointer to the + selected DI_STATE structure. Note that VC++ 2008 does perform this + optimization. + */ + +static void update_state (CARD_ID card) +{ +DIB * const dibptr = (DIB *) dptrs [card]->ctxt; +DI_STATE * const di_card = &di [card]; +uint8 assert = 0; +uint8 deny = 0; +uint16 data; +FLIP_FLOP previous_state; + +if (di_card->cntl_register & CNTL_LSTN) { /* is card a listener? */ + if (!(di_card->status_register & STAT_IRL) /* is IDR empty? */ + && ! FIFO_EMPTY) { /* and more in FIFO? */ + data = fifo_unload (card, cpu_access); /* unload FIFO */ + di_card->input_data_register = data; /* into IDR */ + di_card->status_register |= STAT_IRL; /* set input register loaded status */ + } + } + +else if ((di_card->cntl_register /* is card a talker? */ + & (CNTL_TALK | CNTL_PPE)) == CNTL_TALK) /* and not polling? */ + while (! FIFO_EMPTY /* is data remaining in FIFO? */ + && !(di_card->bus_cntl & BUS_NRFD) /* and NRFD denied? */ + && !(di_card->status_register & STAT_LBO)) { /* and last byte not sent? */ + data = fifo_unload (card, bus_access); /* unload FIFO byte */ + di_bus_source (card, (uint8) data); /* source it to bus */ + } + + +if (di_card->bus_cntl & BUS_IFC /* IFC in progress? */ + && di_card->ifc_timer != 0.0 /* and I am timing? */ + && sim_gtime () > di_card->ifc_timer) { /* and timeout has elapsed? */ + deny = BUS_IFC; /* deny IFC on bus */ + di_card->ifc_timer = 0.0; /* clear IFC timer */ + di_card->status_register &= ~STAT_IFC; /* clear IFC status */ + } + + +if (di_card->cntl_register & CNTL_LSTN) /* is card a listener? */ + if (di_card->cntl_register & CNTL_NRFD /* if explicitly requested */ + || di_card->status_register & STAT_LBI /* or last byte is in */ + || FIFO_FULL) /* or FIFO is full */ + assert = BUS_NRFD; /* then assert NRFD */ + else /* otherwise card is ready for data */ + deny |= BUS_NRFD; /* so deny NRFD */ + +if (assert != deny) /* any change in bus state? */ + di_bus_control (card, CONTROLLER, assert, deny); /* update bus control */ + + +previous_state = di_card->srq; /* save current SRQ state */ + +if (di_card->cntl_register & CNTL_LSTN /* if card is a listener */ + && di_card->status_register & STAT_IRL /* and input register is loaded, */ + || di_card->cntl_register & CNTL_TALK /* or card is a talker */ + && ! FIFO_FULL) /* and FIFO is not full */ + di_card->srq = SET; /* then request a DCPC cycle */ +else + di_card->srq = CLEAR; /* else DCPC service is not needed */ + + +if (DEBUG_PRJ (dptrs [card], DEB_CMDS) + && di_card->srq != previous_state) + fprintf (sim_deb, ">>%s cmds: SRQ %s\n", + dptrs [card]->name, di_card->srq == SET ? "set" : "cleared"); + + +if (di_card->status_register & STAT_IRL /* input register loaded */ + && di_card->cntl_register & CNTL_IRL /* and notification wanted? */ + || di_card->status_register & STAT_LBO /* or last byte out */ + && di_card->cntl_register & CNTL_LBO /* and notification wanted? */ + || di_card->eor == SET /* or end of record seen */ + && !(di_card->status_register & STAT_IRL) /* and input register unloaded? */ + || di_card->bus_cntl & BUS_SRQ /* or SRQ is asserted on the bus */ + && di_card->cntl_register & CNTL_SRQ /* and notification wanted */ + && di_card->cntl_register & CNTL_CIC /* and card is not controller? */ + || !SW8_SYSCTL /* or card is not system controller */ + && di_card->bus_cntl & BUS_REN /* and REN is asserted on the bus */ + && di_card->cntl_register & CNTL_REN /* and notification wanted? */ + || !SW8_SYSCTL /* or card is not system controller */ + && di_card->status_register & STAT_IFC /* and IFC is asserted on the bus */ + && di_card->cntl_register & CNTL_IFC) { /* and notification wanted? */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: Flag set\n", + dptrs [card]->name); + + di_io (dibptr, ioENF, 0); /* set flag and recalculate interrupts */ + } + +else if (di_card->srq != previous_state) /* if SRQ changed state, */ + di_io (dibptr, ioSIR, 0); /* then recalculate interrupts */ + +return; +} + + +/* Load a word or byte into the FIFO. + + A word or byte is loaded into the next available location in the FIFO. The + significance of the data parameter is indicated by the access mode as + follows: + + - For CPU access, the parameter is a 16-bit value. + + - For bus access, the parameter is an 8-bit value in the lower byte and a + zero in the upper byte. + + - For diagnostic access, the parameter is an 8-bit value in the lower byte + that will be duplicated in the upper byte. + + For bus access, byte loading into the FIFO is controlled by the value of the + Input Buffer Pointer (IBP) selector. + + In addition to data words, the FIFO holds tags that mark the last byte + received or to be transmitted and that indicate the state of the ATN and EOI + bus lines (if listening) or the states to assert (if talking). The tag is + assembled into the upper word, the data is assembled into the lower word, and + then the 32-bit value is stored in the next available FIFO location. + + If data is coming from the CPU, the 16-bit value is loaded into the next FIFO + location, and the occupancy count is incremented. + + If the data is coming from the bus, and the input mode is unpacked, the 8-bit + value is loaded into the lower byte of the next FIFO location, and the + occupancy count is incremented. In hardware, the upper FIFO is not clocked; + in simulation, the upper byte is set to zero. The IBP always points at the + lower byte in unpacked mode. + + If the data is coming from the bus, and the input mode is packed, the 8-bit + value is loaded into either the upper or lower byte of the next FIFO + location, depending on the value of the IBP, and the IBP is toggled. If the + value was stored in the lower byte, the occupancy count is incremented. + + A special case occurs when the value is to be stored in the upper byte, and + the LBR tag is set to indicate that this is the last byte to be received. In + this case, the value is stored in both bytes of the next FIFO location, and + the occupancy counter is incremented. + + If data is coming from the diagnostic FIFO loopback, the 8-bit value in the + lower byte is copied to the upper byte, the resulting 16-bit value is loaded + into the next FIFO location, and the occupancy count is incremented. + + + Implementation notes: + + 1. Four tag bits are loaded into the upper word of each FIFO entry: + + - Last Byte Received (while receiving, a line feed is received and the + LF bit is set in the Control Word Register, or a byte with EOI + asserted is received and the EOI bit is set). + + - End of Data Transfer (while transmitting, DCPC asserts the EDT + backplane signal, or an unpacked-mode data word has the LBO bit set, + or a packed-mode OTx is issued without an accompanying CLF). + + - ATN (the state of ATN on the bus if receiving, or the ATN bit in the + unpacked data word if transmitting). + + - EOI (the state of EOI on the bus if receiving, or the EOI bit in the + unpacked data word if transmitting). + + 2. The FIFO is implemented as circular queue to take advantage of REG_CIRC + EXAMINE semantics. REG->qptr is the index of the first word currently in + the FIFO. By specifying REG_CIRC, examining FIFO[0-n] will always + display the words in load order, regardless of the actual array index of + the start of the list. The number of words currently present in the FIFO + is kept in fifo_count (0 = empty, 1-16 = number of words available). + + If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the + index of the new word location. Loading stores the word there and then + increments fifo_count. + + 3. Because the load and unload routines need access to qptr in the REG + structure for the FIFO array, pointers to the REG for each card are + stored in the fifo_reg array during device reset. + + 4. The gcc compiler (at least as of version 4.6.2) does not optimize + repeated use of array-of-structures accesses. Instead, it recalculates + the index each time, even though the index is a constant within the + function. To avoid this performance penalty, we use a pointer to the + selected DI_STATE structure. Note that VC++ 2008 does perform this + optimization. +*/ + +static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access) +{ +uint32 tag, index; +t_bool add_word = TRUE; +DI_STATE * const di_card = &di [card]; + +if (FIFO_FULL) { /* is the FIFO already full? */ + if (DEBUG_PRJ (dptrs [card], DEB_BUF)) + fprintf (sim_deb, ">>%s buf: Attempted load to full FIFO, data %0*o\n", + dptrs [card]->name, (access == bus_access ? 3 : 6), data); + + return; /* return with load ignored */ + } + +if (di_card->cntl_register & CNTL_LSTN) { /* is card receiving? */ + tag = (di_card->bus_cntl /* set tag from bus signals */ + & (BUS_ATN | BUS_EOI)) << BUS_SHIFT; /* shifted to tag locations */ + + if ((di_card->cntl_register & CNTL_EOI /* EOI detection enabled, */ + && di_card->bus_cntl & BUS_EOI) /* and data was tagged with EOI? */ + || (di_card->cntl_register & CNTL_LF /* or LF detection enabled, */ + && GET_LOWER (data) == LF)) { /* and byte is a line feed? */ + tag = tag | TAG_LBR; /* tag as last byte received */ + di_card->status_register |= STAT_LBI; /* set last byte in status */ + } + else /* neither termination condition seen */ + di_card->status_register &= ~STAT_LBI; /* so clear last byte in status */ + } + +else /* card is transmitting */ + tag = (data & (DATA_ATN | DATA_EOI)) << DATA_SHIFT; /* set tag from data shifted to tag location */ + +if (di_card->edt == SET) /* end of data transfer? */ + tag = tag | TAG_EDT; /* set EDT tag */ + + +index = (di_card->fifo_reg->qptr /* calculate index */ + + di_card->fifo_count) % FIFO_SIZE; /* of next available location */ + +if (access == bus_access) { /* bus access? */ + if (di_card->ibp == upper) { /* packed and this is the upper byte? */ + di_card->ibp = lower; /* set lower byte as next */ + + if (tag & TAG_LBR) /* is this the last byte? */ + di_card->fifo [index] = /* copy to both bytes of FIFO */ + tag | SET_BOTH (data); /* and store with tag */ + else { /* more bytes expected */ + di_card->fifo [index] = /* so position this byte */ + tag | SET_UPPER (data); /* and store with tag */ + add_word = FALSE; /* wait for second byte before adding */ + } + } + + else /* this is the lower byte */ + if (di_card->cntl_register & CNTL_PACK) { /* packed mode? */ + di_card->ibp = upper; /* set upper byte as next */ + + di_card->fifo [index] = /* merge in data and tag */ + tag | di_card->fifo [index] | SET_LOWER (data); + } + else /* unpacked mode */ + di_card->fifo [index] = /* position this byte */ + tag | SET_LOWER (data); /* and store with tag */ + } + +else if (access == cpu_access) /* cpu access? */ + di_card->fifo [index] = tag | data; /* store tag and full word in FIFO */ + +else { /* diag access */ + data = SET_BOTH (GET_LOWER (data)); /* copy lower byte to upper byte */ + di_card->fifo [index] = tag | data; /* and store tag and full word in FIFO */ + } + +if (add_word) /* did we add a word to the FIFO? */ + di_card->fifo_count = di_card->fifo_count + 1; /* increment count of words stored */ + +if (DEBUG_PRJ (dptrs [card], DEB_BUF)) { + fprintf (sim_deb, ">>%s buf: Data %0*o tag ", + dptrs [card]->name, (access == bus_access ? 3 : 6), data); + fprint_val (sim_deb, tag >> BUS_SHIFT, 2, 4, PV_RZRO); + fprintf (sim_deb, " loaded into FIFO (%d)\n", di_card->fifo_count); + } + +return; +} + + +/* Unload a word or byte from the FIFO. + + A word or byte is unloaded from the first location in the FIFO. The + significance of the returned value is indicated by the access mode as + follows: + + - For CPU access, a 16-bit value is unloaded and returned. + + - For bus access, an 8-bit value is unloaded and returned. + + - For diagnostic access, an 16-bit value is unloaded, and the lower byte + is returned. + + For bus access, byte unloading from the FIFO is controlled by the value of + the Output Buffer Pointer (OBP) selector. + + If the FIFO is not empty, the first entry is obtained and split into tag and + data words. The LBR tag value is loaded into the EOR flip-flop if the CPU is + accessing. The EDT tag sets Last Byte Out status if the last byte is being + unloaded. + + If the data is going to the CPU, the 16-bit packed data value is returned as + is, or the lower byte of the unpacked value is merged with the tags for ATN + and EOI and returned. The occupancy count is decremented to unload the FIFO + entry. + + If the data is going to the bus, and the input mode is unpacked, the 8-bit + value is returned in the lower byte, and the occupancy count is decremented. + In hardware, the upper FIFO is not clocked; in simulation, the upper byte is + ignored. The OBP always points at the lower byte in unpacked mode. + + If the data is going to the bus, and the input mode is packed, the 8-bit + value is unloaded from either the upper or lower byte of the data word, + depending on the value of the OBP, and returned in the lower byte. The OBP + value is toggled. If the value was obtained from the lower byte, the + occupancy count is decremented to unload the FIFO. Otherwise, the count is + not altered, so that the lower-byte access will be from the same FIFO entry. + + If data is going to the diagnostic FIFO loopback, the lower byte of the + 16-bit value is returned; the upper byte of the returned value is zero. + + + Implementation notes: + + 1. Four tag bits are unloaded from the upper word of each FIFO entry: + + - Last Byte Received (sets the End of Record flip-flop when the last + byte received is loaded into the Input Data Register). + + - End of Data Transfer (sets the LBO bit in the Status Word Register + when the last byte is unloaded from the FIFO). + + - ATN (in unpacked mode, sets the ATN bit in the returned data word + if listening, or controls the bus ATN line if talking; in packed mode, + the tag is ignored). + + - EOI (in unpacked mode, sets the EOI bit in the returned data word if + listening, or asserts the bus EOI line if talking; in packed mode, the + tag is ignored). + + ATN and EOI tag handling is a bit complex. If the card is listening in + the unpacked mode, the ATN tag substitutes for bit 8 of the data word, + and the EOI tag substitutes for bit 9. In the packed mode, bits 8 and 9 + are as stored in the FIFO (they are upper-byte data bits). + + If the card is talking in the unpacked mode, the ATN tag asserts or + denies ATN on the bus if the card is the CIC, and the EOI tag asserts or + denies EOI on the bus. In the packed mode, the ATN bit in the Control + Word Register asserts or denies ATN on the bus if the card is the CIC, + and the EOI bit asserts EOI on the bus if the last byte of the entry + tagged with EDT has been unloaded from the FIFO (which sets LBO status) + or denies EOI otherwise. + + 2. In hardware, the EOR flip-flop is clocked with the Input Data Register. + Therefore, when the card is listening, EOR is set not when the last byte + is unloaded from the FIFO, but rather when that byte is loaded into the + IDR. These two actions occur together when the IDR is empty. + + However, during diagnostic access, data unloaded from the FIFO is + reloaded, and the IDR is never clocked. As the T and L bits must be set + with DIAG in the Control Word Register to enable the loopback path, the + LBR tag will be entered into the FIFO if EOI or LF detection is enabled, + but the EOR flip-flop will not be set when that word falls through to be + unloaded. + + In simulation, EOR is set whenever the LBR tag is unloaded from the FIFO + during CPU access, as a CPU unload is always followed by an IDR store. + + 3. If fifo_count > 0, REG->qptr is the index of the word to remove. Removal + gets the word and then increments qptr (mod FIFO_SIZE) and decrements + fifo_count. + + 4. The gcc compiler (at least as of version 4.6.2) does not optimize + repeated use of array-of-structures accesses. Instead, it recalculates + the index each time, even though the index is a constant within the + function. To avoid this performance penalty, we use a pointer to the + selected DI_STATE structure. Note that VC++ 2008 does perform this + optimization. +*/ + +static uint16 fifo_unload (CARD_ID card, FIFO_ACCESS access) +{ +uint32 data, tag; +t_bool remove_word = TRUE; +DI_STATE * const di_card = &di [card]; + +if (FIFO_EMPTY) { /* is the FIFO already empty? */ + if (DEBUG_PRJ (dptrs [card], DEB_BUF)) + fprintf (sim_deb, ">>%s buf: Attempted unload from empty FIFO\n", + dptrs [card]->name); + + return 0; /* return with no data */ + } + +data = di_card->fifo [di_card->fifo_reg->qptr]; /* get tag and data from the FIFO */ + +tag = data & TAG_MASK; /* mask the tag to just the tag bits */ +data = data & DMASK; /* and the data to just the data bits */ + +if (tag & TAG_EDT /* is this the end of a data transfer */ + && (di_card->obp == lower /* and the lower byte is next */ + || di_card->cntl_register & CNTL_ODD)) /* or we are sending an odd number of bytes? */ + di_card->status_register |= STAT_LBO; /* set the last byte out status */ + + +if (access == cpu_access) { /* cpu access? */ + if (!(di_card->cntl_register & CNTL_PACK)) /* unpacked data format? */ + data = data & ~(DATA_ATN | DATA_EOI) /* substitute ATN/EOI tag values */ + | (tag & (TAG_ATN | TAG_EOI)) >> DATA_SHIFT; /* into the data word */ + + if (tag & TAG_LBR) /* is this the last byte? */ + di_card->eor = SET; /* set */ + else /* or clear */ + di_card->eor = CLEAR; /* the end-of-record flip-flop */ + } + +else if (access == bus_access) /* bus access? */ + if (di_card->obp == upper) { /* is this the upper byte? */ + di_card->obp = lower; /* set the lower byte as next */ + data = GET_UPPER (data); /* mask and position the upper byte in the data word */ + remove_word = FALSE; /* do not unload the FIFO until the next byte */ + } + + else { /* this is the lower byte */ + data = GET_LOWER (data); /* mask and position it in the data word */ + + if (di_card->cntl_register & CNTL_PACK) /* in packed mode? */ + di_card->obp = upper; /* set the upper byte as next */ + } + +else /* diagnostic access */ + data = GET_LOWER (data); /* access is to the lower byte only */ + + +if (remove_word) { /* remove the word from the FIFO? */ + di_card->fifo_reg->qptr = /* update the FIFO queue pointer */ + (di_card->fifo_reg->qptr + 1) % FIFO_SIZE; /* and wrap around as needed */ + + di_card->fifo_count = di_card->fifo_count - 1; /* decrement the FIFO count */ + } + + +if (DEBUG_PRJ (dptrs [card], DEB_BUF)) { + fprintf (sim_deb, ">>%s buf: Data %0*o tag ", + dptrs [card]->name, (access == cpu_access ? 6 : 3), data); + fprint_val (sim_deb, tag >> BUS_SHIFT, 2, 4, PV_RZRO); + fprintf (sim_deb, " unloaded from FIFO (%d)\n", di_card->fifo_count); + } + + +if (di_card->cntl_register & CNTL_TALK) /* is the card talking? */ + if (di_card->cntl_register & CNTL_PACK) /* in packed mode? */ + if (di_card->status_register & STAT_LBO /* yes, is the last byte out? */ + && di_card->cntl_register & CNTL_EOI) /* and EOI control enabled? */ + di_card->bus_cntl |= BUS_EOI; /* assert EOI */ + else + di_card->bus_cntl &= ~BUS_EOI; /* deny EOI */ + + else { /* in unpacked mode */ + if (di_card->cntl_register & CNTL_CIC) /* is card the controller in charge? */ + di_card->bus_cntl = /* assert or deny the ATN bus line */ + di_card->bus_cntl & ~BUS_ATN /* from the ATN tag value */ + | (tag & TAG_ATN) >> BUS_SHIFT; + + di_card->bus_cntl = /* assert or deny the EOI bus line */ + di_card->bus_cntl & ~BUS_EOI /* from the EOI tag value */ + | (tag & TAG_EOI) >> BUS_SHIFT; + } + +return (uint16) data; /* return the data value */ +} + + +/* Print the bus state for debugging. + + The states of the supplied bus control lines are decoded and printed in + mnemonic form to the specified file using the indicated format string. An + asserted bus signal is indicated by its name; a denied signal is omitted. + + + Implementation notes: + + 1. The strings in the cntl_names array must appear in BUS_xxx order. The + first element corresponds to bus bit 0, etc. +*/ + +static void fprint_bus (FILE *file, char *format, uint8 cntl) +{ +static const char *cntl_names [] = { + "ATN", /* bit 0: attention */ + "EOI", /* bit 1: end or identify */ + "DAV", /* bit 2: data available */ + "NRFD", /* bit 3: not ready for data */ + "NDAC", /* bit 4: not data accepted */ + "REN", /* bit 5: remote enable */ + "IFC", /* bit 6: interface clear */ + "SRQ" /* bit 7: service request */ + }; + +uint32 signal; +char mnemonics [40]; + +if (cntl == 0) /* any control signal asserted? */ + strcpy (mnemonics, "---"); /* no; use dashes in lieu of an empty string */ + +else { /* one or more signals are asserted */ + mnemonics [0] = '\0'; + + for (signal = 0; signal <= 7; signal++) /* loop though the set of signals */ + if (cntl & (1 << signal)) { /* is this signal asserted? */ + if (strlen (mnemonics) > 0) /* yes; is it the first one asserted? */ + strcat (mnemonics, " "); /* no, so append a space to separate */ + strcat (mnemonics, cntl_names [signal]); /* append the name of the asserted signal */ + } + } + +fprintf (file, format, mnemonics); /* print the bus state */ +return; +} diff --git a/HP2100/hp2100_di.h b/HP2100/hp2100_di.h new file mode 100644 index 00000000..79d742ab --- /dev/null +++ b/HP2100/hp2100_di.h @@ -0,0 +1,296 @@ +/* hp2100_di.h: HP 12821A HP-IB Disc Interface simulator common definitions + + Copyright (c) 2010-2012, J. David Bryan + + 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. + + DI 12821A Disc Interface + + 14-Feb-12 JDB First release + 16-Nov-10 JDB Created DI common definitions file + + + This file defines the interface between HP-IB device simulators and the + 12821A Disc Interface simulator. It must be included by the device-specific + modules (hp2100_di_da.c, etc.). + + + Implementation notes: + + 1. Three CARD_ID values are defined, corresponding to the Amigo disc (DA), + CS/80 disc (DC), and Amigo mag tape (MA) simulators. At first release, + only the DA device is implemented. However, as the 12821A diagnostic + requires two cards to test I/O fully, a dummy DC device is provided by + the DA simulator. It is enabled only when the DA card is configured for + diagnostic mode. This dummy device may be removed when either the DC or + MA device is implemented. +*/ + + + +/* Program constants */ + +#define FIFO_SIZE 16 /* FIFO depth */ + +typedef enum { da, dc, ma, /* card IDs */ + first_card = da, /* first card ID */ + last_card = ma, /* last card ID */ + card_count } CARD_ID; /* count of card IDs */ + + +/* Device flags and accessors (leaves space for disc/tape flags) */ + +#define DEV_V_BUSADR (DEV_V_UF + 8) /* bits 10-8: HP-IB address */ +#define DEV_V_DIAG (DEV_V_UF + 11) /* bit 11: diagnostic mode */ +#define DEV_V_W1 (DEV_V_UF + 12) /* bit 12: DCPC pacing jumper */ + +#define DEV_M_BUSADR 7 /* bus address mask */ + +#define DEV_BUSADR (DEV_M_BUSADR << DEV_V_BUSADR) +#define DEV_DIAG (1 << DEV_V_DIAG) +#define DEV_W1 (1 << DEV_V_W1) + +#define GET_DIADR(f) (((f) >> DEV_V_BUSADR) & DEV_M_BUSADR) +#define SET_DIADR(f) (((f) & DEV_M_BUSADR) << DEV_V_BUSADR) + + +/* Unit flags and accessors (leaves space for disc/tape flags) */ + +#define UNIT_V_BUSADR (UNIT_V_UF + 8) /* bits 10-8: HP-IB address */ + +#define UNIT_M_BUSADR 7 /* bus address mask */ + +#define UNIT_BUSADR (UNIT_M_BUSADR << UNIT_V_BUSADR) + +#define GET_BUSADR(f) (((f) >> UNIT_V_BUSADR) & UNIT_M_BUSADR) +#define SET_BUSADR(f) (((f) & UNIT_M_BUSADR) << UNIT_V_BUSADR) + + +/* Debug flags */ + +#define DEB_CPU (1 << 0) /* words received from and sent to the CPU */ +#define DEB_CMDS (1 << 1) /* interface commands received from the CPU */ +#define DEB_BUF (1 << 2) /* data read from and written to the card FIFO */ +#define DEB_XFER (1 << 3) /* data received and transmitted via HP-IB */ +#define DEB_RWSC (1 << 4) /* device read/write/status/control commands */ +#define DEB_SERV (1 << 5) /* unit service scheduling calls */ + + +/* HP-IB control state bit flags. + + NOTE that these flags align with the corresponding flags in the DI status + register, so don't change the order! +*/ + +#define BUS_ATN 0001 /* attention */ +#define BUS_EOI 0002 /* end or identify */ +#define BUS_DAV 0004 /* data available */ +#define BUS_NRFD 0010 /* not ready for data */ +#define BUS_NDAC 0020 /* not data accepted */ +#define BUS_REN 0040 /* remote enable */ +#define BUS_IFC 0100 /* interface clear */ +#define BUS_SRQ 0200 /* service request */ + +#define BUS_PPOLL (BUS_ATN | BUS_EOI) /* parallel poll */ + +/* HP-IB data */ + +#define BUS_ADDRESS 0037 /* bus address mask */ +#define BUS_GROUP 0140 /* bus group mask */ +#define BUS_COMMAND 0160 /* bus command type mask */ +#define BUS_DATA 0177 /* bus data mask */ +#define BUS_PARITY 0200 /* bus parity mask */ + +#define BUS_PCG 0000 /* primary command group */ +#define BUS_LAG 0040 /* listen address group */ +#define BUS_TAG 0100 /* talk address group */ +#define BUS_SCG 0140 /* secondary command group */ + +#define BUS_UCG 0020 /* universal command group */ +#define BUS_ACG 0000 /* addressed command group */ + +#define BUS_UNADDRESS 0037 /* unlisten and untalk */ + +#define PPR(a) (uint8) (1 << (7 - (a))) /* parallel poll response */ + + +/* Byte accessors */ + +#define BYTE_SHIFT 8 /* byte shift count */ +#define UPPER_BYTE 0177400 /* high-order byte mask */ +#define LOWER_BYTE 0000377 /* low-order byte mask */ + +#define GET_UPPER(w) (uint8) (((w) & UPPER_BYTE) >> BYTE_SHIFT) +#define GET_LOWER(w) (uint8) ((w) & LOWER_BYTE) + +#define SET_UPPER(b) ((b) << BYTE_SHIFT) +#define SET_LOWER(b) (b) +#define SET_BOTH(b) (SET_UPPER (b) | SET_LOWER (b)) + +typedef enum { upper, /* byte selector */ + lower } SELECTOR; + + +/* Per-card state variables */ + +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP srq; /* SRQ flip-flop */ + FLIP_FLOP edt; /* EDT flip-flop */ + FLIP_FLOP eor; /* EOR flip-flop */ + SELECTOR ibp; /* input byte pointer selector */ + SELECTOR obp; /* output byte pointer selector */ + + uint16 cntl_register; /* control word register */ + uint16 status_register; /* status word register */ + uint16 input_data_register; /* input data register */ + + uint32 fifo [FIFO_SIZE]; /* FIFO buffer */ + uint32 fifo_count; /* FIFO occupancy counter */ + REG *fifo_reg; /* FIFO register pointer */ + + uint32 acceptors; /* unit bitmap of bus acceptors */ + uint32 listeners; /* unit bitmap of bus listeners */ + uint32 talker; /* unit bitmap of bus talker */ + + uint8 bus_cntl; /* HP-IB bus control state (ATN, EOI, etc.) */ + uint8 poll_response; /* address bitmap of parallel poll responses */ + + double ifc_timer; /* 100 microsecond IFC timer */ + } DI_STATE; + + +/* Disc interface VM global register definitions. + + Include these definitions before any device-specific registers. + + + Implementation notes: + + 1. The TMR register is included to ensure that the IFC timer is saved by a + SAVE command. It is declared as a hidden, read-only byte array of a size + compatible with a double-precision floating-point value, as there is no + appropriate macro for the double type. +*/ + +#define DI_REGS(dev) \ + { ORDATA (CWR, di [dev].cntl_register, 16), REG_FIT }, \ + { ORDATA (SWR, di [dev].status_register, 16), REG_FIT }, \ + { ORDATA (IDR, di [dev].input_data_register, 16), REG_FIT }, \ + \ + { DRDATA (FCNT, di [dev].fifo_count, 5) }, \ + { BRDATA (FIFO, di [dev].fifo, 8, 20, FIFO_SIZE), REG_CIRC }, \ + \ + { GRDATA (ACPT, di [dev].acceptors, 2, 4, 0) }, \ + { GRDATA (LSTN, di [dev].listeners, 2, 4, 0) }, \ + { GRDATA (TALK, di [dev].talker, 2, 4, 0) }, \ + { GRDATA (PPR, di [dev].poll_response, 2, 8, 0), REG_FIT }, \ + { GRDATA (BUSCTL, di [dev].bus_cntl, 2, 8, 0), REG_FIT }, \ + \ + { FLDATA (CTL, di [dev].control, 0) }, \ + { FLDATA (FLG, di [dev].flag, 0) }, \ + { FLDATA (FBF, di [dev].flagbuf, 0) }, \ + { FLDATA (SRQ, di [dev].srq, 0) }, \ + { FLDATA (EDT, di [dev].edt, 0) }, \ + { FLDATA (EOR, di [dev].eor, 0) }, \ + \ + { BRDATA (TMR, &di [dev].ifc_timer, 10, CHAR_BIT, sizeof (double)), REG_HRO }, \ + \ + { ORDATA (SC, dev##_dib.select_code, 6), REG_HRO } + + +/* Disc interface VM global modifier definitions. + + Include these definitions before any device-specific modifiers. +*/ + +#define DI_MODS(dev) \ + { MTAB_XTD | MTAB_VDV, 1, "ADDRESS", "ADDRESS", &di_set_address, &di_show_address, &dev }, \ + \ + { MTAB_XTD | MTAB_VDV, 1, NULL, "DIAG", &di_set_cable, NULL, &dev }, \ + { MTAB_XTD | MTAB_VDV, 0, NULL, "HPIB", &di_set_cable, NULL, &dev }, \ + { MTAB_XTD | MTAB_VDV, 0, "CABLE", NULL, NULL, &di_show_cable, &dev }, \ + \ + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &dev }, \ + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dev }, \ + \ + { MTAB_XTD | MTAB_VUN, 0, "BUS", "BUS", &di_set_address, &di_show_address, &dev } + + +/* Disc interface global bus routine definitions */ + +typedef t_bool ACCEPTOR (uint32 unit, uint8 data); +typedef void RESPONDER (CARD_ID card, uint32 unit, uint8 new_cntl); + + +/* Disc interface global variables */ + +extern DI_STATE di []; +extern DEBTAB di_deb []; + + +/* Disc interface global VM routines */ + +extern IOHANDLER di_io; +extern t_stat di_reset (DEVICE *dptr); + +/* Disc interface global SCP routines */ + +extern t_stat di_set_address (UNIT *uptr, int32 value, char *cptr, void *desc); +extern t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc); +extern t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc); +extern t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc); + +/* Disc interface global bus routines */ + +extern t_bool di_bus_source (CARD_ID card, uint8 data); +extern void di_bus_control (CARD_ID card, uint32 unit, uint8 assert, uint8 deny); +extern void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response); + + +/* Amigo disc global VM routines */ + +extern t_stat da_service (UNIT *uptr); +extern t_stat da_boot (int32 unitno, DEVICE *dptr); + +/* Amigo disc global bus routines */ + +extern ACCEPTOR da_bus_accept; +extern RESPONDER da_bus_respond; + + +/* Amigo mag tape global VM routines */ + +extern t_stat ma_service (UNIT *uptr); +extern t_stat ma_boot (int32 unitno, DEVICE *dptr); + +/* Amigo mag tape global SCP routines */ + +extern t_stat ma_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat ma_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); + +/* Amigo mag tape global bus routines */ + +extern ACCEPTOR ma_bus_accept; +extern RESPONDER ma_bus_respond; diff --git a/HP2100/hp2100_di_da.c b/HP2100/hp2100_di_da.c new file mode 100644 index 00000000..24b1766d --- /dev/null +++ b/HP2100/hp2100_di_da.c @@ -0,0 +1,2127 @@ +/* hp2100_di_da.c: HP 12821A HP-IB Disc Interface simulator for Amigo disc drives + + Copyright (c) 2011-2012, J. David Bryan + + 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. + + DA 12821A Disc Interface with Amigo disc drives + + 21-Feb-12 JDB First release + 04-Nov-11 JDB Created DA device + + References: + - HP 13365 Integrated Controller Programming Guide (13365-90901, Feb-1980) + - HP 7910 Disc Drive Service Manual (07910-90903, Apr-1981) + - 12745D Disc Controller (13037) to HP-IB Adapter Kit Installation and + Service Manual (12745-90911, Sep-1983) + - HP's 5 1/4-Inch Winchester Disc Drive Service Documentation + (09134-90032, Aug-1983) + - HP 12992 Loader ROMs Installation Manual (12992-90001, Apr-1986) + - RTE Driver DVA32 Source (92084-18708, revision 2540) + - IEEE Standard Digital Interface for Programmable Instrumentation + (IEEE-488A-1980, Sep-1979) + + + The HP 7906H, 7920H, and 7925H Integrated Controller Disc (ICD) drives were + connected via an 12821A disc interface and provided 20MB, 50MB, and 120MB + capacities. The drives were identical to the 7906M, 7920M, and 7925M + Multi-Access Controller (MAC) units but incorporated internal two-card + controllers in each drive and connected to the CPU interface via HP-IB. Each + controller was dedicated to a single drive and operated similarly to the + 12745 Disc Controller to HP-IB Adapter option for the 13037 Disc Controller + box. The 7906H was introduced in 1980 (there was no 7905H version, as the + 7905 was obsolete by that time). Up to four ICD drives could be connected to + a single 12821A card. The limitation was imposed by the bus loading and the + data transfer rate. + + The ICD command set essentially was the MAC command set modified for + single-unit operation. The unit number and CPU hold bit fields in the opcode + words were unused in the ICD implementation. The Load TIO Register, Wakeup, + and Request Syndrome commands were removed, as Load TIO was used with the HP + 3000, Wakeup was used in a multi-CPU environment, and the simpler ICD + controller did not support ECC. Controller status values 02B (Unit + Available) and 27B (Unit Unavailable) were dropped as the controller + supported only single units, 12B (I/O Program Error) was reused to indicate + HP-IB sequence errors, 13B (Sync Not Received) was added, and 17B (Possibly + Correctable Data Error) was removed as error correction was not supported. + + Some minor redefinitions also occurred. For example, status 14B (End of + Cylinder) was expanded to include an auto-seek beyond the drive limits, and + 37B (Drive Attention) was restricted from head loads and unloads to just head + unloads. + + The command set was expanded to include several commands related to HP-IB + operation. These were, in large part, adapted from the Amigo disc command + protocol outlined in the service manual for the HP 9133/34/35 series of + 5-1/4" Winchester drives. They include the Amigo Identify and Amigo Clear + sequences, Read and Write Loopback channel tests, and controller Self Test + commands. + + Unfortunately, the primary reference for the ICD controller (the HP 13365 + Integrated Controller Programming Guide) does not indicate parallel poll + responses for these HP-IB commands. Therefore, the responses have been + derived from the sequences in the 7910 and 12745 manuals, although they + sometimes conflict. + + This simulator implements the Amigo disc protocol. It calls the 12821A Disc + Interface (DI) simulator to send and receive bytes across the HP-IB to and + from the CPU, and it calls the HP Disc Library to implement the controller + functions related to disc unit operation (e.g., seek, read, write, etc.). + Four units are provided, and any combination of 7906H/20H/25H drives may be + defined. + + The drives respond to the following commands; numeric values are in hex, and + bus addressing is indicated by U [untalk], L [listen], and T [talk]: + + Bus Sec Op Operation + --- --- -- -------------------------------- + U MSA -- Amigo Identify + + L 00 -- Write Data + L 08 00 Cold Load Read + L 08 01 Recalibrate + L 08 02 Seek + L 08 03 Request Status + L 08 04 Request Sector Address + L 08 05 Read + L 08 06 Read Full Sector + L 08 07 Verify + L 08 08 Write + L 08 09 Write Full Sector + L 08 0A Clear + L 08 0B Initialize + L 08 0C Address Record + L 08 0E Read with Offset + L 08 0F Set File Mask + L 08 12 Read without Verify + L 08 14 Request Logical Disc Address + L 08 15 End + L 09 -- Cyclic Redundancy Check + L 10 -- Amigo Clear + L 1E -- Write Loopback + L 1F ss Initiate Self-Test + + T 00 -- Read Data + T 08 -- Read Status + T 09 -- Cyclic Redundancy Check + T 10 -- Device Specified Jump + T 1E -- Read Loopback + T 1F -- Return Self-Test Result + + In addition, the controller responds to the Selected Device Clear primary + (04). + + + HP-IB Transaction Sequences + =========================== + + Amigo Identify + + ATN UNT Untalk + ATN MSA My secondary address + DAB ID data byte #1 = 00H + EOI DAB ID data byte #2 = 03H + ATN OTA Talk 30 + + + Amigo Clear + + ATN MLA My listen address + ATN SCG Secondary command 10H + ppd Parallel poll disabled + EOI DAB Unused data byte + ATN SDC Selected device clear + ATN UNL Unlisten + ... + ppe Parallel poll enabled when clear completes + + + CRC + + ATN MTA My talk address + ATN SCG Secondary command 09H + ppd Parallel poll disabled + DAB Data byte #1 + ... + EOI DAB Data byte #n + ppe Parallel poll enabled + ATN UNT Untalk + + or + + ATN MLA My listen address + ATN SCG Secondary command 09H + ppd Parallel poll disabled + DAB Data byte #1 + ... + EOI DAB Data byte #n + ppe Parallel poll enabled + ATN UNL Unlisten + + + Device Specified Jump + + ATN MTA My talk address + ATN SCG Secondary command 10H + ppd Parallel poll disabled + EOI DAB DSJ data byte + ATN UNT Untalk + + + Initiate Self-Test and Return Self-Test Result + + ATN MLA My listen address + ATN SCG Secondary command 1FH + ppd Parallel poll disabled + EOI DAB Self-test number + ppe Parallel poll enabled + ATN UNL Unlisten + + ATN MTA My talk address + ATN SCG Secondary command 1FH + ppd Parallel poll disabled + EOI DAB Result data byte + ppe Parallel poll enabled + ATN UNT Untalk + + + Write Loopback and Read Loopback + + ATN MLA My listen address + ATN SCG Secondary command 1EH + ppd Parallel poll disabled + DAB Loopback data byte #1 + ... + EOI DAB Loopback data byte #256 + ppe Parallel poll enabled + ATN UNL Unlisten + + ATN MTA My talk address + ATN SCG Secondary command 1EH + ppd Parallel poll disabled + DAB Loopback data byte #1 + ... + EOI DAB Loopback data byte #16 + ppe Parallel poll enabled + ATN UNT Untalk + + + Recalibrate and Seek + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 01H, 02H + ... (one to five + EOI DAB parameter bytes) + ATN UNL Unlisten + ... + ppe Parallel poll enabled when seek completes + + + Clear, Address Record, and Set File Mask + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 0AH, 0CH, 0FH + ... (one to five + EOI DAB parameter bytes) + ppe Parallel poll enabled + ATN UNL Unlisten + + + End + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 15H + EOI DAB Unused data byte + ATN UNL Unlisten + + + Request Status, Request Sector Address, and Request Logical Disc Address + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 03H, 04H, 14H + EOI DAB Unused data byte + ATN UNL Unlisten + + ATN MTA My talk address + ATN SCG Secondary command 08H + DAB Status byte #1 + ... (two to four + EOI DAB status bytes) + ppe Parallel poll enabled + ATN UNT Untalk + + + Cold Load Read, Read, Read Full Sector, Verify, Read with Offset, and Read + without Verify + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 00H, 05H, 06H, 07H, 0EH, 12H + EOI DAB Unused data byte + ATN UNL Unlisten + + ATN MTA My talk address + ATN SCG Secondary command 00H + DAB Read data byte #1 + ... + DAB Read data byte #n + ATN UNT Untalk + ... + ppe Parallel poll enabled when sector ends + + + Write, Write Full Sector, and Initialize + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 08H, 09H, 0BH + EOI DAB Unused data byte + ATN UNL Unlisten + + ATN MLA My listen address + ATN SCG Secondary command 00H + DAB Write data byte #1 + ... + EOI DAB Write data byte #n + ppe Parallel poll enabled + ATN UNL Unlisten + + + Implementation notes: + + 1. The 12745 does not alter the parallel poll response for the + Device-Specified Jump command. + + 2. The 7910 does not perform a parallel poll response enable and disable + between the Initiate Self-Test and Return Self-Test Result commands. + + 3. The 12745 does not disable the parallel poll response for the Read + Loopback command. +*/ + + + +#include "hp2100_defs.h" +#include "hp2100_di.h" +#include "hp_disclib.h" + + + +/* Program constants */ + +#define DA_UNITS 4 /* number of addressable disc units */ + + +/* Interface states */ + +typedef enum { + idle = 0, /* idle = default for reset */ + opcode_wait, /* waiting for opcode reception */ + parameter_wait, /* waiting for parameter reception */ + read_wait, /* waiting for send read data secondary */ + write_wait, /* waiting for receive write data secondary */ + status_wait, /* waiting for send status secondary */ + command_exec, /* executing an interface command */ + command_wait, /* waiting for command completion */ + read_xfer, /* sending read data or status */ + write_xfer, /* receiving write data */ + error_source, /* sending bytes for error recovery */ + error_sink /* receiving bytes for error recovery */ + } IF_STATE; + + +/* Interface state names */ + +static const char *if_state_name [] = { + "idle", + "opcode wait", + "parameter wait", + "read wait", + "write wait", + "status wait", + "command execution", + "command wait", + "read transfer", + "write transfer", + "error source", + "error sink" + }; + + +/* Next interface state after command recognition */ + +static const IF_STATE next_state [] = { + read_wait, /* cold load read */ + command_exec, /* recalibrate */ + command_exec, /* seek */ + status_wait, /* request status */ + status_wait, /* request sector address */ + read_wait, /* read */ + read_wait, /* read full sector */ + command_exec, /* verify */ + write_wait, /* write */ + write_wait, /* write full sector */ + command_exec, /* clear */ + write_wait, /* initialize */ + command_exec, /* address record */ + idle, /* request syndrome */ + read_wait, /* read with offset */ + command_exec, /* set file mask */ + idle, /* invalid */ + idle, /* invalid */ + read_wait, /* read without verify */ + idle, /* load TIO register */ + status_wait, /* request disc address */ + command_exec, /* end */ + idle /* wakeup */ + }; + + +/* Interface commands */ + +typedef enum { + invalid = 0, /* invalid = default for reset */ + + disc_command, /* MLA 08 */ + crc_listen, /* MLA 09 */ + amigo_clear, /* MLA 10 */ + write_loopback, /* MLA 1E */ + initiate_self_test, /* MLA 1F */ + + crc_talk, /* MTA 09 */ + device_specified_jump, /* MTA 10 */ + read_loopback, /* MTA 1E */ + return_self_test_result, /* MTA 1F */ + + amigo_identify /* UNT MSA */ + } IF_COMMAND; + +/* Interface command names */ + +static const char *if_command_name [] = { + "invalid", + + "disc command", + "CRC listen", + "Amigo clear", + "write loopback", + "initiate self-test", + + "CRC talk", + "device specified jump", + "read loopback", + "return self-test result", + + "Amigo identify" + }; + + + +/* Amigo disc state variables */ + +static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */ + +static uint8 if_dsj [DA_UNITS]; /* ICD controller DSJ values */ +static IF_STATE if_state [DA_UNITS]; /* ICD controller state */ +static IF_COMMAND if_command [DA_UNITS]; /* ICD controller command */ + +static CNTLR_VARS icd_cntlr [DA_UNITS] = /* ICD controllers: */ + { { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 0 controller */ + { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 1 controller */ + { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 2 controller */ + { CNTLR_INIT (ICD, buffer, NULL) } }; /* unit 3 controller */ + + + +/* Amigo disc global VM routines */ + +t_stat da_service (UNIT *uptr); +t_stat da_reset (DEVICE *dptr); +t_stat da_attach (UNIT *uptr, char *cptr); +t_stat da_detach (UNIT *uptr); +t_stat da_boot (int32 unitno, DEVICE *dptr); + +/* Amigo disc global SCP routines */ + +t_stat da_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); + +/* Amigo disc global bus routines */ + +t_bool da_bus_accept (uint32 unit, uint8 data); +void da_bus_respond (CARD_ID card, uint32 unit, uint8 new_cntl); + +/* Amigo disc local utility routines */ + +static t_bool start_command (uint32 unit); +static void abort_command (uint32 unit, CNTLR_STATUS status, IF_STATE state); +static void complete_read (uint32 unit); +static void complete_write (uint32 unit); +static void complete_abort (uint32 unit); +static uint8 get_buffer_byte (CVPTR cvptr); +static void put_buffer_byte (CVPTR cvptr, uint8 data); +static t_stat activate_unit (UNIT *uptr); + + + +/* Amigo disc VM global data structures. + + da_dib DA device information block + da_unit DA unit list + da_reg DA register list + da_mod DA modifier list + da_dev DA device descriptor + + + Implementation notes: + + 1. The IFSTAT and IFCMD registers are declared to accommodate the + corresponding arrays of enums. Arrayed registers assume that elements + are allocated space only to the integral number of bytes implied by the + "width" field. The storage size of an enum is implementation-defined, so + we must determine the number of bits for "width" at compile time. + PV_LEFT is used to avoid the large number of leading zeros that would be + displayed if an implementation stored enums in full words. + + 2. The CNVARS register is included to ensure that the controller state + variables array is saved by a SAVE command. It is declared as a hidden, + read-only byte array of a depth compatible with the size of the array. +*/ + +DEVICE da_dev; + +DIB da_dib = { &di_io, DI_DA, da }; + +#define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD) + +UNIT da_unit [] = { + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (0), D7906_WORDS) }, /* bus address 0 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (1), D7906_WORDS) }, /* bus address 1 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (2), D7906_WORDS) }, /* bus address 2 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (3), D7906_WORDS) } /* bus address 3 */ + }; + +REG da_reg [] = { + DI_REGS (da), + + { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) }, + + { BRDATA (DSJ, if_dsj, 10, 2, DA_UNITS) }, + { BRDATA (IFSTAT, if_state, 10, sizeof (IF_STATE) * CHAR_BIT, DA_UNITS), PV_LEFT }, + { BRDATA (IFCMD, if_command, 10, sizeof (IF_COMMAND) * CHAR_BIT, DA_UNITS), PV_LEFT }, + + { BRDATA (CNVARS, icd_cntlr, 10, CHAR_BIT, sizeof (CNTLR_VARS) * DA_UNITS), REG_HRO }, + + { NULL } + }; + +MTAB da_mod [] = { + DI_MODS (da_dev), + + { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &da_load_unload, NULL, NULL }, + { UNIT_UNLOAD, 0, "heads loaded", "LOADED", &da_load_unload, NULL, NULL }, + + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL }, + + { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL }, + { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL }, + + { UNIT_MODEL, MODEL_7906, "7906H", "7906H", &dl_set_model, NULL, NULL }, + { UNIT_MODEL, MODEL_7920, "7920H", "7920H", &dl_set_model, NULL, NULL }, + { UNIT_MODEL, MODEL_7925, "7925H", "7925H", &dl_set_model, NULL, NULL }, + + { 0 } + }; + +DEVICE da_dev = { + "DA", /* device name */ + da_unit, /* unit array */ + da_reg, /* register array */ + da_mod, /* modifier array */ + DA_UNITS, /* number of units */ + 10, /* address radix */ + 26, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &da_reset, /* reset routine */ + &da_boot, /* boot routine */ + &da_attach, /* attach routine */ + &da_detach, /* detach routine */ + &da_dib, /* device information block */ + DEV_DEBUG | DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + di_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL /* logical device name */ + }; + + + +/* Amigo disc global VM routines */ + + +/* Service an Amigo disc drive I/O event. + + The service routine is called to start commands and control the transfer of + data to and from the HP-IB card. The actions to be taken depend on the + current state of the ICD interface. The possibilities are: + + 1. A command is pending on the interface. This occurs only when a command + is received while a Seek or Recalibrate command is in progress. + + 2. A command is ready for execution. + + 3. Data is being sent or received over the HP-IB during command execution. + + 4. Dummy bytes are being sent or received over the HP-IB due to a command + error. + + Entry to the the service routine in any other interface state or to process a + command not allowed in a valid state will return an Internal Error to cause a + simulator stop. Exit from the routine will be either in one of the above + states, or in the idle state if the operation is complete. + + The specific actions taken for the various interface states are as follows: + + command_wait + ============ + + We are entered in this state only if a unit that was busy (still seeking) + was addressed to listen or talk. The card has been held off by asserting + NRFD after receiving MLA or MTA. Upon entry, we complete the seek and then + release the interface by denying NRFD to allow the remainder of the command + sequence to be received from the card. + + command_exec + ============ + + We are entered in this state to initiate, continue, or complete a command. + The command may be a disc command, such as Seek or Read, or an interface + command, such as Amigo Identify or Device-Specified Jump. + + Disc commands call the disc library service routine to perform all of the + common controller actions. Any ICD-specific actions needed, such as + setting the DSJ value, are performed after the call. + + Certain disc commands require multiple execution phases. For example, the + Read command has a start phase that reads data from the disc image file + into the sector buffer, a data phase that transfers bytes from the buffer + to the card, and an end phase that schedules the intersector gap time and + resets to the start phase. Data phase transfers are performed in the + read_exec or write_exec interface states. + + The results of the disc library service are inferred by the controller + state. If the controller is busy, then the command continues in a new + phase. Otherwise, the command either has completed normally or has + terminated with an error. If an error has occurred during a disc command + that transfers data, DSJ is set to 1, and the interface state is changed to + source or sink dummy bytes to complete the command sequence. + + Interface commands may either complete immediately (e.g., Amigo Clear) or + transfer data (e.g., DSJ). + + read_xfer + ========= + + Commands that send data to the CPU enter the service routine to source a + byte to the bus. Bytes are transferred only when ATN and NRFD are denied; + if they are not, we simply exit, as we will be rescheduled when the lines + are dropped. Otherwise, we get a byte from the sector buffer and send it + to the card. If the card has stopped listening, or the buffer is now + empty, then we terminate the transfer and move to the end phase of the + command. Otherwise, we reschedule the next data phase byte transfer. + + Disc and interface commands are handled separately, as EOI is always + asserted on the last byte of an interface command transfer and never on a + (good) disc command transfer. + + write_xfer + ========== + + Commands that receive data from the CPU enter the service routine to + determine whether or not to continue the transfer. Our bus accept routine + has already stored the received byte in the sector buffer and has asserted + NRFD to hold off the card. If the buffer is now full, or the byte was + tagged with EOI, then we terminate the transfer and move to the end phase + of the command. Otherwise, we deny NRFD and exit, as we will be + rescheduled when the next byte arrives. + + error_source + ============ + + If an error occurred during the data transfer phase of a read or status + command, a dummy byte tagged with EOI is sourced to the bus. This allows + the OS driver for the card to terminate the command and request the + controller's status. + + error_sink + ========== + + If an error occurred during the data transfer phase of a write command, + dummy bytes are sunk from the bus until EOI is seen or the card is + unaddressed. This allows the OS driver to complete the command as expected + and to determine the failure by requesting the controller's status. + + + Implementation notes: + + 1. The disc library sets the controller state to idle for a normal End, + Seek, or Recalibrate command and to Wait for all other commands that end + normally. So we determine command completion by checking if the + controller is not busy, rather than checking if the controller is idle. + + Drive Attention status is the normal result of the completion of a Seek + or Recalibrate command. Normal Completion status is the normal result of + all other commands. + + 2. The disc library returns the buffer length in words. We double the + return value to count bytes. + + 3. Some commands, such as DSJ, could be completed in the bus accept routine. + They are serviced here instead to avoid presenting a zero execution time + to the CPU. + + 4. The Amigo command set does not provide the disc with the number of bytes + that will be read, and the unit expects to be untalked when the read is + to terminate. The RTE ICD bootstrap extension does not do this. + Instead, it resets the card via CLC 0,C to terminate the Cold Load Read + that was started by the ICD boot loader ROM. + + In hardware, if the LSTN control bit is cleared, e.g., by CRS, + transmission stops because the card denies NDAC and NRFD (the GPIB + handshake requires NDAC and NRFD to be asserted to start the handshake + sequence; TACS * SDYS * ~NDAC * ~NRFD is an error condition). In + simulation, we handle this by terminating a read transfer if the card + stops accepting. If we did not, then the disc would continue to source + bytes to the bus, overflowing the card FIFO (a FIFO full condition cannot + assert NRFD if the LSTN control bit is clear). +*/ + +t_stat da_service (UNIT *uptr) +{ +uint8 data; +CNTLR_CLASS command_class; +const uint32 unit = uptr - da_dev.units; /* disc unit number */ +const CVPTR cvptr = &icd_cntlr [unit]; /* pointer to controller */ +t_stat result = SCPE_OK; +t_bool release_interface = FALSE; + +switch (if_state [unit]) { /* dispatch interface state */ + + case command_wait: /* command is waiting */ + release_interface = TRUE; /* release interface at end if idle */ + + /* fall into the command_exec handler to process the current command */ + + case command_exec: /* command is executing */ + switch (if_command [unit]) { /* dispatch the interface command */ + + case disc_command: /* execute a disc command */ + result = dl_service_drive (cvptr, uptr); /* service the disc unit */ + + if (cvptr->opcode == clear) /* Clear command? */ + if_dsj [unit] = 2; /* indicate self test complete */ + + if (cvptr->state != cntlr_busy) { /* has the controller stopped? */ + if_state [unit] = idle; /* idle the interface */ + + if (cvptr->status == normal_completion || /* normal completion? */ + cvptr->status == drive_attention) /* or drive attention? */ + break; /* we're done */ + + else { /* if status is abnormal */ + if_dsj [unit] = 1; /* an error has occurred */ + + command_class = dl_classify (*cvptr); /* classify command */ + + if (command_class == class_write) { /* write command failed? */ + if_state [unit] = error_sink; /* sink remaining bytes */ + uptr->wait = cvptr->cmd_time; /* activate to complete processing */ + } + + else if (command_class != class_control) { /* read or status command failed? */ + if_state [unit] = error_source; /* source an error byte */ + uptr->wait = cvptr->cmd_time; /* activate to complete processing */ + } + } + } + + else if (uptr->PHASE == data_phase) { /* starting the data phase? */ + cvptr->length = cvptr->length * 2; /* convert buffer length to bytes */ + + if (dl_classify (*cvptr) == class_write) /* write command? */ + if_state [unit] = write_xfer; /* set for write data transfer */ + else /* read or status command */ + if_state [unit] = read_xfer; /* set for read data transfer */ + } + + break; + + + case amigo_identify: /* Amigo Identify */ + buffer [0] = 0x0003; /* store response in buffer */ + cvptr->length = 2; /* return two bytes */ + + if_state [unit] = read_xfer; /* ready to transfer data */ + uptr->wait = cvptr->cmd_time; /* schedule the transfer */ + + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d Amigo identify response %04XH\n", + unit, buffer [0]); + break; + + + case initiate_self_test: /* Initiate a self test */ + sim_cancel (&da_unit [unit]); /* cancel any operation in progress */ + dl_clear_controller (cvptr, /* hard clear the controller */ + &da_unit [unit], + hard_clear); + if_dsj [unit] = 2; /* set DSJ for self test */ + if_state [unit] = idle; /* command is complete */ + di_poll_response (da, unit, SET); /* with PPR enabled */ + break; + + + case amigo_clear: /* Amigo clear */ + dl_idle_controller (cvptr); /* idle the controller */ + if_dsj [unit] = 0; /* clear the DSJ value */ + if_state [unit] = idle; /* command is complete */ + di_poll_response (da, unit, SET); /* with PPR enabled */ + break; + + + default: /* no other commands are executed */ + result = SCPE_IERR; /* signal an internal error */ + break; + } /* end of command dispatch */ + break; + + + case error_source: /* send data after an error */ + if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) { /* is card ready for data? */ + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + di_bus_source (da, 0); /* send a dummy byte to the card */ + if_state [unit] = idle; /* command is complete */ + } + break; + + + case read_xfer: /* send read data */ + if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) /* is card ready for data? */ + switch (if_command [unit]) { /* dispatch the interface command */ + + case disc_command: /* disc read or status commands */ + data = get_buffer_byte (cvptr); /* get the next byte from the buffer */ + + if (di_bus_source (da, data) == FALSE) /* send data to card; is it listening? */ + cvptr->eod = SET; /* no, so terminate read */ + + if (cvptr->length == 0 || cvptr->eod == SET) { /* is the data phase complete? */ + uptr->PHASE = end_phase; /* set the end phase */ + + if (cvptr->opcode == request_status) /* is it a Request Status command? */ + if_dsj [unit] = 0; /* clear the DSJ value */ + + if_state [unit] = command_exec; /* set to execute the command */ + uptr->wait = cvptr->cmd_time; /* and reschedule the service */ + } + + else /* data phase continues */ + uptr->wait = cvptr->data_time; /* reschedule the next transfer */ + + break; + + + case amigo_identify: + case read_loopback: + case return_self_test_result: + data = get_buffer_byte (cvptr); /* get the next byte from the buffer */ + + if (cvptr->length == 0) /* is the transfer complete? */ + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + + if (di_bus_source (da, data) /* send data to card; is it listening? */ + && cvptr->length > 0) /* and more to transfer? */ + uptr->wait = cvptr->data_time; /* reschedule the next transfer */ + + else { /* transfer is complete */ + if_state [unit] = idle; /* command is complete */ + di_poll_response (da, unit, SET); /* enable PPR */ + } + break; + + + case device_specified_jump: + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + di_bus_source (da, if_dsj [unit]); /* send the DSJ value to the card */ + if_state [unit] = idle; /* command is complete */ + break; + + + case crc_talk: + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + di_bus_source (da, 0); /* send dummy bytes */ + break; /* until the card untalks */ + + + default: /* no other commands send data */ + result = SCPE_IERR; /* signal an internal error */ + break; + } /* end of read data transfer dispatch */ + break; + + + case error_sink: /* absorb data after an error */ + cvptr->index = 0; /* absorb data until EOI */ + + if (cvptr->eod == SET) /* is the transfer complete? */ + if_state [unit] = idle; /* command is complete */ + + di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ + break; + + + case write_xfer: /* receive write data */ + switch (if_command [unit]) { /* dispatch the interface command */ + + case disc_command: /* disc write commands */ + if (cvptr->length == 0 || cvptr->eod == SET) { /* is the data phase complete? */ + uptr->PHASE = end_phase; /* set the end phase */ + + if_state [unit] = command_exec; /* set to execute the command */ + uptr->wait = cvptr->cmd_time; /* and schedule the service */ + + if (cvptr->eod == CLEAR) /* is the transfer continuing? */ + break; /* do not deny NRFD until next service! */ + } + + di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ + break; + + + case write_loopback: + if (cvptr->eod == SET) { /* is the transfer complete? */ + cvptr->length = 16 - cvptr->length; /* set the count of bytes transferred */ + if_state [unit] = idle; /* command is complete */ + } + + di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ + break; + + + default: /* no other commands receive data */ + result = SCPE_IERR; /* signal an internal error */ + break; + } /* end of write data transfer dispatch */ + break; + + + default: /* no other states schedule service */ + result = SCPE_IERR; /* signal an internal error */ + break; + } /* end of interface state dispatch */ + + +if (uptr->wait) /* is service requested? */ + activate_unit (uptr); /* schedule the next event */ + +if (result == SCPE_IERR && DEBUG_PRI (da_dev, DEB_RWSC)) { /* internal error? */ + fprintf (sim_deb, ">>DA rwsc: Unit %d ", unit); + + if (if_state [unit] == command_exec + && if_command [unit] == disc_command) + fprintf (sim_deb, "%s command %s phase ", + dl_opcode_name (ICD, (CNTLR_OPCODE) uptr->OP), + dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); + else + fprintf (sim_deb, "%s state %s ", + if_command_name [if_command [unit]], + if_state_name [if_state [unit]]); + + fputs ("service not handled\n", sim_deb); + } + +if (if_state [unit] == idle) { /* is the command now complete? */ + if (if_command [unit] == disc_command) { /* did a disc command complete? */ + if (cvptr->opcode != end) /* yes; if the command was not End, */ + di_poll_response (da, unit, SET); /* then enable PPR */ + + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d %s disc command completed\n", + unit, dl_opcode_name (ICD, cvptr->opcode)); + } + + else /* an interface command completed */ + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d %s command completed\n", + unit, if_command_name [if_command [unit]]); + + if (release_interface) /* if next command is already pending */ + di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ + } + +return result; /* return the result of the service */ +} + + +/* Reset or preset the simulator. + + In hardware, a self-test is performed by the controller at power-on. When + the self-test completes, the controller sets DSJ = 2 and enables the parallel + poll response. + + A front panel PRESET or programmed CRS has no direct effect on the controller + or drive. However, the card reacts to CRS by clearing its talker and + listener states, so an in-progress read or status command will abort when the + next byte sourced to the bus finds no acceptors. +*/ + +t_stat da_reset (DEVICE *dptr) +{ +uint32 unit; +t_stat status; + +status = di_reset (dptr); /* reset the card */ + +if (status == SCPE_OK && (sim_switches & SWMASK ('P'))) /* card OK and power-on reset? */ + for (unit = 0; unit < dptr->numunits; unit++) { /* loop through units */ + sim_cancel (dptr->units + unit); /* cancel activation */ + dptr->units [unit].CYL = 0; /* reset the head position */ + dptr->units [unit].pos = 0; /* to cylinder 0 */ + + dl_clear_controller (&icd_cntlr [unit], /* hard clear the controller */ + dptr->units + unit, + hard_clear); + + if_state [unit] = idle; /* reset the interface state */ + if_command [unit] = invalid; /* reset the interface command */ + + if_dsj [unit] = 2; /* set DSJ for power up */ + } + +return status; +} + + +/* Attach a unit to a disc image file. + + The simulator considers an attached unit to be connected to the bus, and an + unattached unit to be disconnected, so we set the card's acceptor bit for the + selected unit if the attach is successful. An attached unit is ready if the + heads are loaded and not ready of not. + + This model is slightly different than the MAC (DS) simulation, where an + unattached unit is considered "connected but not ready" -- the same indication + returned by an attached unit whose heads are unloaded. Therefore, the + situation when the simulator is started is that all DS units are "connected to + the controller but not ready," whereas all DA units are "not connected to the + controller." This eliminates the overhead of sending HP-IB messages to unused + units. + + In tabular form, the simulator responses are: + + Enabled Loaded Attached DS (MAC) DA (ICD) + ------- ------ -------- ------------ ------------ + N N N disconnected disconnected + N N Y -- -- + N Y N -- -- + N Y Y -- -- + Y N N unloaded disconnected + Y N Y unloaded unloaded + Y Y N -- -- + Y Y Y ready ready + + The unspecified responses are illegal conditions; for example, the simulator + does not allow an attached unit to be disabled. + + + Implementation notes: + + 1. To conform exactly to the MAC responses would have required intercepting + the SET DISABLED/ENABLED commands in order to clear or set the unit + accepting bits. However, short of intercepting the all SET commands with + a custom command table, there is no way to ensure that unit enables are + observed. Adding ENABLED and DISABLED to the modifiers table and + specifying a validation routine works for the DISABLED case but not the + ENABLED case -- set_unit_enbdis returns SCPE_UDIS before calling the + validation routine. +*/ + +t_stat da_attach (UNIT *uptr, char *cptr) +{ +t_stat result; +const uint32 unit = uptr - da_unit; /* calculate the unit number */ + +result = dl_attach (&icd_cntlr [unit], uptr, cptr); /* attach the drive */ + +if (result == SCPE_OK) /* attach successful? */ + di [da].acceptors |= (1 << unit); /* set the unit's accepting bit */ + +return result; +} + + +/* Detach a disc image file from a unit. + + As explained above, detaching a unit is the hardware equivalent of + disconnecting the drive from the bus, so we clear the unit's acceptor bit is + the detach is successful. +*/ + +t_stat da_detach (UNIT *uptr) +{ +t_stat result; +const uint32 unit = uptr - da_unit; /* calculate the unit number */ + +result = dl_detach (&icd_cntlr [unit], uptr); /* detach the drive */ + +if (result == SCPE_OK) { /* detach successful? */ + di [da].acceptors &= ~(1 << unit); /* clear the unit's accepting bit */ + di_poll_response (da, unit, CLEAR); /* and its PPR, as it's no longer present */ + } + +return result; +} + + +/* Boot an Amigo disc drive. + + The ICD disc bootstrap prorgam is loaded from the HP 12992H Boot Loader ROM + into memory, the I/O instructions are configured from the interface card + select code, and the program is run to boot from the specified unit. The + loader supports booting the disc at bus address 0 only. Before execution, + the S register is automatically set as follows: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + ------ ------ ---------------------- ------------- ----- + ROM # 0 1 select code reserved head + + The boot routine sets bits 15-6 of the S register to appropriate values. + Bits 5-3 and 1-0 retain their original values, so S should be set before + booting. These bits are typically set to 0, although bit 5 is set for an RTE + reconfiguration boot, and bits 1-0 may be set if booting from a head other + than 0 is desired. +*/ + +static const BOOT_ROM da_rom = { + 0102501, /* START LIA 1 GET SWITCH REGISTER SETTING */ + 0100044, /* LSL 4 SHIFT A LEFT 4 */ + 0006111, /* CLE,SLB,RSS SR BIT 12 SET FOR MANUAL BOOT? */ + 0100041, /* LSL 1 NO. SHIFT HEAD # FOR RPL BOOT */ + 0001424, /* ALR,ALR SHIFT HEAD 2, CLEAR SIGN */ + 0033744, /* IOR HDSEC SET EOI BIT */ + 0073744, /* STA HDSEC PLACE IN COMMAND BUFFER */ + 0017756, /* JSB BTCTL SEND DUMMY,U-CLR,PP */ + 0102510, /* LIA IBI READ INPUT REGISTER */ + 0101027, /* ASR 7 SHIFT DRIVE 0 RESPONSE TO LSB */ + 0002011, /* SLA,RSS DID DRIVE 0 RESPOND? */ + 0027710, /* JMP *-3 NO, GO LOOK AGAIN */ + 0107700, /* CLC 0,C */ + 0017756, /* JSB BTCTL SEND TALK, CL-RD,BUS HOLDER */ + 0002300, /* CCE */ + 0017756, /* JSB BTCTL TELL CARD TO LISTEN */ + 0063776, /* LDA DMACW LOAD DMA CONTROL WORD */ + 0102606, /* OTA 6 OUTPUT TO DCPC */ + 0106702, /* CLC 2 READY DCPC */ + 0063735, /* LDA ADDR1 LOAD DMA BUFFER ADDRESS */ + 0102602, /* OTA 2 OUTPUT TO DCPC */ + 0063740, /* LDA DMAWC LOAD DMA WORD COUNT */ + 0102702, /* STC 2 READY DCPC */ + 0102602, /* OTA 2 OUTPUT TO DCPC */ + 0103706, /* STC 6,C START DCPC */ + 0102206, /* TEST SFC 6 SKIP IF DMA NOT DONE */ + 0117750, /* JSB ADDR2,I SUCCESSFUL END OF TRANSFER */ + 0102310, /* SFS IBI SKIP IF DISC ABORTED TRANSFER */ + 0027731, /* JMP TEST RECHECK FOR TRANSFER END */ + 0102011, /* ADDR1 HLT 11B ERROR HALT */ + 0000677, /* UNCLR OCT 677 UNLISTEN */ + 0000737, /* OCT 737 UNTALK */ + 0176624, /* DMAWC OCT 176624 UNIVERSAL CLEAR,LBO */ + 0000440, /* LIST OCT 440 LISTEN BUS ADDRESS 0 */ + 0000550, /* CMSEC OCT 550 SECONDARY GET COMMAND */ + 0000000, /* BOOT OCT 0 COLD LOAD READ COMMAND */ + 0001000, /* HDSEC OCT 1000 HEAD,SECTOR PLUS EOI */ + 0000677, /* UNLST OCT 677 ATN,PRIMARY UNLISTEN,PARITY */ + 0000500, /* TALK OCT 500 SEND READ DATA */ + 0100740, /* RDSEC OCT 100740 SECONDARY READ DATA */ + 0102055, /* ADDR2 OCT 102055 BOOT EXTENSION STARTING ADDRESS */ + 0004003, /* CTLP OCT 4003 INT=LBO,T,CIC */ + 0000047, /* OCT 47 PPE,L,T,CIC */ + 0004003, /* OCT 4003 INT=LBO,T,CIC */ + 0000413, /* OCT 413 ATN,P,L,CIC */ + 0001015, /* OCT 1015 INT=EOI,P,L,CIC */ + 0000000, /* BTCTL NOP */ + 0107710, /* CLC IBI,C RESET IBI */ + 0063751, /* BM LDA CTLP LOAD CONTROL WORD */ + 0102610, /* OTA IBI OUTPUT TO CONTROL REGISTER */ + 0102710, /* STC IBI RETURN IBI TO DATA MODE */ + 0037760, /* ISZ BM INCREMENT CONTROL WORD POINTER */ + 0002240, /* SEZ,CME */ + 0127756, /* JMP BTCTL,I RETURN */ + 0063736, /* LABL LDA UNCLR LOAD DATA WORD */ + 0037766, /* ISZ LABL INCREMENT WORD POINTER */ + 0102610, /* OTA IBI OUTPUT TO HPIB */ + 0002021, /* SSA,RSS SKIP IF LAST WORD */ + 0027766, /* JMP LABL GO BACK FOR NEXT WORD */ + 0102310, /* SFS IBI SKIP IF LAST WORD SENT TO BUS */ + 0027773, /* JMP *-1 RECHECK ACCEPTANCE */ + 0027757, /* JMP BTCTL+1 */ + 0000010, /* DMACW ABS IBI */ + 0170100 /* ABS -START */ + }; + +t_stat da_boot (int32 unitno, DEVICE *dptr) +{ +if (GET_BUSADR (da_unit [unitno].flags) != 0) /* boot supported on bus address 0 only */ + return SCPE_NOFNC; /* report "Command not allowed" if attempted */ + +if (ibl_copy (da_rom, da_dib.select_code)) /* copy the boot ROM to memory and configure */ + return SCPE_IERR; /* return an internal error if failed */ + +SR = SR & (IBL_OPT | IBL_DS_HEAD) /* set S to a reasonable value */ + | IBL_DS | IBL_MAN | (da_dib.select_code << IBL_V_DEV); /* before boot execution */ + +return SCPE_OK; +} + + + +/* Amigo disc global SCP routines */ + + +/* Load or unload a unit's heads. + + The heads are automatically loaded when a unit is attached and unloaded when + a unit is detached. While a unit is attached, the heads may be manually + unloaded; this yields a "not ready" status if the unit is accessed. An + unloaded drive may be manually loaded, returning the unit to "ready" status. + + The ICD controller sets Drive Attention status when the heads unload and also + asserts a parallel poll response if the heads unload while in idle state 2 + (i.e., after an End command). + + + Implementation notes: + + 1. The 13365 manual says on page 28 that Drive Attention status is + "Generated whenever...the drive unloads and the controller is in Idle + State 2 or 3." However, the ICD diagnostic tests for Drive Attention + status on head unload immediately after the Request Status command that + completes the previous step, which leaves the controller in idle state 1. + + Moreover, the diagnostic does NOT check for Drive Attention status if the + Amigo ID is 2 (MAC controller). But the 12745 manual says on page 3-7 + that the status is returned if "...Drive becomes not ready (heads + unload)" with no mention of controller state. + + It appears as though the diagnostic test is exactly backward. However, + we match the diagnostic expectation below. +*/ + +t_stat da_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +const uint32 unit = uptr - da_unit; /* calculate the unit number */ +const t_bool load = (value != UNIT_UNLOAD); /* true if heads are loading */ +t_stat result; + +result = dl_load_unload (&icd_cntlr [unit], uptr, load); /* load or unload the heads */ + +if (result == SCPE_OK && ! load) { /* unload successful? */ + icd_cntlr [unit].status = drive_attention; /* set Drive Attention status */ + + if (uptr->OP == end) /* is the controller in idle state 2? */ + di_poll_response (da, unit, SET); /* enable PPR */ + } + +return result; +} + + + +/* Amigo disc global bus routines */ + + +/* Accept a data byte from the bus. + + The indicated unit is offered a byte that has been sourced to the bus. The + routine returns TRUE or FALSE to indicate whether or not it accepted the + byte. + + Commands from the bus may be universal (applying to all acceptors) or + addressed (applying only to those acceptors that have been addressed to + listen). Data bytes are accepted only if the unit has been addressed to + listen. As we are called for a data transfer or an addressed command only if + we are currently listening, the only bytes that we do not accept are talk or + listen commands directed to another address, or secondary commands when we + are not addressed to listen. + + This routine handles the HP-IB protocol. The type of byte passed is + determined by the state of the ATN signal and, if asserted, by the high-order + bits of the value. Most of the work involves decoding secondary commands and + their associated data parameters. The interface state is changed as needed + to track the command protocol. The states processed in this routine are: + + opcode_wait + =========== + + A receive disc command secondary has been received, and the interface is + waiting for the opcode that should follow. + + parameter_wait + ============== + + A disc opcode or interface command has been received, and the interface is + waiting for a parameter byte that should follow. + + write_wait + ========== + + A disc write command has been received, and the interface is waiting for + the receive write data secondary that should follow. + + read_wait + ========= + + A disc read command has been received, and the interface is waiting for the + send read data secondary that should follow. + + status_wait + =========== + + A disc status command has been received, and the interface is waiting for + the send disc status secondary that should follow. + + write_xfer + ========== + + A disc write is in progress, and the interface is waiting for a data byte + that should follow. + + error_sink + ========== + + A disc write has terminated with an error, and the interface is waiting to + absorb all of the remaining data bytes of the transfer. + + + Disc commands and parameters are assembled in the sector buffer before being + passed to the disc library to start the command. Once the command is + started, then the interface state is set either to execute the command or to + wait for the receipt of a data transfer secondary before executing, depending + on the command. + + Two disc command protocol errors are detected. First, an Illegal Opcode is + identified during the check for the expected number of disc command opcode + parameters. This allows us to sink an arbitrary number of parameter bytes. + Second, an I/O Program Error occurs if an unsupported secondary is received, + or the HP-IB sequence is incorrect. The latter occurs if a command has the + wrong number of parameters, or a secondary data transfer sequence is invalid. + + Disc commands that require data transfers (e.g., read, write, request status) + involve a pair of secondaries. The first transmits the command, and the + second transmits or receives the data. If one occurs without the other, an + I/O Program Error occurs. + + A secondary or command that generates an I/O Program Error is always ignored. + Error recovery is as follows: + + - An unsupported talk secondary sends a single data byte tagged with EOI. + + - An unsupported listen secondary accepts and discards any accompanying data + bytes until EOI or unlisten. + + - A supported command with too few parameter bytes or for which the last + parameter byte is not tagged with EOI (before unlisten) does nothing. + + - A supported command with too many parameter bytes accepts and discards + excess parameter bytes until EOI or unlisten. + + - A read or status command that is not followed by a send data or send + status secondary does nothing. The unexpected secondary is executed + normally. + + - A write command that is not followed by a receive data secondary does + nothing. The unexpected secondary is executed normally. + + - A send data or send status secondary that is not preceded by a read or + status command sends a single data byte tagged with EOI. + + - A receive data secondary that is not preceded by a write command accepts + and discards data bytes until EOI or unlisten. + + The Amigo command sequence does not provide a byte count for disc read and + write commands, so the controller continues to source or accept data bytes + until the device is unaddressed. Normally, this is done by an Unlisten or + Untalk. However, per IEEE-488, a listening device may be unaddressed by IFC, + by an Unlisten, or by addressing the device to talk, and a talking device may + be unaddressed by IFC, by addressing another device to talk (or no device via + Untalk), or by addressing the device to listen. Therefore, we keep track of + whether the unit stopped talking or listening, and if it has, we check for + command termination. + + If the controller is unaddressed in the middle of a sector transfer, the read + or write must be terminated cleanly to ensure that the disc image is + coherent. It is also permissable to untalk the controller before all of the + requested status bytes are returned. + + In addition, the controller has no way to inform the host that an error has + occurred that prevents the command from continuing. For example, a data + error encountered while reading, or a protected track encountered while + writing must still source or sink data bytes until the command is terminated + by the host. The controller handles read errors by sourcing a single data + byte tagged with EOI, and write errors by sinking data bytes until EOI is + seen or the unit is unaddressed. + + Therefore, if the unit is unaddressed while a read, write, or status command + is transferring data, the unit service must be scheduled to end the current + command. Unaddressing while an error condition is present merely terminates + the source or sink operation. + + + Implementation notes: + + 1. The 13365 manual does not indicate that the controller responds to + Universal Clear, but the 12992H loader ROM issues this primary and + expects the controller to initialize. + + 2. It is not necessary to check for listening when processing addressed + commands, as only listeners are called by the bus source. + + 3. The dl_prepare_command routine returns FALSE if the command accesses a + busy unit. However, we check for a busy unit during addressing and hold + off the CPU if it is. Therefore, the unit will never be busy when the + routine is called, so a FALSE return will indicate a rejected command. +*/ + +t_bool da_bus_accept (uint32 unit, uint8 data) +{ +const uint8 message_address = data & BUS_ADDRESS; +t_bool accepted = TRUE; +t_bool initiated = FALSE; +t_bool addressed = FALSE; +t_bool stopped_listening = FALSE; +t_bool stopped_talking = FALSE; +char action [40] = ""; +uint32 my_address; + +if (di [da].bus_cntl & BUS_ATN) { /* is it a bus command (ATN asserted)? */ + switch (data & BUS_GROUP) { /* dispatch the bus group */ + + case BUS_PCG: /* primary command group */ + switch (message_address) { + + case 0x04: /* selected device clear */ + case 0x05: /* SDC with parity freeze */ + case 0x14: /* universal clear */ + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d device cleared\n", unit); + + sim_cancel (&da_unit [unit]); /* cancel any in-progress command */ + dl_idle_controller (&icd_cntlr [unit]); /* idle the controller */ + if_dsj [unit] = 0; /* clear DSJ */ + if_state [unit] = idle; /* idle the interface */ + di_poll_response (da, unit, SET); /* enable PPR */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + strcpy (action, "device clear"); + break; + + + default: /* unsupported universal command */ + break; /* universals are always accepted */ + } + + break; + + + case BUS_LAG: /* listen address group */ + my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ + + if (message_address == my_address) { /* my listen address? */ + di [da].listeners |= (1 << unit); /* set my listener bit */ + di [da].talker &= ~(1 << unit); /* clear my talker bit */ + + addressed = TRUE; /* unit is now addressed */ + stopped_talking = TRUE; /* MLA stops unit from talking */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "listen %d", message_address); + } + + else if (message_address == BUS_UNADDRESS) { /* unlisten? */ + di [da].listeners = 0; /* clear all listeners */ + + stopped_listening = TRUE; /* UNL stops unit from listening */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + strcpy (action, "unlisten"); + } + + else /* other listen address */ + accepted = FALSE; /* is not accepted */ + + break; + + + case BUS_TAG: /* talk address group */ + my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ + + if (message_address == my_address) { /* my talk address? */ + di [da].talker = (1 << unit); /* set my talker bit and clear others */ + di [da].listeners &= ~(1 << unit); /* clear my listener bit */ + + addressed = TRUE; /* unit is now addressed */ + stopped_listening = TRUE; /* MTA stops unit from listening */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "talk %d", message_address); + } + + else { /* some other talker (or untalk) */ + di [da].talker &= ~(1 << unit); /* clear talker */ + + stopped_talking = TRUE; /* UNT or OTA stops unit from talking */ + + if (message_address != BUS_UNADDRESS) /* other talk address? */ + accepted = FALSE; /* is not accepted */ + + else /* untalk */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + strcpy (action, "untalk"); + } + + break; + + + case BUS_SCG: /* secondary command group */ + icd_cntlr [unit].index = 0; /* reset the buffer index */ + + if (di [da].listeners & (1 << unit)) { /* is it a listen secondary? */ + if (if_state [unit] == write_wait /* if waiting for a write data secondary */ + && message_address != 0x00) /* but it's not there, */ + abort_command (unit, io_program_error, /* then abort the pending command */ + idle); /* and process the new command */ + + switch (message_address) { /* dispatch the listen secondary */ + + case 0x00: /* Receive Write Data */ + if (if_state [unit] != write_wait) /* if we're not expecting it */ + abort_command (unit, io_program_error, /* abort and sink any data */ + error_sink); + else { /* sequence is correct */ + if_state [unit] = command_exec; /* now ready to execute */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ + di_bus_control (da, unit, BUS_NRFD, 0); /* assert NRFD to hold off the card */ + } + + initiated = TRUE; /* log the command or abort initiation */ + break; + + case 0x08: /* disc commands */ + if_command [unit] = disc_command; /* set the command */ + if_state [unit] = opcode_wait; /* opcode must follow */ + break; + + case 0x09: /* CRC (Listen) */ + if_command [unit] = crc_listen; /* set the command */ + if_state [unit] = error_sink; /* sink any data that will be coming */ + initiated = TRUE; /* log the command initiation */ + break; + + case 0x10: /* Amigo Clear */ + if_command [unit] = amigo_clear; /* set the command */ + if_state [unit] = parameter_wait; /* a parameter must follow */ + icd_cntlr [unit].length = 1; /* expect one (unused) byte */ + break; + + case 0x1E: /* Write Loopback */ + if_command [unit] = write_loopback; /* set the command */ + if_state [unit] = write_xfer; /* data will be coming */ + icd_cntlr [unit].length = 16; /* accept only the first 16 bytes */ + initiated = TRUE; /* log the command initiation */ + break; + + case 0x1F: /* Initiate Self-Test */ + if_command [unit] = initiate_self_test; /* set the command */ + if_state [unit] = parameter_wait; /* a parameter must follow */ + icd_cntlr [unit].length = 1; /* expect the test ID byte */ + break; + + default: /* an unsupported listen secondary */ + abort_command (unit, io_program_error, /* abort and sink any data */ + error_sink); /* that might accompany the command */ + initiated = TRUE; /* log the abort initiation */ + break; + } + } + + + else if (di [da].talker & (1 << unit)) { /* is it a talk secondary? */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* these are always scheduled and */ + initiated = TRUE; /* logged as initiated */ + + if (if_state [unit] == read_wait /* if waiting for a send data secondary */ + && message_address != 0x00 /* but it's not there */ + || if_state [unit] == status_wait /* or a send status secondary, */ + && message_address != 0x08) /* but it's not there */ + abort_command (unit, io_program_error, /* then abort the pending command */ + idle); /* and process the new command */ + + switch (message_address) { /* dispatch the talk secondary */ + + case 0x00: /* Send Read Data */ + if (if_state [unit] != read_wait) /* if we're not expecting it */ + abort_command (unit, io_program_error, /* abort and source a data byte */ + error_source); /* tagged with EOI */ + else + if_state [unit] = command_exec; /* now ready to execute */ + break; + + case 0x08: /* Read Status */ + if (if_state [unit] != status_wait) /* if we're not expecting it */ + abort_command (unit, io_program_error, /* abort and source a data byte */ + error_source); /* tagged with EOI */ + else /* all status commands */ + if_state [unit] = read_xfer; /* are ready to transfer data */ + break; + + case 0x09: /* CRC (Talk) */ + if_command [unit] = crc_talk; /* set the command */ + if_state [unit] = read_xfer; /* data will be going */ + break; + + case 0x10: /* Device-Specified Jump */ + if_command [unit] = device_specified_jump; /* set the command */ + if_state [unit] = read_xfer; /* data will be going */ + break; + + case 0x1E: /* Read Loopback */ + if_command [unit] = read_loopback; /* set the command */ + if_state [unit] = read_xfer; /* data will be going */ + break; + + case 0x1F: /* Return Self-Test Result */ + if_command [unit] = return_self_test_result; /* set the command */ + if_state [unit] = read_xfer; /* data will be going */ + icd_cntlr [unit].length = 1; /* return one byte that indicates */ + buffer [0] = 0; /* that the self-test passed */ + break; + + default: /* an unsupported talk secondary */ + abort_command (unit, io_program_error, /* abort and source a data byte */ + error_source); /* tagged with EOI */ + break; + } + } + + + else { /* the unit is not addressed */ + my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ + + if (di [da].talker == 0 && di [da].listeners == 0 /* if there are no talkers or listeners */ + && message_address == my_address) { /* and this is my secondary address, */ + if_command [unit] = amigo_identify; /* then this is an Amigo ID sequence */ + if_state [unit] = command_exec; /* set up execution */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ + initiated = TRUE; /* log the command initiation */ + } + + else /* an unaddressed secondary */ + accepted = FALSE; /* is not accepted */ + } + + + if (accepted) { /* was the command accepted? */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "secondary %02XH", message_address); + + if (if_command [unit] != amigo_identify) /* disable PPR for all commands */ + di_poll_response (da, unit, CLEAR); /* except Amigo ID */ + } + + break; /* end of secondary processing */ + } + + + if (addressed && sim_is_active (&da_unit [unit])) { /* is the unit being addressed while busy? */ + if_state [unit] = command_wait; /* change the interface state to wait */ + di_bus_control (da, unit, BUS_NRFD, 0); /* and assert NRFD to hold off the card */ + + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d addressed while controller is busy\n", unit); + } + + if (stopped_listening) { /* was the unit unlistened? */ + if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy, */ + complete_write (unit); /* then check for write completion */ + + else if (if_command [unit] == invalid) /* if a command was aborting, */ + complete_abort (unit); /* then complete it */ + + else if (if_state [unit] == opcode_wait /* if waiting for an opcode */ + || if_state [unit] == parameter_wait) /* or a parameter, */ + abort_command (unit, io_program_error, idle); /* then abort the pending command */ + } + + else if (stopped_talking) { /* was the unit untalked? */ + if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy */ + complete_read (unit); /* then check for read completion */ + + else if (if_command [unit] == invalid) /* if a command was aborting, */ + complete_abort (unit); /* then complete it */ + } + } /* end of bus command processing */ + + +else { /* it is bus data (ATN denied) */ + switch (if_state [unit]) { /* dispatch the interface state */ + + case opcode_wait: /* wait for an opcode */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "opcode %02XH", data & DL_OPCODE_MASK); + + buffer [0] = SET_UPPER (data); /* set the opcode into the buffer */ + + if (dl_prepare_command (&icd_cntlr [unit], /* is the command valid? */ + da_unit, unit)) { + if_state [unit] = parameter_wait; /* set up to get pad byte */ + icd_cntlr [unit].index = 0; /* reset the word index for byte 1 */ + icd_cntlr [unit].length = /* convert the parameter count to bytes */ + icd_cntlr [unit].length * 2 + 1; /* and include the pad byte */ + } + + else { /* the disc command is invalid */ + abort_command (unit, illegal_opcode, /* abort the command */ + error_sink); /* and sink any parameter bytes */ + initiated = TRUE; /* log the abort initiation */ + } /* (the unit cannot be busy) */ + break; + + + case parameter_wait: /* wait for a parameter */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "parameter %02XH", data); + + put_buffer_byte (&icd_cntlr [unit], data); /* add the byte to the buffer */ + + if (icd_cntlr [unit].length == 0) /* is this the last parameter? */ + if (di [da].bus_cntl & BUS_EOI) /* does the host agree? */ + initiated = start_command (unit); /* start the command and log the initiation */ + + else { /* the parameter count is wrong */ + abort_command (unit, io_program_error, /* abort the command and sink */ + error_sink); /* any additional parameter bytes */ + initiated = TRUE; /* log the abort initiation */ + } + break; + + + case write_xfer: /* transfer write data */ + if (icd_cntlr [unit].length > 0) /* if there is more to transfer */ + put_buffer_byte (&icd_cntlr [unit], data); /* then add the byte to the buffer */ + + /* fall into error_sink handler */ + + case error_sink: /* sink data after an error */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "data %03o", data); + + if (di [da].bus_cntl & BUS_EOI) /* is this the last byte from the bus? */ + icd_cntlr [unit].eod = SET; /* indicate EOD to the controller */ + + di_bus_control (da, unit, BUS_NRFD, 0); /* assert NRFD to hold off the card */ + + da_unit [unit].wait = icd_cntlr [unit].data_time; /* schedule the unit */ + break; + + + default: /* data was received in wrong state */ + abort_command (unit, io_program_error, /* report the error */ + error_sink); /* and sink any data that follows */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "unhandled data %03o", data); + break; + } + } + + +if (accepted && DEBUG_PRI (da_dev, DEB_XFER)) + fprintf (sim_deb, ">>DA xfer: HP-IB address %d accepted %s\n", + GET_BUSADR (da_unit [unit].flags), action); + +if (da_unit [unit].wait > 0) /* is service requested? */ + activate_unit (&da_unit [unit]); /* schedule the unit */ + +if (initiated && DEBUG_PRI (da_dev, DEB_RWSC)) + if (if_command [unit] == disc_command) + fprintf (sim_deb, ">>DA rwsc: Unit %d position %d %s disc command initiated\n", + unit, da_unit [unit].pos, dl_opcode_name (ICD, icd_cntlr [unit].opcode)); + else + fprintf (sim_deb, ">>DA rwsc: Unit %d %s command initiated\n", + unit, if_command_name [if_command [unit]]); + +return accepted; /* indicate the acceptance condition */ +} + + +/* Respond to the bus control lines. + + The indicated unit is notified of the new control state on the bus. There + are two conditions to which we must respond: + + 1. An Interface Clear is initiated. IFC unaddresses all units, so any + in-progress disc command must be terminated as if an Untalk and Unlisten + were accepted from the data bus. + + 2. Attention and Not Ready for Data are denied. A device addressed to talk + must wait for ATN to deny before data may be sent. Also, a listener that + has asserted NRFD must deny it before a talker may send data. If the + interface is sending data and both ATN and NRFD are denied, then we + reschedule the service routine to send the next byte. + +*/ + +void da_bus_respond (CARD_ID card, uint32 unit, uint8 new_cntl) +{ +if (new_cntl & BUS_IFC) { /* is interface clear asserted? */ + di [da].listeners = 0; /* unlisten */ + di [da].talker = 0; /* untalk */ + + if (icd_cntlr [unit].state == cntlr_busy) { /* is the controller busy? */ + complete_write (unit); /* check for write completion */ + complete_read (unit); /* or read completion */ + + if (da_unit [unit].wait > 0) /* is service needed? */ + activate_unit (&da_unit [unit]); /* activate the unit */ + } + + else if (if_command [unit] == invalid) /* if a command was aborting, */ + complete_abort (unit); /* then complete it */ + + else if (if_state [unit] == opcode_wait /* if waiting for an opcode */ + || if_state [unit] == parameter_wait) /* or a parameter, */ + abort_command (unit, io_program_error, idle); /* then abort the pending command */ + } + +if (! (new_cntl & (BUS_ATN | BUS_NRFD)) /* in data mode and card is ready for data? */ + && (if_state [unit] == read_xfer /* is interface waiting to send data */ + || if_state [unit] == error_source)) /* or source error bytes? */ + da_service (&da_unit [unit]); /* start or resume the transfer */ +} + + + +/* Amigo disc local utility routines */ + + +/* Start a command with parameters. + + A command that has been pending until all of its parameters were received is + now ready to start. If this is a disc command, call the disc library to + validate the parameters and, if they are OK, to start the command. Status + commands return the status values in the sector buffer and the number of + words that were returned in the buffer length, which we convert to a byte + count. + + If the disc command was accepted, the controller will be busy. In this case, + set the next interface state as determined by the command that is executing. + For example, a Read command sets the interface to read_wait status in order + to wait until the accompanying Send Read Data secondary is received. If the + controller is not busy, then the command was rejected, so we set DSJ = 1 and + leave the interface state in parameter_wait; the controller status will have + been set to the reason for rejection. + + If the interface state is command_exec, then the disc command is ready for + execution, and we return TRUE to schedule the unit service. Otherwise, we + return FALSE, and the appropriate action will be taken by the caller. + + For all other commands, execution begins as soon as the correct parameters + are received, so we set command_exec state and return TRUE. (Only Amigo + Clear and Inititate Self Test require parameters, so they will be the only + other commands that must be started here.) + +set wait = 0 if not executing (e.g., for read wait) + + Implementation notes: + + 1. The ICD implemenation does not need to differentiate between unit and + controller commands, the return value from the dl_start_command routine + is not used. +*/ + +static t_bool start_command (uint32 unit) +{ +if (if_command [unit] == disc_command) { /* starting a disc command? */ + dl_start_command (&icd_cntlr [unit], da_unit, unit); /* ask the controller to start the command */ + + icd_cntlr [unit].length = icd_cntlr [unit].length * 2; /* convert return length from words to bytes */ + + if (icd_cntlr [unit].state == cntlr_busy) /* was the command accepted? */ + if_state [unit] = next_state [icd_cntlr [unit].opcode]; /* set the next interface state */ + else /* the command was rejected */ + if_dsj [unit] = 1; /* so indicate an error */ + + if (if_state [unit] == command_exec) /* if command is executing */ + return TRUE; /* activate the unit */ + + else { /* if we must wait */ + da_unit [unit].wait = 0; /* for another secondary */ + return FALSE; /* skip the activation */ + } + } + +else { /* all other commands */ + if_state [unit] = command_exec; /* execute as soon */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* as they */ + return TRUE; /* are received */ + } +} + + +/* Abort an in-process command. + + A command sequence partially received via the bus must be aborted. The cause + might be an unknown secondary, an illegal disc command opcode, an improper + secondary sequence (e.g., a Read not followed by Send Read Data), an + incorrect number of parameters, or unaddressing before the sequence was + complete. In any event, the controller and interface are set to an abort + state, and the DSJ value is set to 1 to indicate an error. +*/ + +static void abort_command (uint32 unit, CNTLR_STATUS status, IF_STATE state) +{ +if_command [unit] = invalid; /* indicate an invalid command */ +if_state [unit] = state; /* set the interface state as directed */ +if_dsj [unit] = 1; /* set DSJ to indicate an error condition */ +dl_end_command (&icd_cntlr [unit], status); /* place the disc controller into a wait state */ +return; +} + + +/* Complete an in-process read command. + + An Untalk terminates a Read, Read Full Sector, Read Without Verify, Read With + Offset, or Cold Load Read command, which must be tied off cleanly by setting + the end-of-data condition and calling the service routine. This is required + only if the read has not already aborted (e.g., for an auto-seek error). + + If a read is in progress, the controller will be busy, and the interface + state will be either command_exec (if between sectors) or read_xfer (if + within a sector). We set up the end phase for the command and schedule the + disc service to tidy up. + + If a read has aborted, the controller will be waiting, and the interface + state will be error_source. In this latter case, we no nothing, as the + controller has already set the required error status. + + We must be careful NOT to trigger on an Untalk that may follow the opcode and + precede the Send Read Data sequence. In this case, the controller will be + busy, but the interface state will be either read_wait or status_wait. + + + Implementation notes: + + 1. The test for controller busy is made before calling this routine. This + saves the call overhead for the most common case, which is the card is + being unaddressed after command completion. + + 2. There is no need to test if we are processing a disc command, as the + controller would not be busy otherwise. +*/ + +static void complete_read (uint32 unit) +{ +if ((if_state [unit] == command_exec /* is a command executing */ + || if_state [unit] == read_xfer) /* or is data transferring */ + && (dl_classify (icd_cntlr [unit]) == class_read /* and the controller is executing */ + || dl_classify (icd_cntlr [unit]) == class_status)) { /* a read or status? */ + icd_cntlr [unit].eod = SET; /* set the end of data */ + + if_state [unit] = command_exec; /* set to execute */ + da_unit [unit].PHASE = end_phase; /* the completion phase */ + da_unit [unit].wait = icd_cntlr [unit].data_time; /* ensure that the controller will finish */ + } + +return; +} + + +/* Complete an in-process write command. + + Normally, the host sends a byte tagged with EOI to end a Write, Write Full + Sector, or Initialize command. However, an Unlisten may terminate a write, + which must be tied off cleanly by setting the end-of-data condition and + calling the service routine. This is required only if the write has not + already aborted (e.g., for a write-protected disc). + + If a write is in progress, the controller will be busy, and the interface + state will be either command_exec (if between sectors) or write_xfer (if + within a sector). We set up the end phase for the command and schedule the + disc service to tidy up. + + If a write has aborted, the controller will be waiting, and the interface + state will be error_sink. In this latter case, we do nothing, as the + controller has already set the required error status. + + We must be careful NOT to trigger on the Unlisten that may follow the opcode + and precede the Receive Write Data sequence. In this case, the controller + will be busy, but the interface state will be write_wait. + + + Implementation notes: + + 1. The test for controller busy is made before calling this routine. This + saves the call overhead for the most common case, which is the card is + being unaddressed after command completion. + + 2. There is no need to test if we are processing a disc command, as the + controller would not be busy otherwise. +*/ + +static void complete_write (uint32 unit) +{ +if ((if_state [unit] == command_exec /* is a command executing */ + || if_state [unit] == write_xfer) /* or is data transferring */ + && dl_classify (icd_cntlr [unit]) == class_write) { /* and the controller is executing a write? */ + icd_cntlr [unit].eod = SET; /* set the end of data */ + + if_state [unit] = command_exec; /* set to execute */ + da_unit [unit].PHASE = end_phase; /* the completion phase */ + da_unit [unit].wait = icd_cntlr [unit].data_time; /* ensure that the controller will finish */ + } + +return; +} + + +/* Complete an in-process command abort. + + Errors in the command protocol begin an abort sequence that may involve + sourcing or sinking bytes to allow the sequence to complete as expected by + the CPU. Unaddressing the unit terminates the aborted command. + + If an abort is in progress, and the interface is not idle, the end-of-data + indication is set, and the disc service routine is called directly to process + the completion of the abort. The service routine will terminate the + error_source or error_sink state cleanly and then idle the interface. + + + Implementation notes: + + 1. The test for an abort-in-progress is made before calling this routine. + This saves the call overhead for the most common case, which is the card + is being unaddressed after normal command completion. +*/ + +static void complete_abort (uint32 unit) +{ +if (if_state [unit] != idle) { /* is the interface busy? */ + icd_cntlr [unit].eod = SET; /* set the end of data */ + da_service (&da_unit [unit]); /* and process the abort completion */ + } + +return; +} + + +/* Get a byte from the sector buffer. + + The next available byte in the sector buffer is returned to the caller. The + determination of which byte of the 16-bit buffer word to return is made by + the polarity of the buffer byte count. The count always begins with an even + number, as it is set by doubling the word count returned from the disc + library. Therefore, because we decrement the count first, the upper byte is + indicated by an odd count, and the lower byte is indicated by an even count. + The buffer index is incremented only after the lower byte is returned. +*/ + +static uint8 get_buffer_byte (CVPTR cvptr) +{ +cvptr->length = cvptr->length - 1; /* count the byte */ + +if (cvptr->length & 1) /* is the upper byte next? */ + return GET_UPPER (buffer [cvptr->index]); /* return the byte */ +else /* the lower byte is next */ + return GET_LOWER (buffer [cvptr->index++]); /* return the byte and bump the word index */ +} + + +/* Put a byte into the sector buffer. + + The supplied byte is stored in the sector buffer. The determination of which + byte of the 16-bit buffer word to store is made by the polarity of the buffer + byte count. The count always begins with an even number, as it is set by + doubling the word count returned from the disc library. Therefore, because + we decrement the count first, the upper byte is indicated by an odd count, + and the lower byte is indicated by an even count. The buffer index is + incremented only after the lower byte is stored. +*/ + +static void put_buffer_byte (CVPTR cvptr, uint8 data) +{ +cvptr->length = cvptr->length - 1; /* count the byte */ + +if (cvptr->length & 1) /* is the upper byte next? */ + buffer [cvptr->index] = SET_UPPER (data); /* save the byte */ +else /* the lower byte is next */ + buffer [cvptr->index++] |= SET_LOWER (data); /* merge the byte and bump the word index */ +return; +} + + +/* Activate the unit. + + The specified unit is activated using the unit's "wait" time. If debugging + is enabled, the activation is logged to the debug file. +*/ + +static t_stat activate_unit (UNIT *uptr) +{ +uint32 unit; +t_stat result; + +if (DEBUG_PRI (da_dev, DEB_SERV)) { + unit = uptr - da_unit; + + fprintf (sim_deb, ">>DA serv: Unit %d state %s delay %d service scheduled\n", + unit, if_state_name [if_state [unit]], uptr->wait); + } + +result = sim_activate (uptr, uptr->wait); /* activate the unit */ +uptr->wait = 0; /* reset the activation time */ + +return result; /* return the activation status */ +} diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt index c605c425..67cc0fc3 100644 --- a/HP2100/hp2100_diag.txt +++ b/HP2100/hp2100_diag.txt @@ -1,6 +1,6 @@ SIMH/HP 21XX DIAGNOSTICS PERFORMANCE ==================================== - Last update: 2008-08-07 + Last update: 2012-02-13 The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation. @@ -70,7 +70,7 @@ The results of the diagnostic runs are summarized below: 103116 12967 Synchronous Interface 1438 - No simulation 103017 12966 Asynchronous Data Set 1519 3.8-0 Passed 103121 12968 Asynchronous Comm. Interface 1602 - No simulation -103024 12821 ICD Disc Interface 1928 - No simulation +103024 12821 ICD Disc Interface 1928 3.8-2 Passed 104000 2600 Keyboard Display Terminal 1615 - No simulation 104003 Teleprinter 1509 3.2-3 Partial @@ -132,6 +132,7 @@ Part Number Diagnostic Name Code Op. Sys. Code Vers. Resul 12824-16002 Vector Instruction Set Firmware 2026 RTE-IVB 5010 3.8-0 Passed 12829-16006 Vector Instruction Set Firmware 2226 RTE-6/VM 6200 3.8-0 Passed 92835-16006 SIGNAL/1000 Firmware Diagnostic 2040 RTE-6/VM 6200 3.8-0 Passed +91711-12032 ICD/MAC Disc Diagnostic 2201 RTE-IVB 5010 3.8-2 Partial The "SIMH Version" is the version number of the earliest SIMH system that was @@ -1237,6 +1238,105 @@ TEST RESULT: Passed. +------------------------------------- +DSN 103024 - 12821 ICD Disc Interface +------------------------------------- + +TESTED DEVICE: DA, DC (hp2100_di.c, hp2100_di_da.c) + +CONFIGURATION: sim> set DA DIAG + sim> set DA ADDRESS=5 + sim> deposit S 000000 + sim> reset + sim> go 100 + +TEST REPORT: *** HPIB 12821A DIAGNOSTIC *** + + INSTRUCTIONS: + + 1. ENTER ? WHEN YOU NEED MORE INFORMATION. + + 2. INDICATE OCTAL VALUES BY A FINAL B (E.G. 13B). + + 3. SET SR BIT 15 ON TO LOOP ON DIAGNOSTIC, + TOGGLE ON,OFF TO BREAK OUT OF A SINGLE TEST + LOOP (CONVERSATIONAL-MODE). + + 4. SET SR BIT 14 TO SUPPRESS PRESET TEST + + 5. SET SR BIT 13 T0 PRINT ONLY ERROR MESSAGES + (EXCEPT CONFIGURATION MESSAGES). + + 6. SET SR BIT 12 TO DELAY 1 SECOND BETWEEN TESTS + + IS THE FIRST CARD IN SELECT CODE 43B? + IF YES, INPUT CARRIAGE RETURN + OTHERWISE, INPUT THE CORRECT SELECT CODE.. [CR entered] + + INPUT THE LAST OCTAL DIGIT OF THE BUS + ADDRESS (0-7 DERIVED FROM S1-S3) ... 5 + + IS THE SECOND CARD IN SELECT CODE 44B? + IF YES, INPUT CARRIAGE RETURN + IF NO SECOND CARD, INPUT 77B + IF DIAGNOSTIC GUESSED INCORRECTLY AND THERE IS + A SECOND CARD, ENTER CORRECT SELECT CODE... [CR entered] + + INPUT THE LAST OCTAL DIGIT OF THE BUS + ADDRESS (0-7 DERIVED FROM S1-S3) ... 0 + + + PROGRAM OPTIONS: + + CR - CARRIAGE RETURN- (DEFAULT) EXECUTE DIAG. + FROM TEST 0. + + N - BEGIN EXECUTION FROM TEST N + + LN - LOOP ON TEST N + (TOGGLE SW BIT 15 TO REGAIN CONTROL) + + E - EXIT PROGRAM WITH HLT77 + (PRESS RUN TO RE-ENTER PROGRAM) + + F - FORCE TESTING TO SECOND BOARD + + G - GO BACK AND RETEST BOARD ONE + + R - GO BACK TO RECONFIGURATION SECTION + + ? [CR entered] + + PRESS HALT,PRESET,RUN WITHIN 10 SECONDS ! + + [CTRL+E] + Simulation stopped + + sim> reset + sim> go + + TESTING COMPLETED ON SELECT CODE 43B + + PRESS HALT,PRESET,RUN WITHIN 10 SECONDS ! + + [CTRL+E] + Simulation stopped + + sim> reset + sim> go + + TESTING COMPLETED ON SELECT CODE 44B + + (T15)..DI TO HP-IB TO DI TEST PASSES ! + + ? E + + HALT instruction 102077 + +TEST RESULT: Passed. + + + ------------------------ DSN 104003 - Teleprinter ------------------------ @@ -3505,3 +3605,520 @@ TEST REPORT: SIGNAL/1000 FIRMWARE DIAGNOSTIC SIGNAL/1000 FIRMWARE DIAGNOSTIC SUCCESSFUL COMPLETION TEST RESULT: Passed. + + + +------------------------------ +DIAG - ICD/MAC Disc Diagnostic +------------------------------ + +TESTED DEVICE: DA (hp2100_di.c, hp2100_di_da.c) + +BINARY FILE: 91711-12032 Rev. 2201 + +HOST SYSTEM: RTE-IVB Rev. 5010 + +CONFIGURATION: sim> go + +TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC + + DIAG : CAUTION: DATA COULD BE DESTROYED ON THE DISC TESTED. + DIAG : REMOVABLE MEDIA SHOULD BE REPLACED. + + DIAG : List LU (0 for none) ? 0 + DIAG : Do you want to trace disc operations ? YES + DIAG : Start trace at what step ? 0 + DIAG : Trace operations which are not part of the test steps ? NO + DIAG : Stop after first failure ? NO + DIAG : Disc LU ? 41 + DIAG : Disc address ? 0 + DIAG : Drive model number ? 06 + DIAG : Do you want to run the interactive part of the test ? YES + + DIAG : LU 41 address 0 select code 25 7906 drive + + DIAG : CHECK THAT ALL SWITCHES ARE SET CORRECTLY. + DIAG : THE RUN/STOP SWITCH SHOULD BE IN THE RUN POSITION. + DIAG : THE FORMAT SWITCH SHOULD BE ON. + DIAG : THE PROTECT/READ ONLY SWITCH SHOULD BE OFF. + DIAG : Type , + + DIAG : Beginning part 1 of diagnostic. + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : WRITE LOOPBACK REC length 10 + DIAG : READ LOOPBACK REC length 8 + DIAG : test data read test passed + DIAG : STEP 0 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : INITIATE SELF TEST + DIAG : RETURN DSJ 2 + DIAG : RTN SELF-TEST RES result 0 + DIAG : RETURN DSJ 2 + DIAG : STEP 1 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : REQUEST STATUS drive type 0 0 0 50 0 + DIAG : IDENTIFY result 3 0 0 40 0 + DIAG : STEP 3 PASSED + + DIAG : Part 1 of diagnostic completed. + + DIAG : Information for test track selection. + DIAG : Drive address limits: + DIAG : cylinders: 0 - 410 heads: 0 - 3 sectors: 0 - 47 + DIAG : First and last tracks on LU: + DIAG : cylinder 0 head 0 (track 0) + DIAG : cylinder 199 head 1 (track 399) + DIAG : First and last spares on LU: + DIAG : cylinder 200 head 0 (track 400) + DIAG : cylinder 202 head 1 (track 405) + DIAG : Heads on LU (first - last): 0 - 1 + DIAG : Searching entire LU for file directory: + DIAG : NO DIRECTORY OR UNABLE TO READ DIRECTORY ON TEST LU + DIAG : First and last tracks available for testing: + DIAG : cylinder 0 head 0 (track 0) + DIAG : cylinder 199 head 1 (track 399) + DIAG : Default test tracks: + DIAG : cylinder 199 head 0 (track 398) + DIAG : cylinder 199 head 1 (track 399) + DIAG : Use default test tracks ? YES + + DIAG : Checking test track preambles. + DIAG : Test track preambles are OK. + + DIAG : Beginning part 2 of diagnostic. + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : STEP 4 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : REQUEST DISC ADDR cy 199 hd 0 sec 0 0 0 40 0 + DIAG : STEP 5 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : RECALIBRATE 0 + DIAG : REQUEST STATUS drive type 0 0 37 40 0 + DIAG : STEP 6 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : REQUEST SECTOR ADDR sec 2 0 0 40 0 + DIAG : STEP 7 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : CLEAR (OPCODE) + DIAG : RETURN DSJ 2 + DIAG : RETURN DSJ 2 + DIAG : REQUEST STATUS drive type 0 0 0 40 0 + DIAG : STEP 8 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 138 0 0 40 0 + DIAG : decode preamble cy 199 hd 0 sec 0 spd 0 + DIAG : STEP 9 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : WRITE FULL SECTOR length 138 0 0 40 0 + DIAG : STEP 10 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 1 0 0 40 0 + DIAG : STEP 11 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : READ length 128 0 0 40 0 + DIAG : STEP 12 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : READ WITH OFFSET length 128 offset 55 0 0 40 0 + DIAG : STEP 13 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : READ WITHOUT VERIFY length 128 0 0 40 0 + DIAG : STEP 14 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SET FILE MASK mask 0 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 0 14 40 1 + DIAG : STEP 16 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SET FILE MASK mask 2 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 0 0 40 0 + DIAG : STEP 17 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SET FILE MASK mask 2 0 0 40 0 + DIAG : SEEK cy 199 hd 3 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 0 14 40 1 + DIAG : STEP 18 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SET FILE MASK mask 3 0 0 40 0 + DIAG : SEEK cy 199 hd 3 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 0 0 40 0 + DIAG : REQUEST DISC ADDR cy 200 hd 0 sec 1 0 0 40 0 + DIAG : STEP 19 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SET FILE MASK mask 11 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 0 0 40 0 + DIAG : REQUEST DISC ADDR cy 198 hd 0 sec 1 0 0 40 0 + DIAG : STEP 20 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 1 1 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 0 sec 0 spd 0 + DIAG : STEP 21 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 4 4 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : STEP 22 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 2 2 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : STEP 25 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 6 6 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : STEP 26 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 3 3 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : STEP 28 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 4 4 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : STEP 30 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 0 sec 0 spd 0 + DIAG : SET FILE MASK mask 0 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : READ length 128 0 0 40 0 + DIAG : STEP 31 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : SET FILE MASK mask 0 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ length 128 0 0 40 0 + DIAG : STEP 32 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : WRITE length 128 0 0 40 0 + DIAG : STEP 35 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : READ length 128 0 0 40 0 + DIAG : test data read test passed + DIAG : STEP 36 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 1 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 1 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 2 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 2 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 4 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 4 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 8 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 8 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 16 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 16 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 32 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 32 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 64 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 64 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 128 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 128 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 256 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 256 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 410 hd 0 sec 0 0 37 40 0 + DIAG : REQUEST DISC ADDR cy 410 hd 0 sec 0 0 0 40 0 + DIAG : STEP 40 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 1 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 2 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 4 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 8 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 16 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 32 0 0 40 0 + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 48 0 0 40 0 + DIAG : STEP 45 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : secondary HP-IB value 162 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 163 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 164 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 165 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 166 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 167 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 170 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 171 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 172 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 173 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 174 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : secondary HP-IB value 175 + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : STEP 49 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : opcode HP-IB value 1 + DIAG : REQUEST STATUS drive type 0 0 37 40 0 + DIAG : opcode HP-IB value 15 + DIAG : REQUEST STATUS drive type 0 0 1 40 0 + DIAG : opcode HP-IB value 26 + DIAG : REQUEST STATUS drive type 0 0 1 40 0 + DIAG : STEP 50 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 198 hd 1 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : STEP 52 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : STEP 54 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : SET FILE MASK mask 0 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ length 128 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 5 0 37 40 0 + DIAG : READ FULL SECTOR length 138 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : WRITE FULL SECTOR length 138 0 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 1 0 37 40 0 + DIAG : READ length 128 0 0 40 0 + DIAG : STEP 55 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : read without SRD + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : STEP 56 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SWD without write + DIAG : REQUEST STATUS drive type 0 0 12 40 0 + DIAG : STEP 57 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SET FILE MASK mask 3 0 0 40 0 + DIAG : SEEK cy 410 hd 3 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 0 14 44 1 + DIAG : STEP 59 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SET FILE MASK mask 11 0 0 44 0 + DIAG : SEEK cy 0 hd 3 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 0 14 44 1 + DIAG : STEP 60 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 4 sec 0 0 23 44 1 + DIAG : SEEK cy 0 hd 0 sec 0 0 37 40 0 + DIAG : STEP 72 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 411 hd 1 sec 0 0 23 44 1 + DIAG : SEEK cy 0 hd 0 sec 0 0 37 40 0 + DIAG : STEP 73 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 49 0 23 44 1 + DIAG : SEEK cy 0 hd 0 sec 0 0 37 40 0 + DIAG : STEP 74 PASSED + + DIAG : Part 2 of diagnostic completed. + + DIAG : Beginning part 3 of diagnostic (interactive). + + DIAG : PUT RUN/STOP SWITCH IN STOP POSITION + DIAG : Type , + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : REQUEST STATUS drive type 0 0 37 243 0 + DIAG : STEP 80 PASSED + + + DIAG : PUT RUN/STOP SWITCH IN RUN POSITION + DIAG : Type , + DIAG : WAITING FOR THE DRIVE TO BE READY + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : RETURN DSJ 0 + DIAG : REQUEST STATUS drive type 0 0 0 50 0 + DIAG : STEP 81 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : INITIALIZE length 6144 spd 2 2 0 40 0 + DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : STEP 82 FAILED + + + DIAG : TURN OFF FORMAT SWITCH + DIAG : Type , + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : REQUEST STATUS drive type 0 0 0 0 0 + DIAG : STEP 83 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 0 0 + DIAG : WRITE length 1 0 0 0 0 + DIAG : STEP 84 FAILED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 0 0 + DIAG : WRITE FULL SECTOR length 1 0 23 0 1 + DIAG : STEP 85 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 1 sec 0 0 37 0 0 + DIAG : INITIALIZE length 1 spd 0 0 23 0 1 + DIAG : STEP 86 PASSED + + + DIAG : TURN ON FORMAT SWITCH + DIAG : Type , + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : REQUEST STATUS drive type 0 0 0 40 0 + DIAG : STEP 87 PASSED + + + DIAG : TURN ON UPPER PLATTER PROTECT SWITCH + DIAG : Type , + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 140 0 + DIAG : STEP 89 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 140 0 + DIAG : WRITE length 1 0 23 140 1 + DIAG : STEP 90 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 140 0 + DIAG : WRITE FULL SECTOR length 1 0 23 140 1 + DIAG : STEP 91 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 140 0 + DIAG : INITIALIZE length 1 spd 0 0 23 140 1 + DIAG : STEP 92 PASSED + + + DIAG : TURN OFF PROTECT READ ONLY SWITCH + DIAG : Type , + + DIAG : operation parameters/results spd cs ds DSJ + DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : STEP 97 PASSED + + DIAG : Part 3 of diagnostic completed. + + DIAG : Cleaning up. + + DIAG : DIAGNOSTIC TERMINATED. 15 FAILURES DETECTED. + +TEST RESULT: Partially passed. + +TEST NOTES: Steps 11-14 test CRC generation and checking. Steps 21 and 28 + test the defective cylinder bit. Steps 22 and 26 test the spare + cylinder bit. Steps 25, 82, and 84 test the protected cylinder + bit. Step 30 tests track sparing. Steps 52, 54, and 55 test + cylinder, head, and sector miscompares by writing incorrect + preambles. These features are not simulated. diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index f2eddd5c..f244d356 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-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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 @@ DP 12557A 2871 disk subsystem 13210A 7900 disk subsystem + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Added CNTLR_TYPE cast to dp_settype 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size @@ -131,7 +133,7 @@ #define DP_NUMWD (1 << DP_N_NUMWD) /* words/sector */ #define DP_NUMSC2 12 /* sectors/srf 12557 */ #define DP_NUMSC3 24 /* sectors/srf 13210 */ -#define DP_NUMSC (dp_ctype? DP_NUMSC3: DP_NUMSC2) +#define DP_NUMSC (dp_ctype ? DP_NUMSC3 : DP_NUMSC2) #define DP_NUMSF 4 /* surfaces/cylinder */ #define DP_NUMCY 203 /* cylinders/disk */ #define DP_SIZE2 (DP_NUMSF * DP_NUMCY * DP_NUMSC2 * DP_NUMWD) @@ -171,11 +173,11 @@ #define DA_V_SC 0 /* sector */ #define DA_M_SC2 017 #define DA_M_SC3 037 -#define DA_M_SC (dp_ctype? DA_M_SC3: DA_M_SC2) +#define DA_M_SC (dp_ctype ? DA_M_SC3 : DA_M_SC2) #define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) #define DA_CKMASK2 037 /* check mask */ #define DA_CKMASK3 077 -#define DA_CKMASK (dp_ctype? DA_CKMASK3: DA_CKMASK2) +#define DA_CKMASK (dp_ctype ? DA_CKMASK3 : DA_CKMASK2) /* Status in dpc_sta[drv], (u) = unused in 13210, (d) = dynamic */ @@ -215,7 +217,14 @@ struct { FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ } dpc = { CLEAR, CLEAR, CLEAR, CLEAR }; -enum { A12557, A13210 } dp_ctype = A13210; /* ctrl type */ +/* Controller types */ + +typedef enum { + A12557, + A13210 + } CNTLR_TYPE; + +CNTLR_TYPE dp_ctype = A13210; /* ctrl type */ int32 dpc_busy = 0; /* cch unit */ int32 dpc_poll = 0; /* cch poll enable */ int32 dpc_cnt = 0; /* check count */ @@ -289,13 +298,14 @@ REG dpd_reg[] = { { FLDATA (FBF, dpd.flagbuf, 0) }, { FLDATA (XFER, dpd_xfer, 0) }, { FLDATA (WVAL, dpd_wval, 0) }, + { ORDATA (SC, dpd_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, dpd_dib.select_code, 6), REG_HRO }, { NULL } }; MTAB dpd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &dpd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dpd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dpd_dev }, { 0 } }; @@ -350,6 +360,7 @@ REG dpc_reg[] = { DP_NUMDRV, REG_HRO) }, { URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0, DP_NUMDRV, PV_LEFT | REG_HRO) }, + { ORDATA (SC, dpc_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, dpc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -365,8 +376,8 @@ MTAB dpc_mod[] = { &dp_settype, NULL, NULL }, { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &dp_showtype, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &dpd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dpd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dpd_dev }, { 0 } }; @@ -1064,13 +1075,18 @@ t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 i; -if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; +if ((val < 0) || (val > 1) || (cptr != NULL)) + return SCPE_ARG; + for (i = 0; i < DP_NUMDRV; i++) { - if (dpc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; + if (dpc_unit[i].flags & UNIT_ATT) + return SCPE_ALATT; } + for (i = 0; i < DP_NUMDRV; i++) dpc_unit[i].capac = (val? DP_SIZE3: DP_SIZE2); -dp_ctype = val; + +dp_ctype = (CNTLR_TYPE) val; return SCPE_OK; } @@ -1079,8 +1095,11 @@ return SCPE_OK; t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) { -if (dp_ctype == A13210) fprintf (st, "13210A"); -else fprintf (st, "12557A"); +if (dp_ctype == A13210) + fprintf (st, "13210A"); +else + fprintf (st, "12557A"); + return SCPE_OK; } diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index 726aa4ba..3f4062f8 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -1,7 +1,7 @@ /* hp2100_dq.c: HP 2100 12565A disk simulator Copyright (c) 1993-2006, Bill McDermith - Copyright (c) 2004-2011 J. David Bryan + Copyright (c) 2004-2012 J. David Bryan 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 @@ DQ 12565A 2883 disk system + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size @@ -223,13 +224,14 @@ REG dqd_reg[] = { { FLDATA (FBF, dqd.flagbuf, 0) }, { FLDATA (XFER, dqd_xfer, 0) }, { FLDATA (WVAL, dqd_wval, 0) }, + { ORDATA (SC, dqd_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, dqd_dib.select_code, 6), REG_HRO }, { NULL } }; MTAB dqd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &dqd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dqd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dqd_dev }, { 0 } }; @@ -276,6 +278,7 @@ REG dqc_reg[] = { { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT }, { URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0, DQ_NUMDRV, REG_HRO) }, + { ORDATA (SC, dqc_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, dqc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -285,8 +288,8 @@ MTAB dqc_mod[] = { { UNIT_UNLOAD, 0, "heads loaded", "LOADED", dqc_load_unload }, { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &dqd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dqd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dqd_dev }, { 0 } }; diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c index 1ae61f6a..69c8b7f2 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-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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 @@ DR 12606B 2770/2771 fixed head disk 12610B 2773/2774/2775 drum + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 09-Jul-08 JDB Revised drc_boot to use ibl_copy @@ -240,13 +241,14 @@ REG drd_reg[] = { { FLDATA (CTL, drd.control, 0) }, { FLDATA (FLG, drd.flag, 0) }, { ORDATA (BPTR, drd_ptr, 6) }, + { ORDATA (SC, drd_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, drd_dib.select_code, 6), REG_HRO }, { NULL } }; MTAB drd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &drd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &drd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &drd_dev }, { 0 } }; @@ -278,6 +280,7 @@ REG drc_reg[] = { { FLDATA (RUN, drc_run, 0) }, { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, dr_stopioe, 0) }, + { ORDATA (SC, drc_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, drc_dib.select_code, 6), REG_HRO }, { DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO }, { NULL } @@ -300,8 +303,8 @@ MTAB drc_mod[] = { { UNIT_PROT, 0, "unprotected", "UNPROTECTED", NULL }, { MTAB_XTD | MTAB_VDV, 0, "TRACKPROT", "TRACKPROT", &dr_set_prot, &dr_show_prot, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &drd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &drd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &drd_dev }, { 0 } }; diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c index ee22bead..79552417 100644 --- a/HP2100/hp2100_ds.c +++ b/HP2100/hp2100_ds.c @@ -1,6 +1,7 @@ -/* hp2100_ds.c: HP 2100 13037 disk controller simulator +/* hp2100_ds.c: HP 13037D/13175D disc controller/interface simulator - Copyright (c) 2004-2011, Robert M. Supnik + Copyright (c) 2004-2012, Robert M. Supnik + Copyright (c) 2012 J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -15,16 +16,24 @@ 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 AUTHORS 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 + Except as contained in this notice, the names of the authors 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. + in this Software without prior written authorization from the authors. - DS 13037 disk controller + DS 13037D/13175D disc controller/interface + 02-Mar-12 JDB Rewritten to use the MAC/ICD disc controller library + ioIOO now notifies controller service of parameter output + 14-Feb-12 JDB Corrected SRQ generation and FIFO under/overrun detection + Corrected Clear command to conform to the hardware + Fixed Request Status to return Unit Unavailable if illegal + Seek and Cold Load Read now Seek Check if seek in progress + Remodeled command wait for seek completion + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 21-Jun-11 JDB Corrected status returns for disabled drive, auto-seek beyond drive limits, Request Sector Address and Wakeup with invalid or offline unit @@ -41,652 +50,542 @@ 18-Mar-05 RMS Added attached test to detach routine 01-Mar-05 JDB Added SET UNLOAD/LOAD - Reference: + References: - 13037 Disc Controller Technical Information Package (13037-90902, Aug-1980) + - 7925D Disc Drive Service Manual (07925-90913, Apr-1984) + - HP 12992 Loader ROMs Installation Manual (12992-90001, Apr-1986) + - DVR32 RTE Moving Head Driver source (92084-18711, Revision 5000) - States of the controller: the controller uP runs all the time, but most of - the time it is waiting for an event. The simulator only 'runs' the controller - when there's an event to process: change in CPU interface state, change in - disk state, or timeout. The controller has three states: + The 13037D multiple-access (MAC) disc controller supports from one to eight + HP 7905 (15 MB), 7906 (20MB), 7920 (50 MB), and 7925 (120 MB) disc drives + accessed by one to eight CPUs. The controller hardware consists of a 16-bit + microprogrammed processor constructed from 74S181 bit slices and operating at + 5 MHz, a device controller providing the interconnections to the drives and + CPU interfaces, and error correction circuitry that enables the controller to + correct up to a 32-bit error burst. 1024 words of 24-bit firmware are stored + in ROM. - - Idle. No operations other than seek or recalibrate are in progress, and - the CPU interface is disconnected. The controller responds both to new - commands and to drive attention interrupts. - - Wait. No operations other than seek or recalibrate are in progress, but - the CPU interface is connected. The controller responds to new commands - but not to drive attention interrupts. - - Busy. The controller is processing a command. The controller does not - respond to new commands or to drive attention interrupts. + The 13175D disc interface is used to connect the CPU to the 13037 device + controller. In a multiple-CPU system, one interface is strapped to reset the + controller when the CPU's front panel PRESET button is pressed. - The controller busy state is loosely related to the testable (visible) busy - flop. If the visible busy flop is set, the controller is in the busy state; - but the controller can also be busy (processing an invalid opcode or invalid - unit) while visible busy is clear. + This module simulates a 13037D connected to a single 13175D interface. From + one to eight drives may be connected, and drive types may be freely + intermixed. A unit that is enabled but not attached appears to be a + connected drive that does not have a disc pack in place. A unit that is + disabled appears to be disconnected. - Omissions: the following features are not implemented: + This simulator is an adaptation of the code originally written by Bob Supnik. + The functions of the controller have been separated from the functions of the + interface, with the former placed into a separate disc controller library. + This allows the library to support other CPU interfaces, such as the 12821A + HP-IB disc interface, that use substantially different communication + protocols. The library functions implement the controller command set for + the drive units. The interface functions handle the transfer of commands and + data to and from the CPU. - - Drive hold. Since this is a single CPU implementation, the drives are - always available to the CPU. - - Spare, defective, protected. The disk files carry only data. - - Formatting. The disk files carry only data. - - ECC. Data errors are always uncorrectable. + In hardware, the controller runs continuously in one of three states: in the + Poll Loop (idle state), in the Command Wait Loop (wait state), or in command + execution (busy state). In simulation, the controller is run only when a + command is executing or when a transition into or out of the two loops might + occur. Internally, the controller handles these transitions: + + - when a command other than End terminates (busy => wait) + - when the End command terminates (busy => idle) + - when a command timeout occurs (wait => idle) + - when a parameter timeout occurs (busy => idle) + - when a seek completes (if idle and interrupts are enabled, idle => wait) + + The interface must call the controller library to handle these transitions: + + - when a command is received from the CPU (idle or wait => busy) + - when interrupts are enabled (if idle and drive Attention, idle => wait) + + In addition, each transition to the wait state must check for a pending + command, and each transition to the idle state must check for both a pending + command and a drive with Attention status asserted. + + + Implementation notes: + + 1. Although the 13175D has a 16-word FIFO, the "full" level is set at 5 + entries in hardware to avoid a long DCPC preemption time at the start of + a disc write as the FIFO fills. */ -#include + + #include "hp2100_defs.h" +#include "hp_disclib.h" -#define DS_NUMDR 8 /* max drives */ -#define DS_DRMASK (DS_NUMDR - 1) -#define DS_NUMWD 128 /* data words/sec */ -#define DS_NUMWDF 138 /* total words/sec */ -#define DS_FSYNC 0 /* sector offsets */ -#define DS_FCYL 1 -#define DS_FHS 2 -#define DS_FDATA 3 -#define DS_FIFO_SIZE 16 /* fifo size */ -#define DS_FIFO_EMPTY (ds_fifo_cnt == 0) -#define ds_ctrl ds_unit[DS_NUMDR] /* ctrl thread */ -#define ds_timer ds_unit[DS_NUMDR + 1] /* timeout thread */ -#define GET_CURSEC(x,d) ((int32) fmod (sim_gtime() / ((double) (x)), \ - ((double) (drv_tab[d].sc)))) -/* Flags in the unit flags word */ -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */ -#define UNIT_V_DTYPE (UNIT_V_UF + 2) /* disk type */ -#define UNIT_M_DTYPE 3 -#define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ -#define UNIT_V_FMT (UNIT_V_UF + 5) /* format enabled */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_FMT (1 << UNIT_V_FMT) -#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_UNLOAD (1 << UNIT_V_UNLOAD) -#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) -#define UNIT_WPR (UNIT_WLK | UNIT_RO) /* write prot */ +/* Program constants */ -/* Parameters in the unit descriptor */ +#define DS_DRIVES (DL_MAXDRIVE + 1) /* number of disc drive units */ +#define DS_UNITS (DS_DRIVES + DL_AUXUNITS) /* total number of units */ -#define FNC u3 /* function */ -#define CYL u4 /* current cylinder */ -#define STA u5 /* status */ +#define ds_cntlr ds_unit [DL_MAXDRIVE + 1] /* controller unit alias */ -/* Arguments to subroutines */ +#define FIFO_SIZE 16 /* FIFO depth */ -#define CLR_BUSY 0 /* clear visible busy */ -#define SET_BUSY 1 /* set visible busy */ +#define FIFO_EMPTY (ds.fifo_count == 0) /* FIFO empty test */ +#define FIFO_STOP (ds.fifo_count >= 5) /* FIFO stop filling test */ +#define FIFO_FULL (ds.fifo_count == FIFO_SIZE) /* FIFO full test */ -/* Command word - <12:8> are opcode, <7:0> are opcode dependent +#define PRESET_ENABLE TRUE /* Preset Jumper (W4) enabled */ - cold load read <7:6> = head - <5:0> = sector - set file mask <7:4> = retry count - <3:0> = file mask (auto-seek options) - commands with units <7> = hold flag - <4:0> = unit number */ -#define DSC_V_OP 8 /* opcode */ -#define DSC_M_OP 037 -#define DSC_COLD 000 /* cold load read */ -#define DSC_RECAL 001 /* recalibrate */ -#define DSC_SEEK 002 /* seek */ -#define DSC_RSTA 003 /* request status */ -#define DSC_RSA 004 /* request sector addr */ -#define DSC_READ 005 /* read */ -#define DSC_RFULL 006 /* read full */ -#define DSC_VFY 007 /* verify */ -#define DSC_WRITE 010 /* write */ -#define DSC_WFULL 011 /* write full */ -#define DSC_CLEAR 012 /* clear */ -#define DSC_INIT 013 /* initialize */ -#define DSC_AREC 014 /* address record */ -#define DSC_RSYN 015 /* request syndrome */ -#define DSC_ROFF 016 /* read with offset */ -#define DSC_SFM 017 /* set file mask */ -#define DSC_RNOVFY 022 /* read no verify */ -#define DSC_WTIO 023 /* write TIO */ -#define DSC_RDA 024 /* request disk addr */ -#define DSC_END 025 /* end */ -#define DSC_WAKE 026 /* wakeup */ -#define DSC_ATN 035 /* pseudo: ATN */ -#define DSC_BADU 036 /* pseudo: bad unit */ -#define DSC_BADF 037 /* pseudo: bad opcode */ -#define DSC_NEXT 0040 /* state increment */ -#define DSC_2ND 0040 /* subcommand states */ -#define DSC_3RD 0100 -#define DSC_4TH 0140 -#define DSC_V_CHD 6 /* cold load head */ -#define DSC_M_CHD 03 -#define DSC_V_CSC 0 /* cold load sector */ -#define DSC_M_CSC 077 -#define DSC_V_RTY 4 /* retry count */ -#define DSC_M_RTY 017 -#define DSC_V_DECR 3 /* seek decrement */ -#define DSC_V_SPEN 2 /* enable sparing */ -#define DSC_V_CYLM 1 /* cylinder mode */ -#define DSC_V_AUTO 0 /* auto seek */ -#define DSC_V_HOLD 7 /* hold flag */ -#define DSC_V_UNIT 0 /* unit */ -#define DSC_M_UNIT 017 -#define DSC_V_SPAR 15 /* INIT spare */ -#define DSC_V_PROT 14 /* INIT protected */ -#define DSC_V_DFCT 13 /* INIT defective */ +/* Debug flags */ -#define DSC_HOLD (1u << DSC_V_HOLD) -#define DSC_DECR (1u << DSC_V_DECR) -#define DSC_SPEN (1u << DSC_V_SPEN) -#define DSC_CYLM (1u << DSC_V_CYLM) -#define DSC_AUTO (1u << DSC_V_AUTO) -#define DSC_FMASK ((DSC_M_RTY << DSC_V_RTY)|DSC_DECR|\ - DSC_SPEN|DSC_CYLM|DSC_AUTO) -#define DSC_GETOP(x) (((x) >> DSC_V_OP) & DSC_M_OP) -#define DSC_GETUNIT(x) (((x) >> DSC_V_UNIT) & DSC_M_UNIT) -#define DSC_GETCHD(x) (((x) >> DSC_V_CHD) & DSC_M_CHD) -#define DSC_GETCSC(x) (((x) >> DSC_V_CSC) & DSC_M_CSC) -#define DSC_SPAR (1u << DSC_V_SPAR) -#define DSC_PROT (1u << DSC_V_PROT) -#define DSC_DFCT (1u << DSC_V_DFCT) +#define DEB_CPU (1 << 0) /* words received from and sent to the CPU */ +#define DEB_CMDS (1 << 1) /* interface commands received from the CPU */ +#define DEB_BUF (1 << 2) /* data read from and written to the card FIFO */ +#define DEB_RWSC (1 << 3) /* device read/write/status/control commands */ +#define DEB_SERV (1 << 4) /* unit service scheduling calls */ -/* Command flags */ -#define CMF_UNDF 001 /* undefined */ -#define CMF_CLREC 002 /* clear eoc flag */ -#define CMF_CLRS 004 /* clear status */ -#define CMF_UIDLE 010 /* requires unit no */ -/* Cylinder words - 16b */ +/* Per-card state variables */ -/* Head/sector word */ - -#define DSHS_V_HD 8 /* head */ -#define DSHS_M_HD 037 -#define DSHS_V_SC 0 /* sector */ -#define DSHS_M_SC 0377 -#define DSHS_HD (DSHS_M_HD << DSHS_V_HD) -#define DSHS_SC (DSHS_M_SC << DSHS_V_SC) -#define DSHS_GETHD(x) (((x) >> DSHS_V_HD) & DSHS_M_HD) -#define DSHS_GETSC(x) (((x) >> DSHS_V_SC) & DSHS_M_SC) - -/* Status 1 */ - -#define DS1_V_SPAR 15 /* spare - na */ -#define DS1_V_PROT 14 /* protected - na */ -#define DS1_V_DFCT 13 /* defective - na */ -#define DS1_V_STAT 8 /* status */ -#define DS1_OK (000 << DS1_V_STAT) /* normal */ -#define DS1_ILLOP (001 << DS1_V_STAT) /* illegal opcode */ -#define DS1_AVAIL (002 << DS1_V_STAT) /* available */ -#define DS1_CYLCE (007 << DS1_V_STAT) /* cyl compare err */ -#define DS1_UNCOR (010 << DS1_V_STAT) /* uncor data err */ -#define DS1_HSCE (011 << DS1_V_STAT) /* h/s compare err */ -#define DS1_IOPE (012 << DS1_V_STAT) /* IO oper err - na */ -#define DS1_EOCYL (014 << DS1_V_STAT) /* end cylinder */ -#define DS1_OVRUN (016 << DS1_V_STAT) /* overrun */ -#define DS1_CORDE (017 << DS1_V_STAT) /* correctible - na */ -#define DS1_ILLST (020 << DS1_V_STAT) /* illegal spare - na */ -#define DS1_DEFTK (021 << DS1_V_STAT) /* defective trk - na */ -#define DS1_ACCER (022 << DS1_V_STAT) /* access not rdy - na */ -#define DS1_S2ERR (023 << DS1_V_STAT) /* status 2 error */ -#define DS1_TKPER (026 << DS1_V_STAT) /* protected trk - na */ -#define DS1_UNAVL (027 << DS1_V_STAT) /* illegal unit */ -#define DS1_ATN (037 << DS1_V_STAT) /* attention */ -#define DS1_V_UNIT 0 -#define DS1_SPAR (1u << DS1_V_SPAR) -#define DS1_PROT (1u << DS1_V_PROT) -#define DS1_DFCT (1u << DS1_V_DFCT) - -/* Status 2, ^ = kept in unit status, * = dynamic */ - -#define DS2_ERR 0100000 /* *error */ -#define DS2_V_ID 9 /* drive type */ -#define DS2_ATN 0000200 /* ^attention */ -#define DS2_RO 0000100 /* *read only */ -#define DS2_FRM 0000040 /* *format */ -#define DS2_FLT 0000020 /* fault - na */ -#define DS2_FS 0000010 /* ^first status */ -#define DS2_SC 0000004 /* ^seek error */ -#define DS2_NR 0000002 /* *not ready */ -#define DS2_BS 0000001 /* *busy */ -#define DS2_ALLERR (DS2_FLT|DS2_SC|DS2_NR|DS2_BS) - -/* Controller state */ - -#define DS_IDLE 0 /* idle */ -#define DS_WAIT 1 /* command wait */ -#define DS_BUSY 2 /* busy */ - -/* This controller supports four different disk drive types: - - type #sectors/ #surfaces/ #cylinders/ - surface cylinder drive - - 7905 48 3 411 =15MB - 7906 48 4 411 =20MB - 7920 48 5 823 =50MB - 7925 64 9 823 =120MB - - In theory, each drive can be a different type. The size field in - each unit selects the drive capacity for each drive and thus the - drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE. - - The 7905 and 7906 have fixed and removable platters. Consequently, - they are almost always accessed with cylinders limited to each - platter. The 7920 and 7925 have multiple-platter packs, and so are - almost always accessed with cylinders that span all surfaces. - - Disk image files are arranged as a linear set of tracks. To improve - locality, tracks on the 7905 and 7906 images are grouped per-platter, - i.e., all tracks on heads 0 and 1, followed by all tracks on head 2 - (and, for the 7906, head 3), whereas tracks on the 7920 and 7925 are - sequential by cylinder and head number. - - This variable-access geometry is accomplished by defining a "heads - per cylinder" value for the fixed and removable sections of each - drive that indicates the number of heads that should be grouped for - locality. The removable values are set to 2 on the 7905 and 7906, - indicating that those drives typically use cylinders of two surfaces. - They are set to the number of surfaces per drive for the 7920 and - 7925, as those typically use cylinders encompassing the entire - spindle. -*/ - -#define GET_DA(x,y,z,t) \ - (((((y) < drv_tab[t].rh)? \ - (x) * drv_tab[t].rh + (y): \ - drv_tab[t].cyl * drv_tab[t].rh + \ - ((x) * drv_tab[t].fh + (y) - drv_tab[t].rh)) * \ - drv_tab[t].sc + (z)) * DS_NUMWD) - -#define D7905_DTYPE 0 -#define D7905_SECT 48 -#define D7905_SURF 3 -#define D7905_RH 2 -#define D7905_FH (D7905_SURF - D7905_RH) -#define D7905_CYL 411 -#define D7905_ID (2 << DS2_V_ID) -#define D7905_SIZE (D7905_SECT * D7905_SURF * D7905_CYL * DS_NUMWD) - -#define D7906_DTYPE 1 -#define D7906_SECT 48 -#define D7906_SURF 4 -#define D7906_RH 2 -#define D7906_FH (D7906_SURF - D7906_RH) -#define D7906_CYL 411 -#define D7906_ID (0 << DS2_V_ID) -#define D7906_SIZE (D7906_SECT * D7906_SURF * D7906_CYL * DS_NUMWD) - -#define D7920_DTYPE 2 -#define D7920_SECT 48 -#define D7920_SURF 5 -#define D7920_RH D7920_SURF -#define D7920_FH (D7920_SURF - D7920_RH) -#define D7920_CYL 823 -#define D7920_ID (1 << DS2_V_ID) -#define D7920_SIZE (D7920_SECT * D7920_SURF * D7920_CYL * DS_NUMWD) - -#define D7925_DTYPE 3 -#define D7925_SECT 64 -#define D7925_SURF 9 -#define D7925_RH D7925_SURF -#define D7925_FH (D7925_SURF - D7925_RH) -#define D7925_CYL 823 -#define D7925_ID (3 << DS2_V_ID) -#define D7925_SIZE (D7925_SECT * D7925_SURF * D7925_CYL * DS_NUMWD) - -struct drvtyp { - uint32 sc; /* sectors */ - uint32 hd; /* surfaces */ - uint32 cyl; /* cylinders */ - uint32 size; /* #blocks */ - uint32 id; /* device type */ - uint32 rh; /* removable surfaces */ - uint32 fh; /* fixed surfaces */ - }; - -static struct drvtyp drv_tab[] = { - { D7905_SECT, D7905_SURF, D7905_CYL, D7905_SIZE, D7905_ID, D7905_RH, D7905_FH }, - { D7906_SECT, D7906_SURF, D7906_CYL, D7906_SIZE, D7906_ID, D7906_RH, D7906_FH }, - { D7920_SECT, D7920_SURF, D7920_CYL, D7920_SIZE, D7920_ID, D7920_RH, D7920_FH }, - { D7925_SECT, D7925_SURF, D7925_CYL, D7925_SIZE, D7925_ID, D7925_RH, D7925_FH }, - { 0 } - }; - -struct { +typedef struct { FLIP_FLOP control; /* control flip-flop */ FLIP_FLOP flag; /* flag flip-flop */ FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - FLIP_FLOP srq; /* service request flip-flop */ - } ds = { CLEAR, CLEAR, CLEAR, CLEAR }; + FLIP_FLOP srq; /* SRQ flip-flop */ + FLIP_FLOP edt; /* EDT flip-flop */ + FLIP_FLOP cmfol; /* command follows flip-flop */ + FLIP_FLOP cmrdy; /* command ready flip-flop */ + uint16 fifo [FIFO_SIZE]; /* FIFO buffer */ + uint32 fifo_count; /* FIFO occupancy counter */ + REG *fifo_reg; /* FIFO register pointer */ + } CARD_STATE; -uint32 ds_fifo[DS_FIFO_SIZE] = { 0 }; /* fifo */ -uint32 ds_fifo_ip = 0; /* insertion ptr */ -uint32 ds_fifo_rp = 0; /* removal ptr */ -uint32 ds_fifo_cnt = 0; /* count */ -uint32 ds_cmd = 0; /* command word */ -uint32 ds_sr1 = 0; /* status word 1 */ -uint32 ds_busy = 0; /* busy flag */ -uint32 ds_eoc = 0; /* end of cylinder */ -uint32 ds_eod = 0; /* end of data */ -uint32 ds_fmask = 0; /* file mask */ -uint32 ds_cmdf = 0; /* command follows */ -uint32 ds_cmdp = 0; /* command present */ -uint32 ds_cyl = 0; /* disk address: cyl */ -uint32 ds_hs = 0; /* disk address: hs */ -uint32 ds_vctr = 0; /* verify counter */ -uint32 ds_state = 0; /* controller state */ -uint32 ds_lastatn = 0; /* last atn intr */ -int32 ds_stime = 100; /* seek time */ -int32 ds_rtime = 100; /* inter-sector time */ -int32 ds_ctime = 3; /* command time */ -int32 ds_dtime = 1; /* dch time */ -int32 ds_tmo = 2749200; /* timeout = 1.74 sec */ -uint32 ds_ptr = 0; /* buffer ptr */ -uint16 dsxb[DS_NUMWDF]; /* sector buffer */ -static const uint32 ds_opflags[32] = { /* flags for ops */ - CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* cold read */ - CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* recalibrate */ - CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* seek */ - 0, /* read status */ - CMF_CLRS, /* read sector */ - CMF_CLRS|CMF_UIDLE, /* read */ - CMF_CLRS|CMF_UIDLE, /* read full */ - CMF_CLRS|CMF_UIDLE, /* verify */ - CMF_CLRS|CMF_UIDLE, /* write */ - CMF_CLRS|CMF_UIDLE, /* write full */ - CMF_CLRS, /* clear */ - CMF_CLRS|CMF_UIDLE, /* init */ - CMF_CLREC|CMF_CLRS, /* addr record */ - 0, /* read syndrome */ - CMF_CLRS|CMF_UIDLE, /* read offset */ - CMF_CLRS, /* set file mask */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_CLRS|CMF_UIDLE, /* read no verify */ - CMF_CLRS, /* write TIO */ - CMF_CLRS, /* read disk addr */ - CMF_CLRS, /* end */ - CMF_CLRS, /* wake */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS, /* undefined */ - CMF_UNDF|CMF_CLRS /* undefined */ - }; +/* MAC disc state variables */ -DEVICE ds_dev; +static UNIT ds_unit [DS_UNITS]; /* unit array */ -IOHANDLER dsio; +static CARD_STATE ds; /* card state */ + +static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */ + +static CNTLR_VARS mac_cntlr = /* MAC controller */ + { CNTLR_INIT (MAC, buffer, &ds_cntlr) }; + + + +/* MAC disc global VM routines */ + +IOHANDLER ds_io; +t_stat ds_service_drive (UNIT *uptr); +t_stat ds_service_controller (UNIT *uptr); +t_stat ds_service_timer (UNIT *uptr); +t_stat ds_reset (DEVICE *dptr); +t_stat ds_attach (UNIT *uptr, char *cptr); +t_stat ds_detach (UNIT *uptr); +t_stat ds_boot (int32 unitno, DEVICE *dptr); + +/* MAC disc global SCP routines */ -t_stat ds_svc_c (UNIT *uptr); -t_stat ds_svc_u (UNIT *uptr); -t_stat ds_svc_t (UNIT *uptr); -t_stat ds_reset (DEVICE *dptr); -t_stat ds_attach (UNIT *uptr, char *cptr); -t_stat ds_detach (UNIT *uptr); -t_stat ds_boot (int32 unitno, DEVICE *dptr); t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); -t_stat ds_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -void ds_poll (void); -void ds_docmd (uint32 cmd); -void ds_doatn (void); -uint32 ds_updds2 (UNIT *uptr); -void ds_cmd_done (t_bool sf, uint32 sr1); -void ds_wait_for_cpu (UNIT *uptr, uint32 newst); -void ds_set_idle (void); -void ds_sched_ctrl_op (uint32 op, uint32 arg, uint32 busy); -void ds_reqad (uint16 *cyl, uint16 *hs); -void ds_start_seek (UNIT *uptr, uint32 cyl, uint32 newst); -t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy); -void ds_next_sec (UNIT *uptr); -void ds_next_cyl (UNIT *uptr); -t_stat ds_start_rd (UNIT *uptr, uint32 off, t_bool vfy); -void ds_start_wr (UNIT *uptr, t_bool vfy); -void ds_cont_rd (UNIT *uptr, uint32 bsize); -t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize); -void ds_end_rw (UNIT *uptr, uint32 newst); -t_stat ds_set_uncorr (UNIT *uptr); -t_stat ds_clear (void); -void ds_sched_atn (UNIT *uptr); -uint32 ds_fifo_read (void); -void ds_fifo_write (uint32 dat); -void ds_fifo_reset (void); -/* DS data structures +/* MAC disc local utility routines */ - ds_dev DS device descriptor +static void start_command (void); +static void poll_interface (void); +static void poll_drives (void); +static void fifo_load (uint16 data); +static uint16 fifo_unload (void); +static void fifo_clear (void); +static t_stat activate_unit (UNIT *uptr); + + + +/* MAC disc VM data structures. + + ds_dib DS device information block ds_unit DS unit list ds_reg DS register list ds_mod DS modifier list + ds_deb DS debug table + ds_dev DS device descriptor + + For the drive models, the modifiers provide this SHOW behavior: + + - when detached and autosized, prints "autosize" + - when detached and not autosized, prints the model number + - when attached, prints the model number (regardless of autosizing) + + + Implementation notes: + + 1. The validation routine does not allow the model number or autosizing + option to be changed when the unit is attached. Therefore, specifying + UNIT_ATT in the mask field has no deleterious effect. + + 2. The modifier DEVNO is deprecated in favor of SC but is retained for + compatibility. */ -DIB ds_dib = { &dsio, DS }; -UNIT ds_unit[] = { - { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) }, - { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) }, - { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) }, - { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) }, - { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) }, - { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) }, - { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) }, - { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) }, - { UDATA (&ds_svc_c, UNIT_DIS, 0) }, - { UDATA (&ds_svc_t, UNIT_DIS, 0) } +DEVICE ds_dev; + +static DIB ds_dib = { &ds_io, DS }; + +#define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD) + +static UNIT ds_unit [] = { + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 0 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 1 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 2 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 3 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 4 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 5 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 6 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 7 */ + { UDATA (&ds_service_controller, UNIT_DIS, 0) }, /* controller unit */ + { UDATA (&ds_service_timer, UNIT_DIS, 0) } /* timer unit */ }; -REG ds_reg[] = { - { ORDATA (CMD, ds_cmd, 16) }, - { BRDATA (FIFO, ds_fifo, 8, 16, DS_FIFO_SIZE) }, - { ORDATA (SR1, ds_sr1, 16) }, - { ORDATA (VCTR, ds_vctr, 16) }, - { ORDATA (FMASK, ds_fmask, 8) }, - { ORDATA (CYL, ds_cyl, 16) }, - { ORDATA (HS, ds_hs, 16) }, - { ORDATA (STATE, ds_state, 2), REG_RO }, - { ORDATA (LASTA, ds_lastatn, 3) }, - { DRDATA (FIP, ds_fifo_ip, 4) }, - { DRDATA (FRP, ds_fifo_rp, 4) }, - { DRDATA (FCNT, ds_fifo_cnt, 5) }, - { FLDATA (CTL, ds.control, 0) }, - { FLDATA (FLG, ds.flag, 0) }, - { FLDATA (FBF, ds.flagbuf, 0) }, - { FLDATA (SRQ, ds.srq, 0) }, - { FLDATA (BUSY, ds_busy, 0) }, - { FLDATA (CMDF, ds_cmdf, 0) }, - { FLDATA (CMDP, ds_cmdp, 0) }, - { FLDATA (EOC, ds_eoc, 0) }, - { FLDATA (EOD, ds_eod, 0) }, - { BRDATA (DBUF, dsxb, 8, 16, DS_NUMWDF) }, - { DRDATA (DPTR, ds_ptr, 8) }, - { DRDATA (CTIME, ds_ctime, 24), PV_LEFT + REG_NZ }, - { DRDATA (DTIME, ds_dtime, 24), PV_LEFT + REG_NZ }, - { DRDATA (STIME, ds_stime, 24), PV_LEFT + REG_NZ }, - { DRDATA (RTIME, ds_rtime, 24), PV_LEFT + REG_NZ }, - { DRDATA (TIMEOUT, ds_tmo, 31), PV_LEFT + REG_NZ }, - { URDATA (UCYL, ds_unit[0].CYL, 10, 10, 0, - DS_NUMDR + 1, PV_LEFT | REG_HRO) }, - { URDATA (UFNC, ds_unit[0].FNC, 8, 8, 0, - DS_NUMDR + 1, REG_HRO) }, - { URDATA (USTA, ds_unit[0].STA, 8, 16, 0, - DS_NUMDR + 1, REG_HRO) }, - { URDATA (CAPAC, ds_unit[0].capac, 10, T_ADDR_W, 0, - DS_NUMDR, PV_LEFT | REG_HRO) }, - { ORDATA (DEVNO, ds_dib.select_code, 6), REG_HRO }, +static REG ds_reg [] = { + { FLDATA (CMFOL, ds.cmfol, 0) }, + { FLDATA (CMRDY, ds.cmrdy, 0) }, + { BRDATA (FIFO, ds.fifo, 8, 16, FIFO_SIZE), REG_CIRC }, + { DRDATA (FCNT, ds.fifo_count, 5) }, + { ORDATA (FREG, ds.fifo_reg, 32), REG_HRO }, + + { ORDATA (CNTYPE, mac_cntlr.type, 2), REG_HRO }, + { ORDATA (STATE, mac_cntlr.state, 2) }, + { ORDATA (OPCODE, mac_cntlr.opcode, 6) }, + { ORDATA (STATUS, mac_cntlr.status, 6) }, + { FLDATA (EOC, mac_cntlr.eoc, 0) }, + { FLDATA (EOD, mac_cntlr.eod, 0) }, + { ORDATA (SPDU, mac_cntlr.spd_unit, 16) }, + { ORDATA (FLMASK, mac_cntlr.file_mask, 4) }, + { ORDATA (RETRY, mac_cntlr.retry, 4), REG_HRO }, + { ORDATA (CYL, mac_cntlr.cylinder, 16) }, + { ORDATA (HEAD, mac_cntlr.head, 6) }, + { ORDATA (SECTOR, mac_cntlr.sector, 8) }, + { ORDATA (VFYCNT, mac_cntlr.verify_count, 16) }, + { ORDATA (LASPOL, mac_cntlr.poll_unit, 3) }, + { HRDATA (BUFPTR, mac_cntlr.buffer, 32), REG_HRO }, + { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) }, + { DRDATA (INDEX, mac_cntlr.index, 8) }, + { DRDATA (LENGTH, mac_cntlr.length, 8) }, + { HRDATA (AUXPTR, mac_cntlr.aux, 32), REG_HRO }, + { DRDATA (STIME, mac_cntlr.seek_time, 24), PV_LEFT | REG_NZ }, + { DRDATA (ITIME, mac_cntlr.sector_time, 24), PV_LEFT | REG_NZ }, + { DRDATA (CTIME, mac_cntlr.cmd_time, 24), PV_LEFT | REG_NZ }, + { DRDATA (DTIME, mac_cntlr.data_time, 24), PV_LEFT | REG_NZ }, + { DRDATA (WTIME, mac_cntlr.wait_time, 31), PV_LEFT | REG_NZ }, + + { FLDATA (CTL, ds.control, 0) }, + { FLDATA (FLG, ds.flag, 0) }, + { FLDATA (FBF, ds.flagbuf, 0) }, + { FLDATA (SRQ, ds.srq, 0) }, + { FLDATA (EDT, ds.edt, 0) }, + + { URDATA (UCYL, ds_unit[0].CYL, 10, 10, 0, DS_UNITS, PV_LEFT) }, + { URDATA (UOP, ds_unit[0].OP, 8, 6, 0, DS_UNITS, PV_RZRO) }, + { URDATA (USTAT, ds_unit[0].STAT, 2, 8, 0, DS_UNITS, PV_RZRO) }, + { URDATA (UPHASE, ds_unit[0].PHASE, 8, 3, 0, DS_UNITS, PV_RZRO) }, + { URDATA (UPOS, ds_unit[0].pos, 8, T_ADDR_W, 0, DS_UNITS, PV_LEFT) }, + { URDATA (UWAIT, ds_unit[0].wait, 8, 32, 0, DS_UNITS, PV_LEFT) }, + + { ORDATA (SC, ds_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, ds_dib.select_code, 6), REG_HRO }, { NULL } }; -MTAB ds_mod[] = { - { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", ds_load_unload }, - { UNIT_UNLOAD, 0, "heads loaded", "LOADED", ds_load_unload }, - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL }, - { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL }, - { (UNIT_DTYPE+UNIT_ATT), (D7905_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "7905", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (D7906_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "7906", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (D7920_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "7920", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (D7925_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "7925", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7905_DTYPE << UNIT_V_DTYPE), - "7905", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7906_DTYPE << UNIT_V_DTYPE), - "7906", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7920_DTYPE << UNIT_V_DTYPE), - "7920", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7925_DTYPE << UNIT_V_DTYPE), - "7925", NULL, NULL }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { (UNIT_AUTO+UNIT_DTYPE), (D7905_DTYPE << UNIT_V_DTYPE), - NULL, "7905", &ds_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (D7906_DTYPE << UNIT_V_DTYPE), - NULL, "7906", &ds_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (D7920_DTYPE << UNIT_V_DTYPE), - NULL, "7920", &ds_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (D7925_DTYPE << UNIT_V_DTYPE), - NULL, "7925", &ds_set_size }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &ds_dev }, +static MTAB ds_mod [] = { +/* mask match pstring mstring valid disp desc */ + { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &ds_load_unload, NULL, NULL }, + { UNIT_UNLOAD, 0, "heads loaded", "LOADED", &ds_load_unload, NULL, NULL }, + + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL }, + + { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL }, + { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL }, + +/* mask match pstring mstring valid disp desc */ + { UNIT_AUTO | UNIT_ATT, UNIT_AUTO, "autosize", "AUTOSIZE", &dl_set_model, NULL, NULL }, + { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7905, "7905", "7905", &dl_set_model, NULL, NULL }, + { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7906, "7906", "7906", &dl_set_model, NULL, NULL }, + { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7920, "7920", "7920", &dl_set_model, NULL, NULL }, + { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7925, "7925", "7925", &dl_set_model, NULL, NULL }, + { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7905, "7905", NULL, NULL, NULL, NULL }, + { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7906, "7906", NULL, NULL, NULL, NULL }, + { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7920, "7920", NULL, NULL, NULL, NULL }, + { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7925, "7925", NULL, NULL, NULL, NULL }, + + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ds_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ds_dev }, { 0 } }; -DEVICE ds_dev = { - "DS", ds_unit, ds_reg, ds_mod, - DS_NUMDR + 2, 8, 27, 1, 8, 16, - NULL, NULL, &ds_reset, - &ds_boot, &ds_attach, &ds_detach, - &ds_dib, DEV_DISABLE +static DEBTAB ds_deb [] = { + { "CPU", DEB_CPU }, + { "CMDS", DEB_CMDS }, + { "BUF", DEB_BUF }, + { "RWSC", DEB_RWSC }, + { "SERV", DEB_SERV }, + { NULL, 0 } }; +DEVICE ds_dev = { + "DS", /* device name */ + ds_unit, /* unit array */ + ds_reg, /* register array */ + ds_mod, /* modifier array */ + DS_UNITS, /* number of units */ + 8, /* address radix */ + 27, /* address width = 128 MB */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &ds_reset, /* reset routine */ + &ds_boot, /* boot routine */ + &ds_attach, /* attach routine */ + &ds_detach, /* detach routine */ + &ds_dib, /* device information block */ + DEV_DEBUG | DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + ds_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL /* logical device name */ + }; + + + +/* MAC disc global VM routines */ + /* I/O signal handler. - The 13175A disc interface is unusual in that the flag and SRQ signals are - decoupled. This is done to allow DMA transfers at the maximum possible speed - (driving SRQ from the flag limits transfers to only every other cycle). SRQ - is based on the card's FIFO; if data or room in the FIFO is available, SRQ is - set to transfer it. The flag is only used to signal an interrupt at the end - of a command. + The 13175D disc interface data path consists of an input multiplexer/latch + and a 16-word FIFO buffer. The FIFO source may be either the CPU's I/O + input bus or the controller's interface data bus. The output of the FIFO may + be enabled either to the CPU's I/O output bus or the interface data bus. - Also unusual is that SFC and SFS test different things, rather than + The control path consists of the usual control, flag buffer, flag, and SRQ + flip-flops, although flag and SRQ are decoupled to allow the full DCPC + transfer rate through the FIFO (driving SRQ from the flag limits transfers to + only every other cycle). SRQ is based on the FIFO level: if data or room in + the FIFO is available, SRQ is set to transfer it. The flag is only used to + signal an interrupt at the end of a command. + + One unusual aspect is that SFC and SFS test different things, rather than complementary states of the same thing. SFC tests the busy flip-flop, and SFS tests the flag flip-flop. + In addition, the card contains end-of-data-transfer, command-follows, and + command-ready flip-flops. EDT is set when the DCPC EDT signal is asserted + and is used in conjunction with the FIFO level to assert the end-of-data + signal to the controller. The command-follows flip-flop is set by a CLC to + indicate that the next data word output from the CPU is a disc command. The + command-ready flip-flop is set when a command is received to schedule an + interface poll. + + Implementation notes: - 1. The dispatcher runs the command poll after each I/O signal, except for - SIR and ENF. Running the poll for these two will cause multi-drive - access to fail. + 1. In hardware, SRQ is enabled only when the controller is reading or + writing the disc (IFIN or IFOUT functions are asserted) and set when the + FIFO is not empty (read) or not full (write). In simulation, SRQ is set + by the unit service read/write data phase transfers and cleared below + when the FIFO is empty (read) or full (write). + + 2. The DCPC EDT signal cannot set the controller's end-of-data flag directly + because a write EOD must occur only after the FIFO has been drained. + + 3. Polling the interface or drives must be deferred to the end of the I/O + signal service. If they are performed in the IOO/STC handlers + themselves, an associated CLF might clear the flag that was set by the + poll. + + 4. Executing a CLC sets the controller's end-of-data flag, which will abort + a read or write data transfer in progress. Parameter transfers are not + affected. If a command is received when a parameter is expected, the + word is interpreted as data, even though the command-ready flip-flop is + set. The controller firmware only checks DTRDY for a parameter transfer, + and DTRDY is asserted whenever the FIFO is not empty. + + 5. The hardware Interface Function and Flag Buses are not implemented + explicitly. Instead, interface functions and signals are inferred by the + interface by the current command operation and phase. */ -uint32 dsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +uint32 ds_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { +static const char * const output_state [] = { "Data", "Command" }; +const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : ""); + +uint16 data; +t_stat status; IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ +t_bool command_issued = FALSE; +t_bool interrupt_enabled = FALSE; while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ + signal = IONEXT (working_set); /* isolate the next signal */ - switch (signal) { /* dispatch I/O signal */ + switch (signal) { /* dispatch the I/O signal */ case ioCLF: /* clear flag flip-flop */ - ds.flag = ds.flagbuf = CLEAR; /* clear flag */ - ds.srq = CLEAR; /* CLF clears SRQ */ + ds.flag = CLEAR; /* clear the flag */ + ds.flagbuf = CLEAR; /* and flag buffer */ + + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [CLF] Flag cleared\n", sim_deb); break; case ioSTF: /* set flag flip-flop */ case ioENF: /* enable flag */ - ds.flag = ds.flagbuf = SET; /* set flag and flag buffer */ + ds.flag = SET; /* set the flag */ + ds.flagbuf = SET; /* and flag buffer */ + + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [STF] Flag set\n", sim_deb); break; case ioSFC: /* skip if flag is clear */ - setSKF (ds_busy == 0); /* skip if not busy */ + setSKF (mac_cntlr.state != cntlr_busy); /* skip if the controller is not busy */ break; case ioSFS: /* skip if flag is set */ - setstdSKF (ds); + setstdSKF (ds); /* assert SKF if the flag is set */ break; - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, ds_fifo_read ()); /* merge in return status */ + case ioIOI: /* I/O data input */ + data = fifo_unload (); /* unload the next word from the FIFO */ + stat_data = IORETURN (SCPE_OK, data); /* merge in the return status */ + + if (DEBUG_PRI (ds_dev, DEB_CPU)) + fprintf (sim_deb, ">>DS cpu: [LIx%s] Data = %06o\n", hold_or_clear, data); + + if (FIFO_EMPTY) { /* is the FIFO now empty? */ + if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS)) + fprintf (sim_deb, ">>DS cmds: [LIx%s] SRQ cleared\n", hold_or_clear); + + ds.srq = CLEAR; /* clear SRQ */ + + if (ds_cntlr.PHASE == data_phase) { /* is this an outbound parameter? */ + ds_cntlr.wait = mac_cntlr.data_time; /* activate the controller */ + activate_unit (&ds_cntlr); /* to acknowledge the data */ + } + } break; - case ioIOO: /* I/O data output */ - if (ds_cmdf) { /* expecting command? */ - ds_cmd = IODATA (stat_data); /* save command */ - ds_cmdf = 0; - ds_cmdp = 1; /* command present */ + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* mask to just the data word */ + + if (DEBUG_PRI (ds_dev, DEB_CPU)) + fprintf (sim_deb, ">>DS cpu: [OTx%s] %s = %06o\n", + hold_or_clear, output_state [ds.cmfol], data); + + fifo_load (data); /* load the word into the FIFO */ + + if (ds.cmfol == SET) { /* are we expecting a command? */ + ds.cmfol = CLEAR; /* clear the command follows flip-flop */ + ds.cmrdy = SET; /* set the command ready flip-flop */ + command_issued = TRUE; /* and request an interface poll */ } - else - ds_fifo_write (IODATA (stat_data)); /* put in fifo */ + else { /* not a command */ + if (ds_cntlr.PHASE == data_phase) { /* is this an inbound parameter? */ + ds_cntlr.wait = mac_cntlr.data_time; /* activate the controller */ + activate_unit (&ds_cntlr); /* to receive the data */ + } + + if (FIFO_STOP) { /* is the FIFO now full enough? */ + if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS)) + fprintf (sim_deb, ">>DS cmds: [OTx%s] SRQ cleared\n", hold_or_clear); + + ds.srq = CLEAR; /* clear SRQ */ + } + } break; case ioPOPIO: /* power-on preset to I/O */ - ds.flag = ds.flagbuf = SET; /* set flag and flag buffer */ - ds_cmdp = 0; /* clear command ready */ + ds.flag = SET; /* set the flag */ + ds.flagbuf = SET; /* and flag buffer */ + ds.cmrdy = CLEAR; /* clear the command ready flip-flop */ + + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [POPIO] Flag set\n", sim_deb); break; - case ioCRS: /* control reset */ - ds.control = CLEAR; /* clear control */ - ds_cmdf = 0; /* not expecting command */ - ds_clear (); /* do controller CLEAR */ + case ioCRS: /* control reset */ + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [CRS] Master reset\n", sim_deb); + + ds.control = CLEAR; /* clear the control */ + ds.cmfol = CLEAR; /* and command follows flip-flops */ + + if (PRESET_ENABLE) { /* is preset enabled for this interface? */ + fifo_clear (); /* clear the FIFO */ + + status = dl_clear_controller (&mac_cntlr, /* do a hard clear of the controller */ + ds_unit, hard_clear); + + stat_data = IORETURN (status, 0); /* return the status from the controller */ + } break; case ioCLC: /* clear control flip-flop */ - ds.control = CLEAR; /* clear control */ - ds_cmdf = 1; /* expecting command */ - ds_cmdp = 0; /* none pending */ - ds_eod = 1; /* set EOD flag */ - ds_fifo_reset (); /* clear fifo */ + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fprintf (sim_deb, ">>DS cmds: [CLC%s] Control cleared\n", hold_or_clear); + + ds.control = CLEAR; /* clear the control */ + ds.edt = CLEAR; /* and EDT flip-flops */ + ds.cmfol = SET; /* set the command follows flip-flop */ + mac_cntlr.eod = SET; /* set the controller's EOD flag */ + + fifo_clear (); /* clear the FIFO */ break; case ioSTC: /* set control flip-flop */ - ds.control = SET; /* set control */ + ds.control = SET; /* set the control flip-flop */ + + interrupt_enabled = TRUE; /* check for drive attention */ + + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fprintf (sim_deb, ">>DS cmds: [STC%s] Control set\n", hold_or_clear); break; case ioEDT: /* end data transfer */ - ds_eod = 1; /* flag end transfer */ + ds.edt = SET; /* set the EDT flip-flop */ + + if (DEBUG_PRI (ds_dev, DEB_CPU)) + fputs (">>DS cpu: [EDT] DCPC transfer ended\n", sim_deb); break; case ioSIR: /* set interrupt request */ - setstdPRL (ds); /* set standard PRL signal */ - setstdIRQ (ds); /* set standard IRQ signal */ - setSRQ (dibptr->select_code, ds.srq); /* set SRQ signal */ + setstdPRL (ds); /* set the standard PRL signal */ + setstdIRQ (ds); /* set the standard IRQ signal */ + setSRQ (dibptr->select_code, ds.srq); /* set the SRQ signal */ break; case ioIAK: /* interrupt acknowledge */ - ds.flagbuf = CLEAR; + ds.flagbuf = CLEAR; /* clear the flag */ break; @@ -694,1041 +593,884 @@ while (working_set) { break; /* are ignored */ } - working_set = working_set & ~signal; /* remove current signal from set */ + working_set = working_set & ~signal; /* remove the current signal from the set */ } -if (!(signal_set & ioSIR) && !(signal_set & ioENF)) /* if not IRQ update */ - ds_poll (); /* run the controller */ + +if (command_issued) /* was a command received? */ + poll_interface (); /* poll the interface for the next command */ +else if (interrupt_enabled) /* were interrupts enabled? */ + poll_drives (); /* poll the drives for Attention */ return stat_data; } -/* Run the controller polling loop, based on ds_state: +/* Service the disc drive unit. - IDLE commands and ATN interrupts - WAIT commands only - BUSY nothing + The unit service routine is called to execute scheduled controller commands + for the specified unit. The actions to be taken depend on the current state + of the controller and the unit. + + Generally, the controller library service routine handles all of the disc + operations except data transfer to and from the interface. Read transfers + are responsible for loading words from the sector buffer into the FIFO and + enabling SRQ. If the current sector transfer is complete, either due to EDT + assertion or buffer exhaustion, the controller is moved to the end phase to + complete or continue the read with the next sector. In either case, the unit + is rescheduled. If the FIFO overflows, the read terminates with a data + overrun error. + + Write transfers set the initial SRQ to request words from the CPU. As each + arrives, it is unloaded from the FIFO into the sector buffer, and SRQ is + enabled. If the current sector transfer is complete, the controller is moved + to the end phase. If the FIFO underflows, the write terminates with a data + overrun error. + + The synchronous nature of the disc drive requires that data be supplied or + accepted continuously by the CPU. DCPC generally assures that this occurs, + and the FIFO allows for some latency before an overrun or underrun occurs. + + The other operation the interface must handle is seek completion. The + controller handles seek completion by setting Attention status in the drive's + status word. The interface is responsible for polling the drives if the + controller is idle and interrupts are enabled. + + + Implementation notes: + + 1. Every command except Seek, Recalibrate, and End set the flag when the + command completes. A command completes when the controller is no longer + busy (it becomes idle for Seek, Recalibrate, and End, and becomes waiting + for all others). Seek and Recalibrate may generate errors (e.g., heads + unloaded), in which case the flag must be set. But in these cases, the + controller state is waiting, not idle. + + However, it is insufficient simply to check that the controller has moved + to the wait state, because a seek may complete while the controller is + waiting for the next command. For example, a Seek is started on unit 0, + and the controller moves to the idle state. But before the seek + completes, another command is issued that attempts to access unit 1, + which is not ready. The command fails with a Status-2 error, and the + controller moves to the wait state. When the seek completes, the + controller is waiting with error status. We must determine if the seek + completed successfully or not, as we must interrupt in the latter case. + + Therefore, we determine seek completion by checking if the Attention + status was set. Attention sets only if the seek completes successfully. + + (Actually, Attention sets if a seek check occurs, but in that case, the + command terminated before the seek ever started. Also, a seek may + complete while the controller is busy, waiting, or idle.) + + 2. For debug printouts, we want to print the name of the command that has + completed when the controller returns to the idle or wait state. + Normally, we would use the controller's "opcode" field to identify the + command that completed. However, while waiting for Seek or Recalibrate + completion, "opcode" may be set to another command if that command does + not access this drive. For example, it might be set to a Read of + another unit, or a Request Status for this unit. So we can't rely on + "opcode" to report the correct positioning command completion. + + However, we cannot rely on "uptr->OP" either, as it can be changed + during the course of a command. For example, Read Without Verify is + changed to Read after a track crossing. + + Instead, we have to determine whether a seek is completing. If it is, + then we report "uptr->OP"; otherwise, we report "opcode". + + 3. The initial write SRQ must set only at the transition from the start + phase to the data phase. If a write command begins with an auto-seek, + the drive service will be entered twice in the start phase (the first + entry performs the seek, and the second begins the write). In hardware, + SRQ does not assert until the write begins. + + 4. The DCPC EDT signal cannot set the controller's end-of-data flag + directly because a write EOD must only occur after the FIFO has been + drained. */ -void ds_poll (void) +t_stat ds_service_drive (UNIT *uptr) { -if ((ds_state != DS_BUSY) && ds_cmdp) /* cmd pending? */ - ds_docmd (ds_cmd); /* do it */ -if ((ds_state == DS_IDLE) && ds.control) /* idle? */ - ds_doatn (); /* check ATN */ -return; -} +static const char completion_message [] = ">>DS rwsc: Unit %d %s command completed\n"; +t_stat result; +t_bool seek_completion; +FLIP_FLOP entry_srq = ds.srq; /* SRQ state on entry */ +CNTLR_PHASE entry_phase = (CNTLR_PHASE) uptr->PHASE; /* operation phase on entry */ +uint32 entry_status = uptr->STAT; /* drive status on entry */ +result = dl_service_drive (&mac_cntlr, uptr); /* service the drive */ -/* Process a command - ctrl state is either IDLE or WAIT. +if ((CNTLR_PHASE) uptr->PHASE == data_phase) /* is the drive in the data phase? */ + switch ((CNTLR_OPCODE) uptr->OP) { /* dispatch the current operation */ - - A drive may be processing a seek or recalibrate - - The controller unit is idle - - If the command can be processed, ds_state is set to BUSY, and - the interface command buffer is cleared - - If the command cannot be processed, ds_state is set to WAIT, - and the command is retained in the interface command buffer */ - -void ds_docmd (uint32 cmd) -{ -uint32 op, f, unum; - -op = DSC_GETOP (cmd); /* operation */ -f = ds_opflags[op]; /* flags */ -if (op == DSC_COLD) unum = 0; /* boot force unit 0 */ -else unum = DSC_GETUNIT (cmd); /* get unit */ -if ((f & CMF_UIDLE) && (unum < DS_NUMDR) && /* idle required */ - sim_is_active (&ds_unit[unum])) { /* but unit busy? */ - ds_state = DS_WAIT; /* wait */ - return; - } -ds_cmdp = 0; /* flush command */ -ds_state = DS_BUSY; /* ctrl is busy */ -if (f & CMF_CLRS) ds_sr1 = 0; /* clear status */ -if (f & CMF_CLREC) ds_eoc = 0; /* clear end cyl */ -if (f & CMF_UNDF) { /* illegal op? */ - ds_sched_ctrl_op (DSC_BADF, 0, CLR_BUSY); /* sched, clr busy */ - return; - } -switch (op) { - -/* Drive commands */ - - case DSC_COLD: /* cold load read */ - ds_fmask = DSC_SPEN; /* sparing enabled */ - ds_cyl = 0; /* cylinder 0 */ - ds_hs = (DSC_GETCHD (ds_cmd) << DSHS_V_HD) | /* reformat hd/sec */ - (DSC_GETCSC (ds_cmd) << DSHS_V_SC); - case DSC_RECAL: /* recalibrate */ - case DSC_SEEK: /* seek */ - case DSC_RSA: /* read sector address */ - case DSC_READ: /* read */ - case DSC_RFULL: /* read full */ - case DSC_ROFF: /* read offset */ - case DSC_RNOVFY: /* read no verify */ - case DSC_VFY: /* verify */ - case DSC_WRITE: /* write */ - case DSC_WFULL: /* write full */ - case DSC_INIT: /* init */ - ds_sr1 = unum; /* init status */ - if (unum >= DS_NUMDR) { /* invalid unit? */ - ds_sched_ctrl_op (DSC_BADU, unum, CLR_BUSY);/* sched, not busy */ - return; - } - if (op == DSC_INIT) ds_sr1 |= /* init? */ - ((cmd & DSC_SPAR)? DS1_SPAR: 0) | /* copy SPD to stat1 */ - ((cmd & DSC_PROT)? DS1_PROT: 0) | - ((cmd & DSC_DFCT)? DS1_DFCT: 0); - ds_unit[unum].FNC = op; /* save op */ - ds_unit[unum].STA &= ~DS2_ATN; /* clear ATN */ - sim_cancel (&ds_unit[unum]); /* cancel current */ - sim_activate (&ds_unit[unum], ds_ctime); /* schedule unit */ - ds_busy = 1; /* set visible busy */ - break; - -/* Read status commands */ - - case DSC_RSTA: /* read status */ - dsxb[1] = ds_sr1; /* return SR1 */ - ds_sr1 = 0; /* clear SR1 */ - if (unum < DS_NUMDR) { /* return SR2 */ - dsxb[0] = ds_updds2 (&ds_unit[unum]); - ds_unit[unum].STA &= ~DS2_FS; /* clear 1st */ - } - else dsxb[0] = DS2_ERR|DS2_NR; - ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */ - break; - - case DSC_RDA: /* read disk address */ - ds_reqad (&dsxb[1], &dsxb[0]); /* return disk address */ - ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */ - break; - - case DSC_RSYN: /* read syndrome */ - dsxb[6] = ds_sr1; /* return SR1 */ - ds_reqad (&dsxb[5], &dsxb[4]); /* return disk address */ - dsxb[3] = dsxb[2] = dsxb[1] = dsxb[0] = 0; /* syndrome is 0 */ - ds_sched_ctrl_op (DSC_RSTA, 7, SET_BUSY); /* sched 7 wds, busy */ - break; - -/* Other controller commands */ - - case DSC_WAKE: /* wakeup */ - ds_sr1 = unum; /* init status */ - if (unum >= DS_NUMDR) { /* invalid unit? */ - ds_sched_ctrl_op (DSC_BADU, unum, CLR_BUSY);/* sched, not busy */ - return; - } - case DSC_SFM: /* set file mask */ - case DSC_CLEAR: /* clear */ - case DSC_AREC: /* address record */ - case DSC_WTIO: /* write TIO */ - ds_sched_ctrl_op (op, 0, SET_BUSY); /* schedule, busy */ - break; - - case DSC_END: /* end */ - ds_set_idle (); /* idle ctrl */ - break; - } - -return; -} - - -/* Check for attention */ - -void ds_doatn (void) -{ -uint32 i; - -for (i = 0; i < DS_NUMDR; i++) { /* intr disabled? */ - ds_lastatn = (ds_lastatn + 1) & DS_DRMASK; /* loop through units */ - if (ds_unit[ds_lastatn].STA & DS2_ATN) { /* ATN set? */ - ds_unit[ds_lastatn].STA &= ~DS2_ATN; /* clear ATN */ - dsio (&ds_dib, ioENF, 0); /* request interrupt */ - ds_sr1 = DS1_ATN | ds_lastatn; /* set up status 1 */ - ds_state = DS_WAIT; /* block atn intrs */ - return; - } - } -return; -} - - -/* Controller service - - The argument for the function, if any, is stored in uptr->CYL */ - -t_stat ds_svc_c (UNIT *uptr) -{ -uint32 op; - -op = uptr->FNC; -switch (op) { - - case DSC_AREC: /* address record */ - ds_wait_for_cpu (uptr, DSC_AREC|DSC_2ND); /* set flag, new state */ - break; - case DSC_AREC | DSC_2ND: /* poll done */ - if (!DS_FIFO_EMPTY) { /* OTA ds? */ - ds_cyl = ds_fifo_read (); /* save cylinder */ - ds_wait_for_cpu (uptr, DSC_AREC|DSC_3RD); /* set flag, new state */ - } - else sim_activate (uptr, ds_ctime); /* no, continue poll */ - break; - case DSC_AREC | DSC_3RD: /* poll done */ - if (!DS_FIFO_EMPTY) { /* OTA ds? */ - ds_hs = ds_fifo_read (); /* save head/sector */ - ds_cmd_done (0, DS1_OK); /* op done, no flag */ - } - else sim_activate (uptr, ds_ctime); /* no, continue poll */ - break; - - case DSC_RSTA: /* rd stat (all forms) */ - if (DS_FIFO_EMPTY) { /* fifo empty? */ - uptr->CYL--; - ds_fifo_write (dsxb[uptr->CYL]); /* store next status */ - ds_wait_for_cpu (uptr, DSC_RSTA | - (uptr->CYL? 0: DSC_2ND)); /* set flag, new state */ - } - else sim_activate (uptr, ds_ctime); /* no, continue poll */ - break; - case DSC_RSTA | DSC_2ND: /* poll done */ - if (DS_FIFO_EMPTY) ds_cmd_done (0, DS1_OK); /* op done? no flag */ - else sim_activate (uptr, ds_ctime); /* no, continue poll */ - break; - - case DSC_CLEAR: /* clear */ - ds_clear (); /* reset ctrl */ - - ds.control = CLEAR; /* clear CTL, SRQ */ - ds.srq = CLEAR; - dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ - - ds_cmd_done (1, DS1_OK); /* op done, set flag */ - break; - - case DSC_SFM: /* set file mask */ - ds_fmask = ds_cmd & DSC_FMASK; - ds_cmd_done (1, DS1_OK); /* op done, set flag */ - break; - - case DSC_WTIO: /* write I/O */ - ds_cmd_done (0, DS1_OK); /* op done, no flag */ - break; - - case DSC_WAKE: /* wakeup */ - ds_cmd_done (1, DS1_AVAIL); /* op done, set flag */ - break; - - case DSC_BADU: /* invalid unit */ - if (uptr->CYL > 10) ds_cmd_done (1, DS1_UNAVL); /* [11,16]? bad unit */ - else ds_cmd_done (1, DS1_S2ERR); /* else unit not ready */ - break; - - case DSC_BADF: /* invalid operation */ - ds_cmd_done (1, DS1_ILLOP); /* op done, set flag */ - break; - - default: - return SCPE_IERR; - } - -ds_poll (); /* run the controller */ -return SCPE_OK; -} - - -/* Timeout service */ - -t_stat ds_svc_t (UNIT *uptr) -{ -int32 i; - -for (i = 0; i < (DS_NUMDR + 1); i++) /* cancel all ops */ - sim_cancel (&ds_unit[i]); -ds_set_idle (); /* idle the controller */ -ds_fmask = 0; /* clear file mask */ -ds_poll (); /* run the controller */ -return SCPE_OK; -} - - -/* Unit service */ - -t_stat ds_svc_u (UNIT *uptr) -{ -uint32 op, dtyp; -t_stat r; - -op = uptr->FNC; -dtyp = GET_DTYPE (uptr->flags); - -switch (op) { /* case on function */ - -/* Seek and recalibrate */ - - case DSC_RECAL: /* recalibrate */ - if ((uptr->flags & UNIT_UNLOAD) == 0) { /* drive up? */ - ds_start_seek (uptr, 0, DSC_RECAL|DSC_2ND); /* set up seek */ - ds_set_idle (); /* ctrl is idle */ - } - else ds_cmd_done (1, DS1_S2ERR); /* not ready error */ - break; - case DSC_RECAL | DSC_2ND: /* recal complete */ - uptr->STA = uptr->STA | DS2_ATN; /* set attention */ - break; - - case DSC_SEEK: /* seek */ - ds_wait_for_cpu (uptr, DSC_SEEK|DSC_2ND); /* set flag, new state */ - break; - case DSC_SEEK | DSC_2ND: /* waiting for word 1 */ - if (!DS_FIFO_EMPTY) { /* OTA ds? */ - ds_cyl = ds_fifo_read (); /* save cylinder */ - ds_wait_for_cpu (uptr, DSC_SEEK|DSC_3RD); /* set flag, new state */ - } - else sim_activate (uptr, ds_ctime); /* no, continue poll */ - break; - case DSC_SEEK | DSC_3RD: /* waiting for word 2 */ - if (!DS_FIFO_EMPTY) { /* OTA ds? */ - ds_hs = ds_fifo_read (); /* save head/sector */ - if ((uptr->flags & UNIT_UNLOAD) == 0) { /* drive up? */ - ds_start_seek (uptr, ds_cyl, DSC_SEEK|DSC_4TH); /* set up seek */ - ds_set_idle (); /* ctrl is idle */ + case read: /* read operations */ + case read_full_sector: + case read_with_offset: + case read_without_verify: + if (mac_cntlr.length == 0 || ds.edt == SET) { /* is the data phase complete? */ + mac_cntlr.eod = ds.edt; /* set EOD if DCPC is done */ + uptr->PHASE = end_phase; /* set the end phase */ + uptr->wait = mac_cntlr.cmd_time; /* and schedule the controller */ } - else ds_cmd_done (1, DS1_S2ERR); /* else not ready error */ - } - else sim_activate (uptr, ds_ctime); /* continue poll */ - break; - case DSC_SEEK | DSC_4TH: /* seek complete */ - uptr->STA = uptr->STA | DS2_ATN; /* set attention */ - break; -/* Read variants */ + else if (FIFO_FULL) /* is the FIFO already full? */ + dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an overrun */ - case DSC_RSA: /* read sector address */ - if ((uptr->flags & UNIT_UNLOAD) == 0) { /* drive up? */ - dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */ - ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */ - } - else /* no drive or heads unloaded */ - ds_cmd_done (1, DS1_S2ERR); /* not ready error */ - break; + else { + fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */ + mac_cntlr.length--; /* count it */ + ds.srq = SET; /* ask DCPC to pick it up */ + ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ + uptr->wait = mac_cntlr.data_time; /* schedule the next data transfer */ + } - case DSC_ROFF: /* read with offset */ - ds_wait_for_cpu (uptr, DSC_ROFF|DSC_2ND); /* set flag, new state */ - break; - case DSC_ROFF | DSC_2ND: /* poll done */ - if (!DS_FIFO_EMPTY) { /* OTA ds? new state */ - ds_fifo_read (); /* drain fifo */ - uptr->FNC = DSC_READ; - dsio (&ds_dib, ioENF, 0); /* handshake */ - } - sim_activate (uptr, ds_ctime); /* schedule unit */ - break; - - case DSC_COLD: /* cold load read */ - if ((uptr->flags & UNIT_UNLOAD) == 0) /* drive up? */ - ds_start_seek (uptr, 0, DSC_READ); /* set up seek */ - else ds_cmd_done (1, DS1_S2ERR); /* no, not ready error */ - break; - - case DSC_READ: /* read */ - if (r = ds_start_rd (uptr, 0, 1)) return r; /* new sector; error? */ - break; - case DSC_READ | DSC_2ND: /* word transfer */ - ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */ - break; - case DSC_READ | DSC_3RD: /* end of sector */ - ds_end_rw (uptr, DSC_READ); /* see if more to do */ - break; - - case DSC_RNOVFY: /* read, no verify before xfer */ - if (r = ds_start_rd (uptr, 0, 0)) return r; /* new sector; error? */ - break; - case DSC_RNOVFY | DSC_2ND: /* word transfer */ - ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */ - break; - case DSC_RNOVFY | DSC_3RD: /* end of sector */ - ds_end_rw (uptr, /* see if more to do */ - DSHS_GETSC (ds_hs) ? DSC_RNOVFY : DSC_READ); /* start verifying if end of track */ - break; - - case DSC_RFULL: /* read full */ - dsxb[DS_FSYNC] = 0100376; /* fill in header */ - dsxb[DS_FCYL] = uptr->CYL; - dsxb[DS_FHS] = ds_hs; /* before h/s update */ - if (r = ds_start_rd (uptr, DS_FDATA, 0)) /* new sector; error? */ - return r; - break; - case DSC_RFULL | DSC_2ND: /* word transfer */ - ds_cont_rd (uptr, DS_NUMWDF); /* xfr wd, check end */ - break; - case DSC_RFULL | DSC_3RD: /* end of sector */ - ds_end_rw (uptr, DSC_RFULL); /* see if more to do */ - break; - - case DSC_VFY: /* verify */ - ds_wait_for_cpu (uptr, DSC_VFY|DSC_2ND); /* set flag, new state */ - break; - case DSC_VFY | DSC_2ND: /* poll done */ - if (!DS_FIFO_EMPTY) { /* OTA ds? */ - ds_vctr = ds_fifo_read (); /* save count */ - uptr->FNC = DSC_VFY | DSC_3RD; /* next state */ - sim_activate (uptr, ds_rtime); /* delay for transfer */ - } - else sim_activate (uptr, ds_ctime); /* no, continue poll */ - break; - case DSC_VFY | DSC_3RD: /* start sector */ - if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) /* new sector; error? */ break; - ds_next_sec (uptr); /* increment hd, sc */ - break; - case DSC_VFY | DSC_4TH: /* end sector */ - ds_vctr = (ds_vctr - 1) & DMASK; /* decrement count */ - if (ds_vctr) ds_end_rw (uptr, DSC_VFY|DSC_3RD); /* more to do? */ - else ds_cmd_done (1, DS1_OK); /* no, set done */ - break; -/* Write variants */ - case DSC_WRITE: /* write */ - ds_start_wr (uptr, 1); /* new sector */ - break; - case DSC_WRITE | DSC_2ND: - if (r = ds_cont_wr (uptr, 0, DS_NUMWD)) /* write word */ - return r; /* error? */ - break; - case DSC_WRITE | DSC_3RD: /* end sector */ - ds_end_rw (uptr, DSC_WRITE); /* see if more to do */ - break; + case write: /* write operations */ + case write_full_sector: + case initialize: + if (entry_phase == start_phase) { /* is this the phase transition? */ + ds.srq = SET; /* start the DCPC transfer */ + ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ + } - case DSC_INIT: /* init */ - ds_start_wr (uptr, 0); /* new sector */ - break; - case DSC_INIT | DSC_2ND: - if (r = ds_cont_wr (uptr, 0, DS_NUMWD)) /* write word */ - return r; /* error? */ - break; - case DSC_INIT | DSC_3RD: /* end sector */ - ds_end_rw (uptr, DSC_INIT); /* see if more to do */ - break; + else if (FIFO_EMPTY) /* is the FIFO empty? */ + dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an underrun */ - case DSC_WFULL: /* write full */ - ds_start_wr (uptr, 0); /* new sector */ - break; - case DSC_WFULL | DSC_2ND: - if (r = ds_cont_wr (uptr, DS_FDATA, DS_NUMWDF)) /* write word */ - return r; /* error */ - break; - case DSC_WFULL | DSC_3RD: - ds_end_rw (uptr, DSC_WFULL); /* see if more to do */ - break; + else { + buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */ + mac_cntlr.length--; /* count it */ - default: - break; - } + if (ds.edt == SET && FIFO_EMPTY) /* if DCPC is complete and the FIFO is empty */ + mac_cntlr.eod = SET; /* then set the end-of-data flag */ -ds_poll (); -return SCPE_OK; + if (mac_cntlr.length == 0 || mac_cntlr.eod == SET) { /* is the data phase complete? */ + uptr->PHASE = end_phase; /* set the end phase */ + uptr->wait = mac_cntlr.cmd_time; /* and schedule the controller */ + } + + else { + if (ds.edt == CLEAR) { /* if DCPC is still transferring */ + ds.srq = SET; /* then request the next word */ + ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ + } + + uptr->wait = mac_cntlr.data_time; /* schedule the next data transfer */ + } + } + + break; + + + default: /* entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of data phase operation dispatch */ + + +if (DEBUG_PRI (ds_dev, DEB_CMDS) && entry_srq != ds.srq) + fprintf (sim_deb, ">>DS cmds: SRQ %s\n", ds.srq == SET ? "set" : "cleared"); + + +if (uptr->wait) /* is service requested? */ + activate_unit (uptr); /* schedule the next event */ + +seek_completion = ~entry_status & uptr->STAT & DL_S2ATN; /* seek is complete when Attention sets */ + +if (mac_cntlr.state != cntlr_busy) { /* is the command complete? */ + if (mac_cntlr.state == cntlr_wait && !seek_completion) /* is it command and not seek completion? */ + ds_io (&ds_dib, ioENF, 0); /* set the data flag to interrupt the CPU */ + + poll_interface (); /* poll the interface for the next command */ + poll_drives (); /* poll the drives for Attention */ + } + + +if (DEBUG_PRI (ds_dev, DEB_RWSC)) + if (result == SCPE_IERR) /* did an internal error occur? */ + fprintf (sim_deb, ">>DS rwsc: Unit %d %s command %s phase service not handled\n", + uptr - ds_dev.units, + dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP), + dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); + + else if (seek_completion) /* if a seek has completed */ + fprintf (sim_deb, completion_message, /* report the unit command */ + uptr - ds_dev.units, + dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP)); + + else if (mac_cntlr.state == cntlr_wait) /* if the controller has stopped */ + fprintf (sim_deb, completion_message, /* report the controller command */ + uptr - ds_dev.units, + dl_opcode_name (MAC, mac_cntlr.opcode)); + +return result; /* return the result of the service */ } -/* Schedule timed wait for CPU response +/* Service the controller unit. - - Set flag to get CPU attention - - Set specified unit to 'newstate' and schedule - - Schedule timeout */ + The controller service routine is called to execute scheduled controller + commands that do not access drive units. It is also called to obtain command + parameters from the interface and to return command result values to the + interface. -void ds_wait_for_cpu (UNIT *uptr, uint32 newst) -{ -dsio (&ds_dib, ioENF, 0); /* set flag */ -uptr->FNC = newst; /* new state */ -sim_activate (uptr, ds_ctime); /* activate unit */ -sim_cancel (&ds_timer); /* activate timeout */ -sim_activate (&ds_timer, ds_tmo); -return; -} + Most controller commands are handled completely in the library's service + routine, so we call that first. Commands that neither accept nor supply + parameters are complete when the library routine returns, so all we have to + do is set the interface flag if required. + + For parameter transfers in the data phase, the interface is responsible for + moving words between the sector buffer and the FIFO and setting the flag to + notify the CPU. -/* Set idle state + Implementation notes: - - Controller is set to idle state - - Visible busy is cleared - - Timeout is cancelled */ + 1. In hardware, the Read With Offset command sets the data flag after the + offset parameter has been read and the head positioner has been moved by + the indicated amount. The intent is to delay the DCPC start until the + drive is ready to supply data from the disc. -void ds_set_idle (void) -{ -ds_busy = 0; /* busy clear */ -ds_state = DS_IDLE; /* ctrl idle */ -sim_cancel (&ds_timer); /* no timeout */ -return; -} - - -/* Set wait state - - - Set flag if required - - Set controller to wait state - - Clear visible busy - - Schedule timeout */ - -void ds_cmd_done (t_bool sf, uint32 sr1) -{ -if (sf) /* set host flag? */ - dsio (&ds_dib, ioENF, 0); /* set flag */ - -ds_busy = 0; /* clear visible busy */ -ds_sr1 = ds_sr1 | sr1; /* final status */ -ds_state = DS_WAIT; /* ctrl waiting */ -sim_cancel (&ds_timer); /* activate timeout */ -sim_activate (&ds_timer, ds_tmo); -return; -} - - -/* Return drive status (status word 2). - - In hardware, the controller outputs the Address Unit command on the drive tag - bus and the unit number on the drive control bus. The addressed drive - responds by setting its internal "selected" flag. The controller then - outputs Request Status on the tag bug. If a drive is selected but the heads - are unloaded, the drive returns Not Ready and Busy status on the control bus. - If no drive is selected, the control bus floats inactive. This is - interpreted by the controller as Not Ready status (because the drive returns - inactive Ready status). - - Under simulation, an enabled but detached unit corresponds to "selected but - heads unloaded," and a disabled unit corresponds to a non-existent unit. + In simulation, the flag is set as soon as the parameter is received. */ -uint32 ds_updds2 (UNIT *uptr) +t_stat ds_service_controller (UNIT *uptr) { -uint32 sta; -uint32 dtyp = GET_DTYPE (uptr->flags); +t_stat result; +const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; -sta = drv_tab[dtyp].id | /* form status */ - uptr->STA | /* static bits */ - ((uptr->flags & UNIT_WPR) ? DS2_RO : 0) | /* dynamic bits */ - ((uptr->flags & UNIT_FMT) ? DS2_FRM : 0) | - ((uptr->flags & UNIT_DIS) ? DS2_NR : - (uptr->flags & UNIT_UNLOAD) ? DS2_NR | DS2_BS : 0) | - (sim_is_active (uptr) ? DS2_BS : 0); -if (sta & DS2_ALLERR) sta = sta | DS2_ERR; /* set error */ -return sta; -} +result = dl_service_controller (&mac_cntlr, uptr); /* service the controller */ + +switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current phase */ + + case start_phase: /* most controller operations */ + case end_phase: /* start and end on the same phase */ + switch (opcode) { /* dispatch the current operation */ + + case request_status: + case request_sector_address: + case address_record: + case request_syndrome: + case load_tio_register: + case request_disc_address: + case end: + break; /* complete the operation without setting the flag */ -/* Schedule controller operation */ - -void ds_sched_ctrl_op (uint32 op, uint32 arg, uint32 busy) -{ -ds_ctrl.FNC = op; /* save op */ -ds_ctrl.CYL = arg; /* save argument */ -ds_busy = busy; /* set visible busy */ -sim_activate (&ds_ctrl, ds_ctime); /* schedule */ -sim_cancel (&ds_timer); /* activate timeout */ -sim_activate (&ds_timer, ds_tmo); -return; -} + case clear: + case set_file_mask: + case wakeup: + ds_io (&ds_dib, ioENF, 0); /* complete the operation with the flag set */ + break; -/* Request address - if pending eoc, report cylinder + 1 */ - -void ds_reqad (uint16 *cyl, uint16 *hs) -{ -*cyl = ds_cyl + (ds_eoc? 1: 0); -*hs = ds_hs; -return; -} + default: /* entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of start and end phase handlers */ -/* Start seek - schedule whether in bounds or out of bounds */ + case data_phase: + switch (opcode) { /* dispatch the current operation */ -void ds_start_seek (UNIT *uptr, uint32 cyl, uint32 newst) -{ -int32 t; -uint32 hd, sc; -uint32 dtyp = GET_DTYPE (uptr->flags); + case seek: /* operations that accept parameters */ + case verify: + case address_record: + case read_with_offset: + case load_tio_register: + buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */ + mac_cntlr.length--; /* count it */ -uptr->FNC = newst; /* set new state */ -if (cyl >= drv_tab[dtyp].cyl) { /* out of bounds? */ - t = 0; /* don't change cyl */ - uptr->STA = uptr->STA | DS2_SC; /* set seek check */ + if (mac_cntlr.length) /* are there more words to transfer? */ + ds_io (&ds_dib, ioENF, 0); /* set the flag to request the next one */ + + else { /* all parameters have been received */ + uptr->PHASE = end_phase; /* set the end phase */ + + if (opcode == read_with_offset) /* a Read With Offset command sets the flag */ + ds_io (&ds_dib, ioENF, 0); /* to indicate that offsetting is complete */ + + start_command (); /* the command is now ready to execute */ + } + break; + + + case request_status: /* operations that supply parameters */ + case request_sector_address: + case request_syndrome: + case request_disc_address: + if (mac_cntlr.length) { /* are there more words to return? */ + fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */ + mac_cntlr.length--; /* count it */ + + ds_io (&ds_dib, ioENF, 0); /* set the flag to request pickup by the CPU */ + } + + else { /* all parameters have been sent */ + uptr->PHASE = end_phase; /* set the end phase */ + uptr->wait = mac_cntlr.cmd_time; /* schedule the controller */ + activate_unit (uptr); /* to complete the command */ + } + break; + + + default: /* entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of data phase handlers */ + } /* end of phase dispatch */ + + +if (result == SCPE_IERR && DEBUG_PRI (ds_dev, DEB_RWSC)) /* did an internal error occur? */ + fprintf (sim_deb, ">>DS rwsc: Controller %s command %s phase service not handled\n", + dl_opcode_name (MAC, opcode), dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); + + +if (mac_cntlr.state != cntlr_busy) { /* has the controller stopped? */ + poll_interface (); /* poll the interface for the next command */ + poll_drives (); /* poll the drives for Attention status */ + + if (DEBUG_PRI (ds_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DS rwsc: Controller %s command completed\n", + dl_opcode_name (MAC, opcode)); } -else { - t = abs (uptr->CYL - cyl); /* delta cylinders */ - uptr->CYL = cyl; /* put on cylinder */ - hd = DSHS_GETHD (ds_hs); /* invalid head or sec? */ - sc = DSHS_GETSC (ds_hs); - if ((hd >= drv_tab[dtyp].hd) || - (sc >= drv_tab[dtyp].sc)) - uptr->STA = uptr->STA | DS2_SC; /* set seek check */ - else uptr->STA = uptr->STA & ~DS2_SC; /* clear seek check */ - } -sim_activate (uptr, ds_stime * (t + 1)); /* schedule */ -return; + +return result; /* return the result of the service */ } -/* Start next sector for read or write +/* Service the command wait timer unit. - - If error, set command done, return TRUE, nothing is scheduled - - If implicit seek, return TRUE, implicit seek is scheduled, but - state is not changed - we will return here when seek is done - - Otherwise, advance state, set position in file, schedule next state - - If a an auto-seek was done, it may have incremented or decremented beyond the - cylinder bounds. If so, then Seek Check status will have been set. If we - see that, terminate the current command with a Status-2 error. + The command wait timer service routine is called if the command wait timer + expires. The library is called to reset the file mask and idle the + controller. Then the interface is polled for a command and the drives are + polled for Attention status. */ -t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy) +t_stat ds_service_timer (UNIT *uptr) { -uint32 da, hd, sc; -uint32 dtyp = GET_DTYPE (uptr->flags); +t_stat result; -ds_eod = 0; /* init eod */ -ds_ptr = 0; /* init buffer ptr */ -if (uptr->flags & UNIT_UNLOAD | uptr->STA & DS2_SC) { /* drive down or seek check? */ - ds_cmd_done (1, DS1_S2ERR); /* report Status-2 error */ - return TRUE; - } -if (ds_eoc) { /* at end of cylinder? */ - ds_next_cyl (uptr); /* auto seek to next */ - return TRUE; /* or error */ - } -if (vfy && ((uint32) uptr->CYL != ds_cyl)) { /* on wrong cylinder? */ - ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek right cyl */ - return TRUE; - } -hd = DSHS_GETHD (ds_hs); -sc = DSHS_GETSC (ds_hs); -if (((uint32) uptr->CYL >= drv_tab[dtyp].cyl) || /* valid cylinder? (sanity check) */ - (hd >= drv_tab[dtyp].hd) || /* valid head, sector? */ - (sc >= drv_tab[dtyp].sc)) { - uptr->STA = uptr->STA | DS2_SC; /* set seek check */ - ds_cmd_done (1, DS1_S2ERR); /* report Status-2 error */ - return TRUE; - } -da = GET_DA (uptr->CYL, hd, sc, dtyp); /* position in file */ -sim_fseek (uptr->fileref, da * sizeof (uint16), SEEK_SET); /* set file pos */ -uptr->FNC += DSC_NEXT; /* next state */ -sim_activate (uptr, tm); /* activate unit */ -return FALSE; +result = dl_service_timer (&mac_cntlr, uptr); /* service the timer */ + +poll_interface (); /* poll the interface for the next command */ +poll_drives (); /* poll the drives for Attention status */ + +return result; /* return the result of the service */ } -/* Start next sector for read +/* Reset the simulator. - - Do common start for read and write - - If error, return, command has been terminated, nothing scheduled - - If implicit seek, return, seek scheduled - - If no error or seek, state has been advanced and unit scheduled - - Read sector - - If read error, terminate command and return, nothing scheduled - - If no error, advance head/sector, next state scheduled */ - -t_stat ds_start_rd (UNIT *uptr, uint32 off, t_bool vfy) -{ -uint32 t; - -if (ds_start_rw (uptr, ds_rtime, vfy)) return SCPE_OK; /* new sec; err or seek? */ -t = sim_fread (dsxb + off, sizeof (uint16), DS_NUMWD, uptr->fileref); -for (t = t + off ; t < DS_NUMWDF; t++) dsxb[t] = 0; /* fill sector */ -if (ferror (uptr->fileref)) /* error? */ - return ds_set_uncorr (uptr); /* say uncorrectable */ -ds_next_sec (uptr); /* increment hd, sc */ -return SCPE_OK; -} + In hardware, the PON signal clears the Interface Selected flip-flop, + disconnecting the interface from the disc controller. In simulation, the + interface always remains connected to the controller, so no special action is + needed. -/* Start next sector for write + Implementation notes: - - Do common start for read and write - - If error, return, command has been terminated, nothing scheduled - - If implicit seek, return, seek scheduled - - If no error or seek, state has been advanced and unit scheduled - - Clear buffer - - Set service request */ + 1. During a power-on reset, a pointer to the FIFO simulation register is + saved to allow access to the "qptr" field during FIFO loading and + unloading. This enables the SCP to view the FIFO as a circular queue, so + that the bottom word of the FIFO is always displayed as FIFO[0], + regardless of where it is in the actual FIFO array. -void ds_start_wr (UNIT *uptr, t_bool vfy) -{ -uint32 i; - -if ((uptr->flags & UNIT_WPR) || /* write protected? */ - (!vfy && ((uptr->flags & UNIT_FMT) == 0))) { /* format, not enbl? */ - ds_cmd_done (1, DS1_S2ERR); /* error */ - return; - } -if (ds_start_rw (uptr, ds_rtime, vfy)) return; /* new sec; err or seek? */ -for (i = 0; i < DS_NUMWDF; i++) dsxb[i] = 0; /* clear buffer */ -ds.srq = SET; /* request word */ -dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ -return; -} - - -/* Advance to next sector (but not next cylinder) */ - -void ds_next_sec (UNIT *uptr) -{ -uint32 dtyp = GET_DTYPE (uptr->flags); - -ds_hs = ds_hs + 1; /* increment sector */ -if (DSHS_GETSC (ds_hs) < drv_tab[dtyp].sc) return; /* end of track? */ -ds_hs = ds_hs & ~DSHS_SC; /* yes, wrap sector */ -if (ds_fmask & DSC_CYLM) { /* cylinder mode? */ - ds_hs = ds_hs + (1 << DSHS_V_HD); /* increment head */ - if (DSHS_GETHD (ds_hs) < drv_tab[dtyp].hd) return; /* end of cyl? */ - ds_hs = ds_hs & ~DSHS_HD; /* 0 head */ - } -ds_eoc = 1; /* flag end cylinder */ -return; -} - - -/* Advance to next cylinder - - - If autoseek enabled, seek to cylinder +/- 1 - - Otherwise, done with end of cylinder error. - - If we exceed the cylinder range, the seek will set Seek Check status. -*/ - -void ds_next_cyl (UNIT *uptr) -{ -if (ds_fmask & DSC_AUTO) { /* auto seek allowed? */ - if (ds_fmask & DSC_DECR) ds_cyl = (ds_cyl - 1) & DMASK; - else ds_cyl = (ds_cyl + 1) & DMASK; - ds_eoc = 0; /* clear end cylinder */ - ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek, same state */ - } -else ds_cmd_done (1, DS1_EOCYL); /* no, end of cyl err */ -return; -} - - -/* Transfer word for read - - - If end of data, terminate command, nothing scheduled - - Otherwise, transfer word, advance state if last word, schedule */ - -void ds_cont_rd (UNIT *uptr, uint32 bsize) -{ -if (ds_eod) ds_cmd_done (1, DS1_OK); /* DMA end? done */ -else if (ds.srq) { /* overrun? */ - ds_cmd_done (1, DS1_OVRUN); /* set done */ - return; - } -else { - ds_fifo_write (dsxb[ds_ptr++]); /* next word */ - ds.srq = SET; /* request service */ - dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ - if (ds_ptr >= bsize) uptr->FNC += DSC_NEXT; /* sec done? next state */ - sim_activate (uptr, ds_dtime); /* schedule */ - } -return; -} - - -/* Transfer word for write - - - Copy word from fifo to buffer - - If end of data, write buffer, terminate command, nothing scheduled - - If end of sector, write buffer, next state, schedule - - Otherwise, set service request, schedule */ - -t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize) -{ -uint32 i, dat; - -if (ds.srq) { /* overrun? */ - ds_cmd_done (1, DS1_OVRUN); /* set done */ - return SCPE_OK; - } -dsxb[ds_ptr++] = dat = ds_fifo_read (); /* next word */ -if (ds_eod || (ds_ptr >= bsize)) { /* xfr or sector done? */ - for (i = ds_ptr; i < bsize; i++) dsxb[i] = dat; /* fill sector */ - sim_fwrite (dsxb + off, sizeof (uint16), DS_NUMWD, uptr->fileref); - if (ferror (uptr->fileref)) /* error on write? */ - return ds_set_uncorr (uptr); /* uncorrectable */ - ds_next_sec (uptr); /* increment hd, sc */ - if (ds_eod) { /* end data? */ - ds_cmd_done (1, DS1_OK); /* set done */ - return SCPE_OK; - } - else uptr->FNC += DSC_NEXT; /* no, next state */ - } -else { - ds.srq = SET; /* request next word */ - dsio (&ds_dib, ioSIR, 0); /* set interrupt request */ - } -sim_activate (uptr, ds_dtime); /* schedule */ -return SCPE_OK; -} - - -/* End sector for read or write - - - If end of data, terminate command, nothing scheduled - - If end of cylinder, schedule next cylinder - - Else schedule start of next sector */ - -void ds_end_rw (UNIT *uptr, uint32 newst) -{ -uptr->FNC = newst; /* new state */ -if (ds_eod) ds_cmd_done (1, DS1_OK); /* done? */ -else if (ds_eoc) ds_next_cyl (uptr); /* end cyl? seek */ -else sim_activate (uptr, ds_rtime); /* normal transfer */ -return; -} - - -/* Report uncorrectable data error */ - -t_stat ds_set_uncorr (UNIT *uptr) -{ -sim_cancel (uptr); /* cancel any operation */ -ds_cmd_done (1, DS1_UNCOR); /* done with error */ -perror ("DS I/O error"); /* visible error */ -clearerr (uptr->fileref); -ds_poll (); /* force poll */ -return SCPE_IOERR; -} - - -/* Fifo read */ - -uint32 ds_fifo_read (void) -{ -uint32 dat; - -if (ds_fifo_cnt == 0) return ds_fifo[ds_fifo_rp]; -dat = ds_fifo[ds_fifo_rp++]; -if (ds_fifo_rp >= DS_FIFO_SIZE) ds_fifo_rp = 0; -ds_fifo_cnt--; -return dat; -} - -void ds_fifo_write (uint32 dat) -{ -ds_fifo[ds_fifo_ip++] = dat; -if (ds_fifo_ip >= DS_FIFO_SIZE) ds_fifo_ip = 0; -if (ds_fifo_cnt < DS_FIFO_SIZE) ds_fifo_cnt++; -return; -} - -void ds_fifo_reset (void) -{ -uint32 i; - -ds_fifo_ip = ds_fifo_rp = ds_fifo_cnt = 0; -for (i = 0; i < DS_FIFO_SIZE; i++) ds_fifo[i] = 0; -return; -} - - -/* Controller clear */ - -t_stat ds_clear (void) -{ -int32 i; - -ds_cmd = 0; /* clear command */ -ds_cmdf = ds_cmdp = 0; /* clear commands flops */ -ds_fifo_reset (); /* clear fifo */ -ds_eoc = ds_eod = 0; -ds_busy = 0; -ds_state = DS_IDLE; /* ctrl idle */ -ds_lastatn = 0; -ds_fmask = 0; -ds_ptr = 0; -ds_cyl = ds_hs = 0; -ds_vctr = 0; -for (i = 0; i < DS_NUMDR; i++) { /* loop thru drives */ - sim_cancel (&ds_unit[i]); /* cancel activity */ - ds_unit[i].FNC = 0; /* clear function */ - ds_unit[i].CYL = 0; - ds_unit[i].STA = 0; - } -sim_cancel (&ds_ctrl); -sim_cancel (&ds_timer); -return SCPE_OK; -} - - -/* Reset routine. - - The PON signal clears the Interface Selected flip-flop, disconnecting the - interface from the disc controller. Under simulation, the interface always - remains connected to the controller, so we take no special action on - power-up. + 2. SRQ is denied because neither IFIN nor IFOUT is asserted when the + interface is not selected. */ t_stat ds_reset (DEVICE *dptr) { -IOPRESET (&ds_dib); /* PRESET device */ +uint32 unit; + +if (sim_switches & SWMASK ('P')) { /* is this a power-on reset? */ + ds.fifo_reg = find_reg ("FIFO", NULL, dptr); /* find the FIFO register entry */ + + if (ds.fifo_reg == NULL) /* if it cannot be found, */ + return SCPE_IERR; /* report a programming error! */ + + else { /* found it */ + ds.fifo_reg->qptr = 0; /* so reset the FIFO bottom index */ + ds.fifo_count = 0; /* and clear the FIFO */ + } + + for (unit = 0; unit < dptr->numunits; unit++) { /* loop through all of the units */ + sim_cancel (dptr->units + unit); /* cancel activation */ + dptr->units [unit].CYL = 0; /* reset the head position to cylinder 0 */ + dptr->units [unit].pos = 0; /* (irrelevant for the controller and timer) */ + } + } + +IOPRESET (&ds_dib); /* PRESET the device */ ds.srq = CLEAR; /* clear SRQ */ + return SCPE_OK; } -/* Device attach */ +/* Attach a drive unit. + + The specified file is attached to the indicated drive unit. The library + attach routine will load the heads. This will set the First Status and + Attention bits in the drive status, so we poll the drives to ensure that the + CPU is notified that the drive is now online. + + + Implementation notes: + + 1. If we are called during a RESTORE command, the drive status will not be + changed, so polling the drives will have no effect. +*/ t_stat ds_attach (UNIT *uptr, char *cptr) { -uint32 i, p; -t_stat r; +t_stat result; -uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; -r = attach_unit (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) return r; /* error? */ -ds_load_unload (uptr, 0, NULL, NULL); /* if OK, load heads */ -ds_sched_atn (uptr); /* schedule attention */ -if (((uptr->flags & UNIT_AUTO) == 0) || /* static size? */ - ((p = sim_fsize (uptr->fileref)) == 0)) return SCPE_OK; /* new file? */ -for (i = 0; drv_tab[i].sc != 0; i++) { /* find best fit */ - if (p <= (drv_tab[i].size * sizeof (uint16))) { - uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr->capac = drv_tab[i].size; - return SCPE_OK; - } - } -return SCPE_OK; +result = dl_attach (&mac_cntlr, uptr, cptr); /* attach the drive */ + +if (result == SCPE_OK) /* was the attach successful? */ + poll_drives (); /* poll the drives to notify the CPU */ + +return result; } -/* Device detach */ +/* Detach a drive unit. + + The specified file is detached from the indicated drive unit. The library + detach routine will unload the heads. This will set the Attention bit in the + drive status, so we poll the drives to ensure that the CPU is notified that + the drive is now offline. +*/ t_stat ds_detach (UNIT *uptr) { -ds_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads if attached */ -return detach_unit (uptr); +t_stat result; + +result = dl_detach (&mac_cntlr, uptr); /* detach the drive */ + +if (result == SCPE_OK) /* was the detach successful? */ + poll_drives (); /* poll the drives to notify the CPU */ + +return result; } -/* Load and unload heads */ +/* Boot a MAC disc drive. -t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to [un]load */ -if (value == UNIT_UNLOAD) { /* unload heads? */ - uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */ - uptr->STA = DS2_ATN; /* update drive status */ - ds_sched_atn (uptr); /* schedule attention */ - } -else { /* load heads */ - uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */ - uptr->STA = DS2_ATN | DS2_FS; /* update drive status */ - } -return SCPE_OK; -} + The MAC disc bootstrap program is loaded from the HP 12992B Boot Loader ROM + into memory, the I/O instructions are configured from the interface card + select code, and the program is run to boot from the specified unit. The + loader supports booting from cylinder 0 of drive unit 0 only. Before + execution, the S register is automatically set as follows: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + ------ ------ ---------------------- --------- --------- + ROM # 0 1 select code reserved head + + The boot routine sets bits 15-6 of the S register to appropriate values. + Bits 5-3 and 1-0 retain their original values, so S should be set before + booting. These bits are typically set to 0, although bit 5 is set for an RTE + reconfiguration boot, and bits 1-0 may be set if booting from a head other + than 0 is desired. -/* Schedule attention interrupt if CTL set, not restore, and controller idle */ + Implementation notes: -void ds_sched_atn (UNIT *uptr) -{ -int32 i; + 1. The Loader ROMs manual indicates that bits 2-0 select the head to use, + implying that heads 0-7 are valid. However, Table 5 has entries only for + heads 0-3, and the boot loader code will malfunction if heads 4-7 are + specified. The code masks the head number to three bits but forms the + Cold Load Read command by shifting the head number six bits to the left. + As the head field in the command is only two bits wide, specifying heads + 4-7 will result in bit 2 being shifted into the opcode field, resulting + in a Recalibrate command. +*/ -if (!ds.control || (sim_switches & SIM_SW_REST)) return; -for (i = 0; i < (DS_NUMDR + 1); i++) { /* check units, ctrl */ - if (sim_is_active (ds_dev.units + i)) return; - } -uptr->FNC = DSC_ATN; /* pseudo operation */ -sim_activate (uptr, 1); /* do immediately */ -return; -} - - -/* Set size command validation routine */ - -t_stat ds_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATT) return SCPE_ALATT; -uptr->capac = drv_tab[GET_DTYPE (val)].size; -return SCPE_OK; -} - - -/* 13037 bootstrap routine (HP 12992B ROM) */ const BOOT_ROM ds_rom = { - 0017727, /* STRT JSB STAT ; get status */ - 0002021, /* SSA,RSS ; is drive ready? */ - 0027742, /* JMP DMA ; yes, set up DMA */ - 0013714, /* AND B20 ; no, check status bits */ - 0002002, /* SZA ; faulty or hard down? */ - 0102030, /* HLT 30B ; HALT 30B */ - 0027700, /* JMP STRT ; try again */ - 0102011, /* ADR1 OCT 102011 */ - 0102055, /* ADR2 OCT 102055 */ - 0164000, /* CNT DEC -6144 */ - 0000007, /* D7 OCT 7 */ - 0001400, /* STCM OCT 1400 */ - 0000020, /* B20 OCT 20 */ - 0017400, /* STMS OCT 17400 */ - 0000000, /* 9 NOP's */ - 0000000, - 0000000, - 0000000, - 0000000, - 0000000, - 0000000, - 0000000, - 0000000, - 0000000, /* STAT NOP ; status check routine */ - 0107710, /* CLC DC,C ; set command mode */ - 0063713, /* LDA STCM ; get status command */ - 0102610, /* OTA DC ; output status command */ - 0102310, /* SFS DC ; wait for stat#1 word */ - 0027733, /* JMP *-1 */ - 0107510, /* LIB DC,C ; B-reg - status#1 word */ - 0102310, /* SFS DC ; wait for stat#2 word */ - 0027736, /* JMP *-1 */ - 0103510, /* LIA DC,C ; A-reg - status#2 word */ - 0127727, /* JMP STAT,I ; return */ - 0067776, /* DMA LDB DMAC ; get DMA control word */ - 0106606, /* OTB 6 ; output DMA ctrl word */ - 0067707, /* LDB ADR1 ; get memory address */ - 0106702, /* CLC 2 ; set memory addr mode */ - 0106602, /* OTB 2 ; output mem addr to DMA */ - 0102702, /* STC 2 ; set word count mode */ - 0067711, /* LDB CNT ; get word count */ - 0106602, /* OTB 2 ; output word cnt to DMA */ - 0106710, /* CLC CLC DC ; set command follows */ - 0102501, /* LIA 1 ; load switches */ - 0106501, /* LIB 1 ; register settings */ - 0013712, /* AND D7 ; isolate head number */ - 0005750, /* BLF,CLE,SLB ; bit 12 = 0? */ - 0027762, /* JMP *+3 ; no, manual boot */ - 0002002, /* SZA ; yes, RPL, head# = 0? */ - 0001000, /* ALS ; no, head# = 1 --> 2 */ - 0001720, /* ALF,ALS ; form cold load */ - 0001000, /* ALS ; command word */ - 0103706, /* STC 6,C ; activate DMA */ - 0103610, /* OTA DC,C ; output cold load cmd */ - 0102310, /* SFS DC ; is cold load done? */ - 0027766, /* JMP *-1 ; no, wait */ - 0017727, /* JSB STAT ; yes, get status */ - 0060001, /* LDA 1 ; get status word #1 */ - 0013715, /* AND STMS ; isolate status bits */ - 0002002, /* SZA ; is transfer ok? */ - 0027700, /* JMP STRT ; no, try again */ - 0117710, /* JSB ADR2,I ; yes, start program */ - 0000010, /* DMAC ABS DC ; DMA command word */ - 0170100, /* ABS -STRT */ + 0017727, /* START JSB STAT GET STATUS */ + 0002021, /* SSA,RSS IS DRIVE READY ? */ + 0027742, /* JMP DMA YES, SET UP DMA */ + 0013714, /* AND B20 NO, CHECK STATUS BITS */ + 0002002, /* SZA IS DRIVE FAULTY OR HARD DOWN ? */ + 0102030, /* HLT 30B YES, HALT 30B, "RUN" TO TRY AGAIN */ + 0027700, /* JMP START NO, TRY AGAIN FOR DISC READY */ + 0102011, /* ADDR1 OCT 102011 */ + 0102055, /* ADDR2 OCT 102055 */ + 0164000, /* CNT DEC -6144 */ + 0000007, /* D7 OCT 7 */ + 0001400, /* STCMD OCT 1400 */ + 0000020, /* B20 OCT 20 */ + 0017400, /* STMSK OCT 17400 */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* STAT NOP STATUS CHECK SUBROUTINE */ + 0107710, /* CLC DC,C SET STATUS COMMAND MODE */ + 0063713, /* LDA STCMD GET STATUS COMMAND */ + 0102610, /* OTA DC OUTPUT STATUS COMMAND */ + 0102310, /* SFS DC WAIT FOR STATUS#1 WORD */ + 0027733, /* JMP *-1 */ + 0107510, /* LIB DC,C B-REG = STATUS#1 WORD */ + 0102310, /* SFS DC WAIT FOR STATUS#2 WORD */ + 0027736, /* JMP *-1 */ + 0103510, /* LIA DC,C A-REG = STATUS#2 WORD */ + 0127727, /* JMP STAT,I RETURN */ + 0067776, /* DMA LDB DMACW GET DMA CONTROL WORD */ + 0106606, /* OTB 6 OUTPUT DMA CONTROL WORD */ + 0067707, /* LDB ADDR1 GET MEMORY ADDRESS */ + 0106702, /* CLC 2 SET MEMORY ADDRESS INPUT MODE */ + 0106602, /* OTB 2 OUTPUT MEMORY ADDRESS TO DMA */ + 0102702, /* STC 2 SET WORD COUNT INPUT MODE */ + 0067711, /* LDB CNT GET WORD COUNT */ + 0106602, /* OTB 2 OUTPUT WORD COUNT TO DMA */ + 0106710, /* CLDLD CLC DC SET COMMAND INPUT MODE */ + 0102501, /* LIA 1 LOAD SWITCH */ + 0106501, /* LIB 1 REGISTER SETTINGS */ + 0013712, /* AND D7 ISOLATE HEAD NUMBER */ + 0005750, /* BLF,CLE,SLB BIT 12=0? */ + 0027762, /* JMP *+3 NO,MANUAL BOOT */ + 0002002, /* SZA YES,RPL BOOT. HEAD#=0? */ + 0001000, /* ALS NO,HEAD#1, MAKE HEAD#=2 */ + 0001720, /* ALF,ALS FORM COLD LOAD */ + 0001000, /* ALS COMMAND WORD */ + 0103706, /* STC 6,C ACTIVATE DMA */ + 0103610, /* OTA DC,C OUTPUT COLD LOAD COMMAND */ + 0102310, /* SFS DC IS COLD LOAD COMPLETED ? */ + 0027766, /* JMP *-1 NO, WAIT */ + 0017727, /* JSB STAT YES, GET STATUS */ + 0060001, /* LDA 1 */ + 0013715, /* AND STMSK A-REG = STATUS BITS OF STATUS#1 WD */ + 0002002, /* SZA IS TRANSFER OK ? */ + 0027700, /* JMP START NO,TRY AGAIN */ + 0117710, /* EXIT JSB ADDR2,I YES, EXEC LOADED PROGRAM _@ 2055B */ + 0000010, /* DMACW ABS DC */ + 0170100, /* ABS -START */ }; t_stat ds_boot (int32 unitno, DEVICE *dptr) { -int32 dev; +if (unitno != 0) /* boot supported on drive unit 0 only */ + return SCPE_NOFNC; /* report "Command not allowed" if attempted */ + +if (ibl_copy (ds_rom, ds_dib.select_code)) /* copy the boot ROM to memory and configure */ + return SCPE_IERR; /* return an internal error if failed */ + +SR = SR & (IBL_OPT | IBL_DS_HEAD) /* set S to a reasonable value */ + | IBL_DS | IBL_MAN | (ds_dib.select_code << IBL_V_DEV); /* before boot execution */ -if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = ds_dib.select_code; /* get data chan dev */ -if (ibl_copy (ds_rom, dev)) return SCPE_IERR; /* copy boot to memory */ -SR = (SR & (IBL_OPT | IBL_DS_HEAD)) | IBL_DS | IBL_MAN | (dev << IBL_V_DEV); return SCPE_OK; } + + + +/* MAC disc global SCP routines */ + + +/* Load or unload the drive heads. + + The SCP command SET DSn UNLOADED simulates setting the hardware RUN/STOP + switch to STOP. The heads are unloaded, and the drive is spun down. + + The SET DSn LOADED command simulates setting the switch to RUN. The drive is + spun up, and the heads are loaded. + + The library handles command validation and setting the appropriate drive unit + status. +*/ + +t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +const t_bool load = (value != UNIT_UNLOAD); /* true if heads are loading */ + +return dl_load_unload (&mac_cntlr, uptr, load); /* load or unload the heads */ +} + + + +/* MAC disc local utility routines */ + + +/* Start a command. + + The previously prepared command is executed by calling the corresponding + library routine. On entry, the controller's opcode field contains the + command to start, and the buffer contains the command word in element 0 and + the parameters required by the command, if any, beginning in element 1. + + If the command started, the returned pointer will point at the unit to + activate (if that unit's "wait" field is non-zero). If the returned pointer + is NULL, the command failed to start, and the controller status has been set + to indicate the reason. The interface flag is set to notify the CPU of the + failure. + + + Implementation notes: + + 1. If a command that accesses the drive is attempted on a drive currently + seeking, the returned pointer will be valid, but the unit's "wait" time + will be zero. The unit must not be activated (as it already is active). + When the seek completes, the command will be executed automatically. + + If a Seek or Cold Load Read command is attempted on a drive currently + seeking, seek completion will occur normally, but Seek Check status will + be set. + + 2. For debug printouts, we want to print the name of the command (Seek or + Recalibrate) in progress when a new command is started. However, when + the library routine returns, the unit operation and controller opcode + have been changed to reflect the new command. Therefore, we must record + the operation in progress before calling the library. + + The problem is in determining which unit's operation code to record. We + cannot blindly use the unit field from the new command, as recorded in + the controller, as preparation has ensured only that the target unit + number is legal but not necessarily valid. Therefore, we must validate + the unit number before accessing the unit's operation code. + + If the unit number is invalid, the command will not start, but the + compiler does not know this. Therefore, we must ensure that the saved + operation code is initialized, or a "variable used uninitialized" warning + will occur. +*/ + +static void start_command (void) +{ +int32 unit, time; +UNIT *uptr; +CNTLR_OPCODE drive_command; + +unit = GET_S1UNIT (mac_cntlr.spd_unit); /* get the (prepared) unit from the command */ + +if (unit <= DL_MAXDRIVE) /* is the unit number valid? */ + drive_command = (CNTLR_OPCODE) ds_unit [unit].OP; /* get the opcode from the unit that will be used */ +else /* the unit is invalid, so the command will not start */ + drive_command = end; /* but the compiler doesn't know this! */ + +uptr = dl_start_command (&mac_cntlr, ds_unit, DL_MAXDRIVE); /* ask the controller to start the command */ + +if (uptr) { /* did the command start? */ + time = uptr->wait; /* save the activation time */ + + if (time) /* was the unit scheduled? */ + activate_unit (uptr); /* activate it (clears "wait") */ + + if (DEBUG_PRI (ds_dev, DEB_RWSC)) { + unit = uptr - ds_unit; /* get the unit number */ + + if (time == 0) /* was the unit busy? */ + fprintf (sim_deb, ">>DS rwsc: Unit %d %s in progress\n", + unit, dl_opcode_name (MAC, drive_command)); + + fputs (">>DS rwsc: ", sim_deb); + + if (unit > DL_MAXDRIVE) + fputs ("Controller ", sim_deb); + else + fprintf (sim_deb, "Unit %d position %d ", unit, uptr->pos); + + fprintf (sim_deb, "%s command initiated\n", + dl_opcode_name (MAC, mac_cntlr.opcode)); + } + } + +else /* the command failed to start */ + ds_io (&ds_dib, ioENF, 0); /* so set the flag to notify the CPU */ + +return; +} + + +/* Poll the interface for a new command. + + If a new command is available, and the controller is not busy, prepare the + command for execution. If preparation succeeded, and the command needs + parameters before executing, set the flag to request the first one from the + CPU. If no parameters are needed, the command is ready to execute. + + If preparation failed, set the flag to notify the CPU. The controller + status contains the reason for the failure. +*/ + +static void poll_interface (void) +{ +if (ds.cmrdy == SET && mac_cntlr.state != cntlr_busy) { /* are the interface and controller ready? */ + buffer [0] = fifo_unload (); /* unload the command into the buffer */ + + if (dl_prepare_command (&mac_cntlr, ds_unit, DL_MAXDRIVE)) { /* prepare the command; did it succeed? */ + if (mac_cntlr.length) /* does the command require parameters? */ + ds_io (&ds_dib, ioENF, 0); /* set the flag to request the first one */ + else /* if not waiting for parameters */ + start_command (); /* start the command */ + } + + else /* preparation failed */ + ds_io (&ds_dib, ioENF, 0); /* so set the flag to notify the CPU */ + + ds.cmrdy = CLEAR; /* flush the command from the interface */ + } + +return; +} + + +/* Poll the drives for attention requests. + + If the controller is idle and interrupts are allowed, the drives are polled + to see if any drive is requesting attention. If one is found, the controller + resets that drive's Attention status, saves the drive's unit number, sets + Drive Attention status, and waits for a command from the CPU. The interface + sets the flag to notify the CPU. +*/ + +void poll_drives (void) +{ +if (mac_cntlr.state == cntlr_idle && ds.control == SET) /* controller is idle and OK to interrupt? */ + if (dl_poll_drives (&mac_cntlr, ds_unit, DL_MAXDRIVE)) /* poll drives; was Attention seen? */ + ds_io (&ds_dib, ioENF, 0); /* request an interrupt */ +return; +} + + +/* Load a word into the FIFO. + + A word is loaded into the next available location in the FIFO, and the FIFO + occupancy count is incremented. If the FIFO is full on entry, the load is + ignored. + + + Implementation notes: + + 1. The FIFO is implemented as circular queue to take advantage of REG_CIRC + EXAMINE semantics. REG->qptr is the index of the first word currently in + the FIFO. By specifying REG_CIRC, examining FIFO[0-n] will always + display the words in load order, regardless of the actual array index of + the start of the list. The number of words currently present in the FIFO + is kept in fifo_count (0 = empty, 1-16 = number of words available). + + If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the + index of the new word location. Loading stores the word there and then + increments fifo_count. + + 2. Because the load and unload routines need access to qptr in the REG + structure for the FIFO array, a pointer to the REG is stored in the + fifo_reg variable during device reset. +*/ + +static void fifo_load (uint16 data) +{ +uint32 index; + +if (FIFO_FULL) { /* is the FIFO already full? */ + if (DEBUG_PRI (ds_dev, DEB_BUF)) + fprintf (sim_deb, ">>DS buf: Attempted load to full FIFO, data %06o\n", data); + + return; /* return with the load ignored */ + } + +index = (ds.fifo_reg->qptr + ds.fifo_count) % FIFO_SIZE; /* calculate the index of the next available location */ + +ds.fifo [index] = data; /* store the word in the FIFO */ +ds.fifo_count = ds.fifo_count + 1; /* increment the count of words stored */ + +if (DEBUG_PRI (ds_dev, DEB_BUF)) + fprintf (sim_deb, ">>DS buf: Data %06o loaded into FIFO (%d)\n", + data, ds.fifo_count); + +return; +} + + +/* Unload a word from the FIFO. + + A word is unloaded from the first location in the FIFO, and the FIFO + occupancy count is decremented. If the FIFO is empty on entry, the unload + returns dummy data. + + + Implementation notes: + + 1. If fifo_count > 0, REG->qptr is the index of the word to remove. Removal + gets the word and then increments qptr (mod FIFO_SIZE) and decrements + fifo_count. +*/ + +static uint16 fifo_unload (void) +{ +uint16 data; + +if (FIFO_EMPTY) { /* is the FIFO already empty? */ + if (DEBUG_PRI (ds_dev, DEB_BUF)) + fputs (">>DS buf: Attempted unload from empty FIFO\n", sim_deb); + + return 0; /* return with no data */ + } + +data = ds.fifo [ds.fifo_reg->qptr]; /* get the word from the FIFO */ + +ds.fifo_reg->qptr = (ds.fifo_reg->qptr + 1) % FIFO_SIZE; /* update the FIFO queue pointer */ +ds.fifo_count = ds.fifo_count - 1; /* decrement the count of words stored */ + +if (DEBUG_PRI (ds_dev, DEB_BUF)) + fprintf (sim_deb, ">>DS buf: Data %06o unloaded from FIFO (%d)\n", + data, ds.fifo_count); + +return data; +} + + +/* Clear the FIFO. + + The FIFO is cleared by setting the occupancy counter to zero. +*/ + +static void fifo_clear (void) +{ +ds.fifo_count = 0; /* clear the FIFO */ + +if (DEBUG_PRI (ds_dev, DEB_BUF)) + fputs (">>DS buf: FIFO cleared\n", sim_deb); + +return; +} + + +/* Activate the unit. + + The specified unit is activated using the unit's "wait" time. If debugging + is enabled, the activation is logged to the debug file. +*/ + +static t_stat activate_unit (UNIT *uptr) +{ +uint32 unit; +t_stat result; + +if (DEBUG_PRI (ds_dev, DEB_SERV)) { + unit = uptr - ds_unit; /* calculate the unit number */ + + if (uptr == &ds_cntlr) + fprintf (sim_deb, ">>DS serv: Controller delay %d service scheduled\n", + uptr->wait); + else + fprintf (sim_deb, ">>DS serv: Unit %d delay %d service scheduled\n", + unit, uptr->wait); + } + +result = sim_activate (uptr, uptr->wait); /* activate the unit */ +uptr->wait = 0; /* reset the activation time */ + +return result; /* return the activation status */ +} diff --git a/HP2100/hp2100_fp1.c b/HP2100/hp2100_fp1.c index cf078435..94ce633a 100644 --- a/HP2100/hp2100_fp1.c +++ b/HP2100/hp2100_fp1.c @@ -1,6 +1,6 @@ /* hp2100_fp1.c: HP 1000 multiple-precision floating point routines - Copyright (c) 2005-2011, J. David Bryan + Copyright (c) 2005-2012, J. David Bryan 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 @@ in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the author. + 06-Feb-12 JDB Added missing precision on constant "one" in fp_trun 21-Jun-11 JDB Completed the comments for divide; no code changes 08-Jun-08 JDB Quieted bogus gcc warning in fp_exec 10-May-08 JDB Fixed uninitialized return in fp_accum when setting @@ -1421,7 +1422,7 @@ uint32 fp_trun (OP *result, OP source, OPSIZE precision) { t_bool bits_lost; FPU unpacked; -FPU one = { FP_ONEHALF, 1, 0 }; /* 0.5 * 2 ** 1 = 1.0 */ +FPU one = { FP_ONEHALF, 1, fp_t }; /* 0.5 * 2 ** 1 = 1.0 */ OP zero = { { 0, 0, 0, 0, 0 } }; /* 0.0 */ t_uint64 mask = mant_mask[precision] & ~FP_MSIGN; diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 14811d01..595d47e9 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-2011, Robert M Supnik + Copyright (c) 2002-2012, Robert 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 @@ IPLI, IPLO 12875A interprocessor link + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Added CARD_INDEX casts to dib.card_index 07-Apr-11 JDB A failed STC may now be retried 28-Mar-11 JDB Tidied up signal handling 27-Mar-11 JDB Consolidated reporting of consecutive CRS signals @@ -165,6 +167,7 @@ REG ipli_reg [] = { { ORDATA (HOLD, ipl [ipli].hold, 8) }, { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, ipl_stopioe, 0) }, + { ORDATA (SC, ipli_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, ipli_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -174,8 +177,8 @@ MTAB ipl_mod [] = { { UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag }, { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", &ipl_dscln, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &ipli_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &ipli_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ipli_dev }, { 0 } }; @@ -203,6 +206,7 @@ REG iplo_reg [] = { { FLDATA (FBF, ipl [iplo].flagbuf, 0) }, { ORDATA (HOLD, ipl [iplo].hold, 8) }, { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, + { ORDATA (SC, iplo_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, iplo_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -291,7 +295,7 @@ DEVICE iplo_dev = { uint32 iplio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const CARD_INDEX card = dibptr->card_index; /* set card selector */ +CARD_INDEX card = (CARD_INDEX) dibptr->card_index; /* set card selector */ UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */ const char *iotype [] = { "Status", "Command" }; int32 sta; @@ -474,7 +478,7 @@ if (nb < 0) { /* connection closed? */ else if (nb == 0) /* no data? */ return SCPE_OK; -card = (uptr == &iplo_unit); /* set card selector */ +card = (CARD_INDEX) (uptr == &iplo_unit); /* set card selector */ if (uptr->flags & UNIT_HOLD) { /* holdover byte? */ uptr->IBUF = (ipl [card].hold << 8) | (((int32) msg [0]) & 0377); @@ -537,7 +541,7 @@ t_stat ipl_reset (DEVICE *dptr) { UNIT *uptr = dptr->units; DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ -CARD_INDEX card = dibptr->card_index; /* card number */ +CARD_INDEX card = (CARD_INDEX) dibptr->card_index; /* card number */ hp_enbdis_pair (dptr, dptrs [card ^ 1]); /* make pair cons */ diff --git a/HP2100/hp2100_lps.c b/HP2100/hp2100_lps.c index 165c2190..ea51c6fb 100644 --- a/HP2100/hp2100_lps.c +++ b/HP2100/hp2100_lps.c @@ -1,6 +1,6 @@ /* hp2100_lps.c: HP 2100 12653A/2767 line printer simulator - Copyright (c) 1993-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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 @@ LPS 12653A 2767 line printer 12566B microcircuit interface with loopback diagnostic connector + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model Revised detection of CLC at last DMA cycle @@ -245,6 +246,7 @@ REG lps_reg[] = { { DRDATA (RTIME, lps_rtime, 24), PV_LEFT }, { FLDATA (TIMING, lps_timing, 0), REG_HRO }, { FLDATA (STOP_IOE, lps_stopioe, 0) }, + { ORDATA (SC, lps_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, lps_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -262,8 +264,8 @@ MTAB lps_mod[] = { &lps_set_timing, NULL, NULL }, { MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL, NULL, &lps_show_timing, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &lps_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &lps_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &lps_dev }, { 0 } }; diff --git a/HP2100/hp2100_lpt.c b/HP2100/hp2100_lpt.c index 6122841d..84795443 100644 --- a/HP2100/hp2100_lpt.c +++ b/HP2100/hp2100_lpt.c @@ -1,6 +1,6 @@ /* hp2100_lpt.c: HP 2100 12845B line printer simulator - Copyright (c) 1993-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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 @@ LPT 12845B 2607 line printer + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals @@ -137,6 +138,7 @@ REG lpt_reg[] = { { DRDATA (CTIME, lpt_ctime, 24), PV_LEFT }, { DRDATA (PTIME, lpt_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, + { ORDATA (SC, lpt_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, lpt_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -146,8 +148,8 @@ MTAB lpt_mod[] = { { UNIT_POWEROFF, 0, "power on", "POWERON", lpt_restart }, { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL }, { UNIT_OFFLINE, 0, "online", "ONLINE", lpt_restart }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &lpt_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &lpt_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &lpt_dev }, { 0 } }; diff --git a/HP2100/hp2100_mpx.c b/HP2100/hp2100_mpx.c index ab51adf0..65aa65c2 100644 --- a/HP2100/hp2100_mpx.c +++ b/HP2100/hp2100_mpx.c @@ -1,6 +1,6 @@ /* hp2100_mpx.c: HP 12792C eight-channel asynchronous multiplexer simulator - Copyright (c) 2008-2011, J. David Bryan + Copyright (c) 2008-2012, J. David Bryan 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 @@ MPX 12792C 8-channel multiplexer card + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines @@ -105,9 +106,9 @@ The simulation provides both the "realistic timing" described above, as well as an optimized "fast timing" option. Optimization makes three improvements: - 1. Buffered characters are transferred via Telnet in blocks. + 1. Buffered characters are transferred in blocks. - 2. ENQ/ACK handshaking is done locally without involving the Telnet client. + 2. ENQ/ACK handshaking is done locally without involving the client. 3. BS and DEL respond visually more like prior RTE terminal drivers. @@ -599,15 +600,15 @@ t_stat mpx_show_frev (FILE *st, UNIT *uptr, int32 val, void *desc); /* MPX data structures. - mpx_order MPX line connection order table - mpx_ldsc MPX line descriptors - mpx_desc MPX multiplexer descriptor - mpx_dib MPX device information block - mpx_unit MPX unit list - mpx_reg MPX register list - mpx_mod MPX modifier list - mpx_deb MPX debug list - mpx_dev MPX device descriptor + mpx_order MPX line connection order table + mpx_ldsc MPX terminal multiplexer line descriptors + mpx_desc MPX terminal multiplexer device descriptor + mpx_dib MPX device information block + mpx_unit MPX unit list + mpx_reg MPX register list + mpx_mod MPX modifier list + mpx_deb MPX debug list + mpx_dev MPX device descriptor The first eight units correspond to the eight multiplexer line ports. These handle character I/O via the Telnet library. A ninth unit acts as the card @@ -626,19 +627,17 @@ t_stat mpx_show_frev (FILE *st, UNIT *uptr, int32 val, void *desc); ten millisecond period. The controller and poll units are hidden by disabling them, so as to present - a logical picture of the multiplexer to the user. However, we cannot attach - to a disabled unit, so the poll unit is enabled prior to attaching and - disabled thereafter. + a logical picture of the multiplexer to the user. */ +DEVICE mpx_dev; + int32 mpx_order [MPX_PORTS] = { -1 }; /* connection order */ TMLN mpx_ldsc [MPX_PORTS] = { { 0 } }; /* line descriptors */ TMXR mpx_desc = { MPX_PORTS, 0, 0, mpx_ldsc, mpx_order }; /* device descriptor */ DIB mpx_dib = { &mpx_io, MPX }; -DEVICE mpx_dev; - UNIT mpx_unit [] = { { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 0 */ { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 1 */ @@ -685,9 +684,10 @@ REG mpx_reg [] = { { BRDATA (SEP, mpx_sep, 10, 10, MPX_PORTS * 2) }, { BRDATA (PUT, mpx_put, 10, 10, MPX_PORTS * 2) }, - { FLDATA (CTL, mpx.control, 0) }, - { FLDATA (FLG, mpx.flag, 0) }, - { FLDATA (FBF, mpx.flagbuf, 0) }, + { FLDATA (CTL, mpx.control, 0) }, + { FLDATA (FLG, mpx.flag, 0) }, + { FLDATA (FBF, mpx.flagbuf, 0) }, + { ORDATA (SC, mpx_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, mpx_dib.select_code, 6), REG_HRO }, { BRDATA (CONNORD, mpx_order, 10, 32, MPX_PORTS), REG_HRO }, @@ -711,7 +711,8 @@ MTAB mpx_mod [] = { { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat, &mpx_desc }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &mpx_desc }, { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mpx_desc }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mpx_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &mpx_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mpx_dev }, { 0 } }; @@ -742,7 +743,7 @@ DEVICE mpx_dev = { &mpx_attach, /* attach routine */ &mpx_detach, /* detach routine */ &mpx_dib, /* device information block */ - DEV_NET | DEV_DEBUG | DEV_DISABLE, /* device flags */ + DEV_DEBUG | DEV_DISABLE, /* device flags */ 0, /* debug control flags */ mpx_deb, /* debug flag name table */ NULL, /* memory size change routine */ @@ -2052,7 +2053,7 @@ return SCPE_OK; the first serial line and be reported there in a SHOW MPX command. To preserve the logical picture, we attach the port to the Telnet poll unit, - which is normally disabled, inhibiting its display. Attaching to a disabled + which is normally disabled to inhibit its display. Attaching to a disabled unit is not allowed, so we first enable the unit, then attach it, then disable it again. Attachment is reported by the "mpx_status" routine below. @@ -2073,7 +2074,7 @@ mpx_poll.flags = mpx_poll.flags | UNIT_DIS; /* disable unit */ if (status == SCPE_OK) { mpx_poll.wait = POLL_FIRST; /* set up poll */ - sim_activate (&mpx_poll, mpx_poll.wait); /* start Telnet poll immediately */ + sim_activate (&mpx_poll, mpx_poll.wait); /* start poll immediately */ } return status; } @@ -2229,9 +2230,9 @@ return; /* Calculate service time from baud rate. - Service times are based on 1580 instructions per second, which is the 1000 - E-Series execution speed. Baud rate 0 means "don't change" and is handled by - the "Set port key" command executor. + Service times are based on 1580 instructions per millisecond, which is the + 1000 E-Series execution speed. Baud rate 0 means "don't change" and is + handled by the "Set port key" command executor. Baud rate settings of 13-15 are marked as "reserved" in the user manual, but the firmware defines these as 38400, 9600, and 9600 baud, respectively. @@ -2239,9 +2240,8 @@ return; static uint32 service_time (uint16 control_word) { -/* Baud Rates 0- 7 : --, 50, 75, 110, 134.5, 150, 300, 1200, - Baud Rates 8-15 : 1800, 2400, 4800, 9600, 19200, 38400, 9600, 9600 -*/ +/* Baud Rates 0- 7 : --, 50, 75, 110, 134.5, 150, 300, 1200, */ +/* Baud Rates 8-15 : 1800, 2400, 4800, 9600, 19200, 38400, 9600, 9600 */ static const int32 ticks [] = { 0, 316000, 210667, 143636, 117472, 105333, 52667, 13167, 8778, 6583, 3292, 1646, 823, 411, 1646, 1646 }; diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index d9f44416..bc3acca6 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-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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 @@ MS 13181A 7970B 800bpi nine track magnetic tape 13183A 7970E 1600bpi nine track magnetic tape + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Added CNTLR_TYPE cast to ms_settype 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 11-Aug-08 JDB Revised to use AR instead of saved_AR in boot @@ -151,7 +153,14 @@ #define STA_DYN (STA_PE | STA_SEL | STA_TBSY | STA_BOT | \ STA_EOT | STA_WLK | STA_LOCAL) -enum { A13181, A13183 } ms_ctype = A13181; /* ctrl type */ +/* Controller types */ + +typedef enum { + A13181, + A13183 + } CNTLR_TYPE; + +CNTLR_TYPE ms_ctype = A13181; /* ctrl type */ int32 ms_timing = 1; /* timing type */ struct { @@ -260,13 +269,14 @@ REG msd_reg[] = { { BRDATA (DBUF, msxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) }, { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) }, + { ORDATA (SC, msd_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, msd_dib.select_code, 6), REG_HRO }, { NULL } }; MTAB msd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &msd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &msd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &msd_dev }, { 0 } }; @@ -319,6 +329,7 @@ REG msc_reg[] = { { FLDATA (TIMING, ms_timing, 0), REG_HRO }, { FLDATA (STOP_IOE, msc_stopioe, 0) }, { FLDATA (CTYPE, ms_ctype, 0), REG_HRO }, + { ORDATA (SC, msc_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, msc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -346,8 +357,8 @@ MTAB msc_mod[] = { &ms_set_timing, NULL, NULL }, { MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL, NULL, &ms_show_timing, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &msd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &msd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &msd_dev }, { 0 } }; @@ -1079,7 +1090,7 @@ if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; for (i = 0; i < MS_NUMDR; i++) { if (msc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; } -ms_ctype = val; +ms_ctype = (CNTLR_TYPE) val; ms_config_timing (); /* update for new type */ return SCPE_OK; } diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index 32c0f072..144db5de 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-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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,8 +25,9 @@ MT 12559A 3030 nine track magnetic tape + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling - 29-Oct-10 JDB Fixed error in command scan in mtcio ioIOO handler + 29-Oct-10 JDB Fixed command scanning error in mtcio ioIOO handler 26-Oct-10 JDB Changed I/O signal handler for revised signal model 04-Sep-08 JDB Fixed missing flag after CLR command 02-Sep-08 JDB Moved write enable and format commands from MTD to MTC @@ -168,13 +169,14 @@ REG mtd_reg[] = { { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) }, { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) }, + { ORDATA (SC, mtd_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, mtd_dib.select_code, 6), REG_HRO }, { NULL } }; MTAB mtd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &mtd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev }, { 0 } }; @@ -210,6 +212,7 @@ REG mtc_reg[] = { { DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT }, { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, mtc_stopioe, 0) }, + { ORDATA (SC, mtc_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, mtc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -219,8 +222,8 @@ MTAB mtc_mod[] = { { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, { MTAB_XTD | MTAB_VDV | MTAB_VUN, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &mtd_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev }, { 0 } }; diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index 2712f1c4..f341a51d 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-2011, Robert M Supnik + Copyright (c) 2002-2012, Robert 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,MUXM 12920A terminal multiplexor + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines @@ -329,17 +330,12 @@ t_stat mux_detach (UNIT *uptr); t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc); -/* MUX data structures. +/* MUXL/MUXU device information block. - mux_order MUX line connection order table - mux_ldsc MUX line descriptors - mux_desc MUX multiplexer descriptor + The DIBs of adjacent cards must be contained in an array, so they are defined + here and referenced in the lower and upper card device structures. */ -int32 mux_order [MUX_LINES] = { -1 }; /* connection order */ -TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors */ -TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */ - DIB mux_dib[] = { { &muxlio, MUXL }, { &muxuio, MUXU } @@ -358,6 +354,8 @@ DIB mux_dib[] = { muxl_dev MUXL device descriptor */ +TMXR mux_desc; + DEVICE muxl_dev; UNIT muxl_unit[] = { @@ -393,6 +391,7 @@ REG muxl_reg[] = { { BRDATA (BDFR, mux_defer, 8, 1, MUX_LINES) }, { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, MUX_LINES, REG_NZ + PV_LEFT) }, + { ORDATA (SC, muxl_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, muxl_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -409,8 +408,9 @@ MTAB muxl_mod[] = { { 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_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc }, - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, + { MTAB_XTD | MTAB_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &muxl_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, { 0 } }; @@ -442,6 +442,10 @@ DEVICE muxl_dev = { /* MUXU data structures + mux_order MUX line connection order table + mux_ldsc MUX terminal multiplexer line descriptors + mux_desc MUX terminal multiplexer device descriptor + muxu_dib MUXU device information block muxu_unit MUXU unit list muxu_reg MUXU register list @@ -452,11 +456,16 @@ DEVICE muxl_dev = { DEVICE muxu_dev; +int32 mux_order [MUX_LINES] = { -1 }; /* connection order */ +TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors */ +TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */ + UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST }; REG muxu_reg[] = { { ORDATA (IBUF, muxu_ibuf, 16) }, { ORDATA (OBUF, muxu_obuf, 16) }, + { ORDATA (SC, muxu_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, muxu_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -471,7 +480,8 @@ MTAB muxu_mod[] = { { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat, &mux_desc }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &mux_desc }, { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc }, - { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &muxl_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, { 0 } }; @@ -501,7 +511,7 @@ DEVICE muxu_dev = { &mux_attach, /* attach routine */ &mux_detach, /* detach routine */ &muxu_dib, /* device information block */ - DEV_NET | DEV_DISABLE | DEV_DEBUG, /* device flags */ + DEV_DISABLE | DEV_DEBUG, /* device flags */ 0, /* debug control flags */ muxu_deb, /* debug flag name table */ NULL, /* memory size change routine */ @@ -531,12 +541,14 @@ REG muxc_reg[] = { { ORDATA (CHAN, muxc_chan, 4) }, { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) }, { BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) }, + { ORDATA (SC, muxc_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, muxc_dib.select_code, 6), REG_HRO }, { NULL } }; MTAB muxc_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxc_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &muxc_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxc_dev }, { 0 } }; @@ -975,8 +987,6 @@ t_bool loopback; loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ if (!loopback) { /* terminal mode? */ - if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ - if (uptr->wait == POLL_FIRST) /* first poll? */ uptr->wait = sync_poll (INITIAL); /* initial synchronization */ else /* not first */ @@ -1328,7 +1338,7 @@ if (status == SCPE_OK) { sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */ } -return SCPE_OK; +return status; } diff --git a/HP2100/hp2100_pif.c b/HP2100/hp2100_pif.c index 494f5860..ceaaeb8c 100644 --- a/HP2100/hp2100_pif.c +++ b/HP2100/hp2100_pif.c @@ -1,6 +1,6 @@ /* hp2100_pif.c: HP 12620A/12936A privileged interrupt fence simulator - Copyright (c) 2008-2011, J. David Bryan + Copyright (c) 2008-2012, J. David Bryan 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 @@ PIF 12620A/12936A privileged interrupt fence + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals @@ -147,18 +148,20 @@ UNIT pif_unit = { }; REG pif_reg [] = { - { FLDATA (CTL, pif.control, 0) }, - { FLDATA (FLG, pif.flag, 0) }, - { FLDATA (FBF, pif.flagbuf, 0) }, + { FLDATA (CTL, pif.control, 0) }, + { FLDATA (FLG, pif.flag, 0) }, + { FLDATA (FBF, pif.flagbuf, 0) }, + { ORDATA (SC, pif_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, pif_dib.select_code, 6), REG_HRO }, { NULL } }; MTAB pif_mod [] = { - { MTAB_XTD | MTAB_VDV, 0, NULL, "12620A", &pif_set_card, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "12936A", &pif_set_card, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &pif_show_card, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &pif_dev }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "12620A", &pif_set_card, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "12936A", &pif_set_card, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &pif_show_card, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &pif_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &pif_dev }, { 0 } }; diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index ebc8c04f..82740889 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -1,6 +1,6 @@ /* hp2100_stddev.c: HP2100 standard devices simulator - Copyright (c) 1993-2011, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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 @@ TTY 12531C buffered teleprinter interface CLK 12539C time base generator + 12-Feb-12 JDB Add TBG as a logical name for the CLK device + 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 26-Jun-08 JDB Rewrote device I/O to model backplane signals @@ -228,6 +230,7 @@ REG ptr_reg[] = { { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, + { ORDATA (SC, ptr_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, ptr_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -235,8 +238,8 @@ REG ptr_reg[] = { MTAB ptr_mod[] = { { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, { UNIT_DIAG, 0, "reader mode", "READER", NULL }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &ptr_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ptr_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ptr_dev }, { 0 } }; @@ -270,13 +273,14 @@ REG ptp_reg[] = { { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, + { ORDATA (SC, ptp_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, ptp_dib.select_code, 6), REG_HRO }, { NULL } }; MTAB ptp_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &ptp_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ptp_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ptp_dev }, { 0 } }; @@ -322,6 +326,7 @@ REG tty_reg[] = { { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, { DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT }, { FLDATA (STOP_IOE, ttp_stopioe, 0) }, + { ORDATA (SC, tty_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, tty_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -333,8 +338,8 @@ MTAB tty_mod[] = { { TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_opt }, { UNIT_AUTOLF, UNIT_AUTOLF, "autolf", "AUTOLF", &tty_set_alf }, { UNIT_AUTOLF, 0 , NULL, "NOAUTOLF", &tty_set_alf }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &tty_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &tty_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &tty_dev }, { 0 } }; @@ -367,6 +372,7 @@ REG clk_reg[] = { { FLDATA (ERR, clk_error, CLK_V_ERROR) }, { BRDATA (TIME, clk_time, 10, 24, 8) }, { DRDATA (IPTICK, clk_tick, 24), PV_RSPC | REG_RO }, + { ORDATA (SC, clk_dib.select_code, 6), REG_HRO }, { ORDATA (DEVNO, clk_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -374,8 +380,8 @@ REG clk_reg[] = { MTAB clk_mod[] = { { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, { UNIT_DIAG, 0, "calibrated", "CALIBRATED", NULL }, - { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &clk_dev }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &clk_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &clk_dev }, { 0 } }; @@ -384,7 +390,8 @@ DEVICE clk_dev = { 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, NULL, NULL, NULL, - &clk_dib, DEV_DISABLE + &clk_dib, DEV_DISABLE, + 0, NULL, NULL, "TBG" }; diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index 044c2825..c6cd201c 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-2010, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Added hp_setsc, hp_showsc functions to support SC modifier + 15-Dec-11 JDB Added DA and dummy DC devices 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation 26-Oct-10 JDB Changed DIB access for revised signal model 03-Sep-08 JDB Fixed IAK instruction dual-use mnemonic display @@ -78,6 +81,7 @@ extern DEVICE ds_dev; extern DEVICE muxl_dev, muxu_dev, muxc_dev; extern DEVICE ipli_dev, iplo_dev; extern DEVICE pif_dev; +extern DEVICE da_dev, dc_dev; /* SCP data structures and interface routines @@ -118,6 +122,7 @@ DEVICE *sim_devices[] = { &muxl_dev, &muxu_dev, &muxc_dev, &ipli_dev, &iplo_dev, &pif_dev, + &da_dev, &dc_dev, NULL }; @@ -768,39 +773,84 @@ else { /* printable character * } -/* Set device number */ +/* Set select code */ -t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) +t_stat hp_setsc (UNIT *uptr, int32 num, char *cptr, void *desc) { DEVICE *dptr = (DEVICE *) desc; DIB *dibptr; int32 i, newdev; t_stat r; -if (cptr == NULL) return SCPE_ARG; -if ((desc == NULL) || (num > 1)) return SCPE_IERR; +if (cptr == NULL) + return SCPE_ARG; + +if ((desc == NULL) || (num > 1)) + return SCPE_IERR; + dibptr = (DIB *) dptr->ctxt; -if (dibptr == NULL) return SCPE_IERR; + +if (dibptr == NULL) + return SCPE_IERR; + newdev = get_uint (cptr, 8, I_DEVMASK - num, &r); -if (r != SCPE_OK) return r; -if (newdev < VARDEV) return SCPE_ARG; -for (i = 0; i <= num; i++, dibptr++) dibptr->select_code = newdev + i; + +if (r != SCPE_OK) + return r; + +if (newdev < VARDEV) + return SCPE_ARG; + +for (i = 0; i <= num; i++, dibptr++) + dibptr->select_code = newdev + i; + return SCPE_OK; } +/* Show select code */ + +t_stat hp_showsc (FILE *st, UNIT *uptr, int32 num, void *desc) +{ +DEVICE *dptr = (DEVICE *) desc; +DIB *dibptr; +int32 i; + +if ((desc == NULL) || (num > 1)) + return SCPE_IERR; + +dibptr = (DIB *) dptr->ctxt; + +if (dibptr == NULL) + return SCPE_IERR; + +fprintf (st, "select code=%o", dibptr->select_code); + +for (i = 1; i <= num; i++) + fprintf (st, "/%o", dibptr->select_code + i); + +return SCPE_OK; +} + + +/* Set device number */ + +t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) +{ +return hp_setsc (uptr, num, cptr, desc); +} + + /* Show device number */ t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc) { -DEVICE *dptr = (DEVICE *) desc; -DIB *dibptr; -int32 i; +t_stat result; -if ((desc == NULL) || (num > 1)) return SCPE_IERR; -dibptr = (DIB *) dptr->ctxt; -if (dibptr == NULL) return SCPE_IERR; -fprintf (st, "devno=%o", dibptr->select_code); -for (i = 1; i <= num; i++) fprintf (st, "/%o", dibptr->select_code + i); -return SCPE_OK; +result = hp_showsc (st, uptr, num, desc); + +if (result == SCPE_OK) + fputc ('\n', st); + +return result; } diff --git a/HP2100/hp_disclib.c b/HP2100/hp_disclib.c new file mode 100644 index 00000000..2424c05c --- /dev/null +++ b/HP2100/hp_disclib.c @@ -0,0 +1,2407 @@ +/* hp_disclib.c: HP MAC/ICD disc controller simulator library + + Copyright (c) 2011-2012, J. David Bryan + Copyright (c) 2004-2011, Robert 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 + THE AUTHORS 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 names of the authors 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 authors. + + 15-Mar-12 JDB First release + 09-Nov-11 JDB Created disc controller common library from DS simulator + + References: + - 13037 Disc Controller Technical Information Package (13037-90902, Aug-1980) + - HP 13365 Integrated Controller Programming Guide (13365-90901, Feb-1980) + - HP 1000 ICD/MAC Disc Diagnostic Reference Manual (5955-4355, Jun-1984) + - RTE-IVB System Manager's Manual (92068-90006, Jan-1983) + - DVR32 RTE Moving Head Driver source (92084-18711, Revision 5000) + + + This library provides common functions required by HP disc controllers. It + implements the 13037 MAC and 13365 ICD controller command sets used with the + 7905/06/20/25 and 7906H/20H/25H disc drives. + + The library is an adaptation of the code originally written by Bob Supnik + for the DS simulator. DS simulates a 13037 controller connected via a 13175 + disc interface to an HP 1000 computer. To create the library, the functions + of the controller were separated from the functions of the interface. This + allows the library to work with other CPU interfaces, such as the 12821A + HP-IB disc interface, that use substantially different communication + protocols. The library functions implement the controller command set for + the drive units. The interface functions handle the transfer of commands and + data to and from the CPU. + + As a result of this separation, the library does not handle the data transfer + between the controller and the interface directly. Instead, data is moved + between the interface and a sector buffer by the interface simulator, and + then the buffer is passed to the disc library for reading or writing. This + buffer is also used to pass disc commands and parameters to the controller, + and to receive status information from the controller. Only one buffer is + needed per interface, regardless of the number of controllers or units + handled, as a single interface cannot perform data transfers concurrently + with controller commands. + + The library provides routines to prepare, start, and end commands, service + units, and poll drives for Attention status. In addition, routines are + provided to attach and detach disc images from drive units, load and unload + disc heads, classify commands, and provide opcode and phase name strings for + debugging. + + The interface simulator declares a structure that contains the state + variables for a controller. A MAC controller may handle multiple disc units. + An ICD controller handles only a single disc unit, but multiple controllers + may be employed to support several drives on a given interface. The type of + the controller (MAC or ICD) is contained in the structure, which is passed to + the disc library routines. The minor differences in controller action + between the two are handled internally. A macro (CNTLR_INIT) is provided to + initialize the structure. + + The interface simulator also declares the sector buffer. The buffer is an + array containing DL_BUFSIZE 16-bit elements. The address of the buffer is + stored in the controller state structure. The controller maintains the + current index into the buffer, as well as the length of valid data stored + there. Other than setting the length when the controller places data into + the buffer, and resetting the index at the start of a sector read or write, + the interface simulator is free to manipulate these values as desired. + + In general, a user of the library is free to read any of the controller state + variable structure fields. Writing to the fields generally will interfere + with controller operations, with these exceptions: + + Field Name Description + =========== ======================== + status controller status + eod end of data flag + index data buffer index + length data buffer length + seek_time seek delay time + sector_time intersector delay time + cmd_time command start delay time + data_time data transfer delay time + wait_time command wait timeout + + In hardware, the controller executes in three basic states: + + 1. In the Poll Loop, which looks for commands and drive attention requests. + + In each pass of the loop, the next CPU interface in turn is checked for a + command; if present, it is executed. If none are pending, all drives are + checked in turn until one is found with Attention status; if none are + found, the loop continues. If a drive is requesting attention, the + associated CPU interface is connected to check for a command; if present, + it is executed. If not, and the interface allows interrupts, an + interrupt request is made and the Command Wait Loop is entered. If + interrupts are not allowed, the Poll Loop continues. + + 2. In the Command Wait Loop, which looks for commands. + + In each pass of the loop, the current CPU interface is checked for a + command; if present, it is executed. If not, the Command Wait Loop + continues. While in the loop, a 1.8 second timer is running. If it + expires before a command is received, the file mask is reset, and the + Poll Loop is entered. + + 3. In command execution, which processes the current command. + + During command execution, waits for input parameters, seek completion, + data transfers, and output status words are handled internally. Each + wait is governed by the 1.8 second timer; if it expires, the command is + aborted. + + In simulation, these states are represented by the values cntlr_idle, + cntlr_wait, and cntlr_busy, respectively. + + A MAC controller operates from one to eight drives, represented by an array + of one to eight units. When operating multiple units, a pointer to the first + unit of a contiguous array is passed, and the unit number present in the + command is used to index to the target unit. + + A MAC controller emulation requires an array of two contiguous auxiliary + units containing a controller unit and a command wait timeout unit. Commands + that do not access the drive, such as Address Record, are scheduled on the + controller unit to allow controller commands to execute while drive units are + seeking. The command wait timer limits the amount of time the controller will + wait for the interface to supply a command or parameter. A pointer to the + auxiliary unit array is set up during controller state variable + initialization. + + An ICD controller manages a single unit corresponding to the drive in which + the controller is integrated. An interface declares a unit array + corresponding to the number of drives supported and passes the unit number to + use to the command preparation and start routines. Auxiliary units are not + used, and all commands are scheduled on the drive unit associated with a + given controller. + + The library provides a unit service routine to handle all of the disc + commands. The routine is called from the interface service routine to handle + the common disc actions, while the interface routine handles actions specific + to the operation of the interface (such as data transfer). + + The service routine schedules the unit to continue command execution under + these conditions: + + 1. A Seek or Recalibrate command is waiting for the seek completion. + + 2. A read or write command is waiting for the first data transfer of a + sector to start. + + 3. A read or write command is waiting for the next sector to start after + the final data transfer of the preceding sector. + + 4. A Verify command is waiting for the end of the current sector. + + The library also provides controller and timer service routines for MAC + emulations. All three (unit, controller, and timer) must be called from + their respective interface service routines before any interface-specific + actions, if any, are taken. + + On return from the library unit or controller service routines, the "wait" + field of the UNIT structure will be set to the activation time if the unit + is to be scheduled. The caller is responsible for activating the unit. If + the caller uses this feature, the field should be reset to zero before the + next service call. + + The MAC timer unit is activated by the library, and the "wait" field is not + used. The timer starts when a command other than End, Seek, or Recalibrate + completes, and when the controller is waiting for the interface to supply or + accept a parameter during command execution. It stops when an End, Seek, or + Recalibrate command completes, a command is prepared for execution, or the + final parameter has been supplied or accepted by the interface during command + execution. + + The controller maintains six variables in each drive's unit structure: + + wait -- the current service activation time + pos -- the current file offset + u3 (CYL) -- the current drive cylinder + u4 (STAT) -- the drive status (Status-2) + u5 (OP) -- the drive operation in process + u6 (PHASE) -- the current operation phase + + These and other definitions are in the file hp_disclib.h, which must be + included in the interface simulator. + + The controller library supports up to eight drives per MAC controller and one + drive per ICD controller. Unit numbers 0-7 represent valid drive addresses + for a MAC controller. The unit number field is ignored for an ICD + controller, and unit 0 is always implied. In simulation, MAC unit numbers + correspond one-for-one with device units, whereas one ICD controller is + associated with each of the several device units that are independently + addressed as unit 0. + + The MAC controller firmware allows access to unit numbers 8-10 without + causing a Unit Unavailable error. Instead, the controller reports these + legal-but-invalid units as permanently offline. + + + Implementation notes: + + 1. The library does not simulate sector headers and trailers. Initialize + and Write Full Sector commands ignore the SPD bits and the supplied + header and trailer words. Read Full Sector fills in the header with the + current CHS address and sets the SPD bits to zero. The CRC and ECC words + in the trailer are returned as zeros. Programs that depend on drives + retaining the set values will fail. + + 2. The library does not simulate drive hold bits or support multiple CPU + interfaces connected to the same controller. CPU access to a valid drive + always succeeds. + + 3. The library does not simulate interface signals or function bus orders, + except for EOD (End of Data) and BUSY. The interface simulators must + decide for themselves what actions to take (e.g., interrupting the CPU) + on the basis of the controller state. + + 4. The command/sector buffer is an array of 16-bit elements. Byte-oriented + interface simulators, such as the 12821A HP-IB Disc Interface, must do + their own byte packing and unpacking. + + 5. The SAVE command does not save the "wait" and "pos" fields of the UNIT + structure automatically. To ensure that they are saved, they are + referenced by hidden, read-only registers. +*/ + + + +#include + +#include "hp_disclib.h" + + + +/* Command accessors (16-bit word) */ + +#define DL_V_OPCODE 8 /* bits 12- 8: general opcode */ +#define DL_V_HOLD 7 /* bits 7- 7: general hold flag */ +#define DL_V_UNIT 0 /* bits 3- 0: general unit number */ + +#define DL_V_SPD 13 /* bits 15-13: initialize S/P/D flags */ +#define DL_V_CHEAD 6 /* bits 7- 6: cold load head */ +#define DL_V_CSECT 0 /* bits 5- 0: cold load sector */ +#define DL_V_FRETRY 4 /* bits 7- 4: file mask retry count */ +#define DL_V_FDECR 3 /* bits 3- 3: file mask seek decrement */ +#define DL_V_FSPEN 2 /* bits 2- 2: file mask sparing enable */ +#define DL_V_FCYLM 1 /* bits 1- 1: file mask cylinder mode */ +#define DL_V_FAUTSK 0 /* bits 0- 0: file mask auto seek */ + +#define DL_V_FMASK 0 /* bits 3- 0: file mask (combined) */ + + +#define DL_M_OPCODE 037 +#define DL_M_UNIT 017 + +#define DL_M_SPD 007 +#define DL_M_CHEAD 003 +#define DL_M_CSECT 077 +#define DL_M_FRETRY 017 +#define DL_M_FMASK 017 + + +#define GET_OPCODE(c) (CNTLR_OPCODE) (((c) >> DL_V_OPCODE) & DL_M_OPCODE) +#define GET_UNIT(c) (((c) >> DL_V_UNIT) & DL_M_UNIT) + +#define GET_SPD(c) (((c) >> DL_V_SPD) & DL_M_SPD) +#define GET_CHEAD(c) (((c) >> DL_V_CHEAD) & DL_M_CHEAD) +#define GET_CSECT(c) (((c) >> DL_V_CSECT) & DL_M_CSECT) +#define GET_FRETRY(c) (((c) >> DL_V_FRETRY) & DL_M_FRETRY) +#define GET_FMASK(c) (((c) >> DL_V_FMASK) & DL_M_FMASK) + +#define DL_FDECR (1 << DL_V_FDECR) +#define DL_FSPEN (1 << DL_V_FSPEN) +#define DL_FCYLM (1 << DL_V_FCYLM) +#define DL_FAUTSK (1 << DL_V_FAUTSK) + + +/* Parameter accessors (16-bit word) */ + +#define DL_V_HEAD 8 /* bits 12- 8: head number */ +#define DL_V_SECTOR 0 /* bits 7- 0: sector number */ + +#define DL_M_HEAD 0017 +#define DL_M_SECTOR 0377 + +#define GET_HEAD(p) (((p) >> DL_V_HEAD) & DL_M_HEAD) +#define GET_SECTOR(p) (((p) >> DL_V_SECTOR) & DL_M_SECTOR) + +#define SET_HEAD(c) (((c)->head & DL_M_HEAD) << DL_V_HEAD) +#define SET_SECTOR(c) (((c)->sector & DL_M_SECTOR) << DL_V_SECTOR) + + +/* Drive properties table. + + In hardware, drives report their Drive Type numbers to the controller upon + receipt of a Request Status tag bus command. The drive type is used to + determine the legal range of head and sector addresses (the drive itself will + validate the cylinder during seeks). + + In simulation, we set up a table of drive properties and use the model ID as + an index into the table. The table is used to validate seek parameters and + to provide the mapping between CHS addresses and the linear byte addresses + required by the host file access routines. + + The 7905/06/06H drives consist of removable and fixed platters, whereas the + 7920/20H/25/25H drives have only removable multi-platter packs. As a result, + 7905/06 drives are almost always accessed in platter mode, i.e., a given + logical disc area is fully contained on either the removable or fixed + platter, whereas the 7920/25 drives are almost always accessed in cylinder + mode with logical disc areas spanning some or all of the platters. + + Disc image files are arranged as a linear set of tracks. To improve + locality of access, tracks in the 7905/06 images are grouped per-platter, + whereas tracks on the 7920 and 7925 are sequential by cylinder and head + number. + + The simulator maps the tracks on the 7905/06 removable platter (heads 0 and + 1) to the first half of the disc image, and the tracks on the fixed platter + (heads 2 and, for the 7906 only, 3) to the second half of the image. For the + 7906/06H, the cylinder-head order of the tracks is 0-0, 0-1, 1-0, 1-1, ..., + 410-0, 410-1, 0-2, 0-3, 1-2, 1-3, ..., 410-2, 410-3. The 7905 order is the + same, except that head 3 tracks are omitted. + + For the 7920/20H/25/25H, all tracks appear in cylinder-head order, e.g., 0-0, + 0-1, 0-2, 0-3, 0-4, 1-0, 1-1, ..., 822-2, 822-3, 822-4 for the 7920/20H. + + This variable-access geometry is accomplished by defining additional "heads + per cylinder" values for the fixed and removable sections of each drive that + indicates the number of heads that should be grouped for locality. The + removable values are set to 2 on the 7905 and 7906, indicating that those + drives typically use cylinders consisting of two heads. They are set to the + number of heads per drive for the 7920 and 7925, as those typically use + cylinders encompassing the entire pack. +*/ + +#define D7905_RH 2 +#define D7905_FH (D7905_HEADS - D7905_RH) + +#define D7906_RH 2 +#define D7906_FH (D7906_HEADS - D7906_RH) + +#define D7920_RH D7920_HEADS +#define D7920_FH (D7920_HEADS - D7920_RH) + +#define D7925_RH D7925_HEADS +#define D7925_FH (D7925_HEADS - D7925_RH) + +typedef struct { + uint32 sectors; /* sectors per head */ + uint32 heads; /* heads per cylinder*/ + uint32 cylinders; /* cylinders per drive */ + uint32 words; /* words per drive */ + uint32 type; /* drive type */ + uint32 remov_heads; /* number of removable-platter heads */ + uint32 fixed_heads; /* number of fixed-platter heads */ + } DRIVE_PROPERTIES; + + +static const DRIVE_PROPERTIES drive_props [] = { + { D7905_SECTS, D7905_HEADS, D7905_CYLS, D7905_WORDS, D7905_TYPE, D7905_RH, D7905_FH }, + { D7906_SECTS, D7906_HEADS, D7906_CYLS, D7906_WORDS, D7906_TYPE, D7906_RH, D7906_FH }, + { D7920_SECTS, D7920_HEADS, D7920_CYLS, D7920_WORDS, D7920_TYPE, D7920_RH, D7920_FH }, + { D7925_SECTS, D7925_HEADS, D7925_CYLS, D7925_WORDS, D7925_TYPE, D7925_RH, D7925_FH } + }; + +#define PROPS_COUNT (sizeof (drive_props) / sizeof (drive_props [0])) + + +/* Convert a CHS address to a block offset. + + A cylinder/head/sector address is converted into a linear block address that + may be used to calculate a byte offset to pass to the file access routines. + The conversion logic is: + + if Head < removable_heads_per_cylinder then + tracks := Cylinder * removable_heads_per_cylinder + Head; + else + tracks := cylinders_per_drive * removable_heads_per_cylinder + + Cylinder * fixed_heads_per_cylinder + (Head - removable_heads_per_cylinder); + + block := tracks * sectors_per_track + Sector; + + byte_offset := block * words_per_sector * bytes_per_word; + + The byte offset is calculated in two steps to allow for future controller + enhancements to support the CS/80 command set and its associated linear block + addressing mode. +*/ + +#define TO_BLOCK(cylinder,head,sector,model) \ + (((head) < drive_props [model].remov_heads \ + ? (cylinder) * drive_props [model].remov_heads + (head) \ + : drive_props [model].cylinders * drive_props [model].remov_heads \ + + ((cylinder) * drive_props [model].fixed_heads + (head) - drive_props [model].remov_heads)) \ + * drive_props [model].sectors + (sector)) + +#define TO_OFFSET(block) ((block) * DL_WPSEC * sizeof (uint16)) + + +/* Estimate the current sector. + + The sector currently passing under the disc heads is estimated from the + current simulator time (i.e., the count of instructions since startup) and + the simulated disc rotation time. The computation logic is: + + per_sector_time := word_transfer_time * words_per_sector + intersector_time; + + current_sector := (current_time / per_sector_time) MOD sectors_per_track; +*/ + +#define GET_CURSEC(cvptr,uptr) \ + ((uint16) fmod (sim_gtime() / (double) ((cvptr->data_time * DL_WPSEC + cvptr->sector_time)), \ + (double) drive_props [GET_MODEL (uptr->flags)].sectors)) + + +/* Command properties table. + + The validity of each command for a given type of controller is checked + against the command properties table when it is prepared. The table also + includes the count of inbound and outbound properties, the class of the + command, and flags to indicate certain common actions that should be taken. +*/ + +#define CP_V_CLRS 15 /* bits 15-15: command clears the controller status */ +#define CP_V_WAIT 14 /* bits 14-15: command waits for seek completion */ +#define CP_V_UACC 13 /* bits 13-13: command accesses the unit */ +#define CP_V_UCHK 12 /* bits 12-12: command checks for unit legality */ +#define CP_V_UNIT 11 /* bits 11-11: command has a unit field */ +#define CP_V_CTYPE 9 /* bits 10- 9: valid controller types */ +#define CP_V_CLASS 6 /* bits 8- 6: command classification code */ +#define CP_V_INCNT 3 /* bits 5- 3: inbound parameter word count */ +#define CP_V_OUTCNT 0 /* bits 2- 0: outbound parameter word count */ + +#define CP_M_CTYPE 3 /* 2-bit valid controller types mask */ +#define CP_M_CLASS 7 /* 3-bit classification code mask */ +#define CP_M_INCNT 7 /* 3-bit inbound parameter word count mask */ +#define CP_M_OUTCNT 7 /* 3-bit outbound parameter word count mask */ + +#define CP_CLRS (1 << CP_V_CLRS) +#define CP_WAIT (1 << CP_V_WAIT) +#define CP_UACC (1 << CP_V_UACC) +#define CP_UCHK (1 << CP_V_UCHK) +#define CP_UNIT (1 << CP_V_UNIT) + +#define CP_MAC (MAC << CP_V_CTYPE) /* command is valid for MAC controllers */ +#define CP_ICD (ICD << CP_V_CTYPE) /* command is valid for ICD controllers */ + +#define CP_INVAL (class_invalid << CP_V_CLASS) /* invalid classification */ +#define CP_READ (class_read << CP_V_CLASS) /* read classification */ +#define CP_WRITE (class_write << CP_V_CLASS) /* write classification */ +#define CP_CNTL (class_control << CP_V_CLASS) /* control classification */ +#define CP_STAT (class_status << CP_V_CLASS) /* status classification */ + +#define TO_CTYPE(t) (uint32) ((t) << CP_V_CTYPE) + +#define GET_CLASS(c) (CNTLR_CLASS) (((c) >> CP_V_CLASS) & CP_M_CLASS) +#define GET_INCNT(c) (((c) >> CP_V_INCNT) & CP_M_INCNT) +#define GET_OUTCNT(c) (((c) >> CP_V_OUTCNT) & CP_M_OUTCNT) + +// >>> better? +#if 0 +typedef struct { + CNTLR_OPCODE code; + uint32 inbound; + uint32 outbound; + CNTLR_CLASS class; + t_bool mac; + t_bool icd; + t_bool clear_status; + t_bool unit_field; + t_bool unit_check; + t_bool unit_access; + t_bool seek_wait; + } DS_PROPS; + +static const DS_PROPS cmd_props [] = { +/* in out class mac icd clst unit uchk uacc wait */ + { 0, 0, class_read, 1, 1, 1, 0, 1, 1, 0 }, /* cold load read */ + { 0, 0, class_control, 1, 1, 1, 1, 1, 1, 1 }, /* recalibrate */ + { 2, 0, class_control, 1, 1, 1, 1, 1, 1, 0 }, /* seek */ + { 0, 2, class_status, 1, 1, 0, 1, 0, 0, 0 }, /* request status */ + { 0, 1, class_status, 1, 1, 1, 1, 1, 0, 0 }, /* request sector address */ + { 0, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* read */ + { 0, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* read full sector */ + { 1, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* verify */ + { 0, 0, class_write, 1, 1, 1, 1, 1, 1, 1 }, /* write */ + { 0, 0, class_write, 1, 1, 1, 1, 1, 1, 1 }, /* write full sector */ + { 0, 0, class_control, 1, 1, 1, 0, 0, 0, 0 }, /* clear */ + { 0, 0, class_write, 1, 1, 1, 1, 1, 1, 1 }, /* initialize */ + { 2, 0, class_control, 1, 1, 1, 0, 0, 0, 0 }, /* address record */ + { 0, 7, class_status, 1, 0, 0, 0, 0, 0, 0 }, /* request syndrome */ + { 1, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* read with offset */ + { 0, 0, class_control, 1, 1, 1, 0, 0, 0, 0 }, /* set file mask */ + { 0, 0, class_invalid, 0, 0, 1, 0, 0, 0, 0 }, /* invalid */ + { 0, 0, class_invalid, 0, 0, 1, 0, 0, 0, 0 }, /* invalid */ + { 0, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* read without verify */ + { 1, 0, class_status, 1, 0, 1, 0, 0, 0, 0 }, /* load TIO register */ + { 0, 2, class_status, 1, 1, 0, 0, 0, 0, 0 }, /* request disc address */ + { 0, 0, class_control, 1, 1, 1, 0, 0, 0, 0 }, /* end */ + { 0, 0, class_control, 1, 0, 1, 1, 1, 0, 0 } /* wakeup */ + }; +#endif + +static const uint32 cmd_props [] = { + 000 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UCHK | CP_UACC, /* cold load read */ + 000 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* recalibrate */ + 020 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC, /* seek */ + 002 | CP_STAT | CP_MAC | CP_ICD | CP_UNIT, /* request status */ + 001 | CP_STAT | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK, /* request sector address */ + 000 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* read */ + 000 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* read full sector */ + 010 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* verify */ + 000 | CP_WRITE | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* write */ + 000 | CP_WRITE | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* write full sector */ + 000 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS, /* clear */ + 000 | CP_WRITE | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* initialize */ + 020 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS, /* address record */ + 007 | CP_STAT | CP_MAC, /* request syndrome */ + 010 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* read with offset */ + 000 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS, /* set file mask */ + 000 | CP_INVAL | CP_CLRS, /* invalid */ + 000 | CP_INVAL | CP_CLRS, /* invalid */ + 000 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* read without verify */ + 010 | CP_STAT | CP_MAC | CP_CLRS, /* load TIO register */ + 002 | CP_STAT | CP_MAC | CP_ICD, /* request disc address */ + 000 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS, /* end */ + 000 | CP_CNTL | CP_MAC | CP_CLRS | CP_UNIT | CP_UCHK /* wakeup */ + }; + + +/* Auxiliary unit indices */ + +typedef enum { + controller = 0, /* controller unit index */ + timer = 1 /* command wait timer index */ + } AUX_INDEX; + + +/* Controller opcode names */ + +static const char invalid_name [] = "invalid"; + +static const char *opcode_name [] = { + "cold load read", /* 00 */ + "recalibrate", /* 01 */ + "seek", /* 02 */ + "request status", /* 03 */ + "request sector address", /* 04 */ + "read", /* 05 */ + "read full sector", /* 06 */ + "verify", /* 07 */ + "write", /* 10 */ + "write full sector", /* 11 */ + "clear", /* 12 */ + "initialize", /* 13 */ + "address record", /* 14 */ + "request syndrome", /* 15 */ + "read with offset", /* 16 */ + "set file mask", /* 17 */ + invalid_name, /* 20 = invalid */ + invalid_name, /* 21 = invalid */ + "read without verify", /* 22 */ + "load TIO register", /* 23 */ + "request disc address", /* 24 */ + "end", /* 25 */ + "wakeup" /* 26 */ + }; + +/* Controller phase names */ + +static const char *phase_name [] = { + "start", + "data", + "end" + }; + + + +/* Disc library local controller routines */ + +static t_bool start_seek (CVPTR cvptr, UNIT *uptr, CNTLR_OPCODE next_opcode, CNTLR_PHASE next_phase); +static t_stat start_read (CVPTR cvptr, UNIT *uptr); +static void end_read (CVPTR cvptr, UNIT *uptr); +static void start_write (CVPTR cvptr, UNIT *uptr); +static t_stat end_write (CVPTR cvptr, UNIT *uptr); +static t_bool position_sector (CVPTR cvptr, UNIT *uptr, t_bool verify); +static void next_sector (CVPTR cvptr, UNIT *uptr); +static t_stat io_error (CVPTR cvptr, UNIT *uptr); + +/* Disc library local utility routines */ + +static void set_address (CVPTR cvptr, uint32 index); +static void set_timer (CVPTR cvptr, FLIP_FLOP action); +static uint16 drive_status (UNIT *uptr); + + + +/* Disc library global controller routines */ + + +/* Prepare a command for execution. + + On entry, the first word of the controller buffer contains the command to + prepare, the "cvptr" parameter points at the controller state variable + structure, and the "units" parameter points at the first unit of the unit + array. For a MAC controller, the "unit limit" parameter indicates the last + valid unit number, and the unit to use is taken from the unit field of the + command word. For an ICD controller, the parameter indicates the number + of the unit to use directly. + + If a valid command was prepared for execution, the routine returns TRUE and + sets the controller state to "busy." If the command is illegal, the routine + returns FALSE and sets the controller state to "waiting." In the latter + case, the controller status will indicate the reason for the rejection. + + The opcode and unit number (for MAC controllers) are obtained from the buffer + and checked for legality. If either is illegal, the controller status is set + appropriately, and the routine returns FALSE. + + For a valid command and an available unit, the controller's opcode field is + set from the buffer, the length field is set to the number of inbound + parameter words expected, and the index field is set to 1 to point at the + first parameter entry in the buffer. +*/ + +t_bool dl_prepare_command (CVPTR cvptr, UNIT *units, uint32 unit_limit) +{ +uint32 props, unit; +CNTLR_OPCODE opcode; + +set_timer (cvptr, CLEAR); /* stop the command wait timer */ + +opcode = GET_OPCODE (cvptr->buffer [0]); /* get the opcode from the command */ + +if (opcode > last_opcode) /* is the opcode invalid? */ + props = CP_CLRS; /* undefined commands clear prior status */ +else /* the opcode is potentially valid */ + props = cmd_props [opcode]; /* get the command properties */ + +if (cvptr->type == MAC) /* is this a MAC controller? */ + if (props & CP_UNIT) /* is the unit field defined for this command? */ + unit = GET_UNIT (cvptr->buffer [0]); /* get the unit from the command */ + else /* no unit specified in the command */ + unit = 0; /* so the unit is always unit 0 */ + +else /* an ICD controller */ + unit = unit_limit; /* uses the supplied unit number */ + +if (props & CP_CLRS) { /* clear the prior controller status */ + cvptr->status = normal_completion; /* if indicated for this command */ + cvptr->spd_unit = SET_S1UNIT (unit); /* save the unit number for status requests */ + } + +if (props & TO_CTYPE (cvptr->type)) /* is the opcode defined for this controller? */ + if ((props & CP_UCHK) && unit > DL_MAXUNIT) /* if the unit number is checked and is illegal, */ + dl_end_command (cvptr, unit_unavailable); /* end with a unit unavailable error */ + + else { + cvptr->state = cntlr_busy; /* legal unit, so controller is now busy */ + cvptr->opcode = opcode; /* save the controller opcode */ + cvptr->length = GET_INCNT (props); /* set the inbound parameter count */ + cvptr->index = 1; /* point at the first parameter element (if any) */ + + if (cvptr->type == MAC && cvptr->length) { /* MAC controller and inbound parameters? */ + cvptr->aux [controller].OP = opcode; /* save the opcode */ + cvptr->aux [controller].PHASE = data_phase; /* and set the phase for parameter pickup */ + set_timer (cvptr, SET); /* start the timer to wait for the first parameter */ + } + + return TRUE; /* command is now prepared for execution */ + } + +else /* the opcode is undefined */ + dl_end_command (cvptr, illegal_opcode); /* so set bad opcode status */ + +return FALSE; /* the preparation has failed */ +} + + +/* Start a command. + + On entry, the controller's opcode field contains the command to start, and + the buffer contains the command word in element 0 and the parameters required + by the command, if any, beginning in element 1. The call parameters are the + same as those supplied to the "prepare command" routine. + + If the command was started successfully, the routine returns a pointer to the + unit to be activated and sets that unit's "wait" field to the activation + time. The caller should activate the unit upon return to complete or + continue command processing. If the command did not start, the routine + returns NULL. + + If a seek is in progress on a drive when a command accessing that drive is + started, the unit pointer is returned but the unit's "wait" field is set to + zero. In this case, the unit must not be activated (as it already is). + Instead, the unit's opcode and phase fields are set to start the command + automatically when the seek completes. + + For commands that return status from the controller, the buffer will contain + the returned value(s), the buffer index will be zero, and the buffer length + will be set to the number of words returned in the buffer. These words must + be returned to the CPU via the interface. + + + Implementation notes: + + 1. A command must have been prepared by calling dl_prepare_command first. + After preparation, the controller's opcode will be valid, and the unit + number field will be legal (but not necessarily valid) for those commands + that check the unit. + + Unit numbers 0-7 represent valid drive addresses. However, the MAC + controller firmware allows access to unit numbers 8-10 without causing a + Unit Unavailable error. Instead, the controller reports these units as + permanently offline. + + 2. Commands that check for a valid unit do some processing before failing + with a Status-2 (not ready) error. For example, the Seek command accepts + its parameters from the CPU and sets the CHS values into the controller + before failing. + + 3. In hardware, read, write, and recalibrate commands wait in an internal + loop for a pending seek completion and clear the resulting Attention + status before executing. In simulation, we change a seeking drive unit's + opcode and phase fields from seek completion to the start of the next + command. This eliminates the setting of the Attention status and begins + command execution automatically when the seek completes. + + If the seek completed between the command preparation and start, + Attention will have been set. If the unit is idle on entry, we clear the + Attention status unilaterally (it doesn't matter whether or not it was + set; Attention always is clear when commands start). + + 4. The Seek and Cold Load Read commands do not check for a seek or + recalibrate in progress. If the heads are moving, the drive will reject + a seek command with a Seek Check error. The firmware does not test + explicitly for Access Not Ready before executing the command, so the + parameters (e.g., controller CHS addresses) are still set as though the + command succeeded. + + A Seek command will return to the Poll Loop with Seek Check status set. + When the seek in progress completes, the controller will interrupt with + Drive Attention status. The controller address will differ from the + drive address, so it's incumbent upon the caller to issue a Request + Status command after the seek, which will return Status-2 Error status. + + A Cold Load Read command issues a seek to cylinder 0 and then begins a + read, which first waits for seek completion. The Seek Check error will + abort the command at this point with Status-2 Error status. + + In simulation, a Seek command allows the seek in progress to complete + normally, whereas a Cold Load Read command modifies the unit command + and phase from the end phase of Seek or Recalibrate to the start + phase of Read, which will catch the Seek Check error as in hardware. + + 5. The Cold Load Read command checks if the drive is ready before setting + the file mask. Therefore, we normally defer setting the file mask until + the unit service is called. However, if a seek is in progress, then the + drive must be ready, so we set the file mask here. + + 6. ECC is not simulated, so the Request Syndrome command always returns zero + values for the displacement and patterns. + + 7. The Request Status, Request Sector Address, and Wakeup commands reference + drive units but are scheduled on the controller unit because they may be + issued while a drive is processing a seek. + + 8. The activation time is set to one-half of the intersector time (latency) + for read and write commands, and to the controller processing time for + all others. +*/ + +UNIT *dl_start_command (CVPTR cvptr, UNIT *units, uint32 unit_limit) +{ +UNIT *uptr, *rptr; +uint32 props, unit; +t_bool is_seeking = FALSE; + +props = cmd_props [cvptr->opcode]; /* get the command properties */ + +if (cvptr->type == MAC) { /* is this a MAC controller? */ + if (props & CP_UNIT) /* is the unit field defined for this command? */ + unit = GET_UNIT (cvptr->buffer [0]); /* get the unit number from the command */ + else /* no unit is specified in the command */ + unit = 0; /* so the unit number defaults to 0 */ + + if (unit > unit_limit) /* if the unit number is invalid, */ + uptr = NULL; /* it does not correspond to a unit */ + else if (props & CP_UACC) /* if the command accesses a drive, */ + uptr = units + unit; /* get the address of the unit */ + else /* the command accesses the controller only */ + uptr = cvptr->aux + controller; /* so use the controller unit */ + } + +else { /* for an ICD controller, */ + unit = 0; /* the unit value is ignored */ + uptr = units + unit_limit; /* and we use the indicated unit */ + } + +if ((props & CP_UCHK) && !uptr /* if the unit number is checked and is invalid */ + || (props & CP_WAIT) /* or the command waits for the drive */ + && (drive_status (uptr) & DL_S2STOPS)) { /* and the drive is offline or faulted */ + dl_end_command (cvptr, status_2_error); /* then the command ends with a Status-2 error */ + uptr = NULL; /* prevent command from starting */ + } + +else if (uptr) { /* otherwise, we have a valid unit */ + uptr->wait = cvptr->cmd_time; /* most commands use the command delay */ + + if (props & CP_UACC) { /* does the command access the unit? */ + is_seeking = sim_is_active (uptr) != 0; /* see if the unit is busy */ + + if (is_seeking) /* if a seek is in progress, */ + uptr->wait = 0; /* set for no unit activation */ + + else { /* otherwise, the unit is idle */ + uptr->STAT &= ~DL_S2ATN; /* clear the drive Attention status */ + + if (GET_CLASS (props) == class_read /* if a read command */ + || GET_CLASS (props) == class_write) /* or a write command */ + uptr->wait = cvptr->sector_time / 2; /* schedule the sector start latency */ + } + } + } + +cvptr->index = 0; /* reset the buffer index */ +cvptr->length = GET_OUTCNT (props); /* set the count of outbound parameters */ +cvptr->eod = CLEAR; /* clear the end of data flag */ + + +switch (cvptr->opcode) { /* dispatch the command */ + + case cold_load_read: + cvptr->cylinder = 0; /* set cylinder to 0 */ + cvptr->head = GET_CHEAD (cvptr->buffer [0]); /* get the head */ + cvptr->sector = GET_CSECT (cvptr->buffer [0]); /* and sector from the command */ + + if (is_seeking) { /* if a seek is in progress, */ + uptr->STAT |= DL_S2SC; /* a Seek Check occurs */ + cvptr->file_mask = DL_FSPEN; /* set sparing enabled */ + uptr->OP = read; /* start the read on seek completion */ + uptr->PHASE = start_phase; /* and reset the command phase */ + return uptr; /* to allow the seek to complete normally */ + } + + else /* the drive is not seeking */ + uptr->wait = cvptr->cmd_time; /* the command starts with a seek, not a read */ + + break; + + + case seek: + cvptr->cylinder = cvptr->buffer [1]; /* get the supplied cylinder */ + cvptr->head = GET_HEAD (cvptr->buffer [2]); /* and head */ + cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector */ + + if (is_seeking) { /* if a seek is in progress, */ + uptr->STAT |= DL_S2SC; /* a Seek Check occurs */ + dl_idle_controller (cvptr); /* return the controller to the idle condition */ + return uptr; /* to allow the seek to complete normally */ + } + + break; + + + case request_status: + cvptr->buffer [0] = /* set the Status-1 value */ + cvptr->spd_unit | SET_S1STAT (cvptr->status); /* into the buffer */ + + if (unit > unit_limit) /* if the unit number is invalid */ + rptr = NULL; /* it does not correspond to a unit */ + else /* otherwise, the unit is valid */ + rptr = &units [unit]; /* so get the address of the referenced unit */ + + cvptr->buffer [1] = drive_status (rptr); /* set the Status-2 value */ + + if (rptr) /* if the unit is valid */ + rptr->STAT &= ~DL_S2FS; /* clear the First Status bit */ + + cvptr->spd_unit = SET_S1UNIT (unit); /* save the unit number */ + + if (unit > DL_MAXUNIT) /* if the unit number is illegal, */ + cvptr->status = unit_unavailable; /* the next status will be Unit Unavailable */ + else /* a legal unit */ + cvptr->status = normal_completion; /* clears the controller status */ + + break; + + + case request_disc_address: + set_address (cvptr, 0); /* return the CHS values in buffer 0-1 */ + break; + + + case request_sector_address: + if (unit > unit_limit) /* if the unit number is invalid */ + rptr = NULL; /* it does not correspond to a unit */ + else /* otherwise, the unit is valid */ + rptr = &units [unit]; /* so get the address of the referenced unit */ + + if (drive_status (rptr) & DL_S2NR) /* if the drive is not ready, */ + dl_end_command (cvptr, status_2_error); /* terminate with not ready status */ + else /* otherwise, the drive is ready */ + cvptr->buffer [0] = GET_CURSEC (cvptr, rptr); /* so calculate the current sector address */ + break; + + + case request_syndrome: + cvptr->buffer [0] = /* return the Status-1 value in buffer 0 */ + cvptr->spd_unit | SET_S1STAT (cvptr->status); + + set_address (cvptr, 1); /* return the CHS values in buffer 1-2 */ + + cvptr->buffer [3] = 0; /* the displacement is always zero */ + cvptr->buffer [4] = 0; /* the syndrome is always zero */ + cvptr->buffer [5] = 0; + cvptr->buffer [6] = 0; + break; + + + case address_record: + cvptr->cylinder = cvptr->buffer [1]; /* get the supplied cylinder */ + cvptr->head = GET_HEAD (cvptr->buffer [2]); /* and head */ + cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector */ + cvptr->eoc = CLEAR; /* clear the end-of-cylinder flag */ + break; + + + case set_file_mask: + cvptr->file_mask = GET_FMASK (cvptr->buffer [0]); /* get the supplied file mask */ + + if (cvptr->type == MAC) /* if a MAC controller */ + cvptr->retry = GET_FRETRY (cvptr->buffer [0]); /* the retry counter is supplied too */ + break; + + + case initialize: + if (uptr) /* if the unit is valid, */ + cvptr->spd_unit |= /* merge the SPD flags */ + SET_S1SPD (GET_SPD (cvptr->buffer [0])); /* from the command word */ + break; + + + case verify: + cvptr->verify_count = cvptr->buffer [1]; /* get the supplied sector count */ + break; + + + default: /* the remaining commands */ + break; /* are handled in the service routines */ + } + + +if (uptr) { /* if the command accesses a valid unit */ + uptr->OP = cvptr->opcode; /* save the opcode in the unit */ + + if (cvptr->length) /* if the command has outbound parameters, */ + uptr->PHASE = data_phase; /* set up the data phase for the transfer */ + else /* if there are no parameters, */ + uptr->PHASE = start_phase; /* set up the command phase for execution */ + + return uptr; /* return a pointer to the scheduled unit */ + } + +else + return NULL; /* the command did not start */ +} + + +/* Complete a command. + + The current command is terminated with the indicated status. The command + result status is set, the controller enters the command wait state, and the + CPU timer is restarted. +*/ + +void dl_end_command (CVPTR cvptr, CNTLR_STATUS status) +{ +cvptr->status = status; /* set the command result status */ +cvptr->state = cntlr_wait; /* set the controller state to waiting */ +set_timer (cvptr, SET); /* start the command wait timer */ +return; +} + + +/* Poll the drives for attention status. + + If interrupts are enabled on the interface, this routine is called to check + if any drive is requesting attention. The routine returns TRUE if a drive is + requestion attention and FALSE if not. + + Starting with the last unit requesting attention, each drive is checked in + sequence. If a drive has its Attention status set, the controller sets its + unit number, sets the result status to Drive Attention, and enters the + command wait state. The routine returns TRUE to indicate that an interrupt + should be generated. The next time the routine is called, the poll begins + with the last unit that requested attention, so that each unit is given an + equal chance to respond. + + If no unit is requesting attention, the routine returns FALSE to indicate + that no interrupt should be generated. +*/ + +t_bool dl_poll_drives (CVPTR cvptr, UNIT *units, uint32 unit_limit) +{ +uint32 unit; + +for (unit = 0; unit <= unit_limit; unit++) { /* check each unit in turn */ + cvptr->poll_unit = /* start with the last unit checked */ + (cvptr->poll_unit + 1) % (unit_limit + 1); /* and cycle back to unit 0 */ + + if (units [cvptr->poll_unit].STAT & DL_S2ATN) { /* if the unit is requesting attention, */ + units [cvptr->poll_unit].STAT &= ~DL_S2ATN; /* clear the Attention status */ + cvptr->spd_unit = SET_S1UNIT (cvptr->poll_unit); /* set the controller's unit number */ + cvptr->status = drive_attention; /* and status */ + cvptr->state = cntlr_wait; /* and wait for a command */ + return TRUE; /* tell the caller to interrupt */ + } + } + +return FALSE; /* no requests, so no interrupt */ +} + + +/* Service the disc drive unit. + + The unit service routine is called to execute scheduled controller commands + for the specified unit. The actions to be taken depend on the current state + of the controller and the unit. + + In addition to the controller state variables supplied in the call, the + service routine accesses these six variables in the UNIT structure: + + wait -- the current service activation time + pos -- the current file offset + u3 (CYL) -- the current drive cylinder + u4 (STAT) -- the drive status (Status-2) + u5 (OP) -- the drive operation in process + u6 (PHASE) -- the current operation phase + + The activation time is set non-zero if the service should be rescheduled. + The caller is responsible upon return for activating the unit. The file + offset indicates the byte position in the disc image file for the next read + or write operation. + + The drive cylinder gives the current location of the head positioner. This + may differ from the cylinder value in the controller if the Address Record + command has been used. The drive status maintains various per-drive + conditions (e.g., the state of the read-only and format switches, drive + ready, first status). The operation in process and operation phase define + the action to be taken by this service routine. + + Initially, the operation in process is set to the opcode field of the command + when it is started. However, the operation in process may change during + execution (the controller opcode never does). This is to aid code reuse in + the service routine. For example, a Cold Load Read command is changed to a + Read command once the seek portion is complete, and a Read Without Verify + command is changed to a normal Read command after a track boundary is + crossed. + + The operation phase provides different substates for those commands that + transfer data or that have different starting and ending actions. Three + phases are defined: start, data, and end. Commands that do not transfer data + to or from the CPU interface do not have data phases, and commands that + complete upon first service do not have end phases. The service routine + validates phase assignments and returns SCPE_IERR (Internal Error) if entry + is made with an illegal operation phase or a phase that is not valid for a + given operation. + + An operation in the data phase is in the process of transferring data between + the CPU and sector buffer. Because this process is interface-specific, the + service routine does nothing (other than validate) with this phase. It is up + to the caller to transition from the data phase to the end phase when the + transfer is complete. + + If an operation is completed, or an error has occurred, the controller state + on return will be either idle or waiting, instead of busy. The caller should + check the controller state to determine if normal completion or error + recovery is appropriate. + + If the command is continuing, the service activation time will be set + appropriately. The caller should then call sim_activate to schedule the next + service and clear the "wait" field in preparation for the next service call. + + + Implementation notes: + + 1. The Cold Load Read and Seek commands check only the drive's Not Ready + status because seeking clears a Seek Check. The other commands that + access the unit (e.g., Read and Write) have already checked in the + command start routine for Not Ready, Seek Check, or Fault status and + terminated with a Status-2 error. + + 2. Several commands (e.g., Set File Mask, Address Record) are executed + completely within the dl_start_command routine, so all we do here is + finish the command with the expected status. The service routine is + called only to provide the proper command execution delay. + + 3. If a host file system error occurs, the service routine returns SCPE_IERR + to stop simulation. If simulation is resumed, the controller will behave + as though an uncorrectable data error had occurred. +*/ + +t_stat dl_service_drive (CVPTR cvptr, UNIT *uptr) +{ +t_stat result = SCPE_OK; +const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; + +switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ + + case start_phase: + switch (opcode) { /* dispatch the current operation */ + + case recalibrate: + case seek: + if (start_seek (cvptr, uptr, opcode, end_phase) /* start the seek; if it succeeded, */ + && (cvptr->type == MAC)) /* and this a MAC controller, */ + dl_idle_controller (cvptr); /* idle until the seek completes */ + break; + + + case cold_load_read: + if (start_seek (cvptr, uptr, read, start_phase)) /* start the seek; did it succeed? */ + cvptr->file_mask = DL_FSPEN; /* set sparing enabled now */ + break; + + + case read: + case read_with_offset: + case read_without_verify: + cvptr->length = DL_WPSEC; /* transfer just the data */ + result = start_read (cvptr, uptr); /* start the sector read */ + break; + + + case read_full_sector: + cvptr->length = DL_WPFSEC; /* transfer the header/data/trailer */ + result = start_read (cvptr, uptr); /* start the sector read */ + break; + + + case verify: + cvptr->length = 0; /* no data transfer needed */ + result = start_read (cvptr, uptr); /* start the sector read */ + + if (uptr->PHASE == data_phase) { /* did the read start successfully? */ + uptr->PHASE = end_phase; /* skip the data phase for Verify */ + uptr->wait = cvptr->sector_time /* reschedule for the intersector time */ + + cvptr->data_time * DL_WPSEC; /* plus the data read time */ + } + break; + + + case write: + case initialize: + cvptr->length = DL_WPSEC; /* transfer just the data */ + start_write (cvptr, uptr); /* start the sector write */ + break; + + + case write_full_sector: + cvptr->length = DL_WPFSEC; /* transfer the header/data/trailer */ + start_write (cvptr, uptr); /* start the sector write */ + break; + + + case request_status: + case request_sector_address: + case clear: + case address_record: + case request_syndrome: + case set_file_mask: + case load_tio_register: + case request_disc_address: + case end: + case wakeup: + dl_service_controller (cvptr, uptr); /* call the controller for service */ + break; + + + default: /* entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of start phase handlers */ + + + case data_phase: + switch (opcode) { /* dispatch the current operation */ + case read: + case read_full_sector: + case read_with_offset: + case read_without_verify: + case write: + case write_full_sector: + case initialize: + break; /* data transfers are handled by the caller */ + + + default: /* entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of data phase handlers */ + + + case end_phase: + switch (opcode) { /* dispatch the operation command */ + + case recalibrate: + case seek: + if (cvptr->type == ICD) /* is this an ICD controller? */ + dl_end_command (cvptr, drive_attention); /* seek ends with drive attention status */ + else /* if not an ICD controller, */ + uptr->STAT |= DL_S2ATN; /* set Attention in the unit status */ + break; + + + case read: + case read_full_sector: + case read_with_offset: + end_read (cvptr, uptr); /* end the sector read */ + break; + + + case read_without_verify: + if (cvptr->sector == 0) /* have we reached the end of the track? */ + uptr->OP = read; /* begin verifying next time */ + + end_read (cvptr, uptr); /* end the sector read */ + break; + + + case verify: + cvptr->verify_count = /* decrement the count */ + (cvptr->verify_count - 1) & DMASK; /* modulo 65536 */ + + if (cvptr->verify_count == 0) /* more sectors to verify? */ + cvptr->eod = SET; /* no, so terminate the command cleanly */ + + end_read (cvptr, uptr); /* end the sector read */ + break; + + + case write: + case write_full_sector: + case initialize: + result = end_write (cvptr, uptr); /* end the sector write */ + break; + + + case request_status: + case request_sector_address: + case request_disc_address: + dl_service_controller (cvptr, uptr); /* call the controller for service */ + break; + + + default: /* entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of end phase handlers */ + } /* end of phase dispatch */ + +return result; /* return the result of the service */ +} + + +/* Service the controller unit. + + The controller service routine is called to execute scheduled controller + commands that do not access drive units. It is also called to obtain command + parameters from the interface and to return command result values to the + interface. The actions to be taken depend on the current state of the + controller. + + Controller commands are scheduled on a separate unit to allow concurrent + processing while seeks are in progress. For example, a seek may be started + on unit 0. While the seek is in progress, the CPU may request status from + the controller. In between returning the first and second status words to + the CPU, the seek may complete. Separating the controller unit allows seek + completion to be handled while the controller is "busy" waiting for the CPU + to indicate that it is ready for the second word. + + For ICD controllers, the controller unit is not used, and all commands are + scheduled on the drive unit. To reduce code duplication, however, the drive + unit service calls the controller service directly to handle controller + commands. + + The service routine validates phase assignments and returns SCPE_IERR + (Internal Error) if entry is made with an illegal operation phase or a phase + that is not valid for a given operation. + + Implementation notes: + + 1. While the interface simulator is responsible for data phase transfers, + the controller service routine is responsible for (re)starting and + stopping the command wait timer for each parameter sent to and received + from the interface. +*/ + +t_stat dl_service_controller (CVPTR cvptr, UNIT *uptr) +{ +t_stat result = SCPE_OK; +const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; + +switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ + + case start_phase: + case end_phase: + switch (opcode) { /* dispatch the current operation */ + case request_status: + dl_end_command (cvptr, cvptr->status); /* command is complete with no status change */ + break; + + + case clear: + dl_clear_controller (cvptr, uptr, soft_clear); /* clear the controller */ + dl_end_command (cvptr, normal_completion); /* command is complete */ + break; + + + case request_sector_address: + case address_record: + case request_syndrome: + case set_file_mask: + case load_tio_register: + case request_disc_address: + dl_end_command (cvptr, normal_completion); /* command is complete */ + break; + + + case end: + dl_idle_controller (cvptr); /* command is complete with controller idle */ + break; + + + case wakeup: + dl_end_command (cvptr, unit_available); /* command is complete with unit available */ + break; + + + default: /* entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of start and end phase handlers */ + + + case data_phase: + switch (opcode) { /* dispatch the current operation */ + + case seek: + case verify: + case address_record: + case read_with_offset: + case load_tio_register: + if (cvptr->length > 1) /* at least one more parameter to input? */ + set_timer (cvptr, SET); /* restart the timer for the next parameter */ + else /* this is the last one */ + set_timer (cvptr, CLEAR); /* so stop the command wait timer */ + break; + + + case request_status: + case request_sector_address: + case request_syndrome: + case request_disc_address: + if (cvptr->length > 0) /* at least one more to parameter output? */ + set_timer (cvptr, SET); /* restart the timer for the next parameter */ + else /* this is the last one */ + set_timer (cvptr, CLEAR); /* so stop the command wait timer */ + break; + + + default: /* entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of data phase handlers */ + } /* end of phase dispatch */ + +return result; /* return the result of the service */ +} + + +/* Service the command wait timer unit. + + The command wait timer service routine is called if the command wait timer + expires. This indicates that the CPU did not respond to a parameter transfer + or did not issue a new command within the 1.8 second timeout period. The + timer is used with the MAC controller to ensure that a hung CPU does not tie + up the controller, preventing it from servicing other CPUs or drives. ICD + controllers do not use the command wait timer; they will wait forever, as + each controller is dedicated to a single interface. + + When a timeout occurs, the controller unit is cancelled in case the cause was + a parameter timeout. Then the file mask is reset, and the controller is + idled. + + The interface is responsible for polling for a new command and for drive + attention when a timeout occurs. + + Implementation notes: + + 1. Only the controller unit may be active when the command wait timer + expires. A unit is never active because the timer is cancelled when + commands are executing and is restarted after the command completes. +*/ + +t_stat dl_service_timer (CVPTR cvptr, UNIT *uptr) +{ +sim_cancel (cvptr->aux); /* cancel the controller */ + +dl_idle_controller (cvptr); /* idle the controller */ +cvptr->file_mask = 0; /* clear the file mask */ + +return SCPE_OK; +} + + +/* Clear the controller. + + The controller connected to the specified unit is cleared as directed. A MAC + controller is connected to several units, so the unit is used to find the + associated device and thereby the unit array. An ICD controller is connected + only to the specified unit. + + In hardware, four conditions clear the 13037 controller: + + - an initial application of power + - an assertion of the CLEAR signal by the CPU interface + - a timeout of the command wait timer + - a programmed Clear command + + The first two conditions, called "hard clears," are equivalent and cause a + firmware restart with the PWRON flag set. The 13175 interface for the HP + 1000 asserts CLEAR in response to the backplane CRS signal if the PRESET + ENABLE jumper is not installed (which is the usual case). The third + condition also causes a firmware restart but with the PWRON flag clear. The + last condition is executed in the command handler and therefore returns to + the Command Wait Loop instead of the Poll Loop. + + For a hard clear, the 13037 controller will: + + - disconnect the CPU interface + - zero the controller RAM (no drives held, last polled unit number reset) + - issue a Controller Preset to clear all connected drives + - clear the clock offset + - clear the file mask + - enter the Poll Loop (clears the controller status) + + For a timeout clear, the 13037 controller will: + + - disconnect the CPU interface + - clear the hold bits of any drives held by the interface that timed out + - clear the clock offset + - clear the file mask + - enter the Poll Loop (clears the controller status) + + For a programmed "soft" clear, the 13037 controller will: + + - clear the controller status + - issue a Controller Preset to clear all connected drives + - enter the Command Wait Loop + + Controller Preset is a tag bus command that is sent to all drives connected + to the controller. Each drive will: + + - disconnect from the controller + - clear its internal drive faults + - clear its head and sector registers + - clear its illegal head and sector flip-flops + - reset its seek check, first status, drive fault, and attention status + + In simulation, a hard clear occurs when a RESET -P or RESET command is + issued, or a programmed CLC 0 instruction is executed. A soft clear occurs + when a programmed Clear command is started. A timeout clear occurs when the + command wait timer unit is serviced, but this action is handled in the timer + unit service. + + Because the controller execution state is implemented by scheduling command + phases for the target or controller unit, a simulated firmware restart must + abort any in-process activation. However, a firmware restart does not affect + seeks in progress, so these must be allowed to continue to completion so that + their Attention requests will be honored. + + + Implementation notes: + + 1. The specific 13365 controller actions on hard or soft clears are not + documented. Therefore, an ICD controller clear is handled as a MAC + controller clear, except that only the current drive is preset (as an ICD + controller manages only a single drive). + + 2. Neither hard nor soft clears affect the controller flags (e.g., EOC) or + registers (e.g., cylinder address). + + 3. In simulation, an internal seek, such as an auto-seek during a Read + command or the initial seek during a Cold Load Read command, will be + aborted for a hard or timeout clear, whereas in hardware it would + complete normally. This is OK, however, because an internal seek always + clears the drive's Attention status on completion, so aborting the + simulated seek is equivalent to seek completion. + + 4. In simulation, a Controller Preset only resets the specified status bits, + as the remainder of the hardware actions are not implemented. +*/ + +t_stat dl_clear_controller (CVPTR cvptr, UNIT *uptr, CNTLR_CLEAR clear_type) +{ +uint32 unit, unit_count; +DEVICE *dptr = NULL; + +if (clear_type == hard_clear) { /* is this a hard clear? */ + dl_idle_controller (cvptr); /* idle the controller */ + cvptr->file_mask = 0; /* clear the file mask */ + cvptr->poll_unit = 0; /* clear the last unit polled */ + } + +if (cvptr->type == ICD) /* is this an ICD controller? */ + unit_count = 1; /* there is only one unit per controller */ + +else { /* a MAC controller clears all units */ + dptr = find_dev_from_unit (uptr); /* find the associated device */ + + if (dptr == NULL) /* device doesn't exist?!? */ + return SCPE_IERR; /* this is an impossible condition! */ + else /* the device was found */ + unit_count = dptr->numunits; /* so get the number of units */ + } + +for (unit = 0; unit < unit_count; unit++) { /* loop through the unit(s) */ + if (dptr) /* pick up the unit from the device? */ + uptr = dptr->units + unit; /* yes, so get the next unit */ + + if (!(uptr->flags & UNIT_DIS)) { /* is the unit enabled? */ + if (clear_type == hard_clear /* a hard clear cancels */ + && uptr->OP != seek /* only if not seeking */ + && uptr->OP != recalibrate) /* or recalibrating */ + sim_cancel (uptr); /* cancel the service */ + + uptr->STAT &= ~DL_S2CPS; /* do "Controller Preset" for the unit */ + } + } + +return SCPE_OK; +} + + +/* Idle the controller. + + The command wait timer is turned off, the status is reset, and the controller + is returned to the idle state (Poll Loop). +*/ + +void dl_idle_controller (CVPTR cvptr) +{ +cvptr->state = cntlr_idle; /* idle the controller */ +cvptr->status = normal_completion; /* the Poll Loop clears the status */ + +set_timer (cvptr, CLEAR); /* stop the command wait timer */ +return; +} + + + +/* Load or unload the drive heads. + + In hardware, a drive's heads are loaded when a disc pack is installed and the + RUN/STOP switch is set to RUN. The drive reports First Status when the heads + load to indicate that the pack has potentially changed. Setting the switch + to STOP unloads the heads. When the heads are unloaded, the drive reports + Not Ready and Drive Busy status. + + In simulation, the unit must be attached before the heads may be unloaded or + loaded. As the heads should be automatically loaded when a unit is attached + and unloaded when a unit is detached, this routine must be called after + attaching or before detaching. + + + Implementation notes: + + 1. The drive sets its Attention status bit when the heads load or unload. + However, the ICD controller reports Attention only for head unloading. + + 2. Loading or unloading the heads clears Fault and Seek Check status. + + 3. If we are called during a RESTORE command, the unit's flags are not + changed to avoid upsetting the state that was SAVEd. +*/ + +t_stat dl_load_unload (CVPTR cvptr, UNIT *uptr, t_bool load) +{ +if ((uptr->flags & UNIT_ATT) == 0) /* must be attached to [un]load */ + return SCPE_UNATT; /* return "Unit not attached" if not */ + +else if (!(sim_switches & SIM_SW_REST)) /* modify the flags only if not restoring */ + if (load) { /* are we loading the heads? */ + uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* clear the unload flag */ + uptr->STAT = DL_S2FS; /* and set First Status */ + + if (cvptr->type != ICD) /* if this is not an ICD controller */ + uptr->STAT |= DL_S2ATN; /* set Attention status also */ + } + + else { /* we are unloading the heads */ + uptr->flags = uptr->flags | UNIT_UNLOAD; /* set the unload flag */ + uptr->STAT = DL_S2ATN; /* and Attention status */ + } + +return SCPE_OK; +} + + + +/* Disc library global utility routines */ + + +/* Classify the current controller opcode. + + The controller opcode is classified as a read, write, control, or status + command, and the classification is returned to the caller. If the opcode is + illegal or undefined for the indicated controller, the classification is + marked as invalid. +*/ + +CNTLR_CLASS dl_classify (CNTLR_VARS cntlr) +{ +uint32 flags; + +if (cntlr.opcode > last_opcode) /* is the opcode illegal? */ + return class_invalid; /* return an invalid classification */ + +flags = cmd_props [cntlr.opcode]; /* get the opcode properties */ + +if (cntlr.type == MAC && (flags & CP_MAC) /* is the opcode */ + || cntlr.type == ICD && (flags & CP_ICD)) /* defined for this controller? */ + return GET_CLASS (cmd_props [cntlr.opcode]); /* yes, so return the command classification */ +else /* opcode is undefined */ + return class_invalid; /* so return an invalid classification */ +} + + +/* Return the name of an opcode. + + A string representing the supplied controller opcode is returned to the + caller. If the opcode is illegal or undefined for the indicated controller, + the string "invalid" is returned. +*/ + +const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode) +{ +uint32 flags; + +if (opcode > last_opcode) /* is the opcode illegal? */ + return invalid_name; /* return an error indication */ + +flags = cmd_props [opcode]; /* get the opcode properties */ + +if (controller == MAC && (flags & CP_MAC) || /* is the opcode */ + controller == ICD && (flags & CP_ICD)) /* defined for this controller? */ + return opcode_name [opcode]; /* yes, so return the opcode name */ +else /* opcode is undefined, */ + return invalid_name; /* so return an error indication */ +} + + +/* Return the name of a command phase. + + A string representing the supplied phase is returned to the caller. If the + phase is illegal, the string "invalid" is returned. +*/ + +const char *dl_phase_name (CNTLR_PHASE phase) +{ +if (phase > last_phase) /* is the phase illegal? */ + return invalid_name; /* return an error indication */ +else /* phase is defined, */ + return phase_name [phase]; /* so return the phase name */ +} + + + +/* Disc library global VM routines */ + + +/* Attach a disc image file to a unit. + + The file specified by the supplied filename is attached to the indicated + unit. If the attach was successful, the heads are loaded on the drive. + + If the drive is set to auto-type, the size of the image file is compared to + the table of drive capacities to determine which type of drive was used to + create it. If the image file is new, then the previous drive type is + retained. +*/ + +t_stat dl_attach (CVPTR cvptr, UNIT *uptr, char *cptr) +{ +uint32 id, size; +t_stat result; + +result = attach_unit (uptr, cptr); /* attach the unit */ + +if (result != SCPE_OK) /* did the attach fail? */ + return result; /* yes, so return the error status */ + +dl_load_unload (cvptr, uptr, TRUE); /* if the attach succeeded, load the heads */ + +if (uptr->flags & UNIT_AUTO) { /* is auto-typing desired? */ + size = sim_fsize (uptr->fileref) / sizeof (uint16); /* get the file size in words */ + + if (size > 0) /* a new file retains the current drive type */ + for (id = 0; id < PROPS_COUNT; id++) /* find the best fit to the drive types */ + if (size <= drive_props [id].words /* if the file size fits the drive capacity */ + || id == PROPS_COUNT - 1) { /* or this is the largest drive */ + uptr->capac = drive_props [id].words; /* then set the capacity */ + uptr->flags = (uptr->flags & ~UNIT_MODEL) /* and the model */ + | SET_MODEL (id); + break; + } + } + +return SCPE_OK; /* unit was successfully attached */ +} + + +/* Detach a disc image file from a unit. + + The heads are unloaded on the drive, and the attached file, if any, is + detached. +*/ + +t_stat dl_detach (CVPTR cvptr, UNIT *uptr) +{ +dl_load_unload (cvptr, uptr, FALSE); /* unload the heads if attached */ +return detach_unit (uptr); /* and detach the unit */ +} + + +/* Set the drive model. + + This validation routine is called to set the model of disc drive associated + with the specified unit. The "value" parameter indicates the model ID, and + the unit capacity is set to the size indicated. +*/ + +t_stat dl_set_model (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATT) /* cannot alter the disc model */ + return SCPE_ALATT; /* if the unit is attached */ + +if (value != UNIT_AUTO) /* if we are not autosizing */ + uptr->capac = drive_props [GET_MODEL (value)].words; /* set the capacity to the new value */ + +return SCPE_OK; +} + + + +/* Disc library local controller routines */ + + +/* Start a read operation on the current sector. + + The current sector indicated by the controller address is read from the disc + image file into the sector buffer in preparation for data transfer to the + CPU. If the end of the track had been reached, and the file mask permits, + an auto-seek is scheduled instead to allow the read to continue. + + On entry, the end-of-data flag is checked. If it is set, the current read is + completed. Otherwise, the buffer data offset and verify options are set up. + For a Read Full Sector, the sync word is set from the controller type, and + dummy cylinder and head-sector words are generated from the current location + (as would be the case in the absence of track sparing). + + The image file is positioned to the correct sector in preparation for + reading. If the positioning requires a permitted seek, it is scheduled, and + the routine returns with the operation phase unchanged to wait for seek + completion before resuming the read (when the seek completes, the service + routine will be entered, and we will be called again; this time, the + end-of-cylinder flag will be clear and positioning will succeed). If + positioning resulted in an error, the current read is terminated with the + error status set. + + If positioning succeeded within the same cylinder, the sector image is read + into the buffer at an offset determined by the operation (Read Full Sector + leaves room at the start of the buffer for the sector header). If the image + file read did not return a full sector, the remainder of the buffer is padded + with zeros. If the image read failed with a file system error, SCPE_IOERR is + returned from the service routine to cause a simulation stop; resumption is + handled as an Uncorrectable Data Error. + + If the image was read correctly, the next sector address is updated, the + operation phase is set for the data transfer, and the index of the first word + to transfer is set. + + + Implementation notes: + + 1. The length of the transfer required (cvptr->length) must be set before + entry. + + 2. Entry while executing a Read Without Verify or Read Full Sector command + inhibits address verification. The unit opcode is tested instead of the + controller opcode because a Read Without Verify is changed to a Read to + begin verifying after a track switch occurs. +*/ + +static t_stat start_read (CVPTR cvptr, UNIT *uptr) +{ +uint32 count, offset; +t_bool verify; +const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; + +if (cvptr->eod == SET) { /* end of data indicated? */ + dl_end_command (cvptr, normal_completion); /* complete the command */ + return SCPE_OK; + } + +if (opcode == read_full_sector) { /* starting a Read Full Sector command? */ + if (cvptr->type == ICD) /* is this an ICD controller? */ + cvptr->buffer [0] = 0100377; /* ICD does not support ECC */ + else + cvptr->buffer [0] = 0100376; /* MAC does support ECC */ + + set_address (cvptr, 1); /* set the current address into buffer 1-2 */ + offset = 3; /* start the data after the header */ + verify = FALSE; /* no address verification */ + } + +else { /* it's another read command */ + offset = 0; /* data starts at the beginning */ + verify = (opcode != read_without_verify); /* verify unless RWV */ + } + +if (! position_sector (cvptr, uptr, verify)) /* position the sector */ + return SCPE_OK; /* seek in progress or an error occurred */ + +count = sim_fread (cvptr->buffer + offset, /* read the sector from the image */ + sizeof (uint16), DL_WPSEC, /* into the sector buffer */ + uptr->fileref); + +for (count = count + offset; count < cvptr->length; count++) /* pad sector as needed */ + cvptr->buffer [count] = 0; /* e.g., if reading from a new file */ + +if (ferror (uptr->fileref)) /* did a host file system error occur? */ + return io_error (cvptr, uptr); /* set up data error status and stop the simulation */ + +next_sector (cvptr, uptr); /* address the next sector */ + +uptr->PHASE = data_phase; /* set up data transfer phase */ +cvptr->index = 0; /* reset the data index */ + +return SCPE_OK; /* the read was successfully started */ +} + + +/* Finish a read operation on the current sector. + + On entry, the end-of-data flag is checked. If it is set, the current read is + completed. Otherwise, the command phase is reset to start the next sector, + and the disc service is scheduled to allow for the intersector delay. + + + Implementation notes: + + 1. The intersector time is required to allow the ICD interface to set the + end-of-data flag before the next sector begins. The CPU must have enough + time to receive the last byte of the current sector and then unaddress + the disc controller before the first byte of the next sector is sent. If + the time is not long enough, the sector address will be incremented twice + (e.g., a 128-word read of sector 0 will terminate with sector 2 as the + next sector instead of sector 1). +*/ + +static void end_read (CVPTR cvptr, UNIT *uptr) +{ +if (cvptr->eod == SET) /* end of data indicated? */ + dl_end_command (cvptr, normal_completion); /* complete the command */ + +else { /* reading continues */ + uptr->PHASE = start_phase; /* reset to the start phase */ + uptr->wait = cvptr->sector_time; /* delay for the intersector time */ + } + +return; +} + + +/* Start a write operation on the current sector. + + The current sector indicated by the controller address is positioned for + writing from the sector buffer to the disc image file after data transfer + from the CPU. + + On entry, if writing is not permitted, or formatting is required but not + enabled, the command is terminated with an error. Otherwise, the disc image + file is positioned to the correct sector in preparation for writing. + + If the positioning requires a permitted seek, it is scheduled, and the + routine returns with the operation phase unchanged to wait for seek + completion before resuming the write (when the seek completes, the service + routine will be entered, and we will be called again; this time, the + end-of-cylinder flag will be clear and positioning will succeed). If + positioning resulted in an error, the current write is terminated with the + error status set. + + If positioning succeeded within the same cylinder, the operation phase is set + for the data transfer, and the index of the first word to transfer is set. + + + Implementation notes: + + 1. Entry while executing a Write Full Sector or Initialize command inhibits + address verification. In addition, the drive's FORMAT switch must be set + to the enabled position for these commands to succeed. +*/ + +static void start_write (CVPTR cvptr, UNIT *uptr) +{ +const t_bool verify = (CNTLR_OPCODE) uptr->OP == write; /* only Write verifies the sector */ + +if ((uptr->flags & UNIT_WPROT) /* is the unit write protected? */ + || !verify && !(uptr->flags & UNIT_FMT)) /* or is formatting required but not enabled? */ + dl_end_command (cvptr, status_2_error); /* terminate the write with an error */ + +else if (position_sector (cvptr, uptr, verify)) { /* write OK; position the sector */ + uptr->PHASE = data_phase; /* position OK; set up data transfer phase */ + cvptr->index = 0; /* reset the data index */ + } + +return; +} + + +/* Finish a write operation on the current sector. + + The current sector is written from the sector buffer to the disc image file + at the current file position. If the end of the track had been reached, and + the file mask permits, an auto-seek is scheduled instead to allow the write + to continue. + + On entry, the drive is checked to ensure that it is ready for the write. + Then the sector buffer is padded appropriately if a full sector of data was + not transferred. The buffer is written to the disc image file at the + position corresponding to the controller address as set when the sector was + started. The write begins at a buffer offset determined by the command (a + Write Full Sector leaves room at the start of the buffer for the sector + header). + + If the image write failed with a file system error, SCPE_IOERR is returned + from the service routine to cause a simulation stop; resumption is handled as + an Uncorrectable Data Error. If the image was written correctly, the next + sector address is updated. If the end-of-data flag is set, the current write + is completed. Otherwise, the command phase is reset to start the next + sector, and the disc service is scheduled to allow for the intersector delay. + + + Implementation notes: + + 1. A partial sector is filled with 177777B words (ICD) or copies of the last + word (MAC) per page 7-10 of the ICD/MAC Disc Diagnostic manual. +*/ + +static t_stat end_write (CVPTR cvptr, UNIT *uptr) +{ +uint32 count; +uint16 pad; +const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; +const uint32 offset = (opcode == write_full_sector ? 3 : 0); + +if (uptr->flags & UNIT_UNLOAD) { /* if the drive is not ready, */ + dl_end_command (cvptr, access_not_ready); /* terminate the command with an error */ + return SCPE_OK; + } + +if (cvptr->index < DL_WPSEC + offset) { /* was a partial sector transferred? */ + if (cvptr->type == ICD) /* an ICD controller */ + pad = DMASK; /* pads the sector with -1 */ + else /* a MAC controller */ + pad = cvptr->buffer [cvptr->index - 1]; /* pads with the last word written */ + + for (count = cvptr->index; count < DL_WPSEC + offset; count++) + cvptr->buffer [count] = pad; /* pad the sector buffer */ + } + +sim_fwrite (cvptr->buffer + offset, sizeof (uint16), /* write the sector to the file */ + DL_WPSEC, uptr->fileref); + +if (ferror (uptr->fileref)) /* did a host file system error occur? */ + return io_error (cvptr, uptr); /* set up data error status and stop the simulation */ + +next_sector (cvptr, uptr); /* address the next sector */ + +if (cvptr->eod == SET) /* is the end of data indicated? */ + dl_end_command (cvptr, normal_completion); /* complete the command */ + +else { /* writing continues */ + uptr->PHASE = start_phase; /* reset to the start phase */ + uptr->wait = cvptr->sector_time; /* delay for the intersector time */ + } + +return SCPE_OK; +} + + +/* Position the disc image file to the current sector. + + The image file is positioned to the byte address corresponding to the + controller's current cylinder, head, and sector address. Positioning may + involve an auto-seek if the prior read or write addressed the final sector in + a cylinder. If a seek is initiated or an error is detected, the routine + returns FALSE to indicate that the positioning was not performed. If the + file was positioned, the routine returns TRUE. + + On entry, if the controller's end-of-cylinder flag is set, the prior read or + write addressed the final sector in the current cylinder. If the file mask + does not permit auto-seeking, the current command is terminated with an End + of Cylinder error. Otherwise, the cylinder is incremented or decremented as + directed by the file mask, and a seek to the new cylinder is started. + + If the increment or decrement resulted in an out-of-bounds value, the seek + will return Seek Check status, and the command is terminated with an error. + If the seek is legal, the routine returns with the disc service scheduled for + seek completion and the command state unchanged. When the service is called, + the read or write will continue on the new cylinder. + + If the EOC flag was not set, the drive position is checked against the + controller position. If they are different (as may occur with an Address + Record command that specified a different location than the last Seek + command), a seek is started to the correct cylinder, and the routine returns + with the disc service scheduled for seek completion as above. + + If the drive and controller positions agree, the controller CHS address is + validated against the drive limits. If they are invalid, Seek Check status + is set, and the command is terminated with an error. + + If the address is valid, the drive is checked to ensure that it is ready for + positioning. If it is, the the byte offset in the image file is calculated + from the CHS address, and the file is positioned. The disc service is + scheduled to begin the data transfer, and the routine returns TRUE to + indicate that the file position was set. + + + Implementation notes: + + 1. The ICD controller returns an End of Cylinder error if an auto-seek + results in a position beyond the drive limits. The MAC controller + returns a Status-2 error. Both controllers set the Seek Check bit in the + drive status word. +*/ + +static t_bool position_sector (CVPTR cvptr, UNIT *uptr, t_bool verify) +{ +uint32 block; +uint32 model = GET_MODEL (uptr->flags); + +if (cvptr->eoc == SET) /* positioned at the end of a cylinder? */ + if (cvptr->file_mask & DL_FAUTSK) { /* is an auto-seek allowed? */ + if (cvptr->file_mask & DL_FDECR) /* decremental seek? */ + cvptr->cylinder = (cvptr->cylinder - 1) & DMASK; /* decrease cylinder with wraparound */ + else /* incremental seek */ + cvptr->cylinder = (cvptr->cylinder + 1) & DMASK; /* increase cylinder with wraparound */ + + start_seek (cvptr, uptr, /* start the auto-seek */ + (CNTLR_OPCODE) uptr->OP, /* with the current operation */ + (CNTLR_PHASE) uptr->PHASE); /* and phase unchanged */ + + if (uptr->STAT & DL_S2SC) /* did a seek check occur? */ + if (cvptr->type == ICD) /* ICD controller? */ + dl_end_command (cvptr, end_of_cylinder); /* report as end of cylinder error */ + else /* MAC controller? */ + dl_end_command (cvptr, status_2_error); /* report as Status-2 error */ + } + + else /* file mask does not permit auto-seek */ + dl_end_command (cvptr, end_of_cylinder); /* so terminate with an EOC error */ + +else if (verify && (uint32) uptr->CYL != cvptr->cylinder) { /* is the positioner on the wrong cylinder? */ + start_seek (cvptr, uptr, /* start a seek to the correct cylinder */ + (CNTLR_OPCODE) uptr->OP, /* with the current operation */ + (CNTLR_PHASE) uptr->PHASE); /* and phase unchanged */ + + if (uptr->STAT & DL_S2SC) /* did a seek check occur? */ + dl_end_command (cvptr, status_2_error); /* report as Status-2 error */ + } + +else if (((uint32) uptr->CYL >= drive_props [model].cylinders) /* is the cylinder out of bounds? */ + || (cvptr->head >= drive_props [model].heads) /* or the head? */ + || (cvptr->sector >= drive_props [model].sectors)) { /* or the sector? */ + uptr->STAT = uptr->STAT | DL_S2SC; /* set Seek Check status */ + dl_end_command (cvptr, status_2_error); /* and terminate with an error */ + } + +else if (uptr->flags & UNIT_UNLOAD) /* is the drive ready for positioning? */ + dl_end_command (cvptr, access_not_ready); /* terminate the command with an access error */ + +else { /* ready to position the image file */ + block = TO_BLOCK (uptr->CYL, cvptr->head, /* calculate the new block position */ + cvptr->sector, model); /* (for inspection only) */ + uptr->pos = TO_OFFSET (block); /* and then convert to a byte offset */ + + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set the image file position */ + + uptr->wait = cvptr->data_time; /* delay for the data access time */ + return TRUE; /* and report that positioning was accomplished */ + } + +return FALSE; /* report that positioning failed or was deferred */ +} + + +/* Address the next sector. + + The controller's CHS address is incremented to point at the next sector. If + the next sector number is valid, the routine returns. Otherwise, the sector + number is reset to sector 0. If the file mask is set for cylinder mode, the + head is incremented, and if the new head number is valid, the routine + returns. If the head number is invalid, it is reset to head 0, and the + end-of-cylinder flag is set. The EOC flag is also set if the file mask is + set for surface mode. + + The new cylinder address is not set here, because cylinder validation must + only occur when the next sector is actually accessed. Otherwise, reading or + writing the last sector on a track or cylinder with auto-seek disabled would + cause an End of Cylinder error even if the transfer ended with that sector. + Instead, we set the EOC flag to indicate that a cylinder update is pending. + + As a result of this deferred update method, the state of the EOC flag must be + considered when returning the disc address to the CPU. +*/ + +static void next_sector (CVPTR cvptr, UNIT *uptr) +{ +const uint32 model = GET_MODEL (uptr->flags); /* get the disc model */ + +cvptr->sector = cvptr->sector + 1; /* increment the sector number */ + +if (cvptr->sector < drive_props [model].sectors) /* at the end of the track? */ + return; /* no, so the next sector value is OK */ + +cvptr->sector = 0; /* wrap the sector number */ + +if (cvptr->file_mask & DL_FCYLM) { /* are we in cylinder mode? */ + cvptr->head = cvptr->head + 1; /* yes, so increment the head */ + + if (cvptr->head < drive_props [model].heads) /* at the end of the cylinder? */ + return; /* no, so the next head value is OK */ + + cvptr->head = 0; /* wrap the head number */ + } + +cvptr->eoc = SET; /* set the end-of-cylinder flag to */ +return; /* indicate that an update is required */ +} + + +/* Start a seek. + + A seek is initiated on the indicated unit if the drive is ready and the + cylinder, head, and sector values in the controller are valid for the current + drive model. If the current operation is a recalibrate, a seek is initiated + to cylinder 0 instead of the cylinder value stored in the controller. The + routine returns TRUE if the drive was ready for the seek and FALSE if it was + not. + + If the controller cylinder is beyond the drive's limit, Seek Check status is + set in the unit, and the heads are not moved. Otherwise, the relative + cylinder position change is calculated, and the heads are moved to the new + position. + + If the controller head or sector is beyond the drive's limit, Seek Check + status is set in the unit. Otherwise, Seek Check status is cleared, and the + new file offset is calculated. + + A seek check terminates the current command for an ICD controller. For a MAC + controller, the seek check is noted in the drive status, but processing will + continue until the drive sets Attention status. + + Finally, the drive operation and phase are set to the supplied values before + returning. + + + Implementation notes: + + 1. EOC is not reset for recalibrate so that a reseek will return to the same + location as was pending when the recalibrate was done. + + 2. Calculation of the file offset is performed here simply to keep the unit + position register available for inspection. The actual file positioning + is done in position_sector. + + 3. In hardware, a seek to the current location will set Drive Busy status + for 1.3 milliseconds (the head settling time). In simulation, disc + service is scheduled as though a one-cylinder seek was requested. +*/ + +static t_bool start_seek (CVPTR cvptr, UNIT *uptr, CNTLR_OPCODE next_opcode, CNTLR_PHASE next_phase) +{ +int32 delta; +uint32 block, target_cylinder; +const uint32 model = GET_MODEL (uptr->flags); /* get the drive model */ + +if (uptr->flags & UNIT_UNLOAD) { /* are the heads unloaded? */ + dl_end_command (cvptr, status_2_error); /* seek ends with Status-2 error */ + return FALSE; /* drive was not ready */ + } + +if ((CNTLR_OPCODE) uptr->OP == recalibrate) /* is the unit recalibrating? */ + target_cylinder = 0; /* seek to cylinder 0 and don't reset EOC */ + +else { /* Seek command or auto-seek request */ + target_cylinder = cvptr->cylinder; /* seek to the controller cylinder */ + cvptr->eoc = CLEAR; /* clear the end-of-cylinder flag */ + } + +if (target_cylinder >= drive_props [model].cylinders) { /* is the cylinder out of bounds? */ + delta = 0; /* don't change the positioner */ + uptr->STAT = uptr->STAT | DL_S2SC; /* and set Seek Check status */ + } + +else { /* cylinder value is OK */ + delta = abs (uptr->CYL - target_cylinder); /* calculate the relative movement */ + uptr->CYL = target_cylinder; /* and move the positioner */ + + if ((cvptr->head >= drive_props [model].heads) /* if the head */ + || (cvptr->sector >= drive_props [model].sectors)) /* or sector is out of bounds, */ + uptr->STAT = uptr->STAT | DL_S2SC; /* set Seek Check status */ + + else { /* the head and sector are OK */ + uptr->STAT = uptr->STAT & ~DL_S2SC; /* clear Seek Check status */ + + block = TO_BLOCK (uptr->CYL, cvptr->head, /* set up the new block position */ + cvptr->sector, model); /* (for inspection only) */ + uptr->pos = TO_OFFSET (block); /* and then convert to a byte offset */ + } + } + +if ((uptr->STAT & DL_S2SC) && cvptr->type == ICD) /* Seek Check and ICD controller? */ + dl_end_command (cvptr, status_2_error); /* command ends with Status-2 error */ + +else { /* seek OK or this is a MAC controller */ + if (delta == 0) /* if seek is to the same cylinder */ + delta = 1; /* schedule as a one-cylinder seek */ + + uptr->wait = cvptr->seek_time * delta; /* seek delay is based on the relative movement */ + } + +uptr->OP = next_opcode; /* set the next operation */ +uptr->PHASE = next_phase; /* and command phase */ +return TRUE; /* and report that the drive was ready */ +} + + +/* Report an I/O error. + + Errors indicated by the host file system are reported to the console and + simulation is stopped with an "I/O error" message. If the simulation is + continued, the CPU will receive an Uncorrectable Data Error indication from + the controller. +*/ + +static t_stat io_error (CVPTR cvptr, UNIT *uptr) +{ +dl_end_command (cvptr, uncorrectable_data_error); /* terminate the command with an error */ + +perror ("DiscLib I/O error"); /* report the error to the console */ +clearerr (uptr->fileref); /* and clear the error in case we resume */ + +return SCPE_IOERR; /* return an I/O error to stop the simulator */ +} + + + +/* Disc library local utility routines */ + + +/* Set the current controller address into the buffer. + + The controller's current cylinder, head, and sector are packed into two words + and stored in the sector buffer, starting at the index specified. If the + end-of-cylinder flag is set, the cylinder is incremented to reflect the + auto-seek that will be attempted when the next disc access is made. + + + Implementation notes: + + 1. The 13037 firmware always increments the cylinder number if the EOC flag + is set, rather than checking cylinder increment/decrement bit in the file + mask. +*/ + +static void set_address (CVPTR cvptr, uint32 index) +{ +cvptr->buffer [index] = cvptr->cylinder + (cvptr->eoc == SET ? 1 : 0); /* update the cylinder if EOC */ +cvptr->buffer [index + 1] = SET_HEAD (cvptr) | SET_SECTOR (cvptr); /* merge the head and sector */ +return; +} + + +/* Start or stop the command wait timer. + + A MAC controller uses a 1.8 second timer to ensure that it does not wait + forever for a non-responding disc drive or CPU interface. In simulation, MAC + interfaces supply an auxiliary timer unit that is activated when the command + wait timer is started and cancelled when the timer is stopped. + + ICD interfaces do not use the command wait timer. + + + Implementation notes: + + 1. Absolute activation is used because the timer is restarted between + parameter word transfers. +*/ + +static void set_timer (CVPTR cvptr, FLIP_FLOP action) +{ +if (cvptr->type == MAC) /* is this a MAC controller? */ + if (action == SET) /* start the timer? */ + sim_activate_abs (cvptr->aux + timer, /* activate the auxiliary unit */ + cvptr->wait_time); + else /* stop the timer */ + sim_cancel (cvptr->aux + timer); /* by canceling the unit */ +return; +} + + +/* Return the drive status (status word 2). + + In hardware, the controller outputs the Address Unit command on the drive tag + bus and the unit number on the drive control bus. The addressed drive then + responds by setting its internal "selected" flag. The controller then + outputs the Request Status command on the tag bug, and the selected drive + returns its status on the control bus. If a drive is selected but the heads + are unloaded, the drive returns Not Ready and Busy status. If no drive is + selected, the control bus floats inactive. This is interpreted by the + controller as Not Ready status (because the drive returns an inactive Ready + status). + + In simulation, an enabled but detached unit corresponds to "selected but + heads unloaded," and a disabled unit corresponds to a non-existent unit. + + + Implementation notes: + + 1. The Attention, Drive Fault, First Status, and Seek Check flags are stored + in the unit status word. The other status flags are determined + dynamically. + + 2. The Drive Busy bit is set if the unit service is scheduled. In hardware, + this bit indicates that the heads are not positioned over a track, i.e., + that a seek is in progress. In simulation, the only time a Request + Status command is allowed is either when the controller is waiting for + seek completion or for another command. In the latter case, unit service + will not be scheduled, so activation can only be for seek completion. +*/ + +static uint16 drive_status (UNIT *uptr) +{ +uint16 status; +uint32 model; + +if (uptr == NULL) /* if the unit is invalid */ + return DL_S2ERR | DL_S2NR; /* then it does not respond */ + +model = GET_MODEL (uptr->flags); /* get the drive type */ +status = drive_props [model].type | uptr->STAT; /* start with the drive type and unit status */ + +if (uptr->flags & UNIT_WPROT) /* is the write protect switch set? */ + status |= DL_S2RO; /* set the Protected status bit */ + +if (uptr->flags & UNIT_FMT) /* is the format switch enabled? */ + status |= DL_S2FMT; /* set the Format status bit */ + +if (uptr->flags & UNIT_DIS) /* is the unit non-existent? */ + status |= DL_S2NR; /* set the Not Ready bit */ + +else if (uptr->flags & UNIT_UNLOAD) /* are the heads unloaded? */ + status |= DL_S2NR | DL_S2BUSY; /* set the Not Ready and Drive Busy bits */ + +if (sim_is_active (uptr)) /* is the drive positioner moving? */ + status |= DL_S2BUSY; /* set the Drive Busy bit */ + +if (status & DL_S2ERRORS) /* are there any Status-2 errors? */ + status |= DL_S2ERR; /* set the Error bit */ + +return status; /* return the unit status */ +} diff --git a/HP2100/hp_disclib.h b/HP2100/hp_disclib.h new file mode 100644 index 00000000..90056b27 --- /dev/null +++ b/HP2100/hp_disclib.h @@ -0,0 +1,380 @@ +/* hp_disclib.h: HP MAC/ICD disc controller simulator library definitions + + Copyright (c) 2011-2012, J. David Bryan + Copyright (c) 2004-2011, Robert 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 + THE AUTHORS 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 names of the authors 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 authors. + + 15-Mar-12 JDB First release + 09-Nov-11 JDB Created disc controller common library from DS simulator + + + This file defines the interface between interface simulators and the + simulation library for the HP 13037 and 13365 disc controllers. It must be + included by the interface-specific modules (DA, DS, etc.). +*/ + + + +#include "hp2100_defs.h" + + + +/* Program limits */ + +#define DL_MAXDRIVE 7 /* last valid drive number */ +#define DL_MAXUNIT 10 /* last legal unit number */ + +#define DL_AUXUNITS 2 /* number of MAC auxiliary units required */ + +#define DL_WPSEC 128 /* words per normal sector */ +#define DL_WPFSEC 138 /* words per full sector */ +#define DL_BUFSIZE DL_WPFSEC /* required buffer size in words */ + + +/* Default controller times */ + +#define DL_SEEK_TIME 100 /* seek delay time (per cylinder) */ +#define DL_SECTOR_TIME 27 /* intersector delay time */ +#define DL_CMD_TIME 3 /* command start delay time */ +#define DL_DATA_TIME 1 /* data transfer delay time */ + +#define DL_WAIT_TIME 2749200 /* command wait timeout (1.74 seconds) */ + + +/* Common per-unit disc drive state variables */ + +#define CYL u3 /* current drive cylinder */ +#define STAT u4 /* current drive status (Status 2) */ +#define OP u5 /* current drive operation in process */ +#define PHASE u6 /* current command phase */ + + +/* Unit flags and accessors */ + +#define UNIT_V_MODEL (UNIT_V_UF + 0) /* bits 1-0: model ID */ +#define UNIT_V_WLK (UNIT_V_UF + 2) /* bits 2-2: write locked (protect switch) */ +#define UNIT_V_UNLOAD (UNIT_V_UF + 3) /* bits 3-3: heads unloaded */ +#define UNIT_V_FMT (UNIT_V_UF + 4) /* bits 4-4: format enabled */ +#define UNIT_V_AUTO (UNIT_V_UF + 5) /* bits 5-5: autosize */ +#define DL_V_UF (UNIT_V_UF + 6) /* first free unit flag bit */ + +#define UNIT_M_MODEL 3 /* model ID mask */ + +#define UNIT_MODEL (UNIT_M_MODEL << UNIT_V_MODEL) +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_UNLOAD (1 << UNIT_V_UNLOAD) +#define UNIT_FMT (1 << UNIT_V_FMT) +#define UNIT_AUTO (1 << UNIT_V_AUTO) + +#define UNIT_WPROT (UNIT_WLK | UNIT_RO) /* write protected if locked or read-only */ + +#define GET_MODEL(t) (((t) >> UNIT_V_MODEL) & UNIT_M_MODEL) +#define SET_MODEL(t) (((t) & UNIT_M_MODEL) << UNIT_V_MODEL) + + +/* Status-1 accessors */ + +#define DL_V_S1SPD 13 /* bits 15-13: S/P/D flags */ +#define DL_V_S1STAT 8 /* bits 12- 8: controller status */ +#define DL_V_S1UNIT 0 /* bits 7- 0: last unit number */ + +#define DL_M_S1UNIT 15 /* unit mask */ + +#define GET_S1UNIT(v) (((v) >> DL_V_S1UNIT) & DL_M_S1UNIT) + +#define SET_S1SPD(v) ((v) << DL_V_S1SPD) +#define SET_S1STAT(v) ((v) << DL_V_S1STAT) +#define SET_S1UNIT(v) ((v) << DL_V_S1UNIT) + + +/* Status-2 accessors (+ = kept in unit status, - = determined dynamically */ + +#define DL_V_S2ERR 15 /* bits 15-15: (-) any error flag */ +#define DL_V_S2DTYP 9 /* bits 12- 9: (-) drive type */ +#define DL_V_S2ATN 7 /* bits 7- 7: (+) attention flag */ +#define DL_V_S2RO 6 /* bits 6- 6: (-) read only flag */ +#define DL_V_S2FMT 5 /* bits 5- 5: (-) format enabled flag */ +#define DL_V_S2FAULT 4 /* bits 4- 4: (+) drive fault flag */ +#define DL_V_S2FS 3 /* bits 3- 3: (+) first status flag */ +#define DL_V_S2SC 2 /* bits 2- 2: (+) seek error flag */ +#define DL_V_S2NR 1 /* bits 1- 1: (-) not ready flag */ +#define DL_V_S2BUSY 0 /* bits 0- 1: (-) drive busy flag */ + +#define DL_S2ERR (1 << DL_V_S2ERR) +#define DL_S2DTYP (1 << DL_V_S2DTYP) +#define DL_S2ATN (1 << DL_V_S2ATN) +#define DL_S2RO (1 << DL_V_S2RO) +#define DL_S2FMT (1 << DL_V_S2FMT) +#define DL_S2FAULT (1 << DL_V_S2FAULT) +#define DL_S2FS (1 << DL_V_S2FS) +#define DL_S2SC (1 << DL_V_S2SC) +#define DL_S2NR (1 << DL_V_S2NR) +#define DL_S2BUSY (1 << DL_V_S2BUSY) + +#define DL_S2STOPS (DL_S2FAULT | DL_S2SC | DL_S2NR) /* bits that stop drive access */ +#define DL_S2ERRORS (DL_S2FAULT | DL_S2SC | DL_S2NR | DL_S2BUSY) /* bits that set S2ERR */ +#define DL_S2CPS (DL_S2ATN | DL_S2FAULT | DL_S2FS | DL_S2SC) /* bits cleared by Controller Preset */ + + +/* Drive properties. + + The controller library supports four different disc drive models with these + properties: + + Drive Model Drive Sectors Heads per Cylinders Megabytes + Model ID Type per Head Cylinder per Drive per Drive + ----- ----- ----- -------- --------- --------- --------- + 7905 0 2 48 3 411 15 + 7906 1 0 48 4 411 20 + 7920 2 1 48 5 823 50 + 7925 3 3 64 9 823 120 + + The Drive Type is reported by the controller in the second status word + (Status-2) returned by the Request Status command. + + Model IDs are used in the unit flags to identify the unit's model. For the + autosizing feature to work, models must be assigned ascending IDs in order of + ascending drive sizes. +*/ + +#define D7905_MODEL 0 +#define D7905_SECTS 48 +#define D7905_HEADS 3 +#define D7905_CYLS 411 +#define D7905_TYPE (2 << DL_V_S2DTYP) +#define D7905_WORDS (D7905_SECTS * D7905_HEADS * D7905_CYLS * DL_WPSEC) + +#define D7906_MODEL 1 +#define D7906_SECTS 48 +#define D7906_HEADS 4 +#define D7906_CYLS 411 +#define D7906_TYPE (0 << DL_V_S2DTYP) +#define D7906_WORDS (D7906_SECTS * D7906_HEADS * D7906_CYLS * DL_WPSEC) + +#define D7920_MODEL 2 +#define D7920_SECTS 48 +#define D7920_HEADS 5 +#define D7920_CYLS 823 +#define D7920_TYPE (1 << DL_V_S2DTYP) +#define D7920_WORDS (D7920_SECTS * D7920_HEADS * D7920_CYLS * DL_WPSEC) + +#define D7925_MODEL 3 +#define D7925_SECTS 64 +#define D7925_HEADS 9 +#define D7925_CYLS 823 +#define D7925_TYPE (3 << DL_V_S2DTYP) +#define D7925_WORDS (D7925_SECTS * D7925_HEADS * D7925_CYLS * DL_WPSEC) + +#define MODEL_7905 SET_MODEL (D7905_MODEL) +#define MODEL_7906 SET_MODEL (D7906_MODEL) +#define MODEL_7920 SET_MODEL (D7920_MODEL) +#define MODEL_7925 SET_MODEL (D7925_MODEL) + + +/* Controller types (values must be powers of 2) */ + +typedef enum { + MAC = 1, + ICD = 2 + } CNTLR_TYPE; + + +/* Controller opcodes */ + +typedef enum { + cold_load_read = 000, + recalibrate = 001, + seek = 002, + request_status = 003, + request_sector_address = 004, + read = 005, + read_full_sector = 006, + verify = 007, + write = 010, + write_full_sector = 011, + clear = 012, + initialize = 013, + address_record = 014, + request_syndrome = 015, + read_with_offset = 016, + set_file_mask = 017, + read_without_verify = 022, + load_tio_register = 023, + request_disc_address = 024, + end = 025, + wakeup = 026, last_opcode = wakeup /* last opcode */ + } CNTLR_OPCODE; + +#define DL_OPCODE_MASK 037 + + +/* Controller command phases */ + +typedef enum { + start_phase, + data_phase, + end_phase, last_phase = end_phase /* last phase */ + } CNTLR_PHASE; + + +/* Controller status. + + Not all status values are returned by the library. The values not currently + returned are: + + - illegal_drive_type + - cylinder_miscompare + - head_sector_miscompare + - io_program_error + - sync_timeout + - correctable_data_error + - illegal_spare_access + - defective_track + - protected_track +*/ + +typedef enum { + normal_completion = 000, + illegal_opcode = 001, + unit_available = 002, + illegal_drive_type = 003, + cylinder_miscompare = 007, + uncorrectable_data_error = 010, + head_sector_miscompare = 011, + io_program_error = 012, + sync_timeout = 013, + end_of_cylinder = 014, + data_overrun = 016, + correctable_data_error = 017, + illegal_spare_access = 020, + defective_track = 021, + access_not_ready = 022, + status_2_error = 023, + protected_track = 026, + unit_unavailable = 027, + drive_attention = 037 + } CNTLR_STATUS; + + +/* Controller execution states */ + +typedef enum { + cntlr_idle, /* idle */ + cntlr_wait, /* command wait */ + cntlr_busy /* busy */ + } CNTLR_STATE; + + +/* Controller command classifications */ + +typedef enum { + class_invalid, /* invalid classification */ + class_read, /* read classification */ + class_write, /* write classification */ + class_control, /* control classification */ + class_status /* status classification */ + } CNTLR_CLASS; + + +/* Controller clear types */ + +typedef enum { + hard_clear, /* power-on/preset hard clear */ + soft_clear /* programmed soft clear */ + } CNTLR_CLEAR; + + +/* Controller state variables */ + +typedef struct { + CNTLR_TYPE type; /* controller type */ + CNTLR_STATE state; /* controller state */ + CNTLR_OPCODE opcode; /* controller opcode */ + CNTLR_STATUS status; /* controller status */ + FLIP_FLOP eoc; /* end-of-cylinder flag */ + FLIP_FLOP eod; /* end-of-data flag */ + uint32 spd_unit; /* S/P/D flags and unit number */ + uint32 file_mask; /* file mask */ + uint32 retry; /* retry counter */ + uint32 cylinder; /* cylinder address */ + uint32 head; /* head address */ + uint32 sector; /* sector address */ + uint32 verify_count; /* count of sectors to verify */ + uint32 poll_unit; /* last unit polled for attention */ + uint16 *buffer; /* data buffer pointer */ + uint32 index; /* data buffer index */ + uint32 length; /* data buffer length */ + UNIT *aux; /* auxiliary units (controller and timer) */ + int32 seek_time; /* seek delay time (per cylinder) */ + int32 sector_time; /* intersector delay time */ + int32 cmd_time; /* command start delay time */ + int32 data_time; /* data transfer delay time */ + int32 wait_time; /* command wait timeout */ + } CNTLR_VARS; + + +typedef CNTLR_VARS *CVPTR; /* pointer to controller state variables */ + +/* Controller state variables initialiation. + + Parameters are: + + ctype - type of the controller (CNTLR_TYPE) + bufptr - pointer to the data buffer + auxptr - pointer to the auxiliary units (MAC only; NULL for ICD) +*/ + +#define CNTLR_INIT(ctype,bufptr,auxptr) \ + (ctype), cntlr_idle, end, normal_completion, \ + CLEAR, CLEAR, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + (bufptr), 0, 0, (auxptr), \ + DL_SEEK_TIME, DL_SECTOR_TIME, \ + DL_CMD_TIME, DL_DATA_TIME, DL_WAIT_TIME + + + +/* Disc library global controller routines */ + +extern t_bool dl_prepare_command (CVPTR cvptr, UNIT *units, uint32 unit_limit); +extern UNIT *dl_start_command (CVPTR cvptr, UNIT *units, uint32 unit_limit); +extern void dl_end_command (CVPTR cvptr, CNTLR_STATUS status); +extern t_bool dl_poll_drives (CVPTR cvptr, UNIT *units, uint32 unit_limit); +extern t_stat dl_service_drive (CVPTR cvptr, UNIT *uptr); +extern t_stat dl_service_controller (CVPTR cvptr, UNIT *uptr); +extern t_stat dl_service_timer (CVPTR cvptr, UNIT *uptr); +extern void dl_idle_controller (CVPTR cvptr); +extern t_stat dl_clear_controller (CVPTR cvptr, UNIT *uptr, CNTLR_CLEAR clear_type); +extern t_stat dl_load_unload (CVPTR cvptr, UNIT *uptr, t_bool load); + +/* Disc library global utility routines */ + +extern CNTLR_CLASS dl_classify (CNTLR_VARS cntlr); +extern const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode); +extern const char *dl_phase_name (CNTLR_PHASE phase); + +/* Disc library global VM routines */ + +extern t_stat dl_attach (CVPTR cvptr, UNIT *uptr, char *cptr); +extern t_stat dl_detach (CVPTR cvptr, UNIT *uptr); +extern t_stat dl_set_model (UNIT *uptr, int32 value, char *cptr, void *desc); diff --git a/Visual Studio Projects/HP2100.vcproj b/Visual Studio Projects/HP2100.vcproj index d1f1068d..2978e132 100644 --- a/Visual Studio Projects/HP2100.vcproj +++ b/Visual Studio Projects/HP2100.vcproj @@ -225,6 +225,14 @@ RelativePath="..\HP2100\hp2100_cpu7.c" > + + + + @@ -289,6 +297,10 @@ RelativePath="..\HP2100\hp2100_sys.c" > + + @@ -338,6 +350,10 @@ RelativePath="hp2100_defs.h" > + + @@ -346,6 +362,10 @@ RelativePath="..\HP2100\hp2100_fp1.h" > + + diff --git a/descrip.mms b/descrip.mms index 7fd0c78a..f6d73e9c 100644 --- a/descrip.mms +++ b/descrip.mms @@ -334,7 +334,9 @@ HP2100_SOURCE1 = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\ $(HP2100_DIR)HP2100_CPU6.C,$(HP2100_DIR)HP2100_CPU7.C HP2100_LIB2 = $(LIB_DIR)HP2100L2-$(ARCH).OLB HP2100_SOURCE2 = $(HP2100_DIR)HP2100_FP1.C,$(HP2100_DIR)HP2100_BACI.C,\ - $(HP2100_DIR)HP2100_MPX.C,$(HP2100_DIR)HP2100_PIF.C + $(HP2100_DIR)HP2100_MPX.C,$(HP2100_DIR)HP2100_PIF.C \ + $(HP2100_DIR)HP2100_DI.C,$(HP2100_DIR)HP2100_DI_DA.C,\ + $(HP2100_DIR)HP_DISCLIB.C .IFDEF ALPHA_OR_IA64 HP2100_OPTIONS = /INCL=($(SIMH_DIR),$(HP2100_DIR))\ /DEF=($(CC_DEFS),"HAVE_INT64=1") diff --git a/makefile b/makefile index aaea003f..17ab28ee 100644 --- a/makefile +++ b/makefile @@ -470,7 +470,8 @@ HP2100 = ${HP2100D}/hp2100_stddev.c ${HP2100D}/hp2100_dp.c ${HP2100D}/hp2100_dq. ${HP2100D}/hp2100_cpu1.c ${HP2100D}/hp2100_cpu2.c ${HP2100D}/hp2100_cpu3.c \ ${HP2100D}/hp2100_cpu4.c ${HP2100D}/hp2100_cpu5.c ${HP2100D}/hp2100_cpu6.c \ ${HP2100D}/hp2100_cpu7.c ${HP2100D}/hp2100_fp1.c ${HP2100D}/hp2100_baci.c \ - ${HP2100D}/hp2100_mpx.c ${HP2100D}/hp2100_pif.c + ${HP2100D}/hp2100_mpx.c ${HP2100D}/hp2100_pif.c ${HP2100D}/hp2100_di.c \ + ${HP2100D}/hp2100_di_da.c ${HP2100D}/hp_disclib.c HP2100_OPT = -DHAVE_INT64 -I ${HP2100D} From 5284f8f1e66c2234d41f1e533a57d8c7cf72f75c Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 21 Mar 2012 14:45:59 -0700 Subject: [PATCH 020/112] VMS Build cleanup --- descrip.mms | 72 ++++++++++++++++++++++++++++++++----------------- sim_BuildROMs.c | 4 +-- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/descrip.mms b/descrip.mms index f6d73e9c..01229d3d 100644 --- a/descrip.mms +++ b/descrip.mms @@ -160,30 +160,6 @@ BIN_DIR = SYS$DISK:[.BIN] LIB_DIR = SYS$DISK:[.BIN.VMS.LIB] BLD_DIR = SYS$DISK:[.BIN.VMS.LIB.BLD-$(ARCH)] -# Check To Make Sure We Have SYS$DISK:[.BIN] & SYS$DISK:[.LIB] Directory. -# -.FIRST - @ IF "".NES."''CC'" THEN DELETE/SYMBOL/GLOBAL CC - @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LTS."V8.0").AND.("$(NOASYNCH)".EQS."")) THEN WRITE SYS$OUTPUT "*** WARNING **** Build should be invoked with /MACRO=NOASYNCH=1 on this platform" - @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LTS."V8.0").AND.("$(NOASYNCH)".EQS."")) THEN EXIT %x10000000 - @ DEFINE/USER SYS$OUTPUT CC_VERSION.DAT - @ CC/VERSION - @ OPEN /READ VERSION CC_VERSION.DAT - @ READ VERSION CC_VERSION - @ CLOSE VERSION - @ DELETE CC_VERSION.DAT; - @ CC_VERSION = F$ELEMENT(2," ",CC_VERSION) - @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(CC_VERSION.LTS."V6.5-001").AND.("$(NONETWORK)".EQS."")) THEN WRITE SYS$OUTPUT "*** WARNING **** C Compiler is: ''CC_VERSION'" - @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(CC_VERSION.LTS."V6.5-001").AND.("$(NONETWORK)".EQS."").AND.(F$GETSYI("VERSION").GES."V8.0")) THEN WRITE SYS$OUTPUT "*** WARNING **** Build should be invoked with /MACRO=NONETWORK=1 with this compiler" - @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(CC_VERSION.LTS."V6.5-001").AND.("$(NONETWORK)".EQS."").AND.(F$GETSYI("VERSION").LTS."V8.0")) THEN WRITE SYS$OUTPUT "*** WARNING **** Build should be invoked with /MACRO=(NONETWORK=1,NOASYNCH=1) with this compiler" - @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(CC_VERSION.LTS."V6.5-001").AND.("$(NONETWORK)".EQS."")) THEN EXIT %x10000000 - @ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") THEN CREATE/DIRECTORY $(BIN_DIR) - @ IF (F$SEARCH("SYS$DISK:[.BIN]VMS.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) - @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS]LIB.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) - @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS.LIB]BLD-$(ARCH).DIR").EQS."") THEN CREATE/DIRECTORY $(BLD_DIR) - @ IF (F$SEARCH("$(BLD_DIR)*.*").NES."") THEN DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.*;* - @ MMS /NoAction BuildROMs - # Core SIMH File Definitions. # @@ -231,6 +207,51 @@ PCAP_SIMH_INC = /INCL=($(PCAP_DIR)) .ENDIF .ENDIF +# Check To Make Sure We Have SYS$DISK:[.BIN] & SYS$DISK:[.LIB] Directory. +# +.FIRST + @ IF "".NES."''CC'" THEN DELETE/SYMBOL/GLOBAL CC + @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LTS."V8.0").AND.("$(NOASYNCH)".EQS."")) THEN WRITE SYS$OUTPUT "*** WARNING **** Build should be invoked with /MACRO=NOASYNCH=1 on this platform" + @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LTS."V8.0").AND.("$(NOASYNCH)".EQS."")) THEN EXIT %x10000000 + @ DEFINE/USER SYS$OUTPUT CC_VERSION.DAT + @ CC/VERSION + @ OPEN /READ VERSION CC_VERSION.DAT + @ READ VERSION CC_VERSION + @ CLOSE VERSION + @ DELETE CC_VERSION.DAT; + @ CC_VERSION = F$ELEMENT(2," ",CC_VERSION) + @ BAD_CC_VERSION = ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(CC_VERSION.LTS."V6.5-001").AND.("$(NONETWORK)".EQS."")) + @ IF (BAD_CC_VERSION) THEN WRITE SYS$OUTPUT "*** WARNING *** C Compiler is: ''CC_VERSION'" + @ IF (BAD_CC_VERSION.AND.(F$GETSYI("VERSION").GES."V8.0")) THEN WRITE SYS$OUTPUT "*** WARNING *** Build should be invoked with /MACRO=NONETWORK=1 with this compiler" + @ IF (BAD_CC_VERSION.AND.(F$GETSYI("VERSION").LTS."V8.0")) THEN WRITE SYS$OUTPUT "*** WARNING *** Build should be invoked with /MACRO=(NONETWORK=1,NOASYNCH=1) with this compiler" + @ IF (BAD_CC_VERSION) THEN EXIT %x10000000 + @ MISSING_PCAP = (("$(PCAP_EXECLET)".NES."").AND.("$(NONETWORK)".EQS."").AND.(F$SEARCH("$(PCAP_DIR)PCAP-VMS.C").EQS."")) + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** Attempting a Network Build but the VMS-PCAP components are not" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** available" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** " + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** The PCAP-VMS components are presumed (by this procedure) to be" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** located in a directory at the same level as the directory" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** containing the simh source files." + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** For example, if these exist here:" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** " + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** []descrip.mms" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** []scp.c" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** etc." + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** " + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** Then the following should exist:" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** [-.PCAP-VMS]BUILD_ALL.COM" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** [-.PCAP-VMS.PCAP-VCI]" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** [-.PCAP-VMS.PCAPVCM]" + @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** etc." + @ IF (MISSING_PCAP) THEN EXIT %x10000000 + @ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") THEN CREATE/DIRECTORY $(BIN_DIR) + @ IF (F$SEARCH("SYS$DISK:[.BIN]VMS.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) + @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS]LIB.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) + @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS.LIB]BLD-$(ARCH).DIR").EQS."") THEN CREATE/DIRECTORY $(BLD_DIR) + @ IF (F$SEARCH("$(BLD_DIR)*.*").NES."") THEN DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.*;* + @ IF (("$(BUILDING_ROMS)".EQS."").AND.(F$SEARCH("$(BIN_DIR)BuildROMs-$(ARCH).EXE").EQS."")) THEN $(MMS) BUILDROMS/MACRO=(BUILDING_ROMS=1) + + # MITS Altair Simulator Definitions. # ALTAIR_DIR = SYS$DISK:[.ALTAIR] @@ -641,7 +662,6 @@ $(BIN_DIR)BuildROMs-$(ARCH).EXE : sim_BuildROMs.c $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* $ RUN $(BIN_DIR)BuildROMs-$(ARCH).EXE - # # Build The Libraries. # @@ -994,6 +1014,7 @@ $(VAX_LIB1) : $(VAX_SOURCE1) $! $! Building The $(VAX_LIB1) Library. $! + $ RUN $(BIN_DIR)BuildROMs-$(ARCH).EXE $ $(CC)$(VAX_OPTIONS)/OBJ=$(VAX_DIR) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - @@ -1016,6 +1037,7 @@ $(VAX780_LIB1) : $(VAX780_SOURCE1) $! $! Building The $(VAX780_LIB1) Library. $! + $ RUN $(BIN_DIR)BuildROMs-$(ARCH).EXE $ $(CC)$(VAX780_OPTIONS)/OBJ=$(VAX780_DIR) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - diff --git a/sim_BuildROMs.c b/sim_BuildROMs.c index ba573de3..030ee370 100644 --- a/sim_BuildROMs.c +++ b/sim_BuildROMs.c @@ -15,7 +15,7 @@ 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 + MARK PIZZOLATO 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. @@ -181,5 +181,5 @@ main(int argc, char **argv) int status = 0; status += sim_make_ROM_include ("VAX/ka655x.bin", 131072, 0xFF7673B6, "VAX/vax_ka655x_bin.h", "vax_ka655x_bin"); status += sim_make_ROM_include ("VAX/vmb.exe", 44544, 0xFFC014CC, "VAX/vax780_vmb_exe.h", "vax780_vmb_exe"); -exit((status == 0) ? 0 : 1); +exit((status == 0) ? 0 : 2); } From 3049f16af2fa91514c5f7b6d13aa5f3f2bdee062 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 21 Mar 2012 14:46:34 -0700 Subject: [PATCH 021/112] Compiler detected unsigned bug --- Ibm1130/ibm1130_sys.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Ibm1130/ibm1130_sys.c b/Ibm1130/ibm1130_sys.c index 1b3fb86d..2fefc52c 100644 --- a/Ibm1130/ibm1130_sys.c +++ b/Ibm1130/ibm1130_sys.c @@ -459,10 +459,9 @@ int strnicmp (const char *a, const char *b, size_t n) { int ca, cb; - for (;;) { - if (--n < 0) /* still equal after n characters? quit now */ - return 0; + if (n == 0) return 0; /* zero length compare is equal */ + for (;;) { if ((ca = *a) == 0) /* get character, stop on null terminator */ return *b ? -1 : 0; @@ -477,6 +476,9 @@ int strnicmp (const char *a, const char *b, size_t n) return ca; a++, b++; + + if (--n == 0) /* still equal after n characters? quit now */ + return 0; } } From 0270d0ea0dafd5c548f8afdfbe7ed75faaf5b4a2 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 22 Mar 2012 12:20:00 -0700 Subject: [PATCH 022/112] Cleanup based on reports from Michael Bloom --- I7094/i7094_dsk.c | 2 +- PDP11/pdp11_xq.c | 23 ++++++++++------------- PDP11/pdp11_xu.c | 32 ++++++++++++++------------------ PDP18B/pdp18b_cpu.c | 4 ++-- scp.c | 2 -- sim_console.c | 4 +--- sim_disk.c | 6 +++--- 7 files changed, 31 insertions(+), 42 deletions(-) diff --git a/I7094/i7094_dsk.c b/I7094/i7094_dsk.c index 710725f1..4c605c81 100644 --- a/I7094/i7094_dsk.c +++ b/I7094/i7094_dsk.c @@ -1151,9 +1151,9 @@ if (uptr == NULL) if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; dptr = find_dev_from_unit (uptr); -u = uptr - dptr->units; if (dptr == NULL) return SCPE_IERR; +u = uptr - dptr->units; dtyp = GET_DTYPE (uptr->flags); if ((dtyp == TYPE_7320) || (dtyp == TYPE_1301)) diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index e9a05ae4..ba1ff031 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -1132,7 +1132,6 @@ t_stat xq_process_setup(CTLR* xq) int i,j; int count = 0; float secs; - t_stat status; uint32 saved_debug = xq->dev->dctrl; ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; ETH_MAC filters[XQ_FILTER_MAX + 1]; @@ -1225,11 +1224,11 @@ t_stat xq_process_setup(CTLR* xq) for (i = 0; i < XQ_FILTER_MAX; i++) if (memcmp(zeros, &xq->var->setup.macs[i], sizeof(ETH_MAC))) memcpy (filters[count++], xq->var->setup.macs[i], sizeof(ETH_MAC)); - status = eth_filter (xq->var->etherface, count, filters, xq->var->setup.multicast, xq->var->setup.promiscuous); + eth_filter (xq->var->etherface, count, filters, xq->var->setup.multicast, xq->var->setup.promiscuous); /* process MOP information */ if (xq->var->write_buffer.msg[0]) - status = xq_process_mop(xq); + xq_process_mop(xq); /* mark setup block valid */ xq->var->setup.valid = 1; @@ -1366,7 +1365,6 @@ t_stat xq_dispatch_rbdl(CTLR* xq) { int i; int32 rstatus, wstatus; - t_stat status; sim_debug(DBG_TRC, xq->dev, "xq_dispatch_rbdl()\n"); @@ -1394,7 +1392,7 @@ t_stat xq_dispatch_rbdl(CTLR* xq) /* process any waiting packets in receive queue */ if (xq->var->ReadQ.count) - status = xq_process_rbdl(xq); + xq_process_rbdl(xq); return SCPE_OK; } @@ -2250,7 +2248,6 @@ t_stat xq_wr_icr(CTLR* xq, int32 data) t_stat xq_wr(int32 data, int32 PA, int32 access) { - t_stat status; CTLR* xq = xq_pa2ctlr(PA); int index = (PA >> 1) & 07; /* word index */ @@ -2266,19 +2263,19 @@ t_stat xq_wr(int32 data, int32 PA, int32 access) xq->var->iba = (xq->var->iba & 0xFFFF) | ((data & 0xFFFF) << 16); break; case 2: /* ICR */ - status = xq_wr_icr(xq, data); + xq_wr_icr(xq, data); break; case 3: break; case 4: /* SRQR */ - status = xq_wr_srqr(xq, data); + xq_wr_srqr(xq, data); break; case 5: break; case 6: break; case 7: /* ARQR */ - status = xq_wr_arqr(xq, data); + xq_wr_arqr(xq, data); break; } break; @@ -2304,20 +2301,20 @@ t_stat xq_wr(int32 data, int32 PA, int32 access) break; case 3: /* receive bdl high bits */ xq->var->rbdl[1] = data; - status = xq_dispatch_rbdl(xq); /* start receive operation */ + xq_dispatch_rbdl(xq); /* start receive operation */ break; case 4: /* transmit bdl low bits */ xq->var->xbdl[0] = data; break; case 5: /* transmit bdl high bits */ xq->var->xbdl[1] = data; - status = xq_dispatch_xbdl(xq); /* start transmit operation */ + xq_dispatch_xbdl(xq); /* start transmit operation */ break; case 6: /* vector address register */ - status = xq_wr_var(xq, data); + xq_wr_var(xq, data); break; case 7: /* control and status register */ - status = xq_wr_csr(xq, data); + xq_wr_csr(xq, data); break; } break; diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index 28dc50e0..f9cda450 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -553,7 +553,6 @@ t_stat xu_system_id (CTLR* xu, const ETH_MAC dest, uint16 receipt_id) t_stat xu_svc(UNIT* uptr) { int queue_size; - t_stat status; CTLR* xu = xu_unit2ctlr(uptr); const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00}; const int one_second = clk_tps * tmr_poll; @@ -568,7 +567,7 @@ t_stat xu_svc(UNIT* uptr) { 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); + 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 */ @@ -578,7 +577,7 @@ t_stat xu_svc(UNIT* uptr) /* 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_system_id(xu, mop_multicast, 0); /* then send ID packet */ xu->var->idtmr = XU_ID_TIMER_VAL * one_second; /* reset timer */ } @@ -627,7 +626,6 @@ void xu_setclrint(CTLR* xu, int32 bits) t_stat xu_sw_reset (CTLR* xu) { - t_stat status; int i; sim_debug(DBG_TRC, xu->dev, "xu_sw_reset()\n"); @@ -668,9 +666,9 @@ t_stat xu_sw_reset (CTLR* xu) xu->var->setup.macs[1][i] = 0xff; /* Broadcast Address */ xu->var->setup.mac_count = 2; if (xu->var->etherface) - status = eth_filter (xu->var->etherface, xu->var->setup.mac_count, - xu->var->setup.macs, xu->var->setup.multicast, - xu->var->setup.promiscuous); + eth_filter (xu->var->etherface, xu->var->setup.mac_count, + xu->var->setup.macs, xu->var->setup.multicast, + xu->var->setup.promiscuous); /* activate device if not disabled */ if ((xu->dev->flags & DEV_DIS) == 0) { @@ -708,7 +706,7 @@ int32 xu_command(CTLR* xu) uint32 udbb; int fnc, mtlen, i, j; uint16 value, pltlen; - t_stat status, rstatus, wstatus, wstatus2, wstatus3; + t_stat rstatus, wstatus, wstatus2, wstatus3; struct xu_stats* stats = &xu->var->stats; uint16* udb = xu->var->udb; uint16* mac_w = (uint16*) xu->var->mac; @@ -795,9 +793,9 @@ int32 xu_command(CTLR* xu) rstatus = Map_ReadB(udbb, mtlen * 6, (uint8*) &xu->var->setup.macs[2]); if (rstatus == 0) { xu->var->setup.mac_count = mtlen + 2; - status = eth_filter (xu->var->etherface, xu->var->setup.mac_count, - xu->var->setup.macs, xu->var->setup.multicast, - xu->var->setup.promiscuous); + 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; } @@ -922,9 +920,9 @@ int32 xu_command(CTLR* xu) /* 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->setup.macs, xu->var->setup.multicast, - xu->var->setup.promiscuous); + eth_filter (xu->var->etherface, xu->var->setup.mac_count, + xu->var->setup.macs, xu->var->setup.multicast, + xu->var->setup.promiscuous); break; case FC_RSTAT: /* read extended status */ @@ -1339,7 +1337,6 @@ 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", @@ -1368,7 +1365,7 @@ void xu_port_command (CTLR* xu) break; case CMD_GETCMD: /* GET COMMAND */ - bits = xu_command(xu); + xu_command(xu); xu->var->pcsr0 |= PCSR0_DNI; break; @@ -1606,12 +1603,11 @@ t_stat xu_attach(UNIT* uptr, char* cptr) 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); + eth_close (xu->var->etherface); free(xu->var->etherface); xu->var->etherface = 0; free(uptr->filename); diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index 9545390e..4e5a53b0 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -2132,7 +2132,7 @@ if (usmd && (sw & SWMASK ('V'))) { addr = RelocXVM (addr, REL_C); else if (RELOC) addr = Reloc15 (addr, REL_C); - if ((int32) addr < 0) + if (((int32)addr) < 0) return STOP_MME; } #endif @@ -2153,7 +2153,7 @@ if (usmd && (sw & SWMASK ('V'))) { addr = RelocXVM (addr, REL_C); else if (RELOC) addr = Reloc15 (addr, REL_C); - if ((int32) addr < 0) + if (((int32)addr) < 0) return STOP_MME; } #endif diff --git a/scp.c b/scp.c index eac6523a..f61abf70 100644 --- a/scp.c +++ b/scp.c @@ -3991,8 +3991,6 @@ if (!initialized) { } } if (prompt) { /* interactive? */ - char *tmpc; - if (p_readline) { char *tmpc = p_readline (prompt); /* get cmd line */ if (tmpc == NULL) /* bad result? */ diff --git a/sim_console.c b/sim_console.c index 3bffbf42..200749bc 100644 --- a/sim_console.c +++ b/sim_console.c @@ -385,13 +385,11 @@ return SCPE_OK; t_stat sim_set_deboff (int32 flag, char *cptr) { -t_stat r; - if (cptr && (*cptr != 0)) /* now eol? */ return SCPE_2MARG; if (sim_deb == NULL) /* no log? */ return SCPE_OK; -r = sim_close_logfile (&sim_deb_ref); +sim_close_logfile (&sim_deb_ref); sim_deb = NULL; if (!sim_quiet) printf ("Debug output disabled\n"); diff --git a/sim_disk.c b/sim_disk.c index 99f9d088..49a97a2b 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -1024,12 +1024,12 @@ t_stat sim_disk_detach (UNIT *uptr) { struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; int (*close_function)(FILE *f); -FILE *fileref = uptr->fileref; -DEVICE *dptr; +FILE *fileref; t_bool auto_format; if (uptr == NULL) return SCPE_IERR; +fileref = uptr->fileref; switch (DK_GET_FMT (uptr)) { /* case on format */ case DKUF_F_STD: /* Simh */ close_function = fclose; @@ -1045,7 +1045,7 @@ if (!(uptr->flags & UNIT_ATTABLE)) /* attachable? */ return SCPE_NOATT; if (!(uptr->flags & UNIT_ATT)) /* attached? */ return SCPE_OK; -if ((dptr = find_dev_from_unit (uptr)) == NULL) +if (NULL == find_dev_from_unit (uptr)) return SCPE_OK; auto_format = ctx->auto_format; From 2fcb0aad62c890bea6e6fb8fd02c2100fa1932f8 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 22 Mar 2012 14:37:01 -0700 Subject: [PATCH 023/112] Made VMS build more robust and the failure case when VMS-PCAP is missing provide guidance. --- descrip.mms | 61 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/descrip.mms b/descrip.mms index 01229d3d..6f2fcae9 100644 --- a/descrip.mms +++ b/descrip.mms @@ -211,8 +211,10 @@ PCAP_SIMH_INC = /INCL=($(PCAP_DIR)) # .FIRST @ IF "".NES."''CC'" THEN DELETE/SYMBOL/GLOBAL CC - @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LTS."V8.0").AND.("$(NOASYNCH)".EQS."")) THEN WRITE SYS$OUTPUT "*** WARNING **** Build should be invoked with /MACRO=NOASYNCH=1 on this platform" - @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LTS."V8.0").AND.("$(NOASYNCH)".EQS."")) THEN EXIT %x10000000 + @ EXIT_ON_ERROR := IF (ERROR_CONDITION) THEN EXIT %X10000004 + @ ERROR_CONDITION = ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LTS."V8.0").AND.("$(NOASYNCH)".EQS."")) + @ IF (ERROR_CONDITION) THEN WRITE SYS$OUTPUT "*** WARNING **** Build should be invoked with /MACRO=NOASYNCH=1 on this platform" + @ 'EXIT_ON_ERROR @ DEFINE/USER SYS$OUTPUT CC_VERSION.DAT @ CC/VERSION @ OPEN /READ VERSION CC_VERSION.DAT @@ -222,28 +224,41 @@ PCAP_SIMH_INC = /INCL=($(PCAP_DIR)) @ CC_VERSION = F$ELEMENT(2," ",CC_VERSION) @ BAD_CC_VERSION = ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(CC_VERSION.LTS."V6.5-001").AND.("$(NONETWORK)".EQS."")) @ IF (BAD_CC_VERSION) THEN WRITE SYS$OUTPUT "*** WARNING *** C Compiler is: ''CC_VERSION'" - @ IF (BAD_CC_VERSION.AND.(F$GETSYI("VERSION").GES."V8.0")) THEN WRITE SYS$OUTPUT "*** WARNING *** Build should be invoked with /MACRO=NONETWORK=1 with this compiler" - @ IF (BAD_CC_VERSION.AND.(F$GETSYI("VERSION").LTS."V8.0")) THEN WRITE SYS$OUTPUT "*** WARNING *** Build should be invoked with /MACRO=(NONETWORK=1,NOASYNCH=1) with this compiler" - @ IF (BAD_CC_VERSION) THEN EXIT %x10000000 + @ IF (BAD_CC_VERSION.AND.(F$GETSYI("VERSION").GES."V8.0")) THEN - + WRITE SYS$OUTPUT "*** WARNING *** Build should be invoked with /MACRO=NONETWORK=1 with this compiler" + @ IF (BAD_CC_VERSION.AND.(F$GETSYI("VERSION").LTS."V8.0")) THEN - + WRITE SYS$OUTPUT "*** WARNING *** Build should be invoked with /MACRO=(NONETWORK=1,NOASYNCH=1) with this compiler" + @ ERROR_CONDITION = BAD_CC_VERSION + @ 'EXIT_ON_ERROR @ MISSING_PCAP = (("$(PCAP_EXECLET)".NES."").AND.("$(NONETWORK)".EQS."").AND.(F$SEARCH("$(PCAP_DIR)PCAP-VMS.C").EQS."")) - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** Attempting a Network Build but the VMS-PCAP components are not" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** available" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** " - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** The PCAP-VMS components are presumed (by this procedure) to be" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** located in a directory at the same level as the directory" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** containing the simh source files." - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** For example, if these exist here:" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** " - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** []descrip.mms" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** []scp.c" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** etc." - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** " - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** Then the following should exist:" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** [-.PCAP-VMS]BUILD_ALL.COM" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** [-.PCAP-VMS.PCAP-VCI]" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** [-.PCAP-VMS.PCAPVCM]" - @ IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT "*** Error *** etc." - @ IF (MISSING_PCAP) THEN EXIT %x10000000 + @ MISS_SAY := IF (MISSING_PCAP) THEN WRITE SYS$OUTPUT + @ 'MISS_SAY' "*** Error *** Attempting a Network Build but the VMS-PCAP components are not" + @ 'MISS_SAY' "*** Error *** available" + @ 'MISS_SAY' "*** Error *** " + @ 'MISS_SAY' "*** Error *** The vms-pcap.zip file can be downloaded from:" + @ 'MISS_SAY' "*** Error *** " + @ 'MISS_SAY' "*** Error *** https://github.com/markpizz/simh/downloads" + @ 'MISS_SAY' "*** Error *** " + @ 'MISS_SAY' "*** Error *** Be sure to ""unzip -a vms-pcap"" to properly set the file attributes" + @ 'MISS_SAY' "*** Error *** " + @ 'MISS_SAY' "*** Error *** The PCAP-VMS components are presumed (by this procedure) to be" + @ 'MISS_SAY' "*** Error *** located in a directory at the same level as the directory" + @ 'MISS_SAY' "*** Error *** containing the simh source files." + @ 'MISS_SAY' "*** Error *** For example, if these exist here:" + @ 'MISS_SAY' "*** Error *** " + @ 'MISS_SAY' "*** Error *** []descrip.mms" + @ 'MISS_SAY' "*** Error *** []scp.c" + @ 'MISS_SAY' "*** Error *** etc." + @ 'MISS_SAY' "*** Error *** " + @ 'MISS_SAY' "*** Error *** Then the following should exist:" + @ 'MISS_SAY' "*** Error *** [-.PCAP-VMS]BUILD_ALL.COM" + @ 'MISS_SAY' "*** Error *** [-.PCAP-VMS.PCAP-VCI]" + @ 'MISS_SAY' "*** Error *** [-.PCAP-VMS.PCAPVCM]" + @ 'MISS_SAY' "*** Error *** etc." + @ 'MISS_SAY' "*** Error *** " + @ 'MISS_SAY' "*** Error *** Aborting Build" + @ ERROR_CONDITION = MISSING_PCAP + @ 'EXIT_ON_ERROR @ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") THEN CREATE/DIRECTORY $(BIN_DIR) @ IF (F$SEARCH("SYS$DISK:[.BIN]VMS.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS]LIB.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) From e0fbfa6abfb120d7fcc181d548a7d5503529a0d5 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 22 Mar 2012 16:14:30 -0700 Subject: [PATCH 024/112] Fix memory leaks in attach error paths. --- PDP11/pdp11_xq.c | 8 +++++++- PDP11/pdp11_xu.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index ba1ff031..9233550c 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -2611,6 +2611,7 @@ t_stat xq_attach(UNIT* uptr, char* cptr) printf("%s: MAC Address Conflict on LAN for address %s, change the MAC address to a unique value\n", xq->dev->name, buf); if (sim_log) fprintf (sim_log, "%s: MAC Address Conflict on LAN for address %s, change the MAC address to a unique value\n", xq->dev->name, buf); eth_close(xq->var->etherface); + free(tptr); free(xq->var->etherface); xq->var->etherface = NULL; return SCPE_NOATT; @@ -2623,8 +2624,13 @@ t_stat xq_attach(UNIT* uptr, char* cptr) /* init read queue (first time only) */ status = ethq_init(&xq->var->ReadQ, XQ_QUE_MAX); - if (status != SCPE_OK) + if (status != SCPE_OK) { + eth_close(xq->var->etherface); + free(tptr); + free(xq->var->etherface); + xq->var->etherface = NULL; return status; + } if (xq->var->mode == XQ_T_DELQA_PLUS) eth_filter_hash (xq->var->etherface, 1, &xq->var->init.phys, 0, xq->var->init.mode & XQ_IN_MO_PRO, &xq->var->init.hash_filter); diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index f9cda450..83920b7d 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -1587,6 +1587,8 @@ t_stat xu_attach(UNIT* uptr, char* cptr) printf("%s: MAC Address Conflict on LAN for address %s\n", xu->dev->name, buf); if (sim_log) fprintf (sim_log, "%s: MAC Address Conflict on LAN for address %s\n", xu->dev->name, buf); eth_close(xu->var->etherface); + free(tptr); + xu->var->etherface = 0; return SCPE_NOATT; } uptr->filename = tptr; From 5863e1bc38bf06e305d1ca17edf4f78b3f5961d6 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 23 Mar 2012 11:11:07 -0700 Subject: [PATCH 025/112] HP2100 Update from Dave Bryan --- HP2100/hp2100_bugfixes.txt | 73 +++--------- HP2100/hp2100_cpu5.c | 5 +- HP2100/hp2100_diag.txt | 195 +++++++++++++++--------------- HP2100/hp_disclib.c | 236 +++++++++++++------------------------ HP2100/hp_disclib.h | 16 +-- sim_console.c | 3 +- sim_rev.h | 63 ++++++++-- 7 files changed, 269 insertions(+), 322 deletions(-) diff --git a/HP2100/hp2100_bugfixes.txt b/HP2100/hp2100_bugfixes.txt index da1e22a1..57ef7392 100644 --- a/HP2100/hp2100_bugfixes.txt +++ b/HP2100/hp2100_bugfixes.txt @@ -1,6 +1,6 @@ HP 2100 SIMULATOR BUG FIX WRITEUPS ================================== - Last update: 2012-03-17 + Last update: 2012-03-20 1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756 @@ -4386,10 +4386,11 @@ CAUSE: The "exdep_cmd" routine is calling "find_reg_glob" if the "find_reg" routine returns a not-found error for the selected device. - "find_reg_glob" searches for a unique name among all devices and returns - it if found. + "find_reg_glob" searches for a unique name among all devices and returns it + if found. - RESOLUTION: None. + RESOLUTION: Modify "exdep_cmd" (scp.c) to search for a global register + name only if the device was not explicitly specified. STATUS: Fixed in version 3.8-0. @@ -5701,7 +5702,8 @@ -227. PROBLEM: The 79xx disc returns incorrect status for a disabled drive. +227. PROBLEM: The 13037 disc controller returns incorrect status for a disabled + drive. VERSION: 3.8-1 @@ -5711,9 +5713,9 @@ CAUSE: SIMH initially defines the DS device as having eight 7905 drives connected to the controller. Each drive reports "heads unloaded" status - (status-2 bits 1-0 = 11) until it has a disc image attached. If a unit is + (Status-2 bits 1-0 = 11) until it has a disc image attached. If a unit is disabled, it continues to report "heads unloaded" status. It should be - reporting "unit not present" (status-2 bits 1-0 = 10) status. + reporting "unit not present" (Status-2 bits 1-0 = 10) status. RESOLUTION: Modify "ds_updds2" (hp2100_ds.c) to report an "enabled and unloaded" condition as Not Ready and Busy, and a "disabled" condition as @@ -5723,8 +5725,8 @@ -228. PROBLEM: The 79xx disc returns incorrect status for an auto-seek beyond - the drive limits. +228. PROBLEM: The 13037 disc controller returns incorrect status for an + auto-seek beyond the drive limits. VERSION: 3.8-1 @@ -5771,8 +5773,8 @@ -229. PROBLEM: The Read Without Verify command does not verify the address when a - track boundary is crossed. +229. PROBLEM: The 13037 Read Without Verify command does not verify the address + when a track boundary is crossed. VERSION: 3.8-1 @@ -5832,7 +5834,7 @@ -230. PROBLEM: The Request Sector Address command does not check the unit +230. PROBLEM: The 13037 Request Sector Address command does not check the unit number. VERSION: 3.8-1 @@ -5888,7 +5890,7 @@ -231. PROBLEM: The Wakeup command does not check the unit number. +231. PROBLEM: The 13037 Wakeup command does not check the unit number. VERSION: 3.8-1 @@ -6001,7 +6003,7 @@ or SHOW lists but can still be displayed or modified if requested explicitly. Add hp_setsc and hp_showsc functions (hp2100_sys.c) to set and show the select code, and modify hp_setdev and hp_showdev to call hp_setsc - and hp_showsc, respectively, and to work aroung newline suppression for + and hp_showsc, respectively, and to work around newline suppression for MTAB_NMO entries. Modify the documentation to change device number references to select code references. @@ -6171,44 +6173,7 @@ -242. PROBLEM: The DO -E command continues to execute commands after a VM error. - - VERSION: 3.8-1 - - OBSERVATION: According to the manual, when invoking a DO command file and - specifying the -E switch, "command processing (including nested command - invocations) will be aborted if any error is encountered." Errors that - occur as a result of commands, e.g., an invalid unit name supplied to the - ATTACH command, correctly terminate the DO command. However, errors that - occur when running the simulated CPU (e.g., a host I/O error) do not; the - error is printed on the console, but the command file continues to execute. - - CAUSE: When the -E switch is specified, the DO command processor checks - the return status from each command invoked and aborts execution of the - command file if the return is not SCPE_OK. When a RUN, GO, STEP, CONT, or - BOOT command is invoked, the run command processor calls the VM-provided - instruction execution function to start the simulation. - - When simulation is stopped, the instruction executor returns a status code - to indicate why execution has stopped. The reason might be a VM-defined - condition (e.g., execution of a "halt" instruction) or a system condition - (e.g., a host file system I/O error). The run command processor uses this - code to print an error message, but then returns SCPE_OK to the caller. As - the DO command processor never sees the error message, it continues to - execute commands. - - RESOLUTION: Modify "run_cmd" (scp.c) to return the correct status instead - of SCPE_OK. Consolidate the error printing code from "run_cmd", "main", - and "do_cmd" into a new "fprint_error" function that combines both VM stop - and command error messages. Modify the error checkers in "main" and - "do_cmd" to call "fprint_error" to avoid printing messages from "run_cmd" - twice. - - STATUS: Fixed in version 3.9-0. - - - -243. ENHANCEMENT: Modify the 13037 disc simulator to use the common disc +242. ENHANCEMENT: Modify the 13037 disc simulator to use the common disc controller library. VERSION: 3.8-1 @@ -6225,7 +6190,7 @@ -244. ENHANCEMENT: Add debug printout support to the 13037 disc simulator. +243. ENHANCEMENT: Add debug printout support to the 13037 disc simulator. VERSION: 3.8-1 @@ -6238,7 +6203,7 @@ -245. ENHANCEMENT: Eliminate the poll for parameters to 13037 disc commands. +244. ENHANCEMENT: Eliminate the poll for parameters to 13037 disc commands. VERSION: 3.8-1 diff --git a/HP2100/hp2100_cpu5.c b/HP2100/hp2100_cpu5.c index 6285ef10..a680f864 100644 --- a/HP2100/hp2100_cpu5.c +++ b/HP2100/hp2100_cpu5.c @@ -1,7 +1,7 @@ /* hp2100_cpu5.c: HP 1000 RTE-6/VM VMA and RTE-IV EMA instructions Copyright (c) 2007-2008, Holger Veit - Copyright (c) 2006-2011, J. David Bryan + Copyright (c) 2006-2012, J. David Bryan 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 @@ CPU5 RTE-6/VM and RTE-IV firmware option instructions + 20-Mar-12 JDB Added sign extension for dim count in "cpu_ema_resolve" 28-Dec-11 JDB Eliminated unused variable in "cpu_ema_vset" 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) @@ -815,7 +816,7 @@ static t_bool cpu_ema_resolve(uint32 dtbl,uint32 atbl,uint32* sum) int32 sub, act, low, sz; uint32 MA, base; -int32 ndim = ReadW(dtbl++); /* # dimensions */ +int32 ndim = SEXT(ReadW(dtbl++)); /* # dimensions */ if (ndim < 0) return FALSE; /* invalid? */ *sum = 0; /* accu for index calc */ diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt index 67cc0fc3..358e0bb5 100644 --- a/HP2100/hp2100_diag.txt +++ b/HP2100/hp2100_diag.txt @@ -1,6 +1,6 @@ SIMH/HP 21XX DIAGNOSTICS PERFORMANCE ==================================== - Last update: 2012-02-13 + Last update: 2012-02-20 The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation. @@ -127,12 +127,12 @@ offline diagnostics: Date Host Date SIMH Part Number Diagnostic Name Code Op. Sys. Code Vers. Result ----------- ------------------------------- ---- -------- ---- ----- ---------- -92067-16013 Extended Memory Area Firmware 1805 RTE-IVB 5010 3.8-0 Passed -92084-16423 Virtual Memory Area Firmware 2121 RTE-6/VM 6200 3.8-0 Passed 12824-16002 Vector Instruction Set Firmware 2026 RTE-IVB 5010 3.8-0 Passed -12829-16006 Vector Instruction Set Firmware 2226 RTE-6/VM 6200 3.8-0 Passed -92835-16006 SIGNAL/1000 Firmware Diagnostic 2040 RTE-6/VM 6200 3.8-0 Passed 91711-12032 ICD/MAC Disc Diagnostic 2201 RTE-IVB 5010 3.8-2 Partial +92067-16013 Extended Memory Area Firmware 1805 RTE-IVB 5010 3.8-0 Passed +12829-16006 Vector Instruction Set Firmware 2226 RTE-6/VM 6200 3.8-0 Passed +92084-16423 Virtual Memory Area Firmware 2121 RTE-6/VM 6200 3.8-0 Passed +92835-16006 SIGNAL/1000 Firmware Diagnostic 2040 RTE-6/VM 6200 3.8-0 Passed The "SIMH Version" is the version number of the earliest SIMH system that was @@ -3497,54 +3497,6 @@ system. ------------------------------------------------- -#EMA - Extended Memory Array Firmware Diagnostic ------------------------------------------------- - -TESTED DEVICE: CPU (hp2100_cpu5.c) - -BINARY FILE: 92067-16013 Rev. 1805 - -HOST SYSTEM: RTE-IVB Rev. 5010 - -CONFIGURATION: sim> set CPU EMA - sim> go - -TEST REPORT: EMA ON-LINE DIAGNOSTIC SUCCESSFUL COMPLETION - -TEST RESULT: Passed. - - - ------------------------------------------------- -VMACK - Virtual Memory Array Firmware Diagnostic ------------------------------------------------- - -TESTED DEVICE: CPU (hp2100_cpu5.c) - -BINARY FILE: 92084-16423 Rev. 2121 - -HOST SYSTEM: RTE-6/VM Rev. 6200 - -CONFIGURATION: sim> set CPU 1000-F - sim> set CPU VMA - sim> go - -TEST REPORT: VMACK - VMA FIRMWARE DIAGNOSTIC, FIRMWARE REV# 003 - VMACK - .IMAR NO ERRORS DETECTED PASS# 1 - VMACK - .JMAR NO ERRORS DETECTED PASS# 1 - VMACK - .LBP NO ERRORS DETECTED PASS# 1 - VMACK - .LBPR NO ERRORS DETECTED PASS# 1 - VMACK - .LPX NO ERRORS DETECTED PASS# 1 - VMACK - .LPXR NO ERRORS DETECTED PASS# 1 - VMACK - .PMAP NO ERRORS DETECTED PASS# 1 - VMACK - .IMAP NO ERRORS DETECTED PASS# 1 - VMACK - .JMAP NO ERRORS DETECTED PASS# 1 - -TEST RESULT: Passed. - - - -------------------------------------------------- VISOD - Vector Instruction Set Firmware Diagnostic -------------------------------------------------- @@ -3565,49 +3517,6 @@ TEST RESULT: Passed. --------------------------------------------------- -VISOD - Vector Instruction Set Firmware Diagnostic --------------------------------------------------- - -TESTED DEVICE: CPU (hp2100_cpu7.c) - -BINARY FILE: 12829-16006 Rev. 2226 - -HOST SYSTEM: RTE-6/VM Rev. 6200 - -CONFIGURATION: sim> set CPU 1000-F - sim> set CPU VIS - sim> go - -TEST REPORT: VIS ON-LINE DIAGNOSTIC SUCCESSFUL COMPLETION - -TEST RESULT: Passed. - - - ---------------------------------------- -SDIAG - SIGNAL/1000 Firmware Diagnostic ---------------------------------------- - -TESTED DEVICE: CPU (hp2100_cpu7.c) - -BINARY FILE: 92835-16006 Rev. 2040 - -HOST SYSTEM: RTE-6/VM Rev. 6200 - -CONFIGURATION: sim> set CPU 1000-F - sim> set CPU VIS - sim> set CPU SIGNAL - sim> go - -TEST REPORT: SIGNAL/1000 FIRMWARE DIAGNOSTIC - - SIGNAL/1000 FIRMWARE DIAGNOSTIC SUCCESSFUL COMPLETION - -TEST RESULT: Passed. - - - ------------------------------ DIAG - ICD/MAC Disc Diagnostic ------------------------------ @@ -3618,7 +3527,8 @@ BINARY FILE: 91711-12032 Rev. 2201 HOST SYSTEM: RTE-IVB Rev. 5010 -CONFIGURATION: sim> go +CONFIGURATION: sim> set DS0 FORMAT + sim> go TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC @@ -4122,3 +4032,94 @@ TEST NOTES: Steps 11-14 test CRC generation and checking. Steps 21 and 28 bit. Step 30 tests track sparing. Steps 52, 54, and 55 test cylinder, head, and sector miscompares by writing incorrect preambles. These features are not simulated. + + + +------------------------------------------------ +#EMA - Extended Memory Array Firmware Diagnostic +------------------------------------------------ + +TESTED DEVICE: CPU (hp2100_cpu5.c) + +BINARY FILE: 92067-16013 Rev. 1805 + +HOST SYSTEM: RTE-IVB Rev. 5010 + +CONFIGURATION: sim> set CPU EMA + sim> go + +TEST REPORT: EMA ON-LINE DIAGNOSTIC SUCCESSFUL COMPLETION + +TEST RESULT: Passed. + + + +-------------------------------------------------- +VISOD - Vector Instruction Set Firmware Diagnostic +-------------------------------------------------- + +TESTED DEVICE: CPU (hp2100_cpu7.c) + +BINARY FILE: 12829-16006 Rev. 2226 + +HOST SYSTEM: RTE-6/VM Rev. 6200 + +CONFIGURATION: sim> set CPU 1000-F + sim> set CPU VIS + sim> go + +TEST REPORT: VIS ON-LINE DIAGNOSTIC SUCCESSFUL COMPLETION + +TEST RESULT: Passed. + + + +------------------------------------------------ +VMACK - Virtual Memory Array Firmware Diagnostic +------------------------------------------------ + +TESTED DEVICE: CPU (hp2100_cpu5.c) + +BINARY FILE: 92084-16423 Rev. 2121 + +HOST SYSTEM: RTE-6/VM Rev. 6200 + +CONFIGURATION: sim> set CPU 1000-F + sim> set CPU VMA + sim> go + +TEST REPORT: VMACK - VMA FIRMWARE DIAGNOSTIC, FIRMWARE REV# 003 + VMACK - .IMAR NO ERRORS DETECTED PASS# 1 + VMACK - .JMAR NO ERRORS DETECTED PASS# 1 + VMACK - .LBP NO ERRORS DETECTED PASS# 1 + VMACK - .LBPR NO ERRORS DETECTED PASS# 1 + VMACK - .LPX NO ERRORS DETECTED PASS# 1 + VMACK - .LPXR NO ERRORS DETECTED PASS# 1 + VMACK - .PMAP NO ERRORS DETECTED PASS# 1 + VMACK - .IMAP NO ERRORS DETECTED PASS# 1 + VMACK - .JMAP NO ERRORS DETECTED PASS# 1 + +TEST RESULT: Passed. + + + +--------------------------------------- +SDIAG - SIGNAL/1000 Firmware Diagnostic +--------------------------------------- + +TESTED DEVICE: CPU (hp2100_cpu7.c) + +BINARY FILE: 92835-16006 Rev. 2040 + +HOST SYSTEM: RTE-6/VM Rev. 6200 + +CONFIGURATION: sim> set CPU 1000-F + sim> set CPU VIS + sim> set CPU SIGNAL + sim> go + +TEST REPORT: SIGNAL/1000 FIRMWARE DIAGNOSTIC + + SIGNAL/1000 FIRMWARE DIAGNOSTIC SUCCESSFUL COMPLETION + +TEST RESULT: Passed. diff --git a/HP2100/hp_disclib.c b/HP2100/hp_disclib.c index 2424c05c..14e3aaa7 100644 --- a/HP2100/hp_disclib.c +++ b/HP2100/hp_disclib.c @@ -24,7 +24,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. - 15-Mar-12 JDB First release + 20-Mar-12 JDB First release 09-Nov-11 JDB Created disc controller common library from DS simulator References: @@ -436,110 +436,49 @@ static const DRIVE_PROPERTIES drive_props [] = { command, and flags to indicate certain common actions that should be taken. */ -#define CP_V_CLRS 15 /* bits 15-15: command clears the controller status */ -#define CP_V_WAIT 14 /* bits 14-15: command waits for seek completion */ -#define CP_V_UACC 13 /* bits 13-13: command accesses the unit */ -#define CP_V_UCHK 12 /* bits 12-12: command checks for unit legality */ -#define CP_V_UNIT 11 /* bits 11-11: command has a unit field */ -#define CP_V_CTYPE 9 /* bits 10- 9: valid controller types */ -#define CP_V_CLASS 6 /* bits 8- 6: command classification code */ -#define CP_V_INCNT 3 /* bits 5- 3: inbound parameter word count */ -#define CP_V_OUTCNT 0 /* bits 2- 0: outbound parameter word count */ - -#define CP_M_CTYPE 3 /* 2-bit valid controller types mask */ -#define CP_M_CLASS 7 /* 3-bit classification code mask */ -#define CP_M_INCNT 7 /* 3-bit inbound parameter word count mask */ -#define CP_M_OUTCNT 7 /* 3-bit outbound parameter word count mask */ - -#define CP_CLRS (1 << CP_V_CLRS) -#define CP_WAIT (1 << CP_V_WAIT) -#define CP_UACC (1 << CP_V_UACC) -#define CP_UCHK (1 << CP_V_UCHK) -#define CP_UNIT (1 << CP_V_UNIT) - -#define CP_MAC (MAC << CP_V_CTYPE) /* command is valid for MAC controllers */ -#define CP_ICD (ICD << CP_V_CTYPE) /* command is valid for ICD controllers */ - -#define CP_INVAL (class_invalid << CP_V_CLASS) /* invalid classification */ -#define CP_READ (class_read << CP_V_CLASS) /* read classification */ -#define CP_WRITE (class_write << CP_V_CLASS) /* write classification */ -#define CP_CNTL (class_control << CP_V_CLASS) /* control classification */ -#define CP_STAT (class_status << CP_V_CLASS) /* status classification */ - -#define TO_CTYPE(t) (uint32) ((t) << CP_V_CTYPE) - -#define GET_CLASS(c) (CNTLR_CLASS) (((c) >> CP_V_CLASS) & CP_M_CLASS) -#define GET_INCNT(c) (((c) >> CP_V_INCNT) & CP_M_INCNT) -#define GET_OUTCNT(c) (((c) >> CP_V_OUTCNT) & CP_M_OUTCNT) - -// >>> better? -#if 0 typedef struct { - CNTLR_OPCODE code; - uint32 inbound; - uint32 outbound; - CNTLR_CLASS class; - t_bool mac; - t_bool icd; - t_bool clear_status; - t_bool unit_field; - t_bool unit_check; - t_bool unit_access; - t_bool seek_wait; + uint32 params_in; /* count of input parameters */ + uint32 params_out; /* count of output parameters */ + CNTLR_CLASS classification; /* command classification */ + t_bool valid [TYPE_COUNT]; /* per-type command validity */ + t_bool clear_status; /* command clears status */ + t_bool unit_field; /* command has a unit field */ + t_bool unit_check; /* command checks unit number validity */ + t_bool unit_access; /* command accesses the drive unit */ + t_bool seek_wait; /* command waits for seek completion */ } DS_PROPS; -static const DS_PROPS cmd_props [] = { -/* in out class mac icd clst unit uchk uacc wait */ - { 0, 0, class_read, 1, 1, 1, 0, 1, 1, 0 }, /* cold load read */ - { 0, 0, class_control, 1, 1, 1, 1, 1, 1, 1 }, /* recalibrate */ - { 2, 0, class_control, 1, 1, 1, 1, 1, 1, 0 }, /* seek */ - { 0, 2, class_status, 1, 1, 0, 1, 0, 0, 0 }, /* request status */ - { 0, 1, class_status, 1, 1, 1, 1, 1, 0, 0 }, /* request sector address */ - { 0, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* read */ - { 0, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* read full sector */ - { 1, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* verify */ - { 0, 0, class_write, 1, 1, 1, 1, 1, 1, 1 }, /* write */ - { 0, 0, class_write, 1, 1, 1, 1, 1, 1, 1 }, /* write full sector */ - { 0, 0, class_control, 1, 1, 1, 0, 0, 0, 0 }, /* clear */ - { 0, 0, class_write, 1, 1, 1, 1, 1, 1, 1 }, /* initialize */ - { 2, 0, class_control, 1, 1, 1, 0, 0, 0, 0 }, /* address record */ - { 0, 7, class_status, 1, 0, 0, 0, 0, 0, 0 }, /* request syndrome */ - { 1, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* read with offset */ - { 0, 0, class_control, 1, 1, 1, 0, 0, 0, 0 }, /* set file mask */ - { 0, 0, class_invalid, 0, 0, 1, 0, 0, 0, 0 }, /* invalid */ - { 0, 0, class_invalid, 0, 0, 1, 0, 0, 0, 0 }, /* invalid */ - { 0, 0, class_read, 1, 1, 1, 1, 1, 1, 1 }, /* read without verify */ - { 1, 0, class_status, 1, 0, 1, 0, 0, 0, 0 }, /* load TIO register */ - { 0, 2, class_status, 1, 1, 0, 0, 0, 0, 0 }, /* request disc address */ - { 0, 0, class_control, 1, 1, 1, 0, 0, 0, 0 }, /* end */ - { 0, 0, class_control, 1, 0, 1, 1, 1, 0, 0 } /* wakeup */ - }; -#endif +typedef const DS_PROPS *PRPTR; -static const uint32 cmd_props [] = { - 000 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UCHK | CP_UACC, /* cold load read */ - 000 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* recalibrate */ - 020 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC, /* seek */ - 002 | CP_STAT | CP_MAC | CP_ICD | CP_UNIT, /* request status */ - 001 | CP_STAT | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK, /* request sector address */ - 000 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* read */ - 000 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* read full sector */ - 010 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* verify */ - 000 | CP_WRITE | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* write */ - 000 | CP_WRITE | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* write full sector */ - 000 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS, /* clear */ - 000 | CP_WRITE | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* initialize */ - 020 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS, /* address record */ - 007 | CP_STAT | CP_MAC, /* request syndrome */ - 010 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* read with offset */ - 000 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS, /* set file mask */ - 000 | CP_INVAL | CP_CLRS, /* invalid */ - 000 | CP_INVAL | CP_CLRS, /* invalid */ - 000 | CP_READ | CP_MAC | CP_ICD | CP_CLRS | CP_UNIT | CP_UCHK | CP_UACC | CP_WAIT, /* read without verify */ - 010 | CP_STAT | CP_MAC | CP_CLRS, /* load TIO register */ - 002 | CP_STAT | CP_MAC | CP_ICD, /* request disc address */ - 000 | CP_CNTL | CP_MAC | CP_ICD | CP_CLRS, /* end */ - 000 | CP_CNTL | CP_MAC | CP_CLRS | CP_UNIT | CP_UCHK /* wakeup */ +#define T TRUE +#define F FALSE + +static const DS_PROPS cmd_props [] = { +/* par par opcode valid for clear unit unit unit seek */ +/* in out classification MAC ICD stat field check acces wait */ + { 0, 0, class_read, { T, T }, T, F, T, T, F }, /* 00 = cold load read */ + { 0, 0, class_control, { T, T }, T, T, T, T, T }, /* 01 = recalibrate */ + { 2, 0, class_control, { T, T }, T, T, T, T, F }, /* 02 = seek */ + { 0, 2, class_status, { T, T }, F, T, F, F, F }, /* 03 = request status */ + { 0, 1, class_status, { T, T }, T, T, T, F, F }, /* 04 = request sector address */ + { 0, 0, class_read, { T, T }, T, T, T, T, T }, /* 05 = read */ + { 0, 0, class_read, { T, T }, T, T, T, T, T }, /* 06 = read full sector */ + { 1, 0, class_read, { T, T }, T, T, T, T, T }, /* 07 = verify */ + { 0, 0, class_write, { T, T }, T, T, T, T, T }, /* 10 = write */ + { 0, 0, class_write, { T, T }, T, T, T, T, T }, /* 11 = write full sector */ + { 0, 0, class_control, { T, T }, T, F, F, F, F }, /* 12 = clear */ + { 0, 0, class_write, { T, T }, T, T, T, T, T }, /* 13 = initialize */ + { 2, 0, class_control, { T, T }, T, F, F, F, F }, /* 14 = address record */ + { 0, 7, class_status, { T, F }, F, F, F, F, F }, /* 15 = request syndrome */ + { 1, 0, class_read, { T, T }, T, T, T, T, T }, /* 16 = read with offset */ + { 0, 0, class_control, { T, T }, T, F, F, F, F }, /* 17 = set file mask */ + { 0, 0, class_invalid, { F, F }, T, F, F, F, F }, /* 20 = invalid */ + { 0, 0, class_invalid, { F, F }, T, F, F, F, F }, /* 21 = invalid */ + { 0, 0, class_read, { T, T }, T, T, T, T, T }, /* 22 = read without verify */ + { 1, 0, class_status, { T, F }, T, F, F, F, F }, /* 23 = load TIO register */ + { 0, 2, class_status, { T, T }, F, F, F, F, F }, /* 24 = request disc address */ + { 0, 0, class_control, { T, T }, T, F, F, F, F }, /* 25 = end */ + { 0, 0, class_control, { T, F }, T, T, T, F, F } /* 26 = wakeup */ }; @@ -547,7 +486,7 @@ static const uint32 cmd_props [] = { typedef enum { controller = 0, /* controller unit index */ - timer = 1 /* command wait timer index */ + timer /* command wait timer index */ } AUX_INDEX; @@ -640,7 +579,8 @@ static uint16 drive_status (UNIT *uptr); t_bool dl_prepare_command (CVPTR cvptr, UNIT *units, uint32 unit_limit) { -uint32 props, unit; +uint32 unit; +PRPTR props; CNTLR_OPCODE opcode; set_timer (cvptr, CLEAR); /* stop the command wait timer */ @@ -648,12 +588,12 @@ set_timer (cvptr, CLEAR); /* stop the command wait opcode = GET_OPCODE (cvptr->buffer [0]); /* get the opcode from the command */ if (opcode > last_opcode) /* is the opcode invalid? */ - props = CP_CLRS; /* undefined commands clear prior status */ + props = &cmd_props [invalid_opcode]; /* undefined commands clear prior status */ else /* the opcode is potentially valid */ - props = cmd_props [opcode]; /* get the command properties */ + props = &cmd_props [opcode]; /* get the command properties */ if (cvptr->type == MAC) /* is this a MAC controller? */ - if (props & CP_UNIT) /* is the unit field defined for this command? */ + if (props->unit_field) /* is the unit field defined for this command? */ unit = GET_UNIT (cvptr->buffer [0]); /* get the unit from the command */ else /* no unit specified in the command */ unit = 0; /* so the unit is always unit 0 */ @@ -661,19 +601,20 @@ if (cvptr->type == MAC) /* is this a MAC control else /* an ICD controller */ unit = unit_limit; /* uses the supplied unit number */ -if (props & CP_CLRS) { /* clear the prior controller status */ +if (props->clear_status) { /* clear the prior controller status */ cvptr->status = normal_completion; /* if indicated for this command */ cvptr->spd_unit = SET_S1UNIT (unit); /* save the unit number for status requests */ } -if (props & TO_CTYPE (cvptr->type)) /* is the opcode defined for this controller? */ - if ((props & CP_UCHK) && unit > DL_MAXUNIT) /* if the unit number is checked and is illegal, */ +if (cvptr->type <= last_type /* is the controller type legal? */ + && props->valid [cvptr->type]) /* and the opcode defined for this controller? */ + if (props->unit_check && unit > DL_MAXUNIT) /* if the unit number is checked and is illegal, */ dl_end_command (cvptr, unit_unavailable); /* end with a unit unavailable error */ else { cvptr->state = cntlr_busy; /* legal unit, so controller is now busy */ cvptr->opcode = opcode; /* save the controller opcode */ - cvptr->length = GET_INCNT (props); /* set the inbound parameter count */ + cvptr->length = props->params_in; /* set the inbound parameter count */ cvptr->index = 1; /* point at the first parameter element (if any) */ if (cvptr->type == MAC && cvptr->length) { /* MAC controller and inbound parameters? */ @@ -780,28 +721,30 @@ return FALSE; /* the preparation has f drive units but are scheduled on the controller unit because they may be issued while a drive is processing a seek. - 8. The activation time is set to one-half of the intersector time (latency) - for read and write commands, and to the controller processing time for - all others. + 8. The activation time is set to the intersector time (latency) for read and + write commands, and to the controller processing time for all others. + This time cannot be shorter than 20 instructions, or DVR32 will be unable + to start DCPC in time to avoid an over/underrun. */ UNIT *dl_start_command (CVPTR cvptr, UNIT *units, uint32 unit_limit) { UNIT *uptr, *rptr; -uint32 props, unit; +uint32 unit; +PRPTR props; t_bool is_seeking = FALSE; -props = cmd_props [cvptr->opcode]; /* get the command properties */ +props = &cmd_props [cvptr->opcode]; /* get the command properties */ if (cvptr->type == MAC) { /* is this a MAC controller? */ - if (props & CP_UNIT) /* is the unit field defined for this command? */ + if (props->unit_field) /* is the unit field defined for this command? */ unit = GET_UNIT (cvptr->buffer [0]); /* get the unit number from the command */ else /* no unit is specified in the command */ unit = 0; /* so the unit number defaults to 0 */ if (unit > unit_limit) /* if the unit number is invalid, */ uptr = NULL; /* it does not correspond to a unit */ - else if (props & CP_UACC) /* if the command accesses a drive, */ + else if (props->unit_access) /* if the command accesses a drive, */ uptr = units + unit; /* get the address of the unit */ else /* the command accesses the controller only */ uptr = cvptr->aux + controller; /* so use the controller unit */ @@ -812,17 +755,16 @@ else { /* for an ICD controller uptr = units + unit_limit; /* and we use the indicated unit */ } -if ((props & CP_UCHK) && !uptr /* if the unit number is checked and is invalid */ - || (props & CP_WAIT) /* or the command waits for the drive */ - && (drive_status (uptr) & DL_S2STOPS)) { /* and the drive is offline or faulted */ - dl_end_command (cvptr, status_2_error); /* then the command ends with a Status-2 error */ - uptr = NULL; /* prevent command from starting */ +if (props->unit_check && !uptr /* if the unit number is checked and is invalid */ + || props->seek_wait && (drive_status (uptr) & DL_S2STOPS)) { /* or if waiting for an offline drive */ + dl_end_command (cvptr, status_2_error); /* then the command ends with a Status-2 error */ + uptr = NULL; /* prevent the command from starting */ } else if (uptr) { /* otherwise, we have a valid unit */ uptr->wait = cvptr->cmd_time; /* most commands use the command delay */ - if (props & CP_UACC) { /* does the command access the unit? */ + if (props->unit_access) { /* does the command access the unit? */ is_seeking = sim_is_active (uptr) != 0; /* see if the unit is busy */ if (is_seeking) /* if a seek is in progress, */ @@ -831,15 +773,15 @@ else if (uptr) { /* otherwise, we have a else { /* otherwise, the unit is idle */ uptr->STAT &= ~DL_S2ATN; /* clear the drive Attention status */ - if (GET_CLASS (props) == class_read /* if a read command */ - || GET_CLASS (props) == class_write) /* or a write command */ - uptr->wait = cvptr->sector_time / 2; /* schedule the sector start latency */ + if (props->classification == class_read /* if a read command */ + || props->classification == class_write) /* or a write command */ + uptr->wait = cvptr->sector_time; /* schedule the sector start latency */ } } } cvptr->index = 0; /* reset the buffer index */ -cvptr->length = GET_OUTCNT (props); /* set the count of outbound parameters */ +cvptr->length = props->params_out; /* set the count of outbound parameters */ cvptr->eod = CLEAR; /* clear the end of data flag */ @@ -1643,17 +1585,11 @@ return SCPE_OK; CNTLR_CLASS dl_classify (CNTLR_VARS cntlr) { -uint32 flags; - -if (cntlr.opcode > last_opcode) /* is the opcode illegal? */ - return class_invalid; /* return an invalid classification */ - -flags = cmd_props [cntlr.opcode]; /* get the opcode properties */ - -if (cntlr.type == MAC && (flags & CP_MAC) /* is the opcode */ - || cntlr.type == ICD && (flags & CP_ICD)) /* defined for this controller? */ - return GET_CLASS (cmd_props [cntlr.opcode]); /* yes, so return the command classification */ -else /* opcode is undefined */ +if (cntlr.type <= last_type /* if the controller type is legal, */ + && cntlr.opcode <= last_opcode /* and the opcode is legal */ + && cmd_props [cntlr.opcode].valid [cntlr.type]) /* and is defined for this controller, */ + return cmd_props [cntlr.opcode].classification; /* then return the command classification */ +else /* type or opcode is illegal */ return class_invalid; /* so return an invalid classification */ } @@ -1667,17 +1603,11 @@ else /* opcode is undefined * const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode) { -uint32 flags; - -if (opcode > last_opcode) /* is the opcode illegal? */ - return invalid_name; /* return an error indication */ - -flags = cmd_props [opcode]; /* get the opcode properties */ - -if (controller == MAC && (flags & CP_MAC) || /* is the opcode */ - controller == ICD && (flags & CP_ICD)) /* defined for this controller? */ - return opcode_name [opcode]; /* yes, so return the opcode name */ -else /* opcode is undefined, */ +if (controller <= last_type /* if the controller type is legal, */ + && opcode <= last_opcode /* and the opcode is legal */ + && cmd_props [opcode].valid [controller]) /* and is defined for this controller, */ + return opcode_name [opcode]; /* then return the opcode name */ +else /* type or opcode is illegal, */ return invalid_name; /* so return an error indication */ } @@ -1690,10 +1620,10 @@ else /* opcode is undefined, const char *dl_phase_name (CNTLR_PHASE phase) { -if (phase > last_phase) /* is the phase illegal? */ - return invalid_name; /* return an error indication */ -else /* phase is defined, */ - return phase_name [phase]; /* so return the phase name */ +if (phase <= last_phase) /* if the phase is legal, */ + return phase_name [phase]; /* return the phase name */ +else /* phase is illegal, */ + return invalid_name; /* so return an error indication */ } diff --git a/HP2100/hp_disclib.h b/HP2100/hp_disclib.h index 90056b27..52c4a161 100644 --- a/HP2100/hp_disclib.h +++ b/HP2100/hp_disclib.h @@ -24,7 +24,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. - 15-Mar-12 JDB First release + 19-Mar-12 JDB First release 09-Nov-11 JDB Created disc controller common library from DS simulator @@ -191,11 +191,12 @@ #define MODEL_7925 SET_MODEL (D7925_MODEL) -/* Controller types (values must be powers of 2) */ +/* Controller types */ typedef enum { - MAC = 1, - ICD = 2 + MAC = 0, + ICD, last_type = ICD, /* last valid type */ + TYPE_COUNT /* count of controller types */ } CNTLR_TYPE; @@ -218,11 +219,12 @@ typedef enum { request_syndrome = 015, read_with_offset = 016, set_file_mask = 017, + invalid_opcode = 020, read_without_verify = 022, load_tio_register = 023, request_disc_address = 024, end = 025, - wakeup = 026, last_opcode = wakeup /* last opcode */ + wakeup = 026, last_opcode = wakeup /* last valid opcode */ } CNTLR_OPCODE; #define DL_OPCODE_MASK 037 @@ -231,9 +233,9 @@ typedef enum { /* Controller command phases */ typedef enum { - start_phase, + start_phase = 0, data_phase, - end_phase, last_phase = end_phase /* last phase */ + end_phase, last_phase = end_phase /* last valid phase */ } CNTLR_PHASE; diff --git a/sim_console.c b/sim_console.c index 200749bc..6b6d8fcb 100644 --- a/sim_console.c +++ b/sim_console.c @@ -1015,7 +1015,8 @@ t_stat sim_os_poll_kbd (void) int c = -1; DWORD nkbevents, nkbevent; INPUT_RECORD rec; -extern int32 sim_switches; + +\ if ((std_input == NULL) || /* No keyboard for */ (std_input == INVALID_HANDLE_VALUE)) /* background processes */ diff --git a/sim_rev.h b/sim_rev.h index e82247d9..78259a30 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -1,6 +1,6 @@ /* sim_rev.h: simulator revisions and current rev level - Copyright (c) 1993-2011, Robert M Supnik + Copyright (c) 1993-2012, Robert 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,6 +38,7 @@ patch date module(s) and fix(es) 0 xx-yyy-1 scp.c: - added *nix READLINE support (Mark Pizzolato) + - fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) - fixed handling of DO with no arguments (Dave Bryan) - clarified some help messages (Mark Pizzolato) - added "SHOW SHOW" and "SHOW SHOW" commands (Mark Pizzolato) @@ -50,7 +51,8 @@ patch date module(s) and fix(es) - major revision (Dave Hittner and Mark Pizzolato) sim_tmxr.c: - - made option negotiation more reliable (Mark Pizzolato) + - made telnet option negotiation more reliable. + VAX works with PuTTY. (Mark Pizzolato) h316_cpu.c: - fixed bugs in MPY, DIV introduced in 3.8-1 (from Theo Engel) @@ -59,8 +61,13 @@ patch date module(s) and fix(es) hp2100 all peripherals (Dave Bryan): - Changed I/O signal handlers for newly revised signal model + - Deprecated DEVNO modifier in favor of SC hp2100_cpu.c (Dave Bryan): + - Minor speedup in "is_mapped" + - Added casts to cpu_mod, dmasio, dmapio, cpu_reset, dma_reset + - Fixed I/O return status bug for DMA cycles + - Failed I/O cycles now stop on failing instruction - Revised DMA for new multi-card paradigm - Consolidated DMA reset routines - DMA channels renamed from 0,1 to 1,2 to match documentation @@ -70,8 +77,6 @@ patch date module(s) and fix(es) - Fixed DMA requests to enable stealing every cycle - Fixed DMA priority for channel 1 over channel 2 - Corrected comments for "cpu_set_idle" - - Fixed I/O return status bug for DMA cycles - - Failed I/O cycles now stop on failing instruction hp2100_cpu.h: - Changed declarations for VMS compiler @@ -79,15 +84,42 @@ patch date module(s) and fix(es) hp2100_cpu0.c (Dave Bryan): - Removed DS note regarding PIF card (is now implemented) + hp2100_cpu4.c (Dave Bryan): + - Added OPSIZE casts to fp_accum calls in .FPWR/.TPWR + + hp2100_cpu5.c (Dave Bryan): + - Added OPSIZE casts to fp_accum calls in .FPWR/.TPWR + hp2100_cpu6.c (Dave Bryan): - - DMA channels renamed from 0,1 to 1,2 to match documentation + - Eliminated unused variable in "cpu_ema_vset" + + hp2100_cpu7.c (Dave Bryan): + - Corrected "opsize" parameter type in vis_abs hp2100_defs.h (Dave Bryan): + - Added hp_setsc, hp_showsc functions to support SC modifier - DMA channels renamed from 0,1 to 1,2 to match documentation - Revised I/O signal enum values for concurrent signals - Revised I/O macros for new signal handling + - Added DA and DC device select code assignments + + hp2100_di.c (Dave Bryan): + - Implemented 12821A HP-IB Disc Interface + + hp2100_di_da.c (Dave Bryan): + - Implemented 7906H/20H/25H ICD disc drives + + hp2100_dp.c (Dave Bryan): + - Added CNTLR_TYPE cast to dp_settype hp2100_ds.c (Dave Bryan): + - Rewritten to use the MAC/ICD disc controller library + - ioIOO now notifies controller service of parameter output + - Corrected SRQ generation and FIFO under/overrun detection + - Corrected Clear command to conform to the hardware + - Fixed Request Status to return Unit Unavailable if illegal + - Seek and Cold Load Read now Seek Check if seek in progress + - Remodeled command wait for seek completion - Corrected status returns for disabled drive, auto-seek beyond drive limits, Request Sector Address and Wakeup with invalid or offline unit @@ -95,23 +127,38 @@ patch date module(s) and fix(es) Read Without Verify hp2100_fp1.c (Dave Bryan): + - Added missing precision on constant "one" in fp_trun - Completed the comments for divide; no code changes hp2100_ipl.c (Dave Bryan): - - Revised for new multi-card paradigm + - Added CARD_INDEX casts to dib.card_index - A failed STC may now be retried + - Consolidated reporting of consecutive CRS signals + - Revised for new multi-card paradigm hp2100_lps.c (Dave Bryan): - - Corrected 12566B (DIAG mode) jumper settings - Revised detection of CLC at last DMA cycle + - Corrected 12566B (DIAG mode) jumper settings + + hp2100_ms.c (Dave Bryan): + - Added CNTLR_TYPE cast to ms_settype hp2100_mt.c (Dave Bryan): - - Fixed error in command scan in mtcio ioIOO handler + - Fixed command scanning error in mtcio ioIOO handler + + hp2100_stddev.c (Dave Bryan): + - Add TBG as a logical name for the CLK device hp2100_sys.c (Dave Bryan): + - Add TBG as a logical name for the CLK device + - Added hp_setsc, hp_showsc functions to support SC modifier + - Added DA and dummy DC devices - DMA channels renamed from 0,1 to 1,2 to match documentation - Changed DIB access for revised signal model + hp_disclib.c, hp_disclib.h (Dave Bryan) + - Created MAC/ICD disc controller library + i1401_cd.c: - fixed read stacker operation in column binary mode - fixed punch stacker operation (Van Snyder) From 7c51414228906c7e0e131a5794df34838db6619a Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 23 Mar 2012 12:39:42 -0700 Subject: [PATCH 026/112] Fixed sim_debug macro implementation to allow for the case when a sim_debug invocation is used as a single expression following an if condition. Found by Michael Bloom --- scp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scp.h b/scp.h index 52cf2b9f..4a50cffc 100644 --- a/scp.h +++ b/scp.h @@ -131,7 +131,7 @@ void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...); #else void _sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...); extern FILE *sim_deb; /* debug file */ -#define sim_debug(dbits, dptr, ...) if (sim_deb && ((dptr)->dctrl & dbits)) _sim_debug (dbits, dptr, __VA_ARGS__) +#define sim_debug(dbits, dptr, ...) if (sim_deb && ((dptr)->dctrl & dbits)) _sim_debug (dbits, dptr, __VA_ARGS__); else 0 #endif void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr); From 3cc10c3f71c29ea66cdc7b28126871b6b3efe760 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 23 Mar 2012 12:40:20 -0700 Subject: [PATCH 027/112] Fixed vax build issue when building on a vax. --- VAX/vax_fpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index 222e52f0..77215b97 100644 --- a/VAX/vax_fpa.c +++ b/VAX/vax_fpa.c @@ -906,7 +906,7 @@ return rpackg (&a, flo); /* return frac */ /* Floating add */ -void vax_fadd (UFP *a, UFP *b) +void vax_fadd (UFP *a, UFP *b, uint32 mhi, uint32 mlo) { int32 ediff; UFP t; From 380625e404f2f0ec13bfe07573e1ac6cf4e332d3 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 23 Mar 2012 13:05:36 -0700 Subject: [PATCH 028/112] Fixed vax build issue when building on a vax. --- descrip.mms | 3 ++- sim_timer.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/descrip.mms b/descrip.mms index 6f2fcae9..11a2ac7c 100644 --- a/descrip.mms +++ b/descrip.mms @@ -215,8 +215,9 @@ PCAP_SIMH_INC = /INCL=($(PCAP_DIR)) @ ERROR_CONDITION = ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LTS."V8.0").AND.("$(NOASYNCH)".EQS."")) @ IF (ERROR_CONDITION) THEN WRITE SYS$OUTPUT "*** WARNING **** Build should be invoked with /MACRO=NOASYNCH=1 on this platform" @ 'EXIT_ON_ERROR + @ DEFINE/USER SYS$ERROR NLA0: @ DEFINE/USER SYS$OUTPUT CC_VERSION.DAT - @ CC/VERSION + @ CC/DECC/VERSION @ OPEN /READ VERSION CC_VERSION.DAT @ READ VERSION CC_VERSION @ CLOSE VERSION diff --git a/sim_timer.c b/sim_timer.c index fbf5acf3..89a6759d 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -174,7 +174,6 @@ sys$waitfr (2); return sim_os_msec () - stime; } -#if defined(SIM_ASYNCH_IO) #ifdef NEED_CLOCK_GETTIME int clock_gettime(int clk_id, struct timespec *tp) { @@ -191,7 +190,6 @@ tp->tv_nsec = ns*100; return 0; } #endif /* CLOCK_REALTIME */ -#endif /* SIM_ASYNCH_IO */ #elif defined (_WIN32) From 7d07c49e3f07f5cad51a18f8e0d8e3dca9fedb29 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 23 Mar 2012 13:06:37 -0700 Subject: [PATCH 029/112] Credit Matt Burke for PCAP-VMS revisions --- 0readme_39.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/0readme_39.txt b/0readme_39.txt index cfb5b874..d5fb4b10 100644 --- a/0readme_39.txt +++ b/0readme_39.txt @@ -19,6 +19,10 @@ on Windows. 1.1.2 PDP-8 - floating point processor is now enabled + +1.1.3 IA64 VMS Ethernet Support + + - Identified compiler version issues and added IA64 support (Matt Burke) 2. Bugs Fixed From 8255ba937907a29f126f41aeca19d2317bd05f56 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 23 Mar 2012 15:57:26 -0700 Subject: [PATCH 030/112] Fixed typo in prior correction --- swtp/swtp_cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swtp/swtp_cpu.c b/swtp/swtp_cpu.c index e3c69ede..e93797f9 100644 --- a/swtp/swtp_cpu.c +++ b/swtp/swtp_cpu.c @@ -425,7 +425,7 @@ int32 sim_instr (void) condevalZ(IX); break; case 0x09: /* DEX */ - IX = (IX + 1) & ADDRMASK; + IX = (IX - 1) & ADDRMASK; condevalZ(IX); break; case 0x0A: /* CLV */ From 6d11b3bd25fef8a7f10d2f78d04bb5c71efc6d4c Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 24 Mar 2012 12:52:22 -0700 Subject: [PATCH 031/112] Updated HP2100 from Dave Bryan --- HP2100/hp2100_bugfixes.txt | 44 +++++++++++++++++++++++++++++++++++++- HP2100/hp2100_cpu5.c | 13 ++++++++--- sim_rev.h | 5 +++-- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/HP2100/hp2100_bugfixes.txt b/HP2100/hp2100_bugfixes.txt index 57ef7392..90c3bd0f 100644 --- a/HP2100/hp2100_bugfixes.txt +++ b/HP2100/hp2100_bugfixes.txt @@ -1,6 +1,6 @@ HP 2100 SIMULATOR BUG FIX WRITEUPS ================================== - Last update: 2012-03-20 + Last update: 2012-03-23 1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756 @@ -6215,3 +6215,45 @@ service only when a parameter word has been received with an ioIOO signal. STATUS: Fixed in version 3.9-0. + + + +245. PROBLEM: The EMA diagnostic sometimes aborts with a DM error. + + VERSION: 3.8-1 + + OBSERVATION: Running the RTE-IV EMA diagnostic "#EMA" may abort with a DMS + violation: + + DM VIOL = 160377 + DM INST = 105257 + ABE 177750 15 1 + XYO 116123 72137 0 + DM #EMA 16521 + #EMA ABORTED + + The abort occurs in test 8, which executes the .EMAP instruction and passes + a negative number of dimensions. + + CAUSE: The test supplies a dimension count of -32768. The offset of the + specified array element is calculated by the "cpu_ema_resolve" routine by + iterating through the array subscripts. The 16-bit word containing the + dimension count is loaded into a 32-bit signed integer variable as an + unsigned value. Therefore, +32678 dimensions are assumed. However, only + one subscript value is supplied in the call, so subsequent instructions + after the call are interpreted as subscript addresses, yielding random + values from memory. Also, the array descriptor only defines one subscript, + so subsequent memory values are interpreted as subscript bounds and element + counts. + + If one of subscript offsets evaluates to a negative value, the routine + returns FALSE, and the instruction fails. The diagnostic interprets the + cause of the failure as the negative dimension count and passes test 8. + + However, if a subscript address points at a protected page of memory, the + instruction causes a DM violation when the value is retrieved. + + RESOLUTION: Modify "cpu_ema_resolve" (hp2100_cpu5.c) to sign-extend the + 16-bit dimension count. + + STATUS: Fixed in version 3.9-0. diff --git a/HP2100/hp2100_cpu5.c b/HP2100/hp2100_cpu5.c index a680f864..9865f47a 100644 --- a/HP2100/hp2100_cpu5.c +++ b/HP2100/hp2100_cpu5.c @@ -26,7 +26,7 @@ CPU5 RTE-6/VM and RTE-IV firmware option instructions - 20-Mar-12 JDB Added sign extension for dim count in "cpu_ema_resolve" + 23-Mar-12 JDB Added sign extension for dim count in "cpu_ema_resolve" 28-Dec-11 JDB Eliminated unused variable in "cpu_ema_vset" 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) @@ -798,6 +798,12 @@ return reason; 1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a given machine can run one or the other, but not both. + 2. The EMA diagnostic (92067-16013) reports bogus MMAP failures if it is + not loaded at the start of its partition (e.g., because of a LOADR "LO" + command). The "ICMPS" map comparison check in the diagnostic assumes + that the starting page of the program's partition contains the first + instruction of the program and prints "MMAP ERROR" if it does not. + Additional references: - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983). - RTE-IVB Technical Specifications (92068-90013, Jan-1980). @@ -813,10 +819,11 @@ static const OP_PAT op_ema[16] = { /* calculate the 32 bit EMA subscript for an array */ static t_bool cpu_ema_resolve(uint32 dtbl,uint32 atbl,uint32* sum) { -int32 sub, act, low, sz; +int32 sub, act, low, sz, ndim; uint32 MA, base; -int32 ndim = SEXT(ReadW(dtbl++)); /* # dimensions */ +ndim = ReadW(dtbl++); /* # dimensions */ +ndim = SEXT(ndim); /* sign extend */ if (ndim < 0) return FALSE; /* invalid? */ *sum = 0; /* accu for index calc */ diff --git a/sim_rev.h b/sim_rev.h index 78259a30..35abe360 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -88,10 +88,11 @@ patch date module(s) and fix(es) - Added OPSIZE casts to fp_accum calls in .FPWR/.TPWR hp2100_cpu5.c (Dave Bryan): - - Added OPSIZE casts to fp_accum calls in .FPWR/.TPWR + - Added sign extension for dim count in "cpu_ema_resolve" + - Eliminated unused variable in "cpu_ema_vset" hp2100_cpu6.c (Dave Bryan): - - Eliminated unused variable in "cpu_ema_vset" + - DMA channels renamed from 0,1 to 1,2 to match documentation hp2100_cpu7.c (Dave Bryan): - Corrected "opsize" parameter type in vis_abs From 6e813b83647c1ea0ca9b752dfe533d58a5d054ca Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 24 Mar 2012 19:46:37 -0700 Subject: [PATCH 032/112] Merge with v3.9-0-rc2 first pass --- ALTAIR/altair_cpu.c | 3 +- GRI/gri_cpu.c | 2 +- GRI/gri_stddev.c | 2 +- GRI/gri_sys.c | 2 +- H316/h316_cpu.c | 10 ++--- H316/h316_dp.c | 5 ++- H316/h316_fhd.c | 5 ++- H316/h316_lp.c | 4 +- H316/h316_mt.c | 7 ++-- H316/h316_stddev.c | 10 ++--- I1401/i1401_cd.c | 6 +-- I1401/i1401_cpu.c | 18 ++++----- I1401/i1401_lp.c | 2 +- I1401/i1401_mt.c | 26 ++++++------- I1401/i1401_sys.c | 6 +-- I1620/i1620_cd.c | 7 ++-- I1620/i1620_cpu.c | 10 ++--- I1620/i1620_dp.c | 2 +- I1620/i1620_fp.c | 2 +- I1620/i1620_pt.c | 3 +- I1620/i1620_sys.c | 5 ++- I7094/i7094_cd.c | 3 +- I7094/i7094_com.c | 4 +- I7094/i7094_cpu.c | 2 +- I7094/i7094_cpu1.c | 2 +- I7094/i7094_drm.c | 88 ++++++++++++++++++++++++------------------ I7094/i7094_io.c | 8 +++- I7094/i7094_lp.c | 2 +- I7094/i7094_mt.c | 5 ++- Interdata/id16_cpu.c | 8 ++-- Interdata/id32_cpu.c | 8 ++-- Interdata/id32_dboot.c | 2 +- Interdata/id_fd.c | 13 +++---- Interdata/id_idc.c | 4 +- Interdata/id_io.c | 2 +- Interdata/id_lp.c | 2 +- Interdata/id_pas.c | 7 ++-- Interdata/id_pt.c | 2 +- LGP/lgp_cpu.c | 4 +- NOVA/nova_clk.c | 2 +- NOVA/nova_cpu.c | 6 +-- NOVA/nova_dsk.c | 2 +- NOVA/nova_mta.c | 2 +- NOVA/nova_sys.c | 2 +- PDP1/pdp1_cpu.c | 9 +++-- PDP1/pdp1_stddev.c | 19 ++++----- PDP11/pdp11_cis.c | 6 +-- PDP11/pdp11_cpu.c | 27 ++++++------- PDP11/pdp11_cpumod.c | 6 +-- PDP11/pdp11_dz.c | 2 +- PDP11/pdp11_fp.c | 2 +- PDP11/pdp11_hk.c | 3 +- PDP11/pdp11_io.c | 9 +++-- PDP11/pdp11_rf.c | 7 ++-- PDP11/pdp11_rh.c | 5 ++- PDP11/pdp11_rk.c | 2 +- PDP11/pdp11_rl.c | 2 +- PDP11/pdp11_rq.c | 10 ++--- PDP11/pdp11_ry.c | 4 +- PDP11/pdp11_stddev.c | 4 +- PDP11/pdp11_sys.c | 8 ++-- PDP11/pdp11_tc.c | 2 +- PDP11/pdp11_tm.c | 13 +++---- PDP11/pdp11_tq.c | 8 ++-- PDP11/pdp11_ts.c | 6 +-- PDP11/pdp11_tu.c | 4 +- PDP11/pdp11_vh.c | 2 +- PDP18B/pdp18b_cpu.c | 12 +++--- PDP18B/pdp18b_drm.c | 2 +- PDP18B/pdp18b_fpp.c | 3 +- PDP18B/pdp18b_lp.c | 2 +- PDP18B/pdp18b_rf.c | 2 +- PDP18B/pdp18b_stddev.c | 2 +- PDP18B/pdp18b_sys.c | 7 ++-- PDP8/pdp8_fpp.c | 2 +- PDP8/pdp8_sys.c | 4 +- S3/s3_cd.c | 3 +- S3/s3_cpu.c | 4 +- S3/s3_lp.c | 5 ++- S3/s3_sys.c | 4 +- SDS/sds_io.c | 4 +- SDS/sds_mt.c | 5 ++- SDS/sds_sys.c | 4 +- VAX/vax780_sbi.c | 4 +- VAX/vax780_stddev.c | 2 +- VAX/vax780_syslist.c | 2 +- VAX/vax780_uba.c | 2 +- VAX/vax_cis.c | 4 +- VAX/vax_cmode.c | 2 +- VAX/vax_cpu.c | 19 +++++---- VAX/vax_cpu1.c | 10 ++--- VAX/vax_fpa.c | 7 ++-- VAX/vax_io.c | 8 ++-- VAX/vax_mmu.c | 2 +- VAX/vax_octa.c | 4 +- VAX/vax_sys.c | 2 +- VAX/vax_syscm.c | 4 +- VAX/vax_sysdev.c | 8 ++-- VAX/vax_syslist.c | 2 +- makefile | 19 ++++++--- scp.c | 14 ++++--- sim_console.c | 28 +++++++------- sim_rev.h | 76 +++++++++++++++++++++--------------- swtp/swtp_defs.h | 2 +- 104 files changed, 415 insertions(+), 348 deletions(-) diff --git a/ALTAIR/altair_cpu.c b/ALTAIR/altair_cpu.c index 3e97664f..80fce7d6 100644 --- a/ALTAIR/altair_cpu.c +++ b/ALTAIR/altair_cpu.c @@ -1,6 +1,6 @@ /* altair_cpu.c: MITS Altair Intel 8080 CPU simulator - Copyright (c) 1997-2005, Charles E. Owen + Copyright (c) 1997-2012, Charles E. Owen 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 8080 CPU + 19-Mar-12 RMS Fixed data type for breakpoint variables 08-Oct-02 RMS Tied off spurious compiler warnings The register state for the 8080 CPU is: diff --git a/GRI/gri_cpu.c b/GRI/gri_cpu.c index 547b2139..3eb3fa2e 100644 --- a/GRI/gri_cpu.c +++ b/GRI/gri_cpu.c @@ -27,7 +27,7 @@ 14-Jan-08 RMS Added GRI-99 support 28-Apr-07 RMS Removed clock initialization - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 18-Jul-04 RMS Fixed missing ao_update calls in AX, AY write 17-Jul-04 RMS Revised MSR, EAO based on additional documentation 14-Mar-03 RMS Fixed bug in SC queue tracking diff --git a/GRI/gri_stddev.c b/GRI/gri_stddev.c index 412cc200..53a3b13d 100644 --- a/GRI/gri_stddev.c +++ b/GRI/gri_stddev.c @@ -29,7 +29,7 @@ hsp S42-006 high speed punch rtc real time clock - 31-May-08 RMS Fixed declarations (found by Peter Schorn) + 31-May-08 RMS Fixed declarations (Peter Schorn) 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 22-Nov-05 RMS Revised for new terminal processing routines 29-Dec-03 RMS Added support for console backpressure diff --git a/GRI/gri_sys.c b/GRI/gri_sys.c index 5bb5c227..42e793d2 100644 --- a/GRI/gri_sys.c +++ b/GRI/gri_sys.c @@ -24,7 +24,7 @@ in this Software without prior written authorization from Robert M Supnik. 14-Jan-08 RMS Added GRI-99 support - 18-Oct-02 RMS Fixed bug in symbolic decode (found by Hans Pufal) + 18-Oct-02 RMS Fixed bug in symbolic decode (Hans Pufal) */ #include "gri_defs.h" diff --git a/H316/h316_cpu.c b/H316/h316_cpu.c index e8576105..b1ba29bb 100644 --- a/H316/h316_cpu.c +++ b/H316/h316_cpu.c @@ -25,12 +25,12 @@ cpu H316/H516 CPU - 19-Nov-11 RMS Fixed XR behavior (from Adrian Wise) - 19-Nov-11 RMS Fixed bugs in double precision, normalization, SC (from Adrian Wise) - 10-Jan-10 RMS Fixed bugs in LDX, STX introduced in 3.8-1 (from Theo Engel) + 19-Nov-11 RMS Fixed XR behavior (Adrian Wise) + 19-Nov-11 RMS Fixed bugs in double precision, normalization, SC (Adrian Wise) + 10-Jan-10 RMS Fixed bugs in LDX, STX introduced in 3.8-1 (Theo Engel) 28-Apr-07 RMS Removed clock initialization - 03-Apr-06 RMS Fixed bugs in LLL, LRL (from Theo Engel) - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 03-Apr-06 RMS Fixed bugs in LLL, LRL (Theo Engel) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 15-Feb-05 RMS Added start button interrupt 01-Dec-04 RMS Fixed bug in DIV diff --git a/H316/h316_dp.c b/H316/h316_dp.c index 63023cba..40468675 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-2008, Robert M. Supnik + Copyright (c) 2003-2012, Robert 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,7 +27,8 @@ 4651 disk subsystem 4720 disk subsystem - 04-Sep-05 RMS Fixed missing return (found by Peter Schorn) + 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) + 04-Sep-05 RMS Fixed missing return (Peter Schorn) 15-Jul-05 RMS Fixed bug in attach routine 01-Dec-04 RMS Fixed bug in skip on !seeking diff --git a/H316/h316_fhd.c b/H316/h316_fhd.c index afadcb3b..4f20a45a 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-2008, Robert M. Supnik + Copyright (c) 2003-2012, Robert 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,7 +25,8 @@ fhd 516-4400 fixed head disk - 15-May-06 RMS Fixed bug in autosize attach (reported by David Gesswein) + 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) + 15-May-06 RMS Fixed bug in autosize attach (David Gesswein) 04-Jan-04 RMS Changed sim_fsize calling sequence These head-per-track devices are buffered in memory, to minimize overhead. diff --git a/H316/h316_lp.c b/H316/h316_lp.c index 809e3b3c..46151911 100644 --- a/H316/h316_lp.c +++ b/H316/h316_lp.c @@ -25,9 +25,9 @@ lpt line printer - 09-Jun-07 RMS Fixed lost last print line (from Theo Engel) + 09-Jun-07 RMS Fixed lost last print line (Theo Engel) 19-Jan-06 RMS Added UNIT_TEXT flag - 03-Apr-06 RMS Fixed bug in blanks backscanning (from Theo Engel) + 03-Apr-06 RMS Fixed bug in blanks backscanning (Theo Engel) 01-Dec-04 RMS Fixed bug in DMA/DMC support 24-Oct-03 RMS Added DMA/DMC support 25-Apr-03 RMS Revised for extended file support diff --git a/H316/h316_mt.c b/H316/h316_mt.c index 3004a3df..125945a9 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-2008, Robert M. Supnik + Copyright (c) 2003-2012, Robert 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,10 +25,11 @@ mt 516-4100 seven track magnetic tape - 09-Jun-07 RMS Fixed bug in write without stop (from Theo Engel) + 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) + 09-Jun-07 RMS Fixed bug in write without stop (Theo Engel) 16-Feb-06 RMS Added tape capacity checking 26-Aug-05 RMS Revised to use API for write lock check - 08-Feb-05 RMS Fixed error reporting from OCP (found by Philipp Hachtmann) + 08-Feb-05 RMS Fixed error reporting from OCP (Philipp Hachtmann) 01-Dec-04 RMS Fixed bug in DMA/DMC support Magnetic tapes are represented as a series of variable records diff --git a/H316/h316_stddev.c b/H316/h316_stddev.c index 456df262..c358841e 100644 --- a/H316/h316_stddev.c +++ b/H316/h316_stddev.c @@ -28,13 +28,13 @@ tty 316/516-33 teleprinter clk/options 316/516-12 real time clocks/internal options - 09-Jun-07 RMS Fixed bug in clock increment (found by Theo Engel) + 09-Jun-07 RMS Fixed bug in clock increment (Theo Engel) 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode - 03-Apr-06 RMS Fixed bugs in punch state handling (from Theo Engel) + 03-Apr-06 RMS Fixed bugs in punch state handling (Theo Engel) 22-Nov-05 RMS Revised for new terminal processing routines - 05-Feb-05 RMS Fixed bug in OCP '0001 (found by Philipp Hachtmann) - 31-Jan-05 RMS Fixed bug in TTY print (found by Philipp Hachtmann) - 01-Dec-04 RMS Fixed problem in SKS '104 (reported by Philipp Hachtmann) + 05-Feb-05 RMS Fixed bug in OCP '0001 (Philipp Hachtmann) + 31-Jan-05 RMS Fixed bug in TTY print (Philipp Hachtmann) + 01-Dec-04 RMS Fixed problem in SKS '104 (Philipp Hachtmann) Fixed bug in SKS '504 Added PTR detach routine, stops motion Added PTR/PTP ASCII file support diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index f1912cf7..0c7eaa5b 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -36,16 +36,16 @@ This allows cards to be created and edited as normal files. 24-Mar-09 RMS Fixed read stacker operation in column binary mode - Fixed punch stacker operation (from Van Snyder) + Fixed punch stacker operation (Van Snyder) 28-Jun-07 RMS Added support for SS overlap modifiers 19-Jan-07 RMS Added UNIT_TEXT flag 20-Sep-05 RMS Revised for new code tables, compatible colbinary treatment 30-Aug-05 RMS Fixed read, punch to ignore modifier on 1,4 char inst - (reported by Van Snyder) + (Van Snyder) 14-Nov-04 WVS Added column binary support 25-Apr-03 RMS Revised for extended file support 30-May-02 RMS Widened POS to 32b - 30-Jan-02 RMS New zero footprint card bootstrap from Van Snyder + 30-Jan-02 RMS New zero footprint card bootstrap (Van Snyder) 29-Nov-01 RMS Added read only unit support 13-Apr-01 RMS Revised for register arrays */ diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index 71d49610..6868556b 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -24,21 +24,21 @@ in this Software without prior written authorization from Robert M Supnik. 19-Mar-11 RMS Reverted multiple tape indicator implementation - 20-Jan-11 RMS Fixed branch on EOT indicator per hardware (from Van Snyder) + 20-Jan-11 RMS Fixed branch on EOT indicator per hardware (Van Snyder) 07-Nov-10 RMS Fixed divide not to clear word marks in quotient - 24-Apr-10 RMS Revised divide algorithm (from Van Snyder) - 11-Jul-08 RMS Added missing A magtape modifier (from Van Snyder) - Fixed tape indicator implementation (from Bob Abeles) - Fixed bug in ZA and ZS (from Bob Abeles) + 24-Apr-10 RMS Revised divide algorithm (Van Snyder) + 11-Jul-08 RMS Added missing A magtape modifier (Van Snyder) + Fixed tape indicator implementation (Bob Abeles) + Fixed bug in ZA and ZS (Bob Abeles) 07-Jul-07 RMS Removed restriction on load-mode binary tape 28-Jun-07 RMS Added support for SS overlap modifiers - 22-May-06 RMS Fixed format error in CPU history (found by Peter Schorn) - 06-Mar-06 RMS Fixed bug in divide (found by Van Snyder) - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-May-06 RMS Fixed format error in CPU history (Peter Schorn) + 06-Mar-06 RMS Fixed bug in divide (Van Snyder) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 01-Sep-05 RMS Removed error stops in MCE 16-Aug-05 RMS Fixed C++ declaration and cast problems 02-Jun-05 RMS Fixed SSB-SSG clearing on RESET - (reported by Ralph Reinke) + (Ralph Reinke) 14-Nov-04 WVS Added column binary support, debug support 06-Nov-04 RMS Added instruction history 12-Jul-03 RMS Moved ASCII/BCD tables to included file diff --git a/I1401/i1401_lp.c b/I1401/i1401_lp.c index f15ab913..a7906b91 100644 --- a/I1401/i1401_lp.c +++ b/I1401/i1401_lp.c @@ -26,7 +26,7 @@ lpt 1403 line printer 19-Jan-07 RMS Added UNIT_TEXT flag - 07-Mar-05 RMS Fixed bug in write_line (reported by Van Snyder) + 07-Mar-05 RMS Fixed bug in write_line (Van Snyder) 25-Apr-03 RMS Revised for extended file support 30-May-02 RMS Widened POS to 32b 13-Apr-01 RMS Revised for register arrays diff --git a/I1401/i1401_mt.c b/I1401/i1401_mt.c index 56b3cba0..fcd2dea1 100644 --- a/I1401/i1401_mt.c +++ b/I1401/i1401_mt.c @@ -27,21 +27,21 @@ 19-Mar-11 RMS Restored lost edit to insert EOF in memory on read EOF Reverted multiple tape indicator implementation - 20-Jan-11 RMS Fixed branch on END indicator per hardware (from Van Snyder) - 26-Jun-10 RMS Fixed backspace over tapemark not to set EOR (from Van Snyder) - 11-Jul-08 RMS Added -n (no rewind) option to BOOT (from Van Snyder) - Added tape mark detect to diagnostic read (from Bob Abeles) - Added tape mark detect in multi-character records (from Bob Abeles) - Fixed memory leak in tape rewind-unload op (from Bob Abeles) - Fixed bug, BOOT ignores GM+WM in memory (from Bob Abeles) - Fixed handling of indicators (from Bob Abeles) - Fixed bug to mask input to 6b on read (from Bob Abeles) + 20-Jan-11 RMS Fixed branch on END indicator per hardware (Van Snyder) + 26-Jun-10 RMS Fixed backspace over tapemark not to set EOR (Van Snyder) + 11-Jul-08 RMS Added -n (no rewind) option to BOOT (Van Snyder) + Added tape mark detect to diagnostic read (Bob Abeles) + Added tape mark detect in multi-character records (Bob Abeles) + Fixed memory leak in tape rewind-unload op (Bob Abeles) + Fixed bug, BOOT ignores GM+WM in memory (Bob Abeles) + Fixed handling of indicators (Bob Abeles) + Fixed bug to mask input to 6b on read (Bob Abeles) 07-Jul-07 RMS Removed restriction on load-mode binary tape 28-Jun-07 RMS Revised read tape mark behavior based on real hardware - (found by Van Snyder) + (Van Snyder) 16-Feb-06 RMS Added tape capacity checking 15-Sep-05 RMS Yet another fix to load read group mark plus word mark - Added debug printouts (from Van Snyder) + Added debug printouts (Van Snyder) 26-Aug-05 RMS Revised to use API for write lock check 16-Aug-03 RMS End-of-record on load read works like move read (verified on real 1401) @@ -55,11 +55,11 @@ 30-Sep-02 RMS Revamped error handling 28-Aug-02 RMS Added end of medium support 12-Jun-02 RMS End-of-record on move read preserves old WM under GM - (found by Van Snyder) + (Van Snyder) 03-Jun-02 RMS Modified for 1311 support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Added protection against bad record lengths - 30-Jan-02 RMS New zero footprint tape bootstrap from Van Snyder + 30-Jan-02 RMS New zero footprint tape bootstrap (Van Snyder) 20-Jan-02 RMS Changed write enabled modifier 29-Nov-01 RMS Added read only unit support 18-Apr-01 RMS Changed to rewind tape before boot diff --git a/I1401/i1401_sys.c b/I1401/i1401_sys.c index 43387338..3b9dc881 100644 --- a/I1401/i1401_sys.c +++ b/I1401/i1401_sys.c @@ -28,10 +28,10 @@ 14-Nov-04 WVS Added data printout support 16-Mar-03 RMS Fixed mnemonic for MCS 03-Jun-02 RMS Added 1311 support - 18-May-02 RMS Added -D feature from Van Snyder - 26-Jan-02 RMS Fixed H, NOP with no trailing wm (found by Van Snyder) + 18-May-02 RMS Added -D feature (Van Snyder) + 26-Jan-02 RMS Fixed H, NOP with no trailing wm (Van Snyder) 17-Sep-01 RMS Removed multiconsole support - 13-Jul-01 RMS Fixed bug in symbolic output (found by Peter Schorn) + 13-Jul-01 RMS Fixed bug in symbolic output (Peter Schorn) 27-May-01 RMS Added multiconsole support 14-Mar-01 RMS Revised load/dump interface (again) 30-Oct-00 RMS Added support for examine to file diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c index 39783df8..ebb9ccc5 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-2008, Robert M. Supnik + Copyright (c) 2002-2012, Robert 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,9 +26,10 @@ cdr 1622 card reader cdp 1622 card punch + 19-Mar-12 RMS Fixed declarations of saved_pc, io_stop (Mark Pizzolato) 19-Jan-07 RMS Set UNIT_TEXT flag - 13-Jul-06 RMS Fixed card reader fgets call (from Tom McBride) - Fixed card reader boot sequence (from Tom McBride) + 13-Jul-06 RMS Fixed card reader fgets call (Tom McBride) + Fixed card reader boot sequence (Tom McBride) 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility 25-Apr-03 RMS Revised for extended file support diff --git a/I1620/i1620_cpu.c b/I1620/i1620_cpu.c index bf3d761e..4bf36b49 100644 --- a/I1620/i1620_cpu.c +++ b/I1620/i1620_cpu.c @@ -26,15 +26,15 @@ This CPU module incorporates code and comments from the 1620 simulator by Geoff Kuenning, with his permission. - 28-May-06 RMS Fixed bug in cpu history (found by Peter Schorn) - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 28-May-06 RMS Fixed bug in cpu history Peter Schorn) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Nov-04 RMS Added instruction history 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) + 02-Nov-03 RMS Fixed bug in branch digit (Dave Babcock) + 21-Aug-03 RMS Fixed bug in immediate index add (Michael Short) 25-Apr-03 RMS Changed t_addr to uint32 throughout - 18-Oct-02 RMS Fixed bugs in invalid result testing (found by Hans Pufal) + 18-Oct-02 RMS Fixed bugs in invalid result testing (Hans Pufal) The simulated register state for the IBM 1620 is: diff --git a/I1620/i1620_dp.c b/I1620/i1620_dp.c index 7dde5d31..1f8390cb 100644 --- a/I1620/i1620_dp.c +++ b/I1620/i1620_dp.c @@ -35,7 +35,7 @@ to mean the implied sector number that would be in place if the disk pack had been formatted with sequential sector numbers. - 18-Oct-02 RMS Fixed bug in error testing (found by Hans Pufal) + 18-Oct-02 RMS Fixed bug in error testing (Hans Pufal) */ #include "i1620_defs.h" diff --git a/I1620/i1620_fp.c b/I1620/i1620_fp.c index d9d9b510..2b82a0fc 100644 --- a/I1620/i1620_fp.c +++ b/I1620/i1620_fp.c @@ -31,7 +31,7 @@ where S represents flag bits if the mantissa or exponent are negative. - 31-May-2008 RMS Fixed add_field call (found by Peter Schorn) + 31-May-2008 RMS Fixed add_field call (Peter Schorn) */ #include "i1620_defs.h" diff --git a/I1620/i1620_pt.c b/I1620/i1620_pt.c index 89b6dbd4..42a1ac63 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-2008, Robert M Supnik + Copyright (c) 2002-2012, Robert 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 @@ ptr 1621 paper tape reader ptp 1624 paper tape punch + 19-Mar-12 RMS Fixed declaration of io_stop (Mark Pizzolato) 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility 25-Apr-03 RMS Revised for extended file support */ diff --git a/I1620/i1620_sys.c b/I1620/i1620_sys.c index cf0fb94c..df247342 100644 --- a/I1620/i1620_sys.c +++ b/I1620/i1620_sys.c @@ -22,6 +22,8 @@ Except as contained in this notice, the name of Robert M Supnik shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + + 19-Mar-12 RMS Fixed declaration of CCT (Mark Pizzolato) */ #include "i1620_defs.h" @@ -122,7 +124,8 @@ const char *sim_stop_messages[] = { t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { -int32 col, rpt, ptr, mask, cctbuf[CCT_LNT]; +uint32 col, mask, cctbuf[CCT_LNT]; +int32 ptr, rpt; t_stat r; extern int32 cct_lnt, cct_ptr; extern uint32 cct[CCT_LNT]; diff --git a/I7094/i7094_cd.c b/I7094/i7094_cd.c index 8235ef36..cbdcf458 100644 --- a/I7094/i7094_cd.c +++ b/I7094/i7094_cd.c @@ -1,6 +1,6 @@ /* i7094_cd.c: IBM 711/721 card reader/punch - Copyright (c) 2003-2008, Robert M. Supnik + Copyright (c) 2003-2012, Robert 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 @@ cdr 711 card reader cdp 721 card punch + 19-Mar-12 RMS Fixed declaration of sim_switches (Mark Pizzolato) 19-Jan-07 RMS Added UNIT_TEXT 13-Jul-06 RMS Fixed problem with 80 column full cards diff --git a/I7094/i7094_com.c b/I7094/i7094_com.c index 2fd5cf24..b5c7b29d 100644 --- a/I7094/i7094_com.c +++ b/I7094/i7094_com.c @@ -26,8 +26,8 @@ com 7750 controller coml 7750 lines - 12-Aug-2010 RMS Major rewrite for CTSS (from Dave Pitts) - 19-Nov-2008 RMS Revised for common TMXR show routines + 12-Aug-10 RMS Major rewrite for CTSS (Dave Pitts) + 19-Nov-08 RMS Revised for common TMXR show routines This module implements an abstract simulator for the IBM 7750 communications computer as used by the CTSS system. The 7750 supports up to 112 lines; diff --git a/I7094/i7094_cpu.c b/I7094/i7094_cpu.c index 3719999b..f1d46462 100644 --- a/I7094/i7094_cpu.c +++ b/I7094/i7094_cpu.c @@ -28,7 +28,7 @@ 31-Dec-11 RMS Select traps have priority over protect traps Added SRI, SPI Fixed user mode and relocation from CTSS RPQ documentation - 16-Jul-10 RMS Fixed user mode protection (found by Dave Pitts) + 16-Jul-10 RMS Fixed user mode protection (Dave Pitts) Fixed issues in storage nullification mode 28-Apr-07 RMS Removed clock initialization 29-Oct-06 RMS Added additional expanded core instructions diff --git a/I7094/i7094_cpu1.c b/I7094/i7094_cpu1.c index 1b682eb0..1e3bd402 100644 --- a/I7094/i7094_cpu1.c +++ b/I7094/i7094_cpu1.c @@ -26,7 +26,7 @@ 31-Dec-11 RMS Refined PSE and MSE user-mode protection based on CTSS RPQ specification Select traps have priority over protection traps - 16-Jul-10 RMS Fixed PSE and MSE user-mode protection (from Dave Pitts) + 16-Jul-10 RMS Fixed PSE and MSE user-mode protection (Dave Pitts) Added SPUx, SPTx, SPRx */ diff --git a/I7094/i7094_drm.c b/I7094/i7094_drm.c index d7d91da9..50b24c35 100644 --- a/I7094/i7094_drm.c +++ b/I7094/i7094_drm.c @@ -25,6 +25,7 @@ drm 7289/7320A "fast" drum + 23-Mar-12 RMS Corrected disk addressing and logical disk crossing 25-Mar-11 RMS Updated based on RPQ This simulator implements a subset of the functionality of the 7289, as @@ -47,7 +48,7 @@ Limitations in this simulator: - Chain mode is not implemented. - - Write protect switches are not implemented. + - LPCR is not implemented. For speed, the entire drum is buffered in memory. */ @@ -55,10 +56,12 @@ #include "i7094_defs.h" #include -#define DRM_NUMDR 8 /* drums/controller */ +#define DRM_NUMDR 4 /* drums/controller */ /* Drum geometry */ +#define DRM_NUMWDG 1024 /* words/group */ +#define DRM_GPMASK (DRM_NUMWDG - 1) /* group mask */ #define DRM_NUMWDS 2048 /* words/sector */ #define DRM_SCMASK (DRM_NUMWDS - 1) /* sector mask */ #define DRM_NUMSC 16 /* sectors/log drum */ @@ -68,6 +71,7 @@ #define DRM_SIZE (DRM_NUMLD * DRM_NUMWDL) /* words/phys drum */ #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ ((double) DRM_NUMWDS))) +#define GET_PROT(x) ((x[drm_phy] >> (drm_log - 1)) & 1) /* Drum address from channel */ @@ -80,7 +84,7 @@ #define DRM_GETPHY(x) (((uint32) ((x) >> DRM_V_PHY)) & DRM_M_PHY) #define DRM_GETLOG(x) ((((uint32) (x)) >> DRM_V_LOG) & DRM_M_LOG) #define DRM_GETWDA(x) ((((uint32) (x)) >> DRM_V_WDA) & DRM_M_WDA) -#define DRM_GETDA(x) (((DRM_GETLOG(x) - 1) * DRM_NUMWDL) + DRM_GETWDA(x)) +#define DRM_GETDA(l,x) ((((l) - 1) * DRM_NUMWDL) + (x)) /* SCD word */ @@ -88,9 +92,7 @@ #define DRMS_V_INV 33 /* invalid command */ #define DRMS_V_PHY 31 /* physical drum */ #define DRMS_V_LOG 28 /* logical drum */ -#define DRMS_V_HWDA 24 /* high word addr */ -#define DRMS_M_HWDA 017 -#define DRMS_V_GRP 23 /* group */ +#define DRMS_V_WDA 13 /* disk address */ #define DRMS_V_WRP 22 /* write protect */ #define DRMS_V_LPCR 18 /* LPRCR */ #define DRMS_M_LPCR 017 @@ -106,10 +108,12 @@ uint32 drm_ch = CH_G; /* drum channel */ uint32 drm_da = 0; /* drum address */ uint32 drm_phy = 0; /* physical drum */ +uint32 drm_log = 0; /* logical drum */ uint32 drm_sta = 0; /* state */ uint32 drm_op = 0; /* operation */ t_uint64 drm_chob = 0; /* output buf */ uint32 drm_chob_v = 0; /* valid */ +uint32 drm_prot[DRM_NUMDR] = { 0 }; /* drum protect sw */ int32 drm_time = 10; /* inter-word time */ extern uint32 ind_ioc; @@ -138,23 +142,20 @@ UNIT drm_unit[] = { UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, - { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, - { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, - { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, - { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, }; REG drm_reg[] = { { ORDATA (STATE, drm_sta, 3) }, - { ORDATA (DA, drm_da, 18) }, + { ORDATA (UNIT,drm_phy, 2), REG_RO }, + { ORDATA (LOG, drm_log, 3), REG_RO }, + { ORDATA (DA, drm_da, 15) }, { FLDATA (OP, drm_op, 0) }, - { ORDATA (UNIT,drm_phy, 3) }, { ORDATA (CHOB, drm_chob, 36) }, { FLDATA (CHOBV, drm_chob_v, 0) }, + { ORDATA (PROT0, drm_prot[0], 6) }, + { ORDATA (PROT1, drm_prot[1], 6) }, + { ORDATA (PROT2, drm_prot[2], 6) }, + { ORDATA (PROT3, drm_prot[3], 6) }, { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, { DRDATA (CHAN, drm_ch, 3), REG_HRO }, { NULL } @@ -199,24 +200,38 @@ switch (sel) { /* case on cmd */ return SCPE_OK; } +/* Channel diagnostic store routine */ + +t_uint64 drm_sdc (uint32 ch) +{ +t_uint64 val; + + +val = (((t_uint64) ind_ioc) << DRMS_V_IOC) | + (((t_uint64) drm_phy) << DRMS_V_PHY) | + (((t_uint64) drm_log) << DRMS_V_LOG) | + (((t_uint64) (drm_da & ~ DRM_GPMASK)) << DRMS_V_WDA) | + (((t_uint64) GET_PROT(drm_prot)) << DRMS_V_WRP); +return val; +} + /* Channel write routine */ t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags) { -uint32 l; int32 cp, dp; if (drm_sta == DRM_1ST) { drm_phy = DRM_GETPHY (val); /* get unit */ - l = DRM_GETLOG (val); /* get logical address */ - if ((drm_phy >= DRM_NUMDR) || /* invalid unit? */ - (drm_unit[drm_phy].flags & UNIT_DIS) || /* disabled unit? */ - (l == 0) || (l > DRM_NUMLD)) { /* invalid log drum? */ + drm_log = DRM_GETLOG (val); /* get logical disk */ + drm_da = DRM_GETWDA (val); /* get drum word addr */ + if ((drm_unit[drm_phy].flags & UNIT_DIS) || /* disabled unit? */ + (drm_log == 0) || (drm_log > DRM_NUMLD) || /* invalid log drum? */ + ((drm_op != 0) && (GET_PROT (drm_prot) != 0))) { /* write to prot drum? */ ch6_err_disc (ch, U_DRM, CHF_TRC); /* disconnect */ drm_sta = DRM_IDLE; return SCPE_OK; } - drm_da = DRM_GETDA (val); /* get drum addr */ cp = GET_POS (drm_time); /* current pos in sec */ dp = (drm_da & DRM_SCMASK) - cp; /* delta to desired pos */ if (dp <= 0) /* if neg, add rev */ @@ -243,23 +258,19 @@ t_stat drm_svc (UNIT *uptr) { uint32 i; t_uint64 *fbuf = (t_uint64 *) uptr->filebuf; +uint32 da = DRM_GETDA (drm_log, drm_da); if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? */ ch6_err_disc (drm_ch, U_DRM, CHF_TRC); /* set TRC, disc */ drm_sta = DRM_IDLE; /* drum is idle */ return SCPE_UNATT; } -if (drm_da >= DRM_SIZE) { /* nx logical drum? */ - ch6_err_disc (drm_ch, U_DRM, CHF_EOF); /* set EOF, disc */ - drm_sta = DRM_IDLE; /* drum is idle */ - return SCPE_OK; - } switch (drm_sta) { /* case on state */ - case DRM_FILL: /* write, clr sector */ - for (i = drm_da & ~DRM_SCMASK; i <= (drm_da | DRM_SCMASK); i++) - fbuf[i] = 0; /* clear sector */ + case DRM_FILL: /* write, clr group */ + for (i = da & ~DRM_GPMASK; i <= (da | DRM_GPMASK); i++) + fbuf[i] = 0; /* clear group */ if (i >= uptr-> hwmark) uptr->hwmark = i + 1; drm_sta = DRM_DATA; /* now data */ @@ -270,14 +281,14 @@ switch (drm_sta) { /* case on state */ drm_chob_v = 0; else if (ch6_qconn (drm_ch, U_DRM)) /* no, chan conn? */ ind_ioc = 1; /* io check */ - fbuf[drm_da] = drm_chob; /* get data */ - if (drm_da >= uptr->hwmark) - uptr->hwmark = drm_da + 1; - if (!drm_da_incr ()) + fbuf[da] = drm_chob; /* get data */ + if (da >= uptr->hwmark) + uptr->hwmark = da + 1; + if (!drm_da_incr ()) /* room for more? */ ch6_req_wr (drm_ch, U_DRM); } else{ /* read */ - ch6_req_rd (drm_ch, U_DRM, fbuf[drm_da], 0); /* send word to channel */ + ch6_req_rd (drm_ch, U_DRM, fbuf[da], 0); /* send word to channel */ drm_da_incr (); } sim_activate (uptr, drm_time); /* next word */ @@ -293,12 +304,12 @@ switch (drm_sta) { /* case on state */ return SCPE_OK; } -/* Increment drum address - return true, set new state if end of sector */ +/* Increment drum address - return true, set new state if end of logical disk */ t_bool drm_da_incr (void) { -drm_da = (drm_da & ~DRM_LDMASK) | ((drm_da + 1) & DRM_LDMASK); -if ((drm_da & DRM_LDMASK) != 0) +drm_da = (drm_da + 1) & DRM_LDMASK; +if (drm_da != 0) return FALSE; drm_sta = DRM_EOD; return TRUE; @@ -311,6 +322,7 @@ t_stat drm_reset (DEVICE *dptr) uint32 i; drm_phy = 0; +drm_log = 0; drm_da = 0; drm_op = 0; drm_sta = DRM_IDLE; diff --git a/I7094/i7094_io.c b/I7094/i7094_io.c index 00851951..e4e81d13 100644 --- a/I7094/i7094_io.c +++ b/I7094/i7094_io.c @@ -1,6 +1,6 @@ /* i7094_io.c: IBM 7094 I/O subsystem (channels) - Copyright (c) 2003-2006, Robert M. Supnik + Copyright (c) 2003-2012, Robert 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 @@ chana..chanh I/O channels + 19-Mar-12 RMS Fixed declaration of breakpoint variables (Mark Pizzolato) + Notes on channels and CTSS. - CTSS B-core is supported by the addition of a 16th bit to the current @@ -834,10 +836,12 @@ return SCPE_OK; t_stat ch_op_store_diag (uint32 ch, t_uint64 *dat) { +extern t_uint64 drm_sdc (uint32 ch); + if ((ch >= NUM_CHAN) || (ch_dev[ch].flags & DEV_DIS)) return STOP_NXCHN; if (ch_flags[ch] & DEV_7289) - *dat = ind_ioc? SIGN: 0; + *dat = drm_sdc (ch); else if (ch_flags[ch] & DEV_7909) *dat = (((t_uint64) (ch_lcc[ch] & CHF_M_LCC)) << CHF_V_LCC) | (ch_flags[ch] & CHF_SDC_7909); diff --git a/I7094/i7094_lp.c b/I7094/i7094_lp.c index 9f7f8ef2..f6aca08c 100644 --- a/I7094/i7094_lp.c +++ b/I7094/i7094_lp.c @@ -1,6 +1,6 @@ /* i7094_lp.c: IBM 716 line printer simulator - Copyright (c) 2003-2008, Robert M. Supnik + Copyright (c) 2003-2012, Robert 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/I7094/i7094_mt.c b/I7094/i7094_mt.c index c06eb5ac..edf1d06b 100644 --- a/I7094/i7094_mt.c +++ b/I7094/i7094_mt.c @@ -1,6 +1,6 @@ /* i7094_mt.c: IBM 7094 magnetic tape simulator - Copyright (c) 2003-2008, Robert M Supnik + Copyright (c) 2003-2012, Robert 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,7 +25,8 @@ mt magtape simulator - 16-Jul-10 RMS Fixed handling of BSR, BSF (from Dave Pitts) + 19-Mar-12 RMS Fixed declaration of sel_name (Mark Pizzolato) + 16-Jul-10 RMS Fixed handling of BSR, BSF (Dave Pitts) */ #include "i7094_defs.h" diff --git a/Interdata/id16_cpu.c b/Interdata/id16_cpu.c index fdf38ae5..f3ec00ad 100644 --- a/Interdata/id16_cpu.c +++ b/Interdata/id16_cpu.c @@ -28,15 +28,15 @@ 28-Apr-07 RMS Removed clock initialization 27-Oct-06 RMS Added idle support Removed separate PASLA clock - 06-Feb-06 RMS Fixed bug in DH (found by Mark Hittinger) - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 06-Feb-06 RMS Fixed bug in DH (Mark Hittinger) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 25-Aug-05 RMS Fixed DH integer overflow cases 16-Aug-05 RMS Fixed C++ declaration and cast problems - 10-Mar-05 RMS Fixed bug in show history routine (from Mark Hittinger) + 10-Mar-05 RMS Fixed bug in show history routine (Mark Hittinger) Revised examine/deposit to do words rather than bytes 07-Nov-04 RMS Added instruction history 22-Sep-03 RMS Added additional instruction decode types - 07-Feb-03 RMS Fixed bug in SETM, SETMR (found by Mark Pizzolato) + 07-Feb-03 RMS Fixed bug in SETM, SETMR (Mark Pizzolato) The register state for the Interdata 16b CPU is: diff --git a/Interdata/id32_cpu.c b/Interdata/id32_cpu.c index 969b954b..7af43c61 100644 --- a/Interdata/id32_cpu.c +++ b/Interdata/id32_cpu.c @@ -29,13 +29,13 @@ 27-Oct-06 RMS Added idle support Removed separate PASLA clock 09-Mar-06 RMS Added 8 register bank support for 8/32 - 06-Feb-06 RMS Fixed bug in DH (found by Mark Hittinger) - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 06-Feb-06 RMS Fixed bug in DH (Mark Hittinger) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 10-Mar-05 RMS Fixed bug in initial memory allocation - RMS Fixed bug in show history routine (from Mark Hittinger) + RMS Fixed bug in show history routine (Mark Hittinger) RMS Revised examine/deposit to do words rather than bytes - 18-Feb-05 RMS Fixed branches to mask new PC (from Greg Johnson) + 18-Feb-05 RMS Fixed branches to mask new PC (Greg Johnson) 06-Nov-04 RMS Added =n to SHOW HISTORY 25-Jan-04 RMS Revised for device debug support 31-Dec-03 RMS Fixed bug in cpu_set_hist diff --git a/Interdata/id32_dboot.c b/Interdata/id32_dboot.c index 081a3c4b..40ee4167 100644 --- a/Interdata/id32_dboot.c +++ b/Interdata/id32_dboot.c @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 17-Jul-06 RMS Fixed transcription errors (found by Davis Johnson) + 17-Jul-06 RMS Fixed transcription errors (Davis Johnson) 17-Feb-03 RMS Fixed for UNIX bootstrap, upper platter bootstrap */ diff --git a/Interdata/id_fd.c b/Interdata/id_fd.c index 461b54ab..a016436c 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-2008, Robert M Supnik + Copyright (c) 2001-2012, Robert 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 @@ fd M46-630 floppy disk + 19-Mar-12 RMS Fixed macro naming conflict (Mark Pizzolato) + A diskette consists of 77 tracks, each with 26 sectors of 128B. The Interdata floppy uses a logical record numbering scheme from 1 to 2002. Physical tracks are numbered 0-76, physical sectors 1-26. @@ -75,14 +77,11 @@ #define STA_WRP 0x80 /* *write prot */ #define STA_DEF 0x40 /* def track NI */ -#ifdef STA_DEL /* Some platforms define a conflicting symbol here */ -#undef STA_DEL -#endif -#define STA_DEL 0x20 /* del record */ +#define STA_DLR 0x20 /* del record */ #define STA_ERR 0x10 /* error */ #define STA_IDL 0x02 /* idle */ #define STA_OFL 0x01 /* fault */ -#define STA_MASK (STA_DEF|STA_DEL|STA_ERR|STA_BSY|STA_IDL) +#define STA_MASK (STA_DEF|STA_DLR|STA_ERR|STA_BSY|STA_IDL) #define SET_EX (STA_ERR) /* set EX */ /* Extended status, 6 bytes, * = dynamic */ @@ -332,7 +331,7 @@ switch (fnc) { /* case on function */ for (i = 0; i < FD_NUMBY; i++) /* read sector */ fdxb[i] = fbuf[da + i]; if (fbuf[FD_SIZE + uptr->LRN - 1]) { /* deleted? set err */ - fd_sta = fd_sta | STA_DEL; + fd_sta = fd_sta | STA_DLR; fd_es[u][0] = fd_es[u][0] | ES0_DEL; } fd_es[u][2] = GET_SEC (uptr->LRN); /* set ext sec/trk */ diff --git a/Interdata/id_idc.c b/Interdata/id_idc.c index e2ac7003..38854d1c 100644 --- a/Interdata/id_idc.c +++ b/Interdata/id_idc.c @@ -25,8 +25,8 @@ idc MSM/IDC disk controller - 03-Apr-06 RMS Fixed WD/WH handling (found by Davis Johnson) - 30-Mar-06 RMS Fixed bug, nop command should be ignored (found by Davis Johnson) + 03-Apr-06 RMS Fixed WD/WH handling (Davis Johnson) + 30-Mar-06 RMS Fixed bug, nop command should be ignored (Davis Johnson) 25-Apr-03 RMS Revised for extended file support 16-Feb-03 RMS Fixed read to test transfer ok before selch operation diff --git a/Interdata/id_io.c b/Interdata/id_io.c index 98ce4a1d..86228eda 100644 --- a/Interdata/id_io.c +++ b/Interdata/id_io.c @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 30-Mar-06 RMS Fixed bug, GO preserves EXA and SSTA (found by Davis Johnson) + 30-Mar-06 RMS Fixed bug, GO preserves EXA and SSTA (Davis Johnson) 21-Jun-03 RMS Changed subroutine argument for ARM compiler conflict Interdata I/O devices are defined by a device information block: diff --git a/Interdata/id_lp.c b/Interdata/id_lp.c index e1136a42..fcb1c09b 100644 --- a/Interdata/id_lp.c +++ b/Interdata/id_lp.c @@ -25,7 +25,7 @@ lpt M46-206 line printer - 27-May-08 RMS Fixed bug in printing test (from Davis Johnson) + 27-May-08 RMS Fixed bug in printing test (Davis Johnson) 19-Jan-07 RMS Added UNIT_TEXT flag 25-Apr-03 RMS Revised for extended file support */ diff --git a/Interdata/id_pas.c b/Interdata/id_pas.c index 15ccf7e3..7ce00973 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-2008, Robert M Supnik + Copyright (c) 2001-2012, Robert 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) + 21-Mar-12 RMS Fixed TT_GET_MODE test to use TTUF_MODE_x (Michael Bloom) 19-Nov-08 RMS Revised for common TMXR show routines 18-Jun-07 RMS Added UNIT_IDLE flag 18-Oct-06 RMS Synced PASLA to clock @@ -345,7 +346,7 @@ for (ln = 0; ln < PAS_ENAB; ln++) { /* loop thru lines */ else { /* normal */ out = c & 0x7F; /* echo is 7b */ c = sim_tt_inpcvt (c, TT_GET_MODE (pasl_unit[ln].flags)); - if (TT_GET_MODE (pasl_unit[ln].flags) != TT_MODE_8B) + if (TT_GET_MODE (pasl_unit[ln].flags) != TTUF_MODE_8B) c = pas_par (pas_cmd[ln], c); /* apply parity */ pas_rbuf[ln] = c; /* save char */ pas_rchp[ln] = 1; /* char pending */ @@ -378,7 +379,7 @@ uint32 ln = uptr - pasl_unit; /* line # */ if (pas_ldsc[ln].conn) { /* connected? */ if (pas_ldsc[ln].xmte) { /* xmt enabled? */ TMLN *lp = &pas_ldsc[ln]; /* get line */ - if (TT_GET_MODE (pasl_unit[ln].flags) == TT_MODE_8B) + if (TT_GET_MODE (pasl_unit[ln].flags) == TTUF_MODE_8B) c = pas_par (pas_cmd[ln], pas_xbuf[ln]); /* apply parity */ else c = sim_tt_outcvt (pas_xbuf[ln], TT_GET_MODE (pasl_unit[ln].flags)); if (c >= 0) { diff --git a/Interdata/id_pt.c b/Interdata/id_pt.c index 27cc0c85..0dc89bfd 100644 --- a/Interdata/id_pt.c +++ b/Interdata/id_pt.c @@ -26,7 +26,7 @@ pt paper tape reader and punch 25-Apr-03 RMS Revised for extended file support - 10-Apr-03 RMS Fixed type problem in ptr service (from Mark Pizzolato) + 10-Apr-03 RMS Fixed type problem in ptr service (Mark Pizzolato) */ #include "id_defs.h" diff --git a/LGP/lgp_cpu.c b/LGP/lgp_cpu.c index 87e040e8..6b969306 100644 --- a/LGP/lgp_cpu.c +++ b/LGP/lgp_cpu.c @@ -25,8 +25,8 @@ cpu LGP-30 [LGP-21] CPU - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) - 04-Sep-05 RMS Fixed missing returns (found by Peter Schorn) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) + 04-Sep-05 RMS Fixed missing returns (Peter Schorn) 04-Jan-05 RMS Modified VM pointer setup The system state for the LGP-30 [LGP-21] is: diff --git a/NOVA/nova_clk.c b/NOVA/nova_clk.c index d0c888cd..0f9bbdb3 100644 --- a/NOVA/nova_clk.c +++ b/NOVA/nova_clk.c @@ -33,7 +33,7 @@ 17-Sep-01 RMS Added terminal multiplexor support 17-Mar-01 RMS Moved function prototype 05-Mar-01 RMS Added clock calibration - 24-Sep-97 RMS Fixed bug in unit service (found by Charles Owen) + 24-Sep-97 RMS Fixed bug in unit service (Charles Owen) */ #include "nova_defs.h" diff --git a/NOVA/nova_cpu.c b/NOVA/nova_cpu.c index 136163aa..a1caf573 100644 --- a/NOVA/nova_cpu.c +++ b/NOVA/nova_cpu.c @@ -34,10 +34,10 @@ 'ind_max' changed from 16 to 65536 for better unmapped system compatibility, INT_TRAP added for Nova 3, 4 trap instruction handling, 28-Apr-07 RMS Removed clock initialization - 06-Feb-06 RMS Fixed bug in DIVS (found by Mark Hittinger) - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 06-Feb-06 RMS Fixed bug in DIVS (Mark Hittinger) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 25-Aug-05 RMS Fixed DIVS case 2^31 / - 1 - 14-Jan-04 RMS Fixed device enable/disable support (found by Bruce Ray) + 14-Jan-04 RMS Fixed device enable/disable support (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 diff --git a/NOVA/nova_dsk.c b/NOVA/nova_dsk.c index f01063fc..b1cfff3e 100644 --- a/NOVA/nova_dsk.c +++ b/NOVA/nova_dsk.c @@ -29,7 +29,7 @@ DEV_xxx macros now used for consistency, added secret DG DIC function, fixed boot info table size calculation - 15-May-06 RMS Fixed bug in autosize attach (reported by David Gesswein) + 15-May-06 RMS Fixed bug in autosize attach (David Gesswein) 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 diff --git a/NOVA/nova_mta.c b/NOVA/nova_mta.c index 2cd7fe49..787c37ab 100644 --- a/NOVA/nova_mta.c +++ b/NOVA/nova_mta.c @@ -46,7 +46,7 @@ 24-Nov-01 RMS Changed POS, USTAT, FLG to an array 26-Apr-01 RMS Added device enable/disable support 18-Apr-01 RMS Changed to rewind tape before boot - 10-Dec-00 RMS Added Eclipse support from Charles Owen + 10-Dec-00 RMS Added Eclipse support (Charles Owen) 15-Oct-00 RMS Editorial changes 11-Nov-98 CEO Removed clear of mta_ma on iopC 04-Oct-98 RMS V2.4 magtape format diff --git a/NOVA/nova_sys.c b/NOVA/nova_sys.c index 4b066f54..6411e7d5 100644 --- a/NOVA/nova_sys.c +++ b/NOVA/nova_sys.c @@ -41,7 +41,7 @@ 15-Oct-00 RMS Added stack, byte, trap instructions 14-Apr-99 RMS Changed t_addr to unsigned 27-Oct-98 RMS V2.4 load interface - 24-Sep-97 RMS Fixed bug in device name table (found by Charles Owen) + 24-Sep-97 RMS Fixed bug in device name table (Charles Owen) */ #include "nova_defs.h" diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index 40e2a910..7be63f73 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-2008, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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,10 +25,11 @@ cpu PDP-1 central processor - 30-May-07 RMS Fixed typo in SBS clear (from Norm Lastovica) + 210Mar-12 RMS Fixed & vs && in Ea_ch (Michael Bloom) + 30-May-07 RMS Fixed typo in SBS clear (Norm Lastovica) 28-Dec-06 RMS Added 16-channel SBS support, PDP-1D support 28-Jun-06 RMS Fixed bugs in MUS and DIV - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 09-Nov-04 RMS Added instruction history 07-Sep-03 RMS Added additional explanation on I/O simulation @@ -1406,7 +1407,7 @@ else { /* multi-level */ return STOP_IND; } /* end else !extm */ if (IR & IA) { /* automatic mode? */ - if (rm & !sbs_act & ((MB & 0607777) == 0607777)) /* page cross? */ + if (rm && !sbs_act && ((MB & 0607777) == 0607777)) /* page cross? */ return set_rmv (RTB_CHR); MB = inc_bp (MB); /* incr byte ptr */ Write (); /* rewrite */ diff --git a/PDP1/pdp1_stddev.c b/PDP1/pdp1_stddev.c index c5c9f6bc..1d1586dc 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-2008, Robert M. Supnik + Copyright (c) 1993-2012, Robert 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,16 +28,17 @@ tti keyboard tto teleprinter + 21-Mar-12 RMS Fixed unitialized variable in tto_svc (Michael Bloom) 21-Dec-06 RMS Added 16-channel sequence break support - 29-Oct-03 RMS Added PTR FIODEC-to-ASCII translation (from Phil Budne) + 29-Oct-03 RMS Added PTR FIODEC-to-ASCII translation (Phil Budne) 07-Sep-03 RMS Changed ioc to ios 30-Aug-03 RMS Revised PTR to conform to Maintenance Manual; added deadlock prevention on errors 23-Jul-03 RMS Revised to detect I/O wait hang 25-Apr-03 RMS Revised for extended file support 22-Dec-02 RMS Added break support - 29-Nov-02 RMS Fixed output flag initialization (found by Derek Peschel) - 21-Nov-02 RMS Changed typewriter to half duplex (found by Derek Peschel) + 29-Nov-02 RMS Fixed output flag initialization (Derek Peschel) + 21-Nov-02 RMS Changed typewriter to half duplex (Derek Peschel) 06-Oct-02 RMS Revised for V2.10 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support @@ -591,7 +592,6 @@ return SCPE_OK; t_stat tto_svc (UNIT *uptr) { -int32 c; t_stat r; if (tty_buf == FIODEC_UC) /* upper case? */ @@ -599,11 +599,16 @@ if (tty_buf == FIODEC_UC) /* upper case? */ else if (tty_buf == FIODEC_LC) /* lower case? */ tty_uc = 0; else { + int32 c; c = fiodec_to_ascii[tty_buf | tty_uc]; /* translate */ if (c && ((r = sim_putchar_s (c)) != SCPE_OK)) { /* output; error? */ sim_activate (uptr, uptr->wait); /* retry */ return ((r == SCPE_STALL)? SCPE_OK: r); } + if (c == '\r') { /* cr? add lf */ + sim_putchar ('\n'); + uptr->pos = uptr->pos + 1; + } } if (cpls & CPLS_TTO) { /* completion pulse? */ ios = 1; /* restart */ @@ -612,10 +617,6 @@ if (cpls & CPLS_TTO) { /* completion pulse? */ iosta = iosta | IOS_TTO; /* set flag */ dev_req_int (tto_sbs); /* req interrupt */ uptr->pos = uptr->pos + 1; -if (c == '\r') { /* cr? add lf */ - sim_putchar ('\n'); - uptr->pos = uptr->pos + 1; - } return SCPE_OK; } diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c index 9c7fe51b..24dd0168 100644 --- a/PDP11/pdp11_cis.c +++ b/PDP11/pdp11_cis.c @@ -29,12 +29,12 @@ Fixed bug in DIVx (LntDstr calculation) 30-May-06 RMS Added interrupt tests to character instructions Added 11/44 stack probe test to MOVCx (only) - 22-May-06 RMS Fixed bug in decode table (found by John Dundas) - Fixed bug in ASHP (reported by John Dundas) + 22-May-06 RMS Fixed bug in decode table (John Dundas) + Fixed bug in ASHP (John Dundas) Fixed bug in write decimal string with mmgt enabled Fixed bug in 0-length strings in multiply/divide 16-Sep-04 RMS Fixed bug in CMPP/N of negative strings - 17-Oct-02 RMS Fixed compiler warning (found by Hans Pufal) + 17-Oct-02 RMS Fixed compiler warning (Hans Pufal) 08-Oct-02 RMS Fixed macro definitions The commercial instruction set consists of three instruction formats: diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 850b0ffe..0ee91143 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -1,6 +1,6 @@ /* pdp11_cpu.c: PDP-11 CPU simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2012, Robert 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,19 +25,20 @@ cpu PDP-11 CPU - 29-Dec-08 RMS Fixed failure to clear cpu_bme on RESET (found by Walter Mueller) - 22-Apr-08 RMS Fixed MMR0 treatment in RESET (found by Walter Mueller) - 02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas) + 19-Mar-12 RMS Fixed declaration of sim_switches (Mark Pizzolato) + 29-Dec-08 RMS Fixed failure to clear cpu_bme on RESET (Walter Mueller) + 22-Apr-08 RMS Fixed MMR0 treatment in RESET (Walter Mueller) + 02-Feb-08 RMS Fixed DMA memory address limit test (John Dundas) 28-Apr-07 RMS Removed clock initialization 27-Oct-06 RMS Added idle support 18-Oct-06 RMS Fixed bug in ASH -32 C value 24-May-06 RMS Added instruction history 03-May-06 RMS Fixed XOR operand fetch order for 11/70-style systems - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 19-May-05 RMS Replaced WAIT clock queue check with API call - 19-Jan-05 RMS Fixed bug(s) in RESET for 11/70 (reported by Tim Chapman) - 22-Dec-04 RMS Fixed WAIT to work in all modes (from John Dundas) + 19-Jan-05 RMS Fixed bug(s) in RESET for 11/70 (Tim Chapman) + 22-Dec-04 RMS Fixed WAIT to work in all modes (John Dundas) 02-Oct-04 RMS Added model emulation 25-Jan-04 RMS Removed local debug logging support 29-Dec-03 RMS Formalized 18b Qbus support @@ -47,19 +48,19 @@ 01-Feb-03 RMS Changed R display to follow PSW, added SP display 19-Jan-03 RMS Changed mode definitions for Apple Dev Kit conflict 05-Jan-03 RMS Added memory size restore support - 17-Oct-02 RMS Fixed bug in examine/deposit (found by Hans Pufal) + 17-Oct-02 RMS Fixed bug in examine/deposit (Hans Pufal) 08-Oct-02 RMS Revised to build dib_tab dynamically Added SHOW IOSPACE 09-Sep-02 RMS Added KW11P support 14-Jul-02 RMS Fixed bug in MMR0 error status load 03-Jun-02 RMS Fixed relocation add overflow, added PS<15:12> = 1111 special case logic to MFPI and removed it from MTPI - (found by John Dundas) - 29-Apr-02 RMS More fixes to DIV and ASH/ASHC (found by John Dundas) + (John Dundas) + 29-Apr-02 RMS More fixes to DIV and ASH/ASHC (John Dundas) 28-Apr-02 RMS Fixed bugs in illegal instruction 000010 and in - write-only memory pages (found by Wolfgang Helbig) + write-only memory pages (Wolfgang Helbig) 21-Apr-02 RMS Fixed bugs in DIV by zero, DIV overflow, TSTSET, RTS, - ASHC -32, and red zone trap (found by John Dundas) + ASHC -32, and red zone trap (John Dundas) 04-Mar-02 RMS Changed double operand evaluation order for M+ 23-Feb-02 RMS Fixed bug in MAINT, CPUERR, MEMERR read 28-Jan-02 RMS Revised for multiple timers; fixed calc_MMR1 macros @@ -81,7 +82,7 @@ 05-Apr-01 RMS Added TS11/TSV05 support 05-Mar-01 RMS Added clock calibration support 11-Feb-01 RMS Added DECtape support - 25-Jan-01 RMS Fixed 4M memory definition (found by Eric Smith) + 25-Jan-01 RMS Fixed 4M memory definition (Eric Smith) 14-Apr-99 RMS Changed t_addr to unsigned 18-Aug-98 RMS Added CIS support 09-May-98 RMS Fixed bug in DIV overflow test diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index c30d5a88..80a52dc4 100644 --- a/PDP11/pdp11_cpumod.c +++ b/PDP11/pdp11_cpumod.c @@ -27,12 +27,12 @@ 20-May-08 RMS Added JCSR default for KDJ11B, KDJ11E 22-Apr-08 RMS Fixed write behavior of 11/70 MBRK, LOSIZE, HISIZE - (found by Walter Mueller) + (Walter Mueller) 29-Apr-07 RMS Don't run bus setup routine during RESTORE 30-Aug-05 RMS Added additional 11/60 registers 16-Aug-05 RMS Fixed C++ declaration and cast problems - 15-Feb-05 RMS Fixed bug in SHOW MODEL (from Sergey Okhapkin) - 19-Jan-05 RMS Added variable SYSID, MBRK write (from Tim Chapman) + 15-Feb-05 RMS Fixed bug in SHOW MODEL (Sergey Okhapkin) + 19-Jan-05 RMS Added variable SYSID, MBRK write (Tim Chapman) This module includes CPU- and system-specific registers, such as the Unibus map and control registers on 22b Unibus systems, the board registers for the diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index c0610364..bb80d7fa 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -25,7 +25,7 @@ dz DZ11 terminal multiplexor - 29-Dec-08 RMS Added MTAB_NC to SET LOG command (found by Walter Mueller) + 29-Dec-08 RMS Added MTAB_NC to SET LOG command (Walter Mueller) 19-Nov-08 RMS Revised for common TMXR show routines 18-Jun-07 RMS Added UNIT_IDLE flag 29-Oct-06 RMS Synced poll and clock diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 1f18ac9a..2d1db393 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 04-Oct-04 RMS Added FIS instructions 19-Jan-03 RMS Changed mode definitions for Apple Dev Kit conflict 08-Oct-02 RMS Fixed macro definitions diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index f2bb1015..72aa9cfd 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-2008, Robert M Supnik + Copyright (c) 1993-2012, Robert 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 @@ hk RK611/RK06/RK07 disk + 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) 29-Apr-07 RMS NOP and DCLR (at least) do not check drive type MR2 and MR3 only updated on NOP 17-Nov-05 RMS Removed unused variable diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index f8c98240..e5909413 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-2011, Robert M Supnik + Copyright (c) 1993-2012, Robert 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,19 +23,20 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) 12-Dec-11 RMS Fixed Qbus interrupts to treat all IO devices as BR4 19-Nov-08 RMS Moved I/O support routines to I/O library 16-May-08 RMS Added multiple DC11 support Renamed DL11 in autoconfigure - 02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas) + 02-Feb-08 RMS Fixed DMA memory address limit test (John Dundas) 06-Jul-06 RMS Added multiple KL11/DL11 support 15-Oct-05 RMS Fixed bug in autoconfiguration (missing XU) 25-Jul-05 RMS Revised autoconfiguration algorithm and interface 30-Sep-04 RMS Revised Unibus interface - 28-May-04 RMS Revised I/O dispatching (from John Dundas) + 28-May-04 RMS Revised I/O dispatching (John Dundas) 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) + 21-Nov-03 RMS Added check for interrupt slot conflict (Dave Hittner) 12-Mar-03 RMS Added logical name support 08-Oct-02 RMS Trimmed I/O bus addresses Added support for dynamic tables diff --git a/PDP11/pdp11_rf.c b/PDP11/pdp11_rf.c index cd2055ed..439fa7b2 100644 --- a/PDP11/pdp11_rf.c +++ b/PDP11/pdp11_rf.c @@ -1,6 +1,6 @@ /* pdp11_rf.c: RF11 fixed head disk simulator - Copyright (c) 2006-2008, Robert M Supnik + Copyright (c) 2006-2012, Robert 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,7 +25,8 @@ rf RF11 fixed head disk - 25-Dec-06 RMS Fixed bug in unit mask (found by John Dundas) + 19-Mar-12 RMS Fixed bug in updating mem addr extension (Peter Schorn) + 25-Dec-06 RMS Fixed bug in unit mask (John Dundas) 26-Jun-06 RMS Cloned from RF08 simulator The RF11 is a head-per-track disk. To minimize overhead, the entire RF11 @@ -377,7 +378,7 @@ do { } while ((rf_wc != 0) && (rf_burst != 0)); /* brk if wc, no brst */ rf_da = da & DMASK; /* split da */ -rf_dae = (rf_dae & ~RFDAE_DAE) | ((rf_da >> 16) && RFDAE_DAE); +rf_dae = (rf_dae & ~RFDAE_DAE) | ((rf_da >> 16) & RFDAE_DAE); rf_cma = ma & DMASK; /* split ma */ rf_cs = (rf_cs & ~RFCS_MEX) | ((ma >> (16 - RFCS_V_MEX)) & RFCS_MEX); if ((rf_wc != 0) && ((rf_cs & RFCS_ERR) == 0)) /* more to do? */ diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c index 3256c8a6..efc7c043 100644 --- a/PDP11/pdp11_rh.c +++ b/PDP11/pdp11_rh.c @@ -1,6 +1,6 @@ /* pdp11_rh.c: PDP-11 Massbus adapter simulator - Copyright (c) 2005-2008, Robert M Supnik + Copyright (c) 2005-2012, Robert 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,7 +25,8 @@ rha, rhb RH11/RH70 Massbus adapter - 02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas) + 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) + 02-Feb-08 RMS Fixed DMA memory address limit test (John Dundas) 17-May-07 RMS Moved CS1 drive enable to devices 21-Nov-05 RMS Added enable/disable routine 07-Jul-05 RMS Removed extraneous externs diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index 2b7c089c..5e37d54d 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -25,7 +25,7 @@ rk RK11/RKV11/RK05 cartridge disk - 20-Mar-09 RMS Fixed bug in read header (from Walter F Mueller) + 20-Mar-09 RMS Fixed bug in read header (Walter F Mueller) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs 30-Sep-04 RMS Revised Unibus interface diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index ef338bf5..107b8077 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -39,7 +39,7 @@ SET RLn ONLINE/OFFLINE SET RL RLV11/RLV12 (PDP-11 only) SET RL DEBUG/NODEBUG - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs 30-Sep-04 RMS Revised Unibus interface diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index 8ecd715d..716470fc 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -43,20 +43,20 @@ 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread 31-Oct-05 RMS Fixed address width for large files 16-Aug-05 RMS Fixed C++ declaration and cast problems - 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn) + 22-Jul-05 RMS Fixed warning from Solaris C (Doug Gwyn) 17-Jan-05 RMS Added more RA and RD disks 31-Oct-04 RMS Added -L switch (LBNs) to RAUSER size specification 01-Oct-04 RMS Revised Unibus interface Changed to identify as UDA50 in Unibus configurations Changed width to be 16b in all configurations Changed default timing for VAX - 24-Jul-04 RMS VAX controllers luns start with 0 (from Andreas Cejna) + 24-Jul-04 RMS VAX controllers luns start with 0 (Andreas Cejna) 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) + 12-Jan-04 RMS Fixed bug in interrupt control (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) + 11-Jul-03 RMS Fixed bug in user disk size (Chaskiel M Grundman) 19-May-03 RMS Revised for new conditional compilation scheme 25-Apr-03 RMS Revised for extended file support 14-Mar-03 RMS Fixed variable size interaction with save/restore @@ -70,7 +70,7 @@ Fixed status code in HBE error log Consolidated MSCP/TMSCP header file New data structures - 16-Aug-02 RMS Removed unused variables (found by David Hittner) + 16-Aug-02 RMS Removed unused variables (David Hittner) 04-May-02 RMS Fixed bug in polling loop for queued operations 26-Mar-02 RMS Fixed bug, reset routine cleared UF_WPH 09-Mar-02 RMS Adjusted delays for M+ timing bugs diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index 47b51975..a973e2e0 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -25,9 +25,9 @@ ry RX211/RXV21/RX02 floppy disk - 15-May-06 RMS Fixed bug in autosize attach (reported by David Gesswein) + 15-May-06 RMS Fixed bug in autosize attach (David Gesswein) 07-Jul-05 RMS Removed extraneous externs - 18-Feb-05 RMS Fixed bug in boot code (reported by Graham Toal) + 18-Feb-05 RMS Fixed bug in boot code (Graham Toal) 30-Sep-04 RMS Revised Unibus interface 21-Mar-04 RMS Added VAX support 29-Dec-03 RMS Added RXV21 support diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c index ed6ce6e1..d68199b3 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -32,7 +32,7 @@ Added clock coscheduling support 05-Jul-06 RMS Added UC only support for early DOS/RSTS 22-Nov-05 RMS Revised for new terminal processing routines - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 07-Jul-05 RMS Removed extraneous externs 11-Oct-04 RMS Added clock model dependencies 28-May-04 RMS Removed SET TTI CTRL-C @@ -46,7 +46,7 @@ Split DL11 dibs 30-May-02 RMS Widened POS to 32b 26-Jan-02 RMS Revised for multiple timers - 09-Jan-02 RMS Fixed bugs in KW11L (found by John Dundas) + 09-Jan-02 RMS Fixed bugs in KW11L (John Dundas) 06-Jan-02 RMS Split I/O address routines, revised enable/disable support 29-Nov-01 RMS Added read only unit support 09-Nov-01 RMS Added RQDX3 support diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 17ac0423..98ca200b 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -27,16 +27,16 @@ 15-May-08 RMS Added KE11-A, DC11 support Renamed DL11 04-Feb-08 RMS Modified to allow -A, -B use with 8b devices - 25-Jan-08 RMS Added RC11, KG11A support from John Dundas + 25-Jan-08 RMS Added RC11, KG11A support (John Dundas) 10-Sep-07 RMS Cleaned up binary loader 20-Dec-06 RMS Added TA11 support - 12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller) + 12-Nov-06 RMS Fixed operand order in EIS instructions (W.F.J. Mueller) 14-Jul-06 RMS Reordered device list 06-Jul-06 RMS Added multiple KL11/DL11 support 26-Jun-06 RMS Added RF11 support - 17-May-06 RMS Added CR11/CD11 support (from John Dundas) + 17-May-06 RMS Added CR11/CD11 support (John Dundas) 16-Aug-05 RMS Fixed C++ declaration and cast problems - 22-Jul-05 RMS Fixed missing , in initializer (from Doug Gwyn) + 22-Jul-05 RMS Fixed missing , in initializer (Doug Gwyn) 22-Dec-03 RMS Added second DEUNA/DELUA support 18-Oct-03 RMS Added DECtape off reel message 06-May-03 RMS Added support for second DEQNA/DELQA diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index 1b67b4ce..f1451776 100644 --- a/PDP11/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -26,7 +26,7 @@ tc TC11/TU56 DECtape 23-Jun-06 RMS Fixed switch conflict in ATTACH - 10-Feb-06 RMS READ sets extended data bits in TCST (found by Alan Frisbie) + 10-Feb-06 RMS READ sets extended data bits in TCST (Alan Frisbie) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs 30-Sep-04 RMS Revised Unibus interface diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index e6af932c..ee4f2ba6 100644 --- a/PDP11/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -46,23 +46,22 @@ 28-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Fixed max record length, first block bootstrap - (found by Jonathan Engdahl) + (Jonathan Engdahl) 26-Jan-02 RMS Revised bootstrap to conform to M9312 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted UST, POS, FLG to arrays 09-Nov-01 RMS Added bus map support - 18-Oct-01 RMS Added stub diagnostic register (found by Thord Nilson) + 18-Oct-01 RMS Added stub diagnostic register (Thord Nilson) 07-Sep-01 RMS Revised device disable and interrupt mechanisms 26-Apr-01 RMS Added device enable/disable support 18-Apr-01 RMS Changed to rewind tape before boot 14-Apr-99 RMS Changed t_addr to unsigned 04-Oct-98 RMS V2.4 magtape format - 10-May-98 RMS Fixed bug with non-zero unit operation (from Steven Schultz) - 09-May-98 RMS Fixed problems in bootstrap (from Steven Schultz) - 10-Apr-98 RMS Added 2nd block bootstrap (from John Holden, - University of Sydney) - 31-Jul-97 RMS Added bootstrap (from Ethan Dicks, Ohio State) + 10-May-98 RMS Fixed bug with non-zero unit operation (Steven Schultz) + 09-May-98 RMS Fixed problems in bootstrap (Steven Schultz) + 10-Apr-98 RMS Added 2nd block bootstrap (John Holden) + 31-Jul-97 RMS Added bootstrap (Ethan Dicks) 22-Jan-97 RMS V2.3 magtape format 18-Jan-97 RMS Fixed double interrupt, error flag bugs 29-Jun-96 RMS Added unit disable support diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index c4b8fbe8..6c02591e 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -49,10 +49,10 @@ 16-Feb-06 RMS Revised for new magtape capacity checking 31-Oct-05 RMS Fixed address width for large files 16-Aug-05 RMS Fixed C++ declaration and cast problems - 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn) + 22-Jul-05 RMS Fixed warning from Solaris C (Doug Gwyn) 30-Sep-04 RMS Revised Unibus interface - 12-Jun-04 RMS Fixed bug in reporting write protect (reported by Lyle Bickley) - 18-Apr-04 RMS Fixed TQK70 media ID and model byte (found by Robert Schaffrath) + 12-Jun-04 RMS Fixed bug in reporting write protect (Lyle Bickley) + 18-Apr-04 RMS Fixed TQK70 media ID and model byte (Robert Schaffrath) 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 @@ -63,7 +63,7 @@ 22-Feb-03 RMS Fixed ordering bug in queue process Fixed flags table to allow MD_CSE everywhere 09-Jan-03 RMS Fixed bug in transfer end packet status - 17-Oct-02 RMS Fixed bug in read reverse (found by Hans Pufal) + 17-Oct-02 RMS Fixed bug in read reverse (Hans Pufal) */ #if defined (VM_PDP10) /* PDP10 version */ diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index 0d5ff9c9..ccad942a 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-2010, Robert M Supnik + Copyright (c) 1993-2012, Robert 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,7 +26,7 @@ ts TS11/TSV05 magtape 22-May-10 RMS Fixed t_addr printouts for 64b big-endian systems - (found by Mark Pizzolato) + (Mark Pizzolato) 16-Feb-06 RMS Added tape capacity checking 31-Oct-05 RMS Fixed address width for large files 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -59,7 +59,7 @@ 19-Sep-01 RMS Fixed bug in bootstrap 15-Sep-01 RMS Fixed bug in NXM test 07-Sep-01 RMS Revised device disable and interrupt mechanism - 13-Jul-01 RMS Fixed bug in space reverse (found by Peter Schorn) + 13-Jul-01 RMS Fixed bug in space reverse (Peter Schorn) Magnetic tapes are represented as a series of variable 8b records of the form: diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index f4b2144f..f924ebac 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -1,6 +1,6 @@ /* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2012, Robert 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,7 +27,7 @@ 18-Apr-11 MP Fixed t_addr printouts for 64b big-endian systems 17-May-07 RMS CS1 DVA resides in device, not MBA - 29-Apr-07 RMS Fixed bug in setting FCE on TMK (found by Naoki Hamada) + 29-Apr-07 RMS Fixed bug in setting FCE on TMK (Naoki Hamada) 16-Feb-06 RMS Added tape capacity checking 12-Nov-05 RMS Changed default formatter to TM03 (for VMS) 31-Oct-05 RMS Fixed address width for large files diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index e6153f22..fde07975 100644 --- a/PDP11/pdp11_vh.c +++ b/PDP11/pdp11_vh.c @@ -1,6 +1,6 @@ /* pdp11_vh.c: DHQ11 asynchronous terminal multiplexor simulator - Copyright (c) 2004-2010, John A. Dundas III + Copyright (c) 2004-2012, John A. Dundas III Portions derived from work by Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index 4e5a53b0..d9473ac3 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -26,7 +26,7 @@ cpu PDP-4/7/9/15 central processor 28-Apr-07 RMS Removed clock initialization - 26-Dec-06 RMS Fixed boundary test in KT15/XVM (reported by Andrew Warkentin) + 26-Dec-06 RMS Fixed boundary test in KT15/XVM (Andrew Warkentin) 30-Oct-06 RMS Added idle and infinite loop detection 08-Oct-06 RMS Added RDCLK instruction Fixed bug, PC off by one on fetch mem mmgt error @@ -34,7 +34,7 @@ PDP-15 sets API 4 on CAL only if 0-3 inactive CAF clears memory management mode register 27-Jun-06 RMS Reset clears AC, L, and MQ - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 22-Jul-05 RMS Removed AAS, error in V1 reference manual 06-Nov-04 RMS Added =n to SHOW HISTORY @@ -56,14 +56,14 @@ Fixed memory protect/skip interaction Fixed CAF not to reset CPU 12-Mar-03 RMS Added logical name support - 18-Feb-03 RMS Fixed three EAE bugs (found by Hans Pufal) + 18-Feb-03 RMS Fixed three EAE bugs (Hans Pufal) 05-Oct-02 RMS Added DIBs, device number support 25-Jul-02 RMS Added DECtape support for PDP-4 06-Jan-02 RMS Revised enable/disable support 30-Dec-01 RMS Added old PC queue 30-Nov-01 RMS Added extended SET/SHOW support 25-Nov-01 RMS Revised interrupt structure - 19-Sep-01 RMS Fixed bug in EAE (found by Dave Conroy) + 19-Sep-01 RMS Fixed bug in EAE (Dave Conroy) 17-Sep-01 RMS Fixed typo in conditional 10-Aug-01 RMS Removed register from declarations 17-Jul-01 RMS Moved function prototype @@ -2132,7 +2132,7 @@ if (usmd && (sw & SWMASK ('V'))) { addr = RelocXVM (addr, REL_C); else if (RELOC) addr = Reloc15 (addr, REL_C); - if (((int32)addr) < 0) + if (((int32) addr) < 0) return STOP_MME; } #endif @@ -2153,7 +2153,7 @@ if (usmd && (sw & SWMASK ('V'))) { addr = RelocXVM (addr, REL_C); else if (RELOC) addr = Reloc15 (addr, REL_C); - if (((int32)addr) < 0) + if (((int32) addr) < 0) return STOP_MME; } #endif diff --git a/PDP18B/pdp18b_drm.c b/PDP18B/pdp18b_drm.c index 0ae13f2c..c65990b1 100644 --- a/PDP18B/pdp18b_drm.c +++ b/PDP18B/pdp18b_drm.c @@ -30,7 +30,7 @@ 05-Dec-02 RMS Updated from Type 24 documentation 22-Nov-02 RMS Added PDP-4 support 05-Feb-02 RMS Added DIB, device number support - 03-Feb-02 RMS Fixed bug in reset routine (found by Robert Alan Byer) + 03-Feb-02 RMS Fixed bug in reset routine (Robert Alan Byer) 06-Jan-02 RMS Revised enable/disable support 25-Nov-01 RMS Revised interrupt structure 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index a55510e9..d1a098a6 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-2008, Robert M Supnik + Copyright (c) 2003-2012, Robert 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 @@ fpp PDP-15 floating point processor + 19-Mar-12 RMS Fixed declaration of pc queue (Mark Pizzolato) 06-Jul-06 RMS Fixed bugs in left shift, multiply 31-Oct-04 RMS Fixed URFST to mask low 9b of fraction Fixed exception PC setting diff --git a/PDP18B/pdp18b_lp.c b/PDP18B/pdp18b_lp.c index e04698c3..801f05f1 100644 --- a/PDP18B/pdp18b_lp.c +++ b/PDP18B/pdp18b_lp.c @@ -36,7 +36,7 @@ 05-Feb-03 RMS Added LP09, fixed conditionalization 05-Oct-02 RMS Added DIB, device number support 30-May-02 RMS Widened POS to 32b - 03-Feb-02 RMS Fixed typo (found by Robert Alan Byer) + 03-Feb-02 RMS Fixed typo (Robert Alan Byer) 25-Nov-01 RMS Revised interrupt structure 19-Sep-01 RMS Fixed bug in 647 13-Feb-01 RMS Revised for register arrays diff --git a/PDP18B/pdp18b_rf.c b/PDP18B/pdp18b_rf.c index 65a90383..51e6ecd9 100644 --- a/PDP18B/pdp18b_rf.c +++ b/PDP18B/pdp18b_rf.c @@ -27,7 +27,7 @@ (PDP-15) RF15/RS09 04-Oct-06 RMS Fixed bug, DSCD does not clear function register - 15-May-06 RMS Fixed bug in autosize attach (reported by David Gesswein) + 15-May-06 RMS Fixed bug in autosize attach (David Gesswein) 14-Jan-04 RMS Revised IO device call interface Changed sim_fsize calling sequence 26-Oct-03 RMS Cleaned up buffer copy code diff --git a/PDP18B/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c index c93b4cf8..c2e5c827 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -53,7 +53,7 @@ 22-Dec-02 RMS Added break support 01-Nov-02 RMS Added 7B/8B support to terminal 05-Oct-02 RMS Added DIBs, device number support, IORS call - 14-Jul-02 RMS Added ASCII reader/punch support (from Hans Pufal) + 14-Jul-02 RMS Added ASCII reader/punch support (Hans Pufal) 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support 25-Nov-01 RMS Revised interrupt structure diff --git a/PDP18B/pdp18b_sys.c b/PDP18B/pdp18b_sys.c index c843e949..97adc3cf 100644 --- a/PDP18B/pdp18b_sys.c +++ b/PDP18B/pdp18b_sys.c @@ -34,12 +34,12 @@ 30-Jul-03 RMS Fixed FPM class mask 18-Jul-03 RMS Added FP15 support 02-Mar-03 RMS Split loaders apart for greater flexibility - 09-Feb-03 RMS Fixed bug in FMTASC (found by Hans Pufal) + 09-Feb-03 RMS Fixed bug in FMTASC (Hans Pufal) 31-Jan-03 RMS Added support for RB09 05-Oct-02 RMS Added variable device number support 25-Jul-02 RMS Added PDP-4 DECtape support 10-Feb-02 RMS Added PDP-7 DECtape IOT's - 03-Feb-02 RMS Fixed typo (found by Robert Alan Byer) + 03-Feb-02 RMS Fixed typo (Robert Alan Byer) 17-Sep-01 RMS Removed multiconsole support 27-May-01 RMS Added second Teletype support 18-May-01 RMS Added PDP-9,-15 API IOT's @@ -49,8 +49,7 @@ 30-Nov-00 RMS Added PDP-9,-15 RIM/BIN loader format 30-Oct-00 RMS Added support for examine to file 27-Oct-98 RMS V2.4 load interface - 20-Oct-97 RMS Fixed endian dependence in RIM loader - (found by Michael Somos) + 20-Oct-97 RMS Fixed endian dependence in RIM loader (Michael Somos) */ #include "pdp18b_defs.h" diff --git a/PDP8/pdp8_fpp.c b/PDP8/pdp8_fpp.c index 4fb04c01..6845dbe8 100644 --- a/PDP8/pdp8_fpp.c +++ b/PDP8/pdp8_fpp.c @@ -1,6 +1,6 @@ /* pdp8_fpp.c: PDP-8 floating point processor (FPP8A) - Copyright (c) 2007-2010, Robert M Supnik + Copyright (c) 2007-2011, Robert 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_sys.c b/PDP8/pdp8_sys.c index 3b550941..ed7ff85b 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-2009, Robert M Supnik + Copyright (c) 1993-2011, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,7 +24,7 @@ in this Software without prior written authorization from Robert M Supnik. 24-Mar-09 RMS Added link to FPP - 24-Jun-08 RMS Fixed bug in new rim loader (found by Don North) + 24-Jun-08 RMS Fixed bug in new rim loader (Don North) 24-May-08 RMS Fixed signed/unsigned declaration inconsistency 03-Sep-07 RMS Added FPP8 support Rewrote rim and binary loaders diff --git a/S3/s3_cd.c b/S3/s3_cd.c index 99041df5..7ec0e2ab 100644 --- a/S3/s3_cd.c +++ b/S3/s3_cd.c @@ -1,6 +1,6 @@ /* s3_cd.c: IBM 1442 card reader/punch - Copyright (c) 2001-2005, Charles E. Owen + Copyright (c) 2001-2012, Charles E. Owen 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,7 @@ cdp card punch cdp2 card punch stacker 2 + 19-Mar-12 RMS Fixed declaration of conversion tables (Mark Pizzolato) 25-Apr-03 RMS Revised for extended file support 08-Oct-02 RMS Added impossible function catcher diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c index 6b9890b2..b4696484 100644 --- a/S3/s3_cpu.c +++ b/S3/s3_cpu.c @@ -1,6 +1,6 @@ /* s3_cpu.c: IBM System/3 CPU simulator - Copyright (c) 2001-2005, Charles E. Owen + Copyright (c) 2001-2012, Charles E. Owen HPL & SLC instruction code Copyright (c) 2001 by Henk Stegeman Decimal Arithmetic Copyright (c) 2000 by Roger Bowler @@ -29,6 +29,8 @@ cpu System/3 (models 10 and 15) central processor + 19-Mar-12 RMS Changed int to int32 in declarations (Mark Pizzolato) + The IBM System/3 was a popular small-business computing system introduced in 1969 as an entry-level system for businesses that could not afford the lowest rungs of the System/360. Its architecture is inspired by and diff --git a/S3/s3_lp.c b/S3/s3_lp.c index 6c085115..99f85af4 100644 --- a/S3/s3_lp.c +++ b/S3/s3_lp.c @@ -1,6 +1,6 @@ /* s3_lp.c: IBM 1403 line printer simulator - Copyright (c) 2001-2005, Charles E. Owen + Copyright (c) 2001-2012, Charles E. Owen 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 @@ lpt 1403 line printer + 19-Mar-12 RMS Fixed declaration of conversion tables (Mark Pizzolato) 25-Apr-03 RMS Revised for extended file support 08-Oct-02 RMS Added impossible function catcher */ @@ -114,7 +115,7 @@ int32 lpt (int32 op, int32 m, int32 n, int32 data) switch (op) { case 0: /* SIO 1403 */ iodata = 0; - printf("\0"); +// printf("\0"); switch (n) { case 0x00: /* Spacing only */ if (data > 0 && data < 4) diff --git a/S3/s3_sys.c b/S3/s3_sys.c index d4123a6b..39cec895 100644 --- a/S3/s3_sys.c +++ b/S3/s3_sys.c @@ -1,6 +1,6 @@ /* s3_sys.c: IBM System/3 system interface - Copyright (c) 2001-2005, Charles E. Owen + Copyright (c) 2001-2012, Charles E. Owen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -22,6 +22,8 @@ Except as contained in this notice, the name of Charles E. Owen shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Charles E. Owen. + + 19-Mar-12 RMS Fixed declaration of conversion tables (Mark Pizzolato) */ #include diff --git a/SDS/sds_io.c b/SDS/sds_io.c index c7f87b48..4e4dd22b 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-2008, Robert M. Supnik + Copyright (c) 2001-2012, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -22,6 +22,8 @@ Except as contained in this notice, the name of Robert M Supnik shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + + 19-Mar-2012 RMS Fixed various declarations (Mark Pizzolato) */ #include "sds_defs.h" diff --git a/SDS/sds_mt.c b/SDS/sds_mt.c index f7590eec..163d7d23 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-2008, Robert M. Supnik + Copyright (c) 2001-2012, Robert 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 @@ mt 7 track magnetic tape + 19-Mar-12 RMS Fixed bug in scan function decode (Peter Schorn) 16-Feb-06 RMS Added tape capacity checking 07-Dec-04 RMS Added read-only file support 25-Apr-03 RMS Revised for extended file support @@ -209,7 +210,7 @@ switch (fnc) { /* case function */ (inst & CHC_REV)) /* rw & rev? */ return STOP_INVIOP; mt_inst = inst; /* save inst */ - if ((inst & DEV_MTS) && !(inst && DEV_OUT)) /* scanning? */ + if ((inst & DEV_MTS) && !(inst & DEV_OUT)) /* scanning? */ chan_set_flag (mt_dib.chan, CHF_SCAN); /* set chan flg */ xfr_req = xfr_req & ~XFR_MT0; /* clr xfr flag */ sim_activate (uptr, mt_gtime); /* start timer */ diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index f46f4d82..44f98173 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-2008, Robert M Supnik + Copyright (c) 2001-2012, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -22,6 +22,8 @@ Except as contained in this notice, the name of Robert M Supnik shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + + 19-Mar-12 RMS Fixed declarations of CCT arrays (Mark Pizzolato) */ #include "sds_defs.h" diff --git a/VAX/vax780_sbi.c b/VAX/vax780_sbi.c index f047184f..430aa807 100644 --- a/VAX/vax780_sbi.c +++ b/VAX/vax780_sbi.c @@ -27,9 +27,9 @@ sbi bus controller - 21-Mar-2011 RMS Added autoreboot capability (from Mark Pizzalato) + 21-Mar-2011 RMS Added autoreboot capability (Mark Pizzalato) 04-Feb-2011 MP Added RQB, RQC, and RQD as bootable controllers - 31-May-2008 RMS Fixed machine_check calling sequence (found by Peter Schorn) + 31-May-2008 RMS Fixed machine_check calling sequence (Peter Schorn) 03-May-2006 RMS Fixed writes to ACCS 28-May-2008 RMS Inlined physical memory routines */ diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index 814a5f43..84245806 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -60,7 +60,7 @@ Synced keyboard to clock for idling 11-May-06 RMS Revised timer logic for EVKAE 22-Nov-05 RMS Revised for new terminal processing routines - 10-Mar-05 RMS Fixed bug in timer schedule routine (from Mark Hittinger) + 10-Mar-05 RMS Fixed bug in timer schedule routine (Mark Hittinger) 08-Sep-04 RMS Cloned from vax_stddev.c, vax_sysdev.c, and pdp11_rx.c The console floppy protocol is based on the description in the 1982 VAX diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index d35eb932..aad58dbd 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 17-May-06 RMS Added CR11/CD11 support (from John Dundas) + 17-May-06 RMS Added CR11/CD11 support (John Dundas) 01-Oct-04 RMS Cloned from vax_sys.c */ diff --git a/VAX/vax780_uba.c b/VAX/vax780_uba.c index cbbf0c74..245e8a22 100644 --- a/VAX/vax780_uba.c +++ b/VAX/vax780_uba.c @@ -27,7 +27,7 @@ 19-Nov-08 RMS Moved I/O support routines to I/O library 28-May-08 RMS Inlined physical memory routines - 25-Jan-08 RMS Fixed declarations (from Mark Pizzolato) + 25-Jan-08 RMS Fixed declarations (Mark Pizzolato) */ #include "vax_defs.h" diff --git a/VAX/vax_cis.c b/VAX/vax_cis.c index e77680e4..e75a53b8 100644 --- a/VAX/vax_cis.c +++ b/VAX/vax_cis.c @@ -29,7 +29,7 @@ 16-Oct-08 RMS Fixed bug in ASHP left overflow calc (Word/NibbleLShift) Fixed bug in DIVx (LntDstr calculation) 28-May-08 RMS Inlined physical memory routines - 16-May-06 RMS Fixed bug in length calculation (found by Tim Stark) + 16-May-06 RMS Fixed bug in length calculation (Tim Stark) 03-May-06 RMS Fixed MOVTC, MOVTUC to preserve cc's through page faults Fixed MOVTUC to stop on translated == escape Fixed CVTPL to set registers before destination reg write @@ -38,7 +38,7 @@ Fixed EDITPC EO$BLANK_ZERO count, cc test Fixed EDITPC EO$INSERT to insert fill instead of blank Fixed EDITPC EO$LOAD_PLUS/MINUS to skip character - (all reported by Tim Stark) + (Tim Stark) 12-Apr-04 RMS Cloned from pdp11_cis.c and vax_cpu1.c Zero length decimal strings require either zero bytes (trailing) or one byte diff --git a/VAX/vax_cmode.c b/VAX/vax_cmode.c index 8af75a03..24c7f8ac 100644 --- a/VAX/vax_cmode.c +++ b/VAX/vax_cmode.c @@ -27,7 +27,7 @@ On a subset VAX, this module forces a fault if REI attempts to set PSL. 28-May-08 RMS Inlined physical memory routines - 25-Jan-08 RMS Fixed declaration (from Mark Pizzolato) + 25-Jan-08 RMS Fixed declaration (Mark Pizzolato) 03-May-06 RMS Fixed omission of SXT Fixed order of operand fetching in XOR 24-Aug-04 RMS Cloned from PDP-11 CPU diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index e38f7efa..72ae874a 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -36,8 +36,8 @@ Determining a reasonable idle detection pattern does not seem possible for these versions. 13-Sep-11 RMS Fixed XFC, BPT to clear PSL before exception - (found by Camiel Vanderhoeven) - 23-Mar-11 RMS Revised for new idle design (from Mark Pizzolato) + (Camiel Vanderhoeven) + 23-Mar-11 RMS Revised for new idle design (Mark Pizzolato) 05-Jan-11 MP Added Asynch I/O support 24-Apr-10 RMS Added OLDVMS idle timer option Fixed bug in SET CPU IDLE @@ -46,7 +46,7 @@ 13-Aug-07 RMS Fixed bug in read access g-format indexed specifiers 28-Apr-07 RMS Removed clock initialization 29-Oct-06 RMS Added idle support - 22-May-06 RMS Fixed format error in CPU history (found by Peter Schorn) + 22-May-06 RMS Fixed format error in CPU history (Peter Schorn) 10-May-06 RMS Added -kesu switches for virtual addressing modes Fixed bugs in examine virtual Rewrote history function for greater usability @@ -56,32 +56,31 @@ Fixed ACBD/G to test correct operand Fixed access checking on modify-class specifiers Fixed branch displacements in history buffer - (all reported by Tim Stark) + (Tim Stark) 17-Nov-05 RMS Fixed CVTfi with integer overflow to trap if PSW set 13-Nov-05 RMS Fixed breakpoint test with 64b addresses 25-Oct-05 RMS Removed cpu_extmem - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 13-Jan-05 RMS Fixed initial state of cpu_extmem 06-Nov-04 RMS Added =n to SHOW HISTORY 30-Sep-04 RMS Added octaword specifier decodes and instructions Moved model-specific routines to system module 02-Sep-04 RMS Fixed bug in EMODD/G, second word of quad dst not probed - 28-Jun-04 RMS Fixed bug in DIVBx, DIVWx (reported by Peter Trimmel) + 28-Jun-04 RMS Fixed bug in DIVBx, DIVWx (Peter Trimmel) 18-Apr-04 RMS Added octaword macros 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) + 29-Oct-03 RMS Fixed WriteB declaration (Mark Pizzolato) 23-Sep-03 RMS Revised instruction history for dynamic sizing 17-May-03 RMS Fixed operand order in EMODx 23-Apr-03 RMS Revised for 32b/64b t_addr 05-Jan-02 RMS Added memory size restore support - 25-Dec-02 RMS Added instruction history (from Mark Pizzolato) + 25-Dec-02 RMS Added instruction history (Mark Pizzolato) 29-Sep-02 RMS Revised to build dib_tab dynamically - 14-Jul-02 RMS Added halt to console, infinite loop detection - (from Mark Pizzolato) + 14-Jul-02 RMS Added halt to console, infinite loop detection (Mark Pizzolato) 02-May-02 RMS Fixed bug in indexed autoincrement register logging 30-Apr-02 RMS Added TODR powerup routine 18-Apr-02 RMS Cleanup ambiguous signed left shifts diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index ccd0ae34..6e903e60 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -23,14 +23,14 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 15-Mar-12 RMS Fixed potential integer overflow in LDPCTX (from Mark Pizzolato) + 15-Mar-12 RMS Fixed potential integer overflow in LDPCTX (Mark Pizzolato) 25-Nov-11 RMS Added VEC_QBUS test in interrupt handler - 23-Mar-11 RMS Revised idle design (from Mark Pizzolato) + 23-Mar-11 RMS Revised idle design (Mark Pizzolato) 28-May-08 RMS Inlined physical memory routines 29-Apr-07 RMS Separated base register access checks for 11/780 10-May-06 RMS Added access check on system PTE for 11/780 Added mbz check in LDPCTX for 11/780 - 22-Sep-06 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-06 RMS Fixed declarations (Sterling Garwood) 30-Sep-04 RMS Added conditionals for full VAX Moved emulation to vax_cis.c Moved model-specific IPRs to system module @@ -38,8 +38,8 @@ 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) - Fixed PROBEx to mask mode to 2b (found by Kevin Handy) + 14-Apr-02 RMS Fixed prv_mode handling for interrupts (Tim Stark) + Fixed PROBEx to mask mode to 2b (Kevin Handy) This module contains the instruction simulators for diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index 77215b97..7b789cb5 100644 --- a/VAX/vax_fpa.c +++ b/VAX/vax_fpa.c @@ -23,9 +23,10 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 23-Mar-12 RMS Fixed missing arguments in 32b floating add (Mark Pizzolato) 15-Sep-11 RMS Fixed integer overflow bug in EMODx Fixed POLYx normalizing before add mask bug - (both from Camiel Vanderhoeven) + (Camiel Vanderhoeven) 28-May-08 RMS Inlined physical memory routines 16-May-06 RMS Fixed bug in 32b floating multiply routine Fixed bug in 64b extended modulus routine @@ -37,8 +38,8 @@ Fixed POLYF, POLYD, POLYG to mask mul reslt to 31b/63b/63b Fixed fp add routine to test for zero via fraction to support "denormal" argument from POLYF, POLYD, POLYG - (all reported by Tim Stark) - 27-Sep-05 RMS Fixed bug in 32b structure definitions (from Jason Stevens) + (Tim Stark) + 27-Sep-05 RMS Fixed bug in 32b structure definitions (Jason Stevens) 30-Sep-04 RMS Comment and formating changes based on vax_octa.c 18-Apr-04 RMS Moved format definitions to vax_defs.h 19-Jun-03 RMS Simplified add algorithm diff --git a/VAX/vax_io.c b/VAX/vax_io.c index d0646c3f..48a2da35 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -26,7 +26,7 @@ qba Qbus adapter 28-May-08 RMS Inlined physical memory routines - 25-Jan-08 RMS Fixed declarations (from Mark Pizzolato) + 25-Jan-08 RMS Fixed declarations (Mark Pizzolato) 03-Dec-05 RMS Added SHOW QBA VIRT and ex/dep via map 05-Oct-05 RMS Fixed bug in autoconfiguration (missing XU) 25-Jul-05 RMS Revised autoconfiguration algorithm and interface @@ -34,11 +34,11 @@ Moved mem_err, crd_err interrupts here from vax_cpu.c 09-Sep-04 RMS Integrated powerup into RESET (with -p) 05-Sep-04 RMS Added CRD interrupt handling - 28-May-04 RMS Revised I/O dispatching (from John Dundas) + 28-May-04 RMS Revised I/O dispatching (John Dundas) 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) + 21-Nov-03 RMS Added check for interrupt slot conflict (Dave Hittner) + 29-Oct-03 RMS Fixed WriteX declaration (Mark Pizzolato) 19-Apr-03 RMS Added optimized byte and word DMA routines 12-Mar-03 RMS Added logical name support 22-Dec-02 RMS Added console halt support diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index 1733d311..177b61e8 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -26,7 +26,7 @@ 21-Jul-08 RMS Removed inlining support 28-May-08 RMS Inlined physical memory routines 29-Apr-07 RMS Added address masking for system page table reads - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 30-Sep-04 RMS Comment and formating changes 19-Sep-03 RMS Fixed upper/lower case linkage problems on VMS 01-Jun-03 RMS Fixed compilation problem with USE_ADDR64 diff --git a/VAX/vax_octa.c b/VAX/vax_octa.c index b4e0fd3e..efb1a99c 100644 --- a/VAX/vax_octa.c +++ b/VAX/vax_octa.c @@ -27,7 +27,7 @@ 15-Sep-11 RMS Fixed integer overflow bug in EMODH Fixed POLYH normalizing before add mask bug - (both from Camiel Vanderhoeven) + (Camiel Vanderhoeven) 28-May-08 RMS Inlined physical memory routines 10-May-06 RMS Fixed bug in reported VA on faulting cross-page write 03-May-06 RMS Fixed MNEGH to test negated sign, clear C @@ -40,7 +40,7 @@ Fixed fp add routine to test for zero via fraction to support "denormal" argument from POLYH Fixed EMODH to concatenate 15b of 16b extension - (all reported by Tim Stark) + (Tim Stark) 15-Jul-04 RMS Cloned from 32b VAX floating point implementation */ diff --git a/VAX/vax_sys.c b/VAX/vax_sys.c index b9f2b95c..149f67d9 100644 --- a/VAX/vax_sys.c +++ b/VAX/vax_sys.c @@ -26,7 +26,7 @@ 21-Mar-11 RMS Modified string for STOP_BOOT message 19-Nov-08 RMS Moved bad block routine to I/O library 03-Nov-05 RMS Added 780 stop codes - 04-Sep-05 RMS Fixed missing assignment (found by Peter Schorn) + 04-Sep-05 RMS Fixed missing assignment (Peter Schorn) 16-Aug-05 RMS Fixed C++ declaration and cast problems 15-Sep-04 RMS Fixed bugs in character display and parse 30-Sep-04 RMS Fixed bugs in parsing indirect displacement modes diff --git a/VAX/vax_syscm.c b/VAX/vax_syscm.c index edc17edf..40cec63b 100644 --- a/VAX/vax_syscm.c +++ b/VAX/vax_syscm.c @@ -24,8 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. 22-May-10 RMS Fixed t_addr printouts for 64b big-endian systems - (found by Mark Pizzolato) - 12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller) + (Mark Pizzolato) + 12-Nov-06 RMS Fixed operand order in EIS instructions (W.F.J. Mueller) 27-Sep-05 RMS Fixed warnings compiling with 64b addresses 15-Sep-04 RMS Cloned from pdp11_sys.c */ diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index 7121d109..27eae37c 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -32,10 +32,10 @@ cso console storage output sysd system devices (SSC miscellany) - 23-Dec-10 RMS Added power clear call to boot routine (from Mark Pizzolato) + 23-Dec-10 RMS Added power clear call to boot routine (Mark Pizzolato) 25-Oct-05 RMS Automated CMCTL extended memory 16-Aug-05 RMS Fixed C++ declaration and cast problems - 10-Mar-05 RMS Fixed bug in timer schedule routine (from Mark Hittinger) + 10-Mar-05 RMS Fixed bug in timer schedule routine (Mark Hittinger) 30-Sep-04 RMS Moved CADR, MSER, CONPC, CONPSL, machine_check, cpu_boot, con_halt here from vax_cpu.c Moved model-specific IPR's here from vax_cpu1.c @@ -46,10 +46,10 @@ 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) + 19-Aug-02 RMS Removed unused variables (David Hittner) Allowed NVR to be attached to file 30-May-02 RMS Widened POS to 32b - 28-Feb-02 RMS Fixed bug, missing end of table (found by Lars Brinkhoff) + 28-Feb-02 RMS Fixed bug, missing end of table (Lars Brinkhoff) */ #include "vax_defs.h" diff --git a/VAX/vax_syslist.c b/VAX/vax_syslist.c index aba7119c..054c5e43 100644 --- a/VAX/vax_syslist.c +++ b/VAX/vax_syslist.c @@ -24,7 +24,7 @@ in this Software without prior written authorization from Robert M Supnik. 17-Oct-06 RMS Re-ordered device list - 17-May-06 RMS Added CR11/CD11 support (from John Dundas) + 17-May-06 RMS Added CR11/CD11 support (John Dundas) 01-Oct-2004 RMS Cloned from vax_sys.c */ diff --git a/makefile b/makefile index 17ab28ee..d349974f 100644 --- a/makefile +++ b/makefile @@ -35,7 +35,8 @@ ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) NETWORK_USEFUL = true ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) - BUILD_MULTIPLE = (s) + BUILD_MULTIPLE = s + BUILD_SINGLE := $(MAKECMDGOALS) $(BUILD_SINGLE) else BUILD_SINGLE := $(MAKECMDGOALS) $(BUILD_SINGLE) endif @@ -43,7 +44,8 @@ else ifeq ($(MAKECMDGOALS),) # default target is all NETWORK_USEFUL = true - BUILD_MULTIPLE = (s) + BUILD_MULTIPLE = s + BUILD_SINGLE := all $(BUILD_SINGLE) endif endif ifeq ($(WIN32),) #*nix Environments (&& cygwin) @@ -63,6 +65,7 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) OSNAME = windows-build endif GCC_VERSION = $(shell $(GCC) --version /dev/null | grep GCC | awk '{ print $$3 }') + LTO_EXCLUDE_VERSIONS = PCAPLIB = pcap ifeq (agcc,$(findstring agcc,$(GCC))) # Android target build? OS_CCDEFS = -D_GNU_SOURCE @@ -249,6 +252,7 @@ else GCC = gcc GCC_Path := $(dir $(shell where gcc.exe)) GCC_VERSION = $(word 3,$(shell $(GCC) --version)) + LTO_EXCLUDE_VERSIONS = 4.5.2 ifeq (pthreads,$(shell if exist ..\windows-build\pthreads\Pre-built.2\include\pthread.h echo pthreads)) PTHREADS_CCDEFS = -DUSE_READER_THREAD -DPTW32_STATIC_LIB -I../windows-build/pthreads/Pre-built.2/include ifeq (,$(NOASYNCH)) @@ -298,6 +302,9 @@ else ifneq (3,$(GCC_MAJOR_VERSION)) GCC_OPTIMIZERS = $(shell $(GCC) --help=optimizers) endif + ifneq (,$(findstring $(GCC_VERSION),$(LTO_EXCLUDE_VERSIONS))) + NO_LTO = 1 + endif ifneq (,$(findstring inline-functions,$(GCC_OPTIMIZERS))) CFLAGS_O += -finline-functions endif @@ -316,9 +323,11 @@ else ifneq (,$(findstring strict-overflow,$(GCC_OPTIMIZERS))) CFLAGS_O += -fno-strict-overflow endif - ifneq (,$(findstring lto,$(GCC_OPTIMIZERS))) - CFLAGS_O += -flto -fwhole-program - LDFLAGS_O += -flto -fwhole-program + ifeq (,$(NO_LTO)) + ifneq (,$(findstring lto,$(GCC_OPTIMIZERS))) + CFLAGS_O += -flto -fwhole-program + LDFLAGS_O += -flto -fwhole-program + endif endif BUILD_FEATURES = - compiler optimizations and no debugging support endif diff --git a/scp.c b/scp.c index f61abf70..d9ebd0b6 100644 --- a/scp.c +++ b/scp.c @@ -1,6 +1,6 @@ /* scp.c: simulator control program - Copyright (c) 1993-2011, Robert M Supnik + Copyright (c) 1993-2012, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 20-Mar-12 MP Fixes to "SHOW SHOW" commands 06-Jan-12 JDB Fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) 25-Sep-11 MP Added the ability for a simulator built with SIM_ASYNCH_IO to change whether I/O is actually done @@ -1947,8 +1948,8 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) { fprintf (st, " Step timer"); else if ((dptr = find_dev_from_unit (uptr)) != NULL) { fprintf (st, " %s", sim_dname (dptr)); - if (dptr->numunits > 1) fprintf (st, " unit %d", - (int32) (uptr - dptr->units)); + if (dptr->numunits > 1) + fprintf (st, " unit %d", (int32) (uptr - dptr->units)); } else fprintf (st, " Unknown"); fprintf (st, " at %d\n", accum + uptr->time); @@ -3279,9 +3280,10 @@ t_stat r = 0; t_addr k; t_value pcval; -if (v >= SCPE_BASE) fprintf (st, "\n%s, %s: ", - sim_error_text (v), pc->name); -else fprintf (st, "\n%s, %s: ", sim_stop_messages[v], pc->name); +if (v >= SCPE_BASE) + fprintf (st, "\n%s, %s: ", sim_error_text (v), pc->name); +else + fprintf (st, "\n%s, %s: ", sim_stop_messages[v], pc->name); pcval = get_rval (pc, 0); if (sim_vm_fprint_addr) sim_vm_fprint_addr (st, dptr, (t_addr) pcval); diff --git a/sim_console.c b/sim_console.c index 6b6d8fcb..c9b2ebe0 100644 --- a/sim_console.c +++ b/sim_console.c @@ -1,6 +1,6 @@ /* sim_console.c: simulator console I/O library - Copyright (c) 1993-2011, Robert M Supnik + Copyright (c) 1993-2012, Robert 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 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 18-Mar-12 RMS Removed unused reference to sim_switches (Dave Bryan) 07-Dec-11 MP Added sim_ttisatty to support reasonable behaviour (i.e. avoid in infinite loop) in the main command input loop when EOF is detected and input is coming from @@ -58,27 +59,26 @@ 22-Nov-05 RMS Added central input/output conversion support 05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy 28-Oct-04 JDB Fixed SET CONSOLE to allow comma-separated parameters - 20-Aug-04 RMS Added OS/2 EMX fixes (from Holger Veit) - 14-Jul-04 RMS Revised Windows console code (from Dave Bryan) + 20-Aug-04 RMS Added OS/2 EMX fixes (Holger Veit) + 14-Jul-04 RMS Revised Windows console code (Dave Bryan) 28-May-04 RMS Added SET/SHOW CONSOLE RMS Added break, delete character maps 02-Jan-04 RMS Removed timer routines, added Telnet console routines RMS Moved console logging to OS-independent code - 25-Apr-03 RMS Added long seek support from Mark Pizzolato - Added Unix priority control from Mark Pizzolato + 25-Apr-03 RMS Added long seek support (Mark Pizzolato) + Added Unix priority control (Mark Pizzolato) 24-Sep-02 RMS Removed VT support, added Telnet console support - Added CGI support (from Brian Knittel) - Added MacOS sleep (from Peter Schorn) - 14-Jul-02 RMS Added Windows priority control from Mark Pizzolato - 20-May-02 RMS Added Windows VT support from Fischer Franz - 01-Feb-02 RMS Added VAX fix from Robert Alan Byer - 19-Sep-01 RMS More Mac changes + Added CGI support (Brian Knittel) + Added MacOS sleep (Peter Schorn) + 14-Jul-02 RMS Added Windows priority control (Mark Pizzolato) + 20-May-02 RMS Added Windows VT support (Fischer Franz) + 01-Feb-02 RMS Added VAX fix (Robert Alan Byer) + 19-Sep-01 RMS More MacOS changes 31-Aug-01 RMS Changed int64 to t_int64 for Windoze - 20-Jul-01 RMS Added Macintosh support (from Louis Chretien, Peter Schorn, - and Ben Supnik) + 20-Jul-01 RMS Added Macintosh support (Louis Chretien, Peter Schorn, Ben Supnik) 15-May-01 RMS Added logging support 05-Mar-01 RMS Added clock calibration support - 08-Dec-00 BKR Added OS/2 support (from Bruce Ray) + 08-Dec-00 BKR Added OS/2 support (Bruce Ray) 18-Aug-98 RMS Added BeOS support 13-Oct-97 RMS Added NetBSD terminal support 25-Jan-97 RMS Added POSIX terminal I/O support diff --git a/sim_rev.h b/sim_rev.h index 35abe360..f3fefd3e 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -38,8 +38,8 @@ patch date module(s) and fix(es) 0 xx-yyy-1 scp.c: - added *nix READLINE support (Mark Pizzolato) - - fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) - fixed handling of DO with no arguments (Dave Bryan) + - fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) - clarified some help messages (Mark Pizzolato) - added "SHOW SHOW" and "SHOW SHOW" commands (Mark Pizzolato) - fixed bug in deposit stride for numeric input (John Dundas) @@ -51,8 +51,7 @@ patch date module(s) and fix(es) - major revision (Dave Hittner and Mark Pizzolato) sim_tmxr.c: - - made telnet option negotiation more reliable. - VAX works with PuTTY. (Mark Pizzolato) + - made option negotiation more reliable (Mark Pizzolato) h316_cpu.c: - fixed bugs in MPY, DIV introduced in 3.8-1 (from Theo Engel) @@ -97,14 +96,14 @@ patch date module(s) and fix(es) hp2100_cpu7.c (Dave Bryan): - Corrected "opsize" parameter type in vis_abs - hp2100_defs.h (Dave Bryan): + hp2100_defs.h (Dave Bryan): - Added hp_setsc, hp_showsc functions to support SC modifier - DMA channels renamed from 0,1 to 1,2 to match documentation - Revised I/O signal enum values for concurrent signals - Revised I/O macros for new signal handling - Added DA and DC device select code assignments - hp2100_di.c (Dave Bryan): + hp2100_di.c, hp2100_di.h (Dave Bryan): - Implemented 12821A HP-IB Disc Interface hp2100_di_da.c (Dave Bryan): @@ -112,8 +111,8 @@ patch date module(s) and fix(es) hp2100_dp.c (Dave Bryan): - Added CNTLR_TYPE cast to dp_settype - - hp2100_ds.c (Dave Bryan): + + hp2100_ds.c (Dave Bryan): - Rewritten to use the MAC/ICD disc controller library - ioIOO now notifies controller service of parameter output - Corrected SRQ generation and FIFO under/overrun detection @@ -138,25 +137,25 @@ patch date module(s) and fix(es) - Revised for new multi-card paradigm hp2100_lps.c (Dave Bryan): - - Revised detection of CLC at last DMA cycle + - Revised detection of CLC at last DMA cycle - Corrected 12566B (DIAG mode) jumper settings hp2100_ms.c (Dave Bryan): - Added CNTLR_TYPE cast to ms_settype - + hp2100_mt.c (Dave Bryan): - Fixed command scanning error in mtcio ioIOO handler hp2100_stddev.c (Dave Bryan): - Add TBG as a logical name for the CLK device - + hp2100_sys.c (Dave Bryan): - - Add TBG as a logical name for the CLK device + - Deprecated DEVNO in favor of SC - Added hp_setsc, hp_showsc functions to support SC modifier - Added DA and dummy DC devices - DMA channels renamed from 0,1 to 1,2 to match documentation - Changed DIB access for revised signal model - + hp_disclib.c, hp_disclib.h (Dave Bryan) - Created MAC/ICD disc controller library @@ -164,6 +163,9 @@ patch date module(s) and fix(es) - fixed read stacker operation in column binary mode - fixed punch stacker operation (Van Snyder) + id_pas.c: + - fixed TT_GET_MODE test to use TTUF_MODE_x (Michael Bloom) + 1401_cpu.c: - reverted multiple tape indicator implementation - fixed EOT indicator test not to clear indicator (Van Snyder) @@ -176,12 +178,21 @@ patch date module(s) and fix(es) - fixed backspace over tapemark not to set EOR (Van Snyder) - added no rewind option (Van Snyder) + pdp1_cpu.c: + - fixed misuse of & instead of && in Ea_ch (Michael Bloom) + + pdp1_stddev.c: + - fixed unitialized variable in tty output service (Michael Bloom) + pdp11_defs.h: - fixed priority of PIRQ vs IO; added INT_INTERNALn pdp11_io.c: - fixed Qbus interrupts to treat all IO devices as BR4 + ppd11_rf.c + - fixed bug in updating mem addr extension (Peter Schorn) + pdp11_rk.c: - fixed bug in read header (Walter F Mueller) @@ -191,7 +202,7 @@ patch date module(s) and fix(es) pdp11_rq.c: - added RD32 support - pdp11_tq.c: + pdp11_tq.c: (Mark Pizzolato) - set UNIT_SXC flag when a tape mark is encountered during forward motion read operations - fixed logic which clears UNIT_SXC to check command modifier @@ -201,51 +212,52 @@ patch date module(s) and fix(es) - fixed debug output of tape file positions when they are 64b - added more debug output after positioning operations - added textual display of the command being performed - (all of the above from Mark Pizzolato) - fixed comments about register addresses pdp11_ts.c: - - fixed t_addr printouts for 64b big-endian systems - (from Mark Pizzolato) + - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) - pdp8_fpp.c: - - many bug fixes (all from Rick Murphy); now functional + pdp8_fpp.c: (Rick Murphy) + - many bug fixes; now functional pdp8_sys.c: - added link to FPP pdp8_td.c: - - fixed SDLC to clear AC (from Dave Gesswein) + - fixed SDLC to clear AC (Dave Gesswein) + + sds_mt.c: + - fixed bug in scan function decode (Peter Schorn) vax_cpu.c: - - revised idle design (from Mark Pizzolato) + - revised idle design Mark Pizzolato) - fixed bug in SET CPU IDLE - fixed failure to clear PSL in BPT, XFC vax_cpu1.c: - - revised idle design (from Mark Pizzolato) + - revised idle design Mark Pizzolato) - added VEC_QMODE test in interrupt handler - vax_fpa.c - - fixed integer overflow bug in EMODx (from Camiel Vanderhoeven) - - fixed POLYx normalizing before add mask bug (from Camiel Vanderhoeven) + vax_fpa.c: + - fixed integer overflow bug in EMODx (Camiel Vanderhoeven) + - fixed POLYx normalizing before add mask bug (Camiel Vanderhoeven) + - fixed missing arguments in 32b floating add (Mark Pizzolato) - vax_octa.c - - fixed integer overflow bug in EMODH (from Camiel Vanderhoeven) - - fixed POLYH normalizing before add mask bug (from Camiel Vanderhoeven) + vax_octa.c (Camiel Vanderhoeven) + - fixed integer overflow bug in EMODH + - fixed POLYH normalizing before add mask bug vax_syscm.c: - - fixed t_addr printouts for 64b big-endian systems - (from Mark Pizzolato) + - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) vax_sysdev.c: - - added power clear call to boot routine (from Mark Pizzolato) + - added power clear call to boot routine (Mark Pizzolato) vax780_sbi.c: - - added AUTORESTART switch support (from Mark Pizzolato) + - added AUTORESTART switch support (Mark Pizzolato) vax780_stddev.c - - added REBOOT support (from Mark Pizzolato) + - added REBOOT support (Mark Pizzolato) vaxmod_def.h - moved all Qbus devices to BR4; deleted RP definitions diff --git a/swtp/swtp_defs.h b/swtp/swtp_defs.h index cf9041ad..42bb2e3a 100644 --- a/swtp/swtp_defs.h +++ b/swtp/swtp_defs.h @@ -27,7 +27,7 @@ Copyright (c) 2005, 2007, William Beech */ -#include "sim_defs.h" // simulator defs +#include "sim_defs.h" // simulator defs /* Memory */ From c2050705543a3d96884470d5117a2f0dfc62ee27 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 25 Mar 2012 07:36:37 -0700 Subject: [PATCH 033/112] Fix makefile for better GCC version determination and optimization enabling on more platforms --- makefile | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/makefile b/makefile index d349974f..6ee1e4c4 100644 --- a/makefile +++ b/makefile @@ -64,7 +64,7 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) OSTYPE = cygwin OSNAME = windows-build endif - GCC_VERSION = $(shell $(GCC) --version /dev/null | grep GCC | awk '{ print $$3 }') + GCC_VERSION = $(shell $(GCC) -v /dev/null 2>&1 | grep 'gcc version' | awk '{ print $$3 }') LTO_EXCLUDE_VERSIONS = PCAPLIB = pcap ifeq (agcc,$(findstring agcc,$(GCC))) # Android target build? @@ -80,6 +80,8 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) ifeq (Darwin,$(OSTYPE)) OSNAME = OSX LIBEXT = dylib + GCC_OPTIMIZERS_CMD = $(GCC) -v --help 2>&1 + GCC_WARNINGS_CMD = $(GCC) -v --help 2>&1 else ifeq (Linux,$(OSTYPE)) LIBPATH := $(sort $(foreach lib,$(shell /sbin/ldconfig -p | grep ' => /' | sed 's/^.* => //'),$(dir $(lib)))) @@ -300,31 +302,34 @@ else LDFLAGS_O = GCC_MAJOR_VERSION = $(firstword $(subst ., ,$(GCC_VERSION))) ifneq (3,$(GCC_MAJOR_VERSION)) - GCC_OPTIMIZERS = $(shell $(GCC) --help=optimizers) + ifeq (,$(GCC_OPTIMIZERS_CMD)) + GCC_OPTIMIZERS_CMD = $(GCC) --help=optimizers + endif + GCC_OPTIMIZERS = $(shell $(GCC_OPTIMIZERS_CMD)) endif ifneq (,$(findstring $(GCC_VERSION),$(LTO_EXCLUDE_VERSIONS))) NO_LTO = 1 endif - ifneq (,$(findstring inline-functions,$(GCC_OPTIMIZERS))) + ifneq (,$(findstring -finline-functions,$(GCC_OPTIMIZERS))) CFLAGS_O += -finline-functions endif - ifneq (,$(findstring gcse-after-reload,$(GCC_OPTIMIZERS))) + ifneq (,$(findstring -fgcse-after-reload,$(GCC_OPTIMIZERS))) CFLAGS_O += -fgcse-after-reload endif - ifneq (,$(findstring predictive-commoning,$(GCC_OPTIMIZERS))) + ifneq (,$(findstring -fpredictive-commoning,$(GCC_OPTIMIZERS))) CFLAGS_O += -fpredictive-commoning endif - ifneq (,$(findstring ipa-cp-clone,$(GCC_OPTIMIZERS))) + ifneq (,$(findstring -fipa-cp-clone,$(GCC_OPTIMIZERS))) CFLAGS_O += -fipa-cp-clone endif - ifneq (,$(findstring unsafe-loop-optimizations,$(GCC_OPTIMIZERS))) + ifneq (,$(findstring -funsafe-loop-optimizations,$(GCC_OPTIMIZERS))) CFLAGS_O += -fno-unsafe-loop-optimizations endif - ifneq (,$(findstring strict-overflow,$(GCC_OPTIMIZERS))) + ifneq (,$(findstring -fstrict-overflow,$(GCC_OPTIMIZERS))) CFLAGS_O += -fno-strict-overflow endif ifeq (,$(NO_LTO)) - ifneq (,$(findstring lto,$(GCC_OPTIMIZERS))) + ifneq (,$(findstring -flto,$(GCC_OPTIMIZERS))) CFLAGS_O += -flto -fwhole-program LDFLAGS_O += -flto -fwhole-program endif @@ -332,7 +337,10 @@ else BUILD_FEATURES = - compiler optimizations and no debugging support endif ifneq (3,$(GCC_MAJOR_VERSION)) - ifneq (,$(findstring unused-result,$(shell $(GCC) --help=warnings))) + ifeq (,$(GCC_WARNINGS_CMD)) + GCC_WARNINGS_CMD = $(GCC) --help=warnings + endif + ifneq (,$(findstring -Wunused-result,$(shell $(GCC_WARNINGS_CMD)))) CFLAGS_O += -Wno-unused-result endif endif From 027c921cfc87c5768839394459eab7127d0e29c6 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 25 Mar 2012 15:55:36 -0700 Subject: [PATCH 034/112] More robust and correct readline support and fix to VMS build for HP2100 --- descrip.mms | 2 +- makefile | 22 +++++++++++----------- scp.c | 2 ++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/descrip.mms b/descrip.mms index 11a2ac7c..8eaeab75 100644 --- a/descrip.mms +++ b/descrip.mms @@ -371,7 +371,7 @@ HP2100_SOURCE1 = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\ $(HP2100_DIR)HP2100_CPU6.C,$(HP2100_DIR)HP2100_CPU7.C HP2100_LIB2 = $(LIB_DIR)HP2100L2-$(ARCH).OLB HP2100_SOURCE2 = $(HP2100_DIR)HP2100_FP1.C,$(HP2100_DIR)HP2100_BACI.C,\ - $(HP2100_DIR)HP2100_MPX.C,$(HP2100_DIR)HP2100_PIF.C \ + $(HP2100_DIR)HP2100_MPX.C,$(HP2100_DIR)HP2100_PIF.C,\ $(HP2100_DIR)HP2100_DI.C,$(HP2100_DIR)HP2100_DI_DA.C,\ $(HP2100_DIR)HP_DISCLIB.C .IFDEF ALPHA_OR_IA64 diff --git a/makefile b/makefile index 6ee1e4c4..615d45e3 100644 --- a/makefile +++ b/makefile @@ -32,13 +32,11 @@ # CC Command (and platform available options). (Poor man's autoconf) # # building the pdp11, or any vax simulator could use networking support +BUILD_SINGLE := $(MAKECMDGOALS) $(BLANK_SUFFIX) ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) NETWORK_USEFUL = true ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) BUILD_MULTIPLE = s - BUILD_SINGLE := $(MAKECMDGOALS) $(BUILD_SINGLE) - else - BUILD_SINGLE := $(MAKECMDGOALS) $(BUILD_SINGLE) endif else ifeq ($(MAKECMDGOALS),) @@ -210,8 +208,8 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) else $(error using libpcap: $(call find_lib,$(PCAPLIB)) missing pcap.h) endif - LIBEXT = $(LIBEXTSAVE) endif + LIBEXT = $(LIBEXTSAVE) endif ifneq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) # Given we have libpcap components, consider other network connections as well @@ -344,14 +342,16 @@ ifneq (3,$(GCC_MAJOR_VERSION)) CFLAGS_O += -Wno-unused-result endif endif -BUILD_FEATURES := $(BUILD_FEATURES). GCC Version: $(GCC_VERSION) -$(info ***) -$(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with:) -$(info *** $(BUILD_FEATURES).) -ifneq (,$(NETWORK_FEATURES)) - $(info *** $(NETWORK_FEATURES).) +ifeq (clean,$(MAKECMDGOALS)) + BUILD_FEATURES := $(BUILD_FEATURES). GCC Version: $(GCC_VERSION) + $(info ***) + $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with:) + $(info *** $(BUILD_FEATURES).) + ifneq (,$(NETWORK_FEATURES)) + $(info *** $(NETWORK_FEATURES).) + endif + $(info ***) endif -$(info ***) ifneq ($(DONT_USE_ROMS),) ROMS_OPT = -DDONT_USE_INTERNAL_ROM else diff --git a/scp.c b/scp.c index d9ebd0b6..54bcaf53 100644 --- a/scp.c +++ b/scp.c @@ -3987,6 +3987,8 @@ if (!initialized) { handle = dlopen("libreadline." __STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL); if (!handle) handle = dlopen("libreadline." __STR(HAVE_DLOPEN) ".6", RTLD_NOW|RTLD_GLOBAL); + if (!handle) + handle = dlopen("libreadline." __STR(HAVE_DLOPEN) ".5", RTLD_NOW|RTLD_GLOBAL); if (handle) { p_readline = dlsym(handle, "readline"); p_add_history = dlsym(handle, "add_history"); From 8cc2ef03c760cdc8e58ac554694fffed9c446b0f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 26 Mar 2012 04:59:46 -0700 Subject: [PATCH 035/112] Fixed regression in handling (ignoring) error conditions while processing simple do file. --- scp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scp.c b/scp.c index 54bcaf53..c79ea7e7 100644 --- a/scp.c +++ b/scp.c @@ -1018,10 +1018,11 @@ do { } if (*cptr == 0) /* ignore blank */ continue; - if (echo) /* echo if -v */ + if (echo) { /* echo if -v */ printf("do> %s\n", cptr); - if (echo && sim_log) - fprintf (sim_log, "do> %s\n", cptr); + if (sim_log) + fprintf (sim_log, "do> %s\n", cptr); + } if (*cptr == ':') /* ignore label */ continue; cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ @@ -1058,9 +1059,6 @@ do { stat = stat & ~SCPE_DOFAILED; /* remove possible flag */ } switch (stat) { - case SCPE_OK: - case SCPE_STEP: - break; case SCPE_AFAIL: staying = (sim_on_check[sim_do_depth] && /* if trap action defined */ sim_on_actions[sim_do_depth][stat]); /* use it, otherwise exit */ @@ -1068,8 +1066,10 @@ do { case SCPE_EXIT: staying = FALSE; break; + case SCPE_OK: + case SCPE_STEP: + break; default: - staying = sim_on_check[sim_do_depth]; break; } if ((staying || !interactive) && /* report error if staying */ From 0dd51850997f2e6100678c5b9a878be38b7c05a7 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 26 Mar 2012 11:53:06 -0700 Subject: [PATCH 036/112] Added VH device to the VAX780 --- VAX/vax780_defs.h | 10 ++++++++++ VAX/vax780_syslist.c | 2 ++ 2 files changed, 12 insertions(+) diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index b1308753..9e170172 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -281,6 +281,8 @@ typedef struct { #define IOLN_RQC 004 #define IOBA_RQD (IOPAGEBASE + IOBA_RQC + IOLN_RQC) #define IOLN_RQD 004 +#define IOBA_VH (IOPAGEBASE + 000440) /* DHU11 */ +#define IOLN_VH 020 #define IOBA_RQ (IOPAGEBASE + 012150) /* UDA50 */ #define IOLN_RQ 004 #define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */ @@ -328,6 +330,8 @@ typedef struct { #define INT_V_PTR 1 #define INT_V_PTP 2 #define INT_V_CR 3 +#define INT_V_VHRX 4 +#define INT_V_VHTX 5 #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) @@ -339,6 +343,8 @@ typedef struct { #define INT_RY (1u << INT_V_RY) #define INT_XU (1u << INT_V_XU) #define INT_LPT (1u << INT_V_LPT) +#define INT_VHRX (1u << INT_V_VHRX) +#define INT_VHTX (1u << INT_V_VHTX) #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) #define INT_CR (1u << INT_V_CR) @@ -356,6 +362,8 @@ typedef struct { #define IPL_PTR (0x14 - IPL_HMIN) #define IPL_PTP (0x14 - IPL_HMIN) #define IPL_CR (0x14 - IPL_HMIN) +#define IPL_VHRX (0x14 - IPL_HMIN) +#define IPL_VHTX (0x14 - IPL_HMIN) /* Device vectors */ @@ -376,6 +384,8 @@ typedef struct { #define VEC_RY 0264 #define VEC_DZRX 0300 #define VEC_DZTX 0304 +#define VEC_VHRX 0310 +#define VEC_VHTX 0314 /* Interrupt macros */ diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index aad58dbd..9025f616 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -52,6 +52,7 @@ extern DEVICE ts_dev; extern DEVICE tq_dev; extern DEVICE tu_dev; extern DEVICE dz_dev; +extern DEVICE vh_dev; extern DEVICE xu_dev, xub_dev; extern int32 sim_switches; @@ -74,6 +75,7 @@ DEVICE *sim_devices[] = { &tto_dev, &fl_dev, &dz_dev, + &vh_dev, &cr_dev, &lpt_dev, &rp_dev, From 7ea8831c7bf025fbf0ca297f5541453f60a3b190 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 26 Mar 2012 12:17:07 -0700 Subject: [PATCH 037/112] Added do command default file extension for file being opened of '.sim' --- scp.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/scp.c b/scp.c index c79ea7e7..bc450ea5 100644 --- a/scp.c +++ b/scp.c @@ -994,12 +994,15 @@ for (nargs = 0; nargs < 10; ) { /* extract arguments */ if ((nargs <= 0) || (do_arg [0] == NULL)) /* need at least 1 */ return SCPE_2FARG; if ((fpin = fopen (do_arg[0], "r")) == NULL) { /* file failed to open? */ - if (flag == 0) /* cmd line file? */ - fprintf (stderr, "Can't open file %s\n", do_arg[0]); - if (flag > 1) - return SCPE_OPENERR | SCPE_DOFAILED; /* return failure with flag */ - else - return SCPE_OPENERR; /* return failure */ + strcat (strcpy (cbuf, do_arg[0]), ".sim"); /* try again with .sim extension */ + if ((fpin = fopen (cbuf, "r")) == NULL) { /* failed a second time? */ + if (flag == 0) /* cmd line file? */ + fprintf (stderr, "Can't open file %s\n", do_arg[0]); + if (flag > 1) + return SCPE_OPENERR | SCPE_DOFAILED; /* return failure with flag */ + else + return SCPE_OPENERR; /* return failure */ + } } if (flag < 1) /* start at level 1 */ flag = 1; From 7e68046c59c8d54a5974d6f4dbb7f145278cc5fc Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 26 Mar 2012 12:17:30 -0700 Subject: [PATCH 038/112] Added VH to VAX780 Visual Studio Project --- Visual Studio Projects/VAX780.vcproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj index fdb15cc3..52c14deb 100644 --- a/Visual Studio Projects/VAX780.vcproj +++ b/Visual Studio Projects/VAX780.vcproj @@ -253,6 +253,10 @@ RelativePath="..\PDP11\pdp11_tu.c" > + + From 38bbdd2de94e71b53693d82cf6803f1e31b8e75e Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 29 Mar 2012 04:05:39 -0700 Subject: [PATCH 039/112] Added VH to the VAX780 build (makefile and descrip.mms) --- descrip.mms | 2 +- makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/descrip.mms b/descrip.mms index 8eaeab75..4c6310fe 100644 --- a/descrip.mms +++ b/descrip.mms @@ -608,7 +608,7 @@ VAX780_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_RY.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_TU.C,$(PDP11_DIR)PDP11_HK.C,\ - $(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_IO_LIB.C .IFDEF ALPHA_OR_IA64 VAX780_OPTIONS = /INCL=($(SIMH_DIR),$(VAX780_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS),"VAX_780=1") diff --git a/makefile b/makefile index 615d45e3..977376e1 100644 --- a/makefile +++ b/makefile @@ -446,7 +446,7 @@ VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c \ - ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_io_lib.c VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} From 9449c1fc3f42ac5842239043d0092a108558dfa7 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 29 Mar 2012 09:12:08 -0700 Subject: [PATCH 040/112] Restored announcing GCC version and build options lost in manual merge from v3.9-0-rc2 --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 977376e1..73ad35d0 100644 --- a/makefile +++ b/makefile @@ -342,7 +342,7 @@ ifneq (3,$(GCC_MAJOR_VERSION)) CFLAGS_O += -Wno-unused-result endif endif -ifeq (clean,$(MAKECMDGOALS)) +ifneq (clean,$(MAKECMDGOALS)) BUILD_FEATURES := $(BUILD_FEATURES). GCC Version: $(GCC_VERSION) $(info ***) $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with:) From 4a78242c6f56d2e8e76589a07f3b0da051a4d35f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 30 Mar 2012 10:58:01 -0700 Subject: [PATCH 041/112] Cleaner GCC options detection on older GCC versions on varioous platforms Added missing host NIC MAC address determination for VMS hosts --- makefile | 4 +-- sim_ether.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/makefile b/makefile index 73ad35d0..e10f058a 100644 --- a/makefile +++ b/makefile @@ -75,11 +75,11 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) INCPATH:=/usr/include LIBPATH:=/usr/lib OS_CCDEFS = -D_GNU_SOURCE + GCC_OPTIMIZERS_CMD = $(GCC) -v --help 2>&1 + GCC_WARNINGS_CMD = $(GCC) -v --help 2>&1 ifeq (Darwin,$(OSTYPE)) OSNAME = OSX LIBEXT = dylib - GCC_OPTIMIZERS_CMD = $(GCC) -v --help 2>&1 - GCC_WARNINGS_CMD = $(GCC) -v --help 2>&1 else ifeq (Linux,$(OSTYPE)) LIBPATH := $(sort $(foreach lib,$(shell /sbin/ldconfig -p | grep ' => /' | sed 's/^.* => //'),$(dir $(lib)))) diff --git a/sim_ether.c b/sim_ether.c index 0b4dcfec..c8278cfc 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -163,6 +163,7 @@ Modification history: + 30-Mar-12 MP Added host NIC address determination on supported VMS platforms 01-Mar-12 MP Made host NIC address determination on *nix platforms more robust. 01-Mar-12 MP Added host NIC address determination work when building @@ -1216,6 +1217,94 @@ static int pcap_mac_if_win32(char *AdapterName, unsigned char MACAddress[6]) #endif return ReturnValue; } +#endif /* defined(_WIN32) || defined(__CYGWIN__) */ + +#if defined (__VMS) && !defined(__VAX) +#include +#include +#include +#include +#include +#include +#include + +static int pcap_mac_if_vms(char *AdapterName, unsigned char MACAddress[6]) +{ + char VMS_Device[16]; + $DESCRIPTOR(Device, VMS_Device); + unsigned short iosb[4]; + unsigned short *w; + unsigned char *pha = NULL; + unsigned char *hwa = NULL; + int tmpval; + int status; + unsigned short characteristics[512]; + long chardesc[] = {sizeof(characteristics), (long)&characteristics}; + unsigned short chan; +#pragma member_alignment save +#pragma nomember_alignment + static struct { + short fmt; + long val_fmt; + short pty; + long val_pty; + short pad; + long val_pad; + } setup = { + NMA$C_PCLI_FMT, NMA$C_LINFM_ETH, + NMA$C_PCLI_PTY, 0x0090, + NMA$C_PCLI_PAD, NMA$C_STATE_OFF, + }; +#pragma member_alignment restore + long setupdesc[] = {sizeof(setup), (long)&setup}; + + /* Convert Interface Name to VMS Device Name */ + /* This is a name shuffle */ + /* WE0 becomes EWA0: */ + /* SE1 becomes ESB0: */ + /* XE0 becomes EXA0: */ + tmpval = (int)(AdapterName[2]-'0'); + if ((tmpval < 0) || (tmpval > 25)) + return -1; + VMS_Device[0] = toupper(AdapterName[1]); + VMS_Device[1] = toupper(AdapterName[0]); + VMS_Device[2] = 'A' + tmpval; + VMS_Device[3] = '0'; + VMS_Device[4] = '\0'; + VMS_Device[5] = '\0'; + Device.dsc$w_length = strlen(VMS_Device); + if (!$VMS_STATUS_SUCCESS( sys$assign (&Device, &chan, 0, 0, 0) )) + return -1; + status = sys$qiow (0, chan, IO$_SETMODE|IO$M_CTRL|IO$M_STARTUP, &iosb, 0, 0, + 0, &setupdesc, 0, 0, 0, 0); + if ((!$VMS_STATUS_SUCCESS(status)) || (!$VMS_STATUS_SUCCESS(iosb[0]))) { + sys$dassgn(chan); + return -1; + } + status = sys$qiow (0, chan, IO$_SENSEMODE|IO$M_CTRL, &iosb, 0, 0, + 0, &chardesc, 0, 0, 0, 0); + sys$dassgn(chan); + if ((!$VMS_STATUS_SUCCESS(status)) || (!$VMS_STATUS_SUCCESS(iosb[0]))) + return -1; + for (w=characteristics; w < &characteristics[iosb[1]]; ) { + if ((((*w)&0xFFF) == NMA$C_PCLI_HWA) && (6 == *(w+1))) + hwa = (unsigned char *)(w + 2); + if ((((*w)&0xFFF) == NMA$C_PCLI_PHA) && (6 == *(w+1))) + pha = (unsigned char *)(w + 2); + if (((*w)&0x1000) == 0) + w += 3; /* Skip over Longword Parameter */ + else + w += (2 + ((1 + *(w+1))/2)); /* Skip over String Parameter */ + } + if (pha != NULL) /* Prefer Physical Address */ + memcpy(MACAddress, pha, 6); + else + if (hwa != NULL) /* Fallback to Hardware Address */ + memcpy(MACAddress, hwa, 6); + else + return -1; + return 0; +} #endif static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname) @@ -1225,7 +1314,10 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname) #if defined(_WIN32) || defined(__CYGWIN__) if (!pcap_mac_if_win32(devname, dev->host_nic_phy_hw_addr)) dev->have_host_nic_phy_addr = 1; -#elif !defined (__VMS) && !defined(__CYGWIN__) +#elif defined (__VMS) && !defined(__VAX) + if (!pcap_mac_if_vms(devname, dev->host_nic_phy_hw_addr)) + dev->have_host_nic_phy_addr = 1; +#elif !defined(__CYGWIN__) && !defined(__VMS) if (1) { char command[1024]; FILE *f; From 6e6fdd02ae17a5d3f0bdf32583c572b7bca3f953 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 31 Mar 2012 14:43:59 -0700 Subject: [PATCH 042/112] Fixed VMS Build of DEBUG simulators --- descrip.mms | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/descrip.mms b/descrip.mms index 4c6310fe..b28a15bd 100644 --- a/descrip.mms +++ b/descrip.mms @@ -87,6 +87,7 @@ CC_DEBUG = /DEBUG .IFDEF DEBUG LINK_DEBUG = /DEBUG/TRACEBACK CC_OPTIMIZE = /NOOPTIMIZE +NEST_DEBUG = ,DEBUG=1 .IFDEF MMSALPHA ALPHA_OR_IA64 = 1 @@ -265,7 +266,7 @@ PCAP_SIMH_INC = /INCL=($(PCAP_DIR)) @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS]LIB.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS.LIB]BLD-$(ARCH).DIR").EQS."") THEN CREATE/DIRECTORY $(BLD_DIR) @ IF (F$SEARCH("$(BLD_DIR)*.*").NES."") THEN DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.*;* - @ IF (("$(BUILDING_ROMS)".EQS."").AND.(F$SEARCH("$(BIN_DIR)BuildROMs-$(ARCH).EXE").EQS."")) THEN $(MMS) BUILDROMS/MACRO=(BUILDING_ROMS=1) + @ IF (("$(BUILDING_ROMS)".EQS."").AND.(F$SEARCH("$(BIN_DIR)BuildROMs-$(ARCH).EXE").EQS."")) THEN $(MMS) BUILDROMS/MACRO=(BUILDING_ROMS=1$(NEST_DEBUG)) # MITS Altair Simulator Definitions. @@ -676,7 +677,7 @@ $(BIN_DIR)BuildROMs-$(ARCH).EXE : sim_BuildROMs.c $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)BUILDROMS-$(ARCH).EXE - $(BLD_DIR)SIM_BUILDROMS.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* - $ RUN $(BIN_DIR)BuildROMs-$(ARCH).EXE + $ RUN/NODEBUG $(BIN_DIR)BuildROMs-$(ARCH).EXE # # Build The Libraries. @@ -1030,7 +1031,7 @@ $(VAX_LIB1) : $(VAX_SOURCE1) $! $! Building The $(VAX_LIB1) Library. $! - $ RUN $(BIN_DIR)BuildROMs-$(ARCH).EXE + $ RUN/NODEBUG $(BIN_DIR)BuildROMs-$(ARCH).EXE $ $(CC)$(VAX_OPTIONS)/OBJ=$(VAX_DIR) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - @@ -1053,7 +1054,7 @@ $(VAX780_LIB1) : $(VAX780_SOURCE1) $! $! Building The $(VAX780_LIB1) Library. $! - $ RUN $(BIN_DIR)BuildROMs-$(ARCH).EXE + $ RUN/NODEBUG $(BIN_DIR)BuildROMs-$(ARCH).EXE $ $(CC)$(VAX780_OPTIONS)/OBJ=$(VAX780_DIR) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - From 7ac35575245845537f3f00478fce653a31a18b3c Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 2 Apr 2012 14:05:12 -0700 Subject: [PATCH 043/112] Fixed bug under Asynch I/O where I/O completion did not delay the appropriate time before passing back device status to a simulator. Found by Sergey Oboguev. --- 0readmeAsynchIO.txt | 10 ++++++++-- PDP11/pdp11_rp.c | 3 +-- PDP11/pdp11_rq.c | 9 ++++----- PDP11/pdp11_tq.c | 9 ++++----- sim_disk.c | 13 ++++++++----- sim_disk.h | 3 ++- sim_tape.c | 10 ++++++---- sim_tape.h | 2 +- 8 files changed, 34 insertions(+), 25 deletions(-) diff --git a/0readmeAsynchIO.txt b/0readmeAsynchIO.txt index 00f5b7c6..76af706d 100644 --- a/0readmeAsynchIO.txt +++ b/0readmeAsynchIO.txt @@ -89,7 +89,7 @@ example there now exists the routines: t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback); The Purpose of the callback function is to record the I/O completion status -and then to schedule the activation of the unit. +and then to schedule the activation of the unit. Considerations: Avoiding multiple concurrent users of the unit structure. While asynch @@ -108,7 +108,13 @@ The callback routine must save the I/O completion status in a place which the next invocation of the unit service routine will reference and act on it. This allows device code to return error conditions back to scp in a consistent way without regard to how the callback -routine (and the actual I/O) may have been executed. +routine (and the actual I/O) may have been executed. When the callback +routine is called, it will already be on the simulator event queue with +an event time which was specified when the unit was attached or via a +call to sim_disk_set_async. If no value has been specified then it +will have been scheduled with a delay time of 0. If a different event +firing time is desired, then the callback completion routine should +call sim_activate_abs to schedule the event at the appropriate time. Required change in device coding. Devices which wish to leverage the benefits of asynch I/O must rearrange diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index f3503cc7..2b8cfef6 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -782,7 +782,6 @@ void rp_io_complete (UNIT *uptr, t_stat status) { uptr->io_status = status; uptr->io_complete = 1; -sim_activate (uptr, 0); } /* Service unit timeout @@ -1030,7 +1029,7 @@ t_stat r; uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; r = sim_disk_attach (uptr, cptr, RP_NUMWD * sizeof (uint16), sizeof (uint16), TRUE, 0, - drv_tab[GET_DTYPE (uptr->flags)].name, drv_tab[GET_DTYPE (uptr->flags)].sect); + drv_tab[GET_DTYPE (uptr->flags)].name, drv_tab[GET_DTYPE (uptr->flags)].sect, 0); if (r != SCPE_OK) /* error? */ return r; drv = (int32) (uptr - rp_dev.units); /* get drv number */ diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index 716470fc..eca8a552 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -1800,10 +1800,9 @@ sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_io_complete(status=%d)\n", status); uptr->io_status = status; uptr->io_complete = 1; -if (elapsed > rq_xtime) - sim_activate (uptr, 0); -else - sim_activate (uptr, rq_xtime-elapsed); +/* Reschedule for the appropriate delay */ +if (elapsed <= rq_xtime) + sim_activate_abs (uptr, rq_xtime-elapsed); } /* Unit service for data transfer commands */ @@ -2487,7 +2486,7 @@ t_stat rq_attach (UNIT *uptr, char *cptr) MSC *cp = rq_ctxmap[uptr->cnum]; t_stat r; -r = sim_disk_attach (uptr, cptr, RQ_NUMBY, sizeof (uint16), (uptr->flags & UNIT_NOAUTO), DBG_DSK, drv_tab[GET_DTYPE (uptr->flags)].name, 0); +r = sim_disk_attach (uptr, cptr, RQ_NUMBY, sizeof (uint16), (uptr->flags & UNIT_NOAUTO), DBG_DSK, drv_tab[GET_DTYPE (uptr->flags)].name, 0, 0); if (r != SCPE_OK) return r; diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 6c02591e..30f49b12 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -1286,10 +1286,9 @@ sim_debug(DBG_TRC, &tq_dev, "tq_io_complete(status=%d)\n", status); res->io_status = status; res->io_complete = 1; -if (elapsed > tq_xtime) - sim_activate (uptr, 0); -else - sim_activate (uptr, tq_xtime-elapsed); +/* Reschedule for the appropriate delay */ +if (elapsed <= tq_xtime) + sim_activate_abs (uptr, tq_xtime-elapsed); } @@ -2025,7 +2024,7 @@ t_stat tq_attach (UNIT *uptr, char *cptr) { t_stat r; -r = sim_tape_attach_ex (uptr, cptr, DBG_TAP); +r = sim_tape_attach_ex (uptr, cptr, DBG_TAP, 0); if (r != SCPE_OK) return r; if (tq_csta == CST_UP) diff --git a/sim_disk.c b/sim_disk.c index 49a97a2b..32627227 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -733,9 +733,11 @@ static void _sim_disk_io_flush (UNIT *uptr) uint32 f = DK_GET_FMT (uptr); #if defined (SIM_ASYNCH_IO) +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + sim_disk_clr_async (uptr); if (sim_asynch_enabled) - sim_disk_set_async (uptr, 0); + sim_disk_set_async (uptr, ctx->asynch_io_latency); #endif switch (f) { /* case on format */ case DKUF_F_STD: /* Simh */ @@ -760,7 +762,8 @@ return stat; } -t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, uint32 dbit, const char *dtype, uint32 pdp11tracksize) +t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, + uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay) { struct disk_context *ctx; DEVICE *dptr; @@ -797,7 +800,7 @@ if (sim_switches & SWMASK ('D')) { /* create difference dis vhd = sim_vhd_disk_create_diff (gbuf, cptr); if (vhd) { sim_vhd_disk_close (vhd); - return sim_disk_attach (uptr, gbuf, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize); + return sim_disk_attach (uptr, gbuf, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize, completion_delay); } return SCPE_ARG; } @@ -816,7 +819,7 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop sim_switches |= SWMASK ('R') | SWMASK ('E'); sim_quiet = TRUE; /* First open the source of the copy operation */ - r = sim_disk_attach (uptr, cptr, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize); + r = sim_disk_attach (uptr, cptr, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize, completion_delay); sim_quiet = saved_sim_quiet; if (r != SCPE_OK) { sim_switches = saved_sim_switches; @@ -1013,7 +1016,7 @@ if (capac && (capac != (t_addr)-1)) uptr->capac = capac/ctx->capac_factor; #if defined (SIM_ASYNCH_IO) -sim_disk_set_async (uptr, 0); +sim_disk_set_async (uptr, completion_delay); #endif uptr->io_flush = _sim_disk_io_flush; diff --git a/sim_disk.h b/sim_disk.h index 3fa70e9d..b704604e 100644 --- a/sim_disk.h +++ b/sim_disk.h @@ -64,7 +64,8 @@ typedef void (*DISK_PCALLBACK)(UNIT *unit, t_stat status); /* Prototypes */ -t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, uint32 debugbit, const char *drivetype, uint32 pdp11_tracksize); +t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, + uint32 debugbit, const char *drivetype, uint32 pdp11_tracksize, int completion_delay); t_stat sim_disk_detach (UNIT *uptr); t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects); t_stat sim_disk_rdsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects, DISK_PCALLBACK callback); diff --git a/sim_tape.c b/sim_tape.c index d66d584b..2878c08e 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -367,9 +367,11 @@ return SCPE_OK; static void _sim_tape_io_flush (UNIT *uptr) { #if defined (SIM_ASYNCH_IO) +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + sim_tape_clr_async (uptr); if (sim_asynch_enabled) - sim_tape_set_async (uptr, 0); + sim_tape_set_async (uptr, ctx->asynch_io_latency); #endif fflush (uptr->fileref); } @@ -378,10 +380,10 @@ fflush (uptr->fileref); t_stat sim_tape_attach (UNIT *uptr, char *cptr) { -return sim_tape_attach_ex (uptr, cptr, 0); +return sim_tape_attach_ex (uptr, cptr, 0, 0); } -t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit) +t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit, int completion_delay) { struct tape_context *ctx; uint32 objc; @@ -429,7 +431,7 @@ ctx->dbit = dbit; /* save debug bit */ sim_tape_rewind (uptr); #if defined (SIM_ASYNCH_IO) -sim_tape_set_async (uptr, 0); +sim_tape_set_async (uptr, completion_delay); #endif uptr->io_flush = _sim_tape_io_flush; diff --git a/sim_tape.h b/sim_tape.h index 3d9f785e..3ce45ebd 100644 --- a/sim_tape.h +++ b/sim_tape.h @@ -121,7 +121,7 @@ typedef void (*TAPE_PCALLBACK)(UNIT *unit, t_stat status); /* Prototypes */ -t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit); +t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit, int completion_delay); t_stat sim_tape_attach (UNIT *uptr, char *cptr); t_stat sim_tape_detach (UNIT *uptr); t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max); From ab3af3062d3e5b4401a4537e6156d509293c9b1f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 4 Apr 2012 11:05:24 -0700 Subject: [PATCH 044/112] - Changed asynch queue insertion and removal to use a lock free algorithm based only on InterlockedCompareExchangePointer. We can now use this lock free approach on IA64 host systems as well. - Removed flawed logic which assumed that sim_interval was meaningful when referenced by an asynchronous thread. - Adjust the event_time of events removed from the asynch queue to account for the average time spent on the queue before the event was noticed by the instruction execution thread. - Added a sim_activate_notbefore function which specifies an rtime which is the earliest time the event should fire. - Changed the 'wakeup from idle' logic to force an immediate asynch queue check if the wakeup was not due to a timeout (i.e. it was due to an asynch queue insertion). - Fixed the descrip.mms to build asynchronous support on AXP and IA64 VMS with kernel threads enabled --- PDP11/pdp11_rq.c | 4 +- PDP11/pdp11_tq.c | 4 +- VAX/vax_cpu.c | 2 +- descrip.mms | 24 ++++++- scp.c | 30 ++++++++- scp.h | 1 + sim_defs.h | 168 ++++++++++++++++++++++++++--------------------- sim_timer.c | 5 +- 8 files changed, 149 insertions(+), 89 deletions(-) diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index eca8a552..130cea40 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -1794,15 +1794,13 @@ return 0; /* success! */ void rq_io_complete (UNIT *uptr, t_stat status) { MSC *cp = rq_ctxmap[uptr->cnum]; -int32 elapsed = sim_grtime()-uptr->iostarttime; sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_io_complete(status=%d)\n", status); uptr->io_status = status; uptr->io_complete = 1; /* Reschedule for the appropriate delay */ -if (elapsed <= rq_xtime) - sim_activate_abs (uptr, rq_xtime-elapsed); +sim_activate_notbefore (uptr, uptr->iostarttime+rq_xtime); } /* Unit service for data transfer commands */ diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 30f49b12..cd67ba9f 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -1280,15 +1280,13 @@ return ST_SUC; /* success! */ void tq_io_complete (UNIT *uptr, t_stat status) { struct tq_req_results *res = (struct tq_req_results *)uptr->results; -int32 elapsed = sim_grtime()-uptr->iostarttime; sim_debug(DBG_TRC, &tq_dev, "tq_io_complete(status=%d)\n", status); res->io_status = status; res->io_complete = 1; /* Reschedule for the appropriate delay */ -if (elapsed <= tq_xtime) - sim_activate_abs (uptr, tq_xtime-elapsed); +sim_activate_notbefore (uptr, uptr->iostarttime+tq_xtime); } diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 72ae874a..3c1c9140 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -626,7 +626,7 @@ for ( ;; ) { } fault_PC = PC; recqptr = 0; /* clr recovery q */ - AIO_CHECK_EVENT; + AIO_CHECK_EVENT; /* queue async events */ if (sim_interval <= 0) { /* chk clock queue */ temp = sim_process_event (); if (temp) diff --git a/descrip.mms b/descrip.mms index b28a15bd..e02bd0e3 100644 --- a/descrip.mms +++ b/descrip.mms @@ -85,7 +85,6 @@ CC_DEBUG = /DEBUG .IFDEF DEBUG -LINK_DEBUG = /DEBUG/TRACEBACK CC_OPTIMIZE = /NOOPTIMIZE NEST_DEBUG = ,DEBUG=1 @@ -95,27 +94,37 @@ CC_FLAGS = /PREF=ALL .IFDEF NOASYNCH ARCH = AXP-NOASYNCH-DBG CC_DEFS = "_LARGEFILE" +LINK_DEBUG = /DEBUG/TRACEBACK .ELSE ARCH = AXP-DBG CC_DEFS = "_LARGEFILE","SIM_ASYNCH_IO=1" +LINK_DEBUG = /DEBUG/TRACEBACK/THREADS_ENABLE .ENDIF .ENDIF .IFDEF MMSIA64 ALPHA_OR_IA64 = 1 CC_FLAGS = /PREF=ALL +.IFDEF NOASYNCH +ARCH = I64-NOASYNCH-DBG +CC_DEFS = "_LARGEFILE" +LINK_DEBUG = /DEBUG/TRACEBACK +.ELSE ARCH = I64-DBG CC_DEFS = "_LARGEFILE","SIM_ASYNCH_IO=1" +LINK_DEBUG = /DEBUG/TRACEBACK/THREADS_ENABLE +.ENDIF .ENDIF .IFDEF MMSVAX CC_FLAGS = $(CC_FLAGS) ARCH = VAX-DBG CC_DEFS = "__VAX" +LINK_DEBUG = /DEBUG/TRACEBACK .ENDIF .ELSE -LINK_DEBUG = /NODEBUG/NOTRACEBACK +# !DEBUG .IFDEF MMSALPHA ALPHA_OR_IA64 = 1 @@ -124,9 +133,11 @@ CC_FLAGS = /PREF=ALL .IFDEF NOASYNCH ARCH = AXP-NOASYNCH CC_DEFS = "_LARGEFILE" +LINK_DEBUG = /NODEBUG/NOTRACEBACK .ELSE ARCH = AXP CC_DEFS = "_LARGEFILE","SIM_ASYNCH_IO=1" +LINK_DEBUG = /NODEBUG/NOTRACEBACK/THREADS_ENABLE .ENDIF LINK_SECTION_BINDING = /SECTION_BINDING .ENDIF @@ -135,8 +146,15 @@ LINK_SECTION_BINDING = /SECTION_BINDING ALPHA_OR_IA64 = 1 CC_OPTIMIZE = /OPT=(LEV=5) CC_FLAGS = /PREF=ALL +.IFDEF NOASYNCH +ARCH = I64-NOASYNCH +CC_DEFS = "_LARGEFILE" +LINK_DEBUG = /NODEBUG/NOTRACEBACK +.ELSE ARCH = I64 CC_DEFS = "_LARGEFILE","SIM_ASYNCH_IO=1" +LINK_DEBUG = /NODEBUG/NOTRACEBACK/THREADS_ENABLE +.ENDIF .ENDIF .IFDEF MMSVAX @@ -144,10 +162,12 @@ CC_OPTIMIZE = /OPTIMIZE CC_FLAGS = $(CC_FLAGS) ARCH = VAX CC_DEFS = "__VAX" +LINK_DEBUG = /NODEBUG/NOTRACEBACK .ENDIF .ENDIF + # Define Our Compiler Flags & Define The Compile Command OUR_CC_FLAGS = $(CC_FLAGS)$(CC_DEBUG)$(CC_OPTIMIZE) \ /NEST=PRIMARY/NAME=(AS_IS,SHORT) diff --git a/scp.c b/scp.c index bc450ea5..779345c2 100644 --- a/scp.c +++ b/scp.c @@ -1961,17 +1961,17 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) { #if defined (SIM_ASYNCH_IO) pthread_mutex_lock (&sim_asynch_lock); fprintf (st, "asynchronous pending event queue\n"); -if (sim_asynch_queue == (void *)-1) +if (sim_asynch_queue == AIO_LIST_END) fprintf (st, "Empty\n"); else { - for (uptr = sim_asynch_queue; uptr != (void *)-1; uptr = uptr->a_next) { + for (uptr = sim_asynch_queue; uptr != AIO_LIST_END; uptr = uptr->a_next) { if ((dptr = find_dev_from_unit (uptr)) != NULL) { fprintf (st, " %s", sim_dname (dptr)); if (dptr->numunits > 1) fprintf (st, " unit %d", (int32) (uptr - dptr->units)); } else fprintf (st, " Unknown"); - fprintf (st, " event delay %d, queue time %d\n", uptr->a_event_time, uptr->a_sim_interval); + fprintf (st, " event delay %d\n", uptr->a_event_time); } } fprintf (st, "asynch latency: %d nanoseconds\n", sim_asynch_latency); @@ -4914,6 +4914,30 @@ sim_cancel (uptr); return sim_activate (uptr, event_time); } +/* sim_activate_notbefore - activate (queue) event even if event already scheduled + but not before the specified time + + Inputs: + uptr = pointer to unit + rtime = relative timeout + Outputs: + reason = result (SCPE_OK if ok) +*/ + +t_stat sim_activate_notbefore (UNIT *uptr, int32 rtime) +{ +uint32 rtimenow, urtime = (uint32)rtime; + +AIO_ACTIVATE (sim_activate_notbefore, uptr, rtime); +sim_cancel (uptr); +rtimenow = sim_grtime(); +sim_cancel (uptr); +if (0x80000000 <= urtime-rtimenow) + return sim_activate (uptr, 0); +else + return sim_activate (uptr, urtime-rtimenow); +} + /* sim_cancel - cancel (dequeue) event Inputs: diff --git a/scp.h b/scp.h index 4a50cffc..15902b4a 100644 --- a/scp.h +++ b/scp.h @@ -83,6 +83,7 @@ t_stat echo_cmd (int32 flag, char *ptr); t_stat sim_process_event (void); t_stat sim_activate (UNIT *uptr, int32 interval); t_stat sim_activate_abs (UNIT *uptr, int32 interval); +t_stat sim_activate_notbefore (UNIT *uptr, int32 rtime); t_stat sim_cancel (UNIT *uptr); int32 sim_is_active (UNIT *uptr); double sim_gtime (void); diff --git a/sim_defs.h b/sim_defs.h index 4df30c98..99dc596e 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -368,7 +368,6 @@ struct sim_unit { void (*a_check_completion)(struct sim_unit *); struct sim_unit *a_next; /* next asynch active */ int32 a_event_time; - int32 a_sim_interval; t_stat (*a_activate_call)(struct sim_unit *, int32); #endif }; @@ -564,35 +563,40 @@ extern pthread_mutex_t sim_asynch_lock; extern pthread_cond_t sim_asynch_wake; extern pthread_t sim_asynch_main_threadid; extern struct sim_unit *sim_asynch_queue; -extern t_bool sim_idle_wait; +extern volatile t_bool sim_idle_wait; extern t_bool sim_asynch_enabled; extern int32 sim_asynch_check; extern int32 sim_asynch_latency; extern int32 sim_asynch_inst_latency; +#define AIO_LIST_END ((void *)1) /* Chosen to deliberately not be a valid pointer (alignment) */ #define AIO_INIT \ if (1) { \ sim_asynch_main_threadid = pthread_self(); \ - /* Empty list/list end uses the point value (void *)-1. \ + /* Empty list/list end uses the point value (void *)1. \ This allows NULL in an entry's a_next pointer to \ indicate that the entry is not currently in any list */ \ - sim_asynch_queue = (void *)-1; \ + sim_asynch_queue = AIO_LIST_END; \ } #define AIO_CLEANUP \ if (1) { \ pthread_mutex_destroy(&sim_asynch_lock); \ pthread_cond_destroy(&sim_asynch_wake); \ } + +#if defined(__DECC_VER) +#include +#if defined(__IA64) +#define USE_AIO_INTRINSICS 1 +#endif +#endif #if defined(_WIN32) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) #define USE_AIO_INTRINSICS 1 #endif #ifdef USE_AIO_INTRINSICS /* This approach uses intrinsics to manage access to the link list head */ -/* sim_asynch_queue. However, once the list head state has been determined */ -/* a lock is used to manage the list update and entry removal. */ -/* This approach avoids the ABA issues with a completly lock free approach */ -/* since the ABA problem is very likely to happen with this use model, and */ -/* it avoids the lock overhead for the simple list head checking. */ +/* sim_asynch_queue. This implementation is a completely lock free design */ +/* which avoids the potential ABA issues. */ #ifdef _WIN32 #include #ifdef ERROR @@ -600,76 +604,90 @@ extern int32 sim_asynch_inst_latency; #endif /* ERROR */ #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) #define InterlockedCompareExchangePointer(Destination, Exchange, Comparand) __sync_val_compare_and_swap(Destination, Comparand, Exchange) -#define InterlockedExchangePointer(Destination, value) __sync_lock_test_and_set(Destination, value) +#elif defined(__DECC_VER) +#define InterlockedCompareExchangePointer(Destination, Exchange, Comparand) (void *)((int32)_InterlockedCompareExchange64_rel(Destination, Exchange, Comparand)) #else -#error "Implementation of functions InterlockedCompareExchangePointer() and InterlockedExchangePointer() are needed to build with USE_AIO_INTRINSICS" +#error "Implementation of function InterlockedCompareExchangePointer() is needed to build with USE_AIO_INTRINSICS" #endif #define AIO_QUEUE_VAL InterlockedCompareExchangePointer(&sim_asynch_queue, sim_asynch_queue, NULL) -#define AIO_QUEUE_SET(val) InterlockedExchangePointer(&sim_asynch_queue, val) +#define AIO_QUEUE_SET(val, queue) InterlockedCompareExchangePointer(&sim_asynch_queue, val, queue) #define AIO_UPDATE_QUEUE \ - if (1) { \ - UNIT *uptr; \ - if (AIO_QUEUE_VAL != (void *)-1) { \ - pthread_mutex_lock (&sim_asynch_lock); \ - while ((uptr = AIO_QUEUE_VAL) != (void *)-1) { \ - int32 a_event_time; \ - AIO_QUEUE_SET(uptr->a_next); \ - uptr->a_next = NULL; /* hygiene */ \ - a_event_time = uptr->a_event_time-(uptr->a_sim_interval-sim_interval); \ - if (a_event_time < 0) a_event_time = 0; \ - uptr->a_activate_call (uptr, a_event_time); \ - if (uptr->a_check_completion) { \ - pthread_mutex_unlock (&sim_asynch_lock); \ - uptr->a_check_completion (uptr); \ - pthread_mutex_lock (&sim_asynch_lock); \ - } \ - } \ - pthread_mutex_unlock (&sim_asynch_lock); \ + if (AIO_QUEUE_VAL != AIO_LIST_END) { /* List !Empty */ \ + UNIT *q, *uptr; \ + int32 a_event_time; \ + do \ + q = AIO_QUEUE_VAL; \ + while (q != AIO_QUEUE_SET(AIO_LIST_END, q)); \ + while (q != AIO_LIST_END) { /* List !Empty */ \ + uptr = q; \ + q = q->a_next; \ + uptr->a_next = NULL; /* hygiene */ \ + if (uptr->a_activate_call != &sim_activate_notbefore) { \ + a_event_time = uptr->a_event_time-((sim_asynch_inst_latency+1)/2); \ + if (a_event_time < 0) \ + a_event_time = 0; \ + } \ + else \ + a_event_time = uptr->a_event_time; \ + uptr->a_activate_call (uptr, a_event_time); \ + if (uptr->a_check_completion) \ + uptr->a_check_completion (uptr); \ } \ - sim_asynch_check = sim_asynch_inst_latency; \ - } -#define AIO_ACTIVATE(caller, uptr, event_time) \ - if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \ - pthread_mutex_lock (&sim_asynch_lock); \ - if (uptr->a_next) { \ - uptr->a_activate_call = sim_activate_abs; \ - } else { \ - uptr->a_next = AIO_QUEUE_VAL; \ - uptr->a_event_time = event_time; \ - uptr->a_sim_interval = sim_interval; \ - uptr->a_activate_call = caller; \ - AIO_QUEUE_SET(uptr); \ - } \ - if (sim_idle_wait) \ - pthread_cond_signal (&sim_asynch_wake); \ - pthread_mutex_unlock (&sim_asynch_lock); \ - return SCPE_OK; \ - } + } else 0 +#define AIO_ACTIVATE(caller, uptr, event_time) \ + if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \ + if (uptr->a_next) { \ + uptr->a_activate_call = sim_activate_abs; \ + } else { \ + UNIT *q, *qe; \ + uptr->a_event_time = event_time; \ + uptr->a_activate_call = sim_activate; \ + uptr->a_next = AIO_LIST_END; /* Mark as on list */ \ + do { \ + do \ + q = AIO_QUEUE_VAL; \ + while (q != AIO_QUEUE_SET(AIO_LIST_END, q));/* Grab current list */ \ + for (qe = uptr; qe->a_next != AIO_LIST_END; qe = qe->a_next); \ + qe->a_next = q; /* append current list */\ + do \ + q = AIO_QUEUE_VAL; \ + while (q != AIO_QUEUE_SET(uptr, q)); \ + uptr = q; \ + } while (uptr != AIO_LIST_END); \ + } \ + if (sim_idle_wait) \ + pthread_cond_signal (&sim_asynch_wake); \ + return SCPE_OK; \ + } else 0 #else /* !USE_AIO_INTRINSICS */ /* This approach uses a pthread mutex to manage access to the link list */ /* head sim_asynch_queue. It will always work, but may be slower than the */ -/* partially lock free approach when using USE_AIO_INTRINSICS */ -#define AIO_UPDATE_QUEUE \ - if (1) { \ - UNIT *uptr; \ - pthread_mutex_lock (&sim_asynch_lock); \ - while (sim_asynch_queue != (void *)-1) { /* List !Empty */ \ - int32 a_event_time; \ - uptr = sim_asynch_queue; \ - sim_asynch_queue = uptr->a_next; \ - uptr->a_next = NULL; \ - a_event_time = uptr->a_event_time-(uptr->a_sim_interval-sim_interval); \ - if (a_event_time < 0) a_event_time = 0; \ - uptr->a_activate_call (uptr, a_event_time); \ - if (uptr->a_check_completion) { \ - pthread_mutex_unlock (&sim_asynch_lock); \ - uptr->a_check_completion (uptr); \ - pthread_mutex_lock (&sim_asynch_lock); \ - } \ - } \ - pthread_mutex_unlock (&sim_asynch_lock); \ - sim_asynch_check = sim_asynch_inst_latency; \ - } +/* lock free approach when using USE_AIO_INTRINSICS */ +#define AIO_UPDATE_QUEUE \ + if (1) { \ + UNIT *uptr; \ + pthread_mutex_lock (&sim_asynch_lock); \ + while (sim_asynch_queue != AIO_LIST_END) { /* List !Empty */ \ + int32 a_event_time; \ + uptr = sim_asynch_queue; \ + sim_asynch_queue = uptr->a_next; \ + uptr->a_next = NULL; \ + if (uptr->a_activate_call != &sim_activate_notbefore) { \ + a_event_time = uptr->a_event_time-((sim_asynch_inst_latency+1)/2); \ + if (a_event_time < 0) \ + a_event_time = 0; \ + } \ + else \ + a_event_time = uptr->a_event_time; \ + uptr->a_activate_call (uptr, a_event_time); \ + if (uptr->a_check_completion) { \ + pthread_mutex_unlock (&sim_asynch_lock); \ + uptr->a_check_completion (uptr); \ + pthread_mutex_lock (&sim_asynch_lock); \ + } \ + } \ + pthread_mutex_unlock (&sim_asynch_lock); \ + } else 0 #define AIO_ACTIVATE(caller, uptr, event_time) \ if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \ pthread_mutex_lock (&sim_asynch_lock); \ @@ -678,7 +696,6 @@ extern int32 sim_asynch_inst_latency; } else { \ uptr->a_next = sim_asynch_queue; \ uptr->a_event_time = event_time; \ - uptr->a_sim_interval = sim_interval; \ uptr->a_activate_call = caller; \ sim_asynch_queue = uptr; \ } \ @@ -686,19 +703,20 @@ extern int32 sim_asynch_inst_latency; pthread_cond_signal (&sim_asynch_wake); \ pthread_mutex_unlock (&sim_asynch_lock); \ return SCPE_OK; \ - } + } else 0 #endif /* USE_AIO_INTRINSICS */ #define AIO_VALIDATE if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) abort() #define AIO_CHECK_EVENT \ if (0 > --sim_asynch_check) { \ AIO_UPDATE_QUEUE; \ - } + sim_asynch_check = sim_asynch_inst_latency; \ + } else 0 #define AIO_SET_INTERRUPT_LATENCY(instpersec) \ if (1) { \ sim_asynch_inst_latency = (int32)((((double)(instpersec))*sim_asynch_latency)/1000000000);\ if (sim_asynch_inst_latency == 0) \ sim_asynch_inst_latency = 1; \ - } + } else 0 #else /* !SIM_ASYNCH_IO */ #define AIO_UPDATE_QUEUE #define AIO_ACTIVATE(caller, uptr, event_time) diff --git a/sim_timer.c b/sim_timer.c index 89a6759d..20f47d0e 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -80,7 +80,7 @@ #include t_bool sim_idle_enab = FALSE; /* global flag */ -t_bool sim_idle_wait = FALSE; /* global flag */ +volatile t_bool sim_idle_wait = FALSE; /* global flag */ static uint32 sim_idle_rate_ms = 0; static uint32 sim_idle_stable = SIM_IDLE_STDFLT; @@ -457,7 +457,8 @@ if (done_time.tv_nsec > 1000000000) { } pthread_mutex_lock (&sim_asynch_lock); sim_idle_wait = TRUE; -pthread_cond_timedwait (&sim_asynch_wake, &sim_asynch_lock, &done_time); +if (!pthread_cond_timedwait (&sim_asynch_wake, &sim_asynch_lock, &done_time)) + sim_asynch_check = 0; /* force check of asynch queue now */ sim_idle_wait = FALSE; pthread_mutex_unlock (&sim_asynch_lock); return sim_os_msec() - start_time; From a14a1ab5cd87edc64d17947f84eeae023e474061 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 4 Apr 2012 11:08:56 -0700 Subject: [PATCH 045/112] Added missing synchronization when dispatching asynchronous calls. From Sergey Oboguev --- sim_tape.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sim_tape.c b/sim_tape.c index 2878c08e..8c4d7bce 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -151,6 +151,7 @@ if ((!callback) || !ctx->asynch_io) struct tape_context *ctx = \ (struct tape_context *)uptr->tape_ctx; \ \ + pthread_mutex_lock (&ctx->io_lock); \ \ sim_debug (ctx->dbit, ctx->dptr, \ "sim_tape AIO_CALL(op=%d, unit=%d)\n", op, uptr-ctx->dptr->units);\ @@ -168,6 +169,7 @@ if ((!callback) || !ctx->asynch_io) ctx->objupdate = _obj; \ ctx->callback = _callback; \ pthread_cond_signal (&ctx->io_cond); \ + pthread_mutex_unlock (&ctx->io_lock); \ } \ else \ if (_callback) \ From 40deb20ccd385b4deb34c5934c363c155fb08896 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 4 Apr 2012 12:31:43 -0700 Subject: [PATCH 046/112] HP2100 update from Dave Bryan --- 0readme_39.txt | 26 +- HP2100/hp2100_bugfixes.txt | 25 +- HP2100/hp2100_di.c | 664 ++++++++++++++++++------------------- HP2100/hp2100_di.h | 50 +-- HP2100/hp2100_di_da.c | 482 +++++++++++++-------------- HP2100/hp2100_diag.txt | 213 ++++++------ HP2100/hp2100_dp.c | 6 +- HP2100/hp2100_dq.c | 2 +- HP2100/hp2100_ds.c | 175 +++++----- HP2100/hp2100_mpx.c | 2 +- HP2100/hp2100_ms.c | 4 +- HP2100/hp2100_mt.c | 3 +- HP2100/hp2100_stddev.c | 4 +- HP2100/hp_disclib.c | 410 ++++++++++++----------- HP2100/hp_disclib.h | 43 +-- doc/hp2100_doc.doc | Bin 166400 -> 174592 bytes 16 files changed, 1087 insertions(+), 1022 deletions(-) diff --git a/0readme_39.txt b/0readme_39.txt index d5fb4b10..e5b3509e 100644 --- a/0readme_39.txt +++ b/0readme_39.txt @@ -2,7 +2,8 @@ Notes For V3.9 The makefile now works for all *nix platforms and with cygwin and MinGW32 -on Windows. +on Windows. It will automatically detect the availability of libpcap +components and build network capable simulators if they are available. 1. New Features @@ -14,15 +15,32 @@ on Windows. - added *nix READLINE support (Mark Pizzolato) - added "SHOW SHOW" and "SHOW SHOW" commands (Mark Pizzolato) - added support for BREAK key on Windows (Mark Pizzolato) - + - added ethernet support (Mark Pizzolato) + windows host <-> simulator NIC sharing + native tap interfaces on BSD, Linux and OSX + vde (Virtual Distributed Ethernet) networking + Large Send Offload support + UDP and TCP Checksum offload support + dynamic libpcap loading on *nix platforms 1.1.2 PDP-8 - floating point processor is now enabled - -1.1.3 IA64 VMS Ethernet Support + +1.1.3 HP2100 (Dave Bryan) + + - added support for 12821A HP-IB disk controller, + 7906H/20H/25H disks + +1.1.4 PDP11 and VAX (Mark Pizzolato) + + - Added DELQA-Plus device. + +1.1.5 IA64 VMS Ethernet Support - Identified compiler version issues and added IA64 support (Matt Burke) + +1.1.6 Visual Studio Projects (Mark Pizzolato) 2. Bugs Fixed diff --git a/HP2100/hp2100_bugfixes.txt b/HP2100/hp2100_bugfixes.txt index 90c3bd0f..80793696 100644 --- a/HP2100/hp2100_bugfixes.txt +++ b/HP2100/hp2100_bugfixes.txt @@ -1,6 +1,6 @@ HP 2100 SIMULATOR BUG FIX WRITEUPS ================================== - Last update: 2012-03-23 + Last update: 2012-03-25 1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756 @@ -6257,3 +6257,26 @@ 16-bit dimension count. STATUS: Fixed in version 3.9-0. + + + +246. PROBLEM: SHOW MTC SHOW lists the FORMAT modifier twice. + + VERSION: 3.8-1 + + OBSERVATION: Entering the planned SHOW MTC SHOW command results in the + following display: + + sim> SHOW MTC SHOW + sh{ow} MTC FORMAT, SC, DEVNO + sh{ow} MTCn FORMAT + + FORMAT is listed both as a device and as a unit modifier. + + CAUSE: The FORMAT entry in the modifier table contains both the MTAB_VDV + and the MTAB_VUN flags. + + RESOLUTION: Remove the redundant MTAB_VUN flag from the "mtc_mod" array + (hp2100_mt.c). + + STATUS: Fixed in version 3.9-0. diff --git a/HP2100/hp2100_di.c b/HP2100/hp2100_di.c index 4b790ff1..98cc4ef0 100644 --- a/HP2100/hp2100_di.c +++ b/HP2100/hp2100_di.c @@ -39,21 +39,21 @@ The 12821A was a high-speed implementation of the Hewlett-Packard Interface Bus (HP-IB, formalized as IEEE Std. 488-1978). It was used to interface HP-IB disc and tape devices, such as the HP 7906H, 7908A, and 7974A, to the - HP 1000 running RTE-IVB and RTE-6/VM. Three device command protocols were + HP 1000 running RTE-IVB or RTE-6/VM. Three device command protocols were supported by the I/O drivers: Amigo discs by driver DVA32, CS/80 discs by DVM33, and Amigo tapes by DVS23. In an RTE environment, the 12821A was the system controller. While electrically compatible with the HP-IB specification and capable of receiving addressing commands from the bus, the 12821A did not use the full IEEE-488 - protocol. Card talker and listener states were set by bits in a control + protocol. Card talker and listener states were set by bits in the control register, rather than by receiving talk and listen commands over the bus. The bus address of the card could be set via DIP switches, but this feature was only used by the diagnostic. The card supported packed and unpacked transfers across the bus. Up to four - devices could be connected to each card; the limit was imposed by the maximum - electrical loading on the bus compatible with the high data rate. + devices could be connected to each card; this limit was imposed by the + maximum electrical loading on the bus compatible with the high data rate. The 12821A had a 16-word FIFO buffer and could sustain DCPC transfers of one megabyte per second. Burst transfers by the CPU to fill or empty the FIFO @@ -69,15 +69,15 @@ The simulator is logically partitioned into three sets of functions: the interface card simulation, the HP-IB bus simulation, and the device simulation. This is the card simulation and the card portion of the HP-IB - simulation. Separate files for the tape and disc devices contain the device - simulations and the device portions of the HP-IB simulations. + simulation. Separate modules for the tape and disc devices contain the + device simulations and the device portions of the HP-IB simulations. - This simulation is written to allow the definition of multiple DI cards in a + This simulator is written to allow the definition of multiple DI cards in a system. The RTE operating system provided separate I/O drivers for the Amigo disc, Amigo tape, and CS/80 disc devices. As only one I/O driver could control a given interface, separate interfaces were required if more than one - device class was installed. For example, it was not possible to install an - Amigo disc and an Amigo tape on the same interface card. + device class was installed. For example, it was not possible to control an + Amigo disc and an Amigo tape connected to the same interface card. Implementation notes: @@ -92,7 +92,7 @@ to be the system controller. This cannot be changed by the user. 3. The simulator behaves as though card jumper W1 (DCPC pacing) is in - position B. This cannot be changed by the user. + position B. This currently cannot be changed by the user. */ @@ -119,7 +119,7 @@ /* Control Word Register */ #define CNTL_SRQ 0100000 /* enable service request interrupt */ -#define CNTL_IFC 0040000 /* assert IFC, enable IFC interrupt */ +#define CNTL_IFC 0040000 /* assert IFC or enable IFC interrupt */ #define CNTL_REN 0020000 /* assert remote enable */ #define CNTL_IRL 0010000 /* enable input-register-loaded interrupt */ #define CNTL_LBO 0004000 /* enable last-byte-out interrupt */ @@ -144,8 +144,8 @@ #define STAT_IRL 0010000 /* input register loaded */ #define STAT_LBO 0004000 /* last byte out */ #define STAT_LBI 0002000 /* last byte in */ -#define STAT_EOIBUS 0001000 /* end or identify */ -#define STAT_ATNBUS 0000400 /* attention */ +#define STAT_EOIBUS 0001000 /* end or identify bus state */ +#define STAT_ATNBUS 0000400 /* attention bus state */ #define STAT_IFC 0000200 /* interface clear seen */ #define STAT_ODD 0000020 /* odd number of bytes */ #define STAT_SYSCTL 0000010 /* system controller */ @@ -167,7 +167,7 @@ #define DATA_SHIFT 8 /* left shift count to align DATA_ATN, EOI with tag */ #define TAG_ATN 0000200000 /* bit 16: attention */ -#define TAG_EOI 0000400000 /* bit 17: end-or-identify */ +#define TAG_EOI 0000400000 /* bit 17: end or identify */ #define TAG_EDT 0001000000 /* bit 18: end of data transfer */ #define TAG_LBR 0002000000 /* bit 19: last byte received */ @@ -219,16 +219,16 @@ static void di_bus_poll (CARD_ID card); static void master_reset (CARD_ID card); static void update_state (CARD_ID card); -static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access); +static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access); static uint16 fifo_unload (CARD_ID card, FIFO_ACCESS access); -static void fprint_bus (FILE *file, char *format, uint8 cntl); +static void fprint_bus (FILE *file, char *format, uint8 cntl); /* Dummy DC device. - This dummy device allows the DI diagnostic to test inter-card signals. Test - 15 can only be performed if there are two DIs available. + This temporary dummy device allows the DI diagnostic to test inter-card + signals. Test 15 can only be performed if there are two DIs available. This device provides a second "bare" card. Normally, it is disabled and cannot be enabled by the user. Enabling or disabling DIAG mode on the DA @@ -331,28 +331,28 @@ DEBTAB di_deb [] = { written to the FIFO. The flip-flop is set by the EDT backplane signal when the last cycle of a DCPC transfer is executing, or during programmed output transfers when CLF does not accompany IOO in packed mode, or when bit 15 of - the data word is set in unpacked mode. It remains set until cleared by a - master reset. The output of the EDT flip-flop drives the EDT tag input of + the data word is set in unpacked mode. It remains set until it is cleared by + a master reset. The output of the EDT flip-flop drives the EDT tag input of the FIFO. The LBO signal indicates that the final data byte of a transfer has been sourced to the bus. The flip-flop is set when the last byte of the entry tagged with EDT has been unloaded from the FIFO. It is cleared by a master - reset, or when an entry not tagged with EDT is unloaded. The output of the + reset or when an entry not tagged with EDT is unloaded. The output of the LBO flip-flop drives the LBO bit in the Status Word. The LBI signal indicates that the final byte of an input transfer has been accepted from the bus. The flip-flop is set when a byte tagged with EOI is received and the EOI bit in the control register is set, or a line-feed byte is received and the LF bit in the control register is set. It is cleared by - a master reset, or when neither of these conditions is true. The input of - the LBI flip-flop also drives the LBR (last byte received) tag input of the - FIFO, and the output of the flip-flop drives the LBI bit in the Status Word. + a master reset or when neither of these conditions is true. The input of the + LBI flip-flop also drives the LBR (last byte received) tag input of the FIFO, + and the output of the flip-flop drives the LBI bit in the Status Word. The EOR signal indicates that the final data word of a transfer is available in the Input Data Register. The flip-flop is set when the last byte of the entry tagged with LBR has been unloaded from the FIFO and written to the IDR. - It is cleared by a master reset, or when an entry not tagged with LBR is + It is cleared by a master reset or when an entry not tagged with LBR is unloaded and written to the IDR. The output of the EOR flip-flop sets the flag flip-flop when the IDR is unloaded. @@ -367,21 +367,21 @@ DEBTAB di_deb [] = { 2. The DIAG, T, and L control bits enable a data loopback path on the card. An IOO issued to the card unloads a word from the FIFO and then loads the - lower byte into both bytes of the FIFO. The data word output with the - IOO instruction is not used. + lower byte back into both bytes of the FIFO. The data word output with + the IOO instruction is not used. In hardware, IOO triggers the FIFO unload and reload; T and L are - required only for the loopback path. If L is not asserted, the FIFO is - loaded with 177777 due to the floating bus. If L is asserted and T is - not, the FIFO is loaded with 000000 due to pullups on the DIO lines. + required only for the loopback path. If L is not asserted, then the FIFO + is loaded with 177777 due to the floating bus. If L is asserted and T is + not, then the FIFO is loaded with 000000 due to pullups on the DIO lines. In simulation, we look only for DIAG and assume that T/L are set properly, i.e., unloaded data is reloaded. 3. In hardware, the SRQ and NRFD lines are open-collector and may be driven simultaneously from several bus devices. Simulating this fully would - require keeping the state of the lines for each device, and deriving the - common bus signals from the logical AND/OR of the state values. - Fortunately, some simplifications are possible. + require keeping the state of the lines for each device and deriving the + common bus signals from the logical OR of the state values. Fortunately, + some simplifications are possible. The DI asserts SRQ only if control word bit 15 is 1 and bit 0 is 0. Other bit combinations deny SRQ; as neither the Amigo nor CS/80 protocols @@ -434,25 +434,25 @@ DI_STATE * const di_card = &di [card]; uint8 assert, deny; /* new bus control states */ uint16 data; -t_bool update_required = TRUE; /* TRUE if CLF must update card state */ +t_bool update_required = TRUE; /* TRUE if CLF must update the card state */ IOSIGNAL signal; IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ + signal = IONEXT (working_set); /* isolate the next signal */ - switch (signal) { /* dispatch I/O signal */ + switch (signal) { /* dispatch an I/O signal */ case ioCLF: /* clear flag flip-flop */ - di_card->flag = CLEAR; /* clear flag */ + di_card->flag = CLEAR; /* clear the flag */ di_card->flagbuf = CLEAR; /* and flag buffer */ if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) fprintf (sim_deb, ">>%s cmds: [CLF] Flag cleared\n", dptrs [card]->name); - if (update_required) /* if card state has changed */ + if (update_required) /* if the card state has changed */ update_state (card); /* then update the state */ break; @@ -465,7 +465,7 @@ while (working_set) { /* fall into ENF handler */ case ioENF: /* enable flag */ - di_card->flag = SET; /* set flag */ + di_card->flag = SET; /* set the flag */ di_card->flagbuf = SET; /* and flag buffer */ break; @@ -481,21 +481,21 @@ while (working_set) { case ioIOI: /* I/O data input */ - if (di_card->control == SET) { /* control set = data mode? */ - data = di_card->input_data_register; /* read input data register */ - di_card->status_register &= ~STAT_IRL; /* clear input register loaded status */ + if (di_card->control == SET) { /* is the card in data mode? */ + data = di_card->input_data_register; /* read the input data register */ + di_card->status_register &= ~STAT_IRL; /* clear the input register loaded status */ - if (FIFO_EMPTY && di_card->eor == CLEAR) { /* FIFO empty and end of record not seen? */ + if (FIFO_EMPTY && di_card->eor == CLEAR) { /* is the FIFO empty and end of record not seen? */ if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS)) fprintf (sim_deb, ">>%s cmds: SRQ cleared\n", dptrs [card]->name); di_card->srq = CLEAR; /* clear SRQ */ - update_required = FALSE; /* card state does not change */ + update_required = FALSE; /* the card state does not change */ } } - else { /* control clear = status mode */ + else { /* the card is in status mode */ di_card->status_register &= /* clear the values to be computed, */ STAT_IRL | STAT_LBO /* preserving those set elsewhere */ | STAT_LBI | STAT_IFC; @@ -505,14 +505,14 @@ while (working_set) { & (CNTL_CIC | CNTL_TALK | CNTL_LSTN); - if (SW8_SYSCTL) /* if SW8 set, card is system controller */ - di_card->status_register |= STAT_SYSCTL; + if (SW8_SYSCTL) /* if SW8 is set, */ + di_card->status_register |= STAT_SYSCTL; /* the card is the system controller */ if (di_card->ibp == lower) /* if lower byte input is next */ - di_card->status_register |= STAT_ODD; /* then last transfer was odd */ + di_card->status_register |= STAT_ODD; /* then the last transfer was odd */ - di_card->status_register |= /* set bus status bits */ - (di_card->bus_cntl /* from corresponding bus control lines */ + di_card->status_register |= /* set the bus status bits */ + (di_card->bus_cntl /* from the corresponding bus control lines */ & (BUS_SRQ | BUS_IFC | BUS_REN | BUS_EOI | BUS_ATN)) << DATA_SHIFT; @@ -524,10 +524,10 @@ while (working_set) { dptrs [card]->name, hold_or_clear, input_state [di_card->control], data); - if (update_required && !(signal_set & ioCLF)) /* if update and CLF not present, */ - update_state (card); /* update state, else ioCLF will update */ + if (update_required && !(signal_set & ioCLF)) /* if an update is required and CLF is not present, */ + update_state (card); /* update the state, else ioCLF will update it */ - stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + stat_data = IORETURN (SCPE_OK, data); /* merge in the return status */ break; @@ -539,26 +539,26 @@ while (working_set) { dptrs [card]->name, hold_or_clear, output_state [di_card->control], data); - if (di_card->control == SET) { /* control set = data mode */ + if (di_card->control == SET) { /* is the card in data mode? */ if (signal_set & ioEDT) /* if end of DCPC transfer */ - di_card->edt = SET; /* set EDT flip-flop */ + di_card->edt = SET; /* set the EDT flip-flop */ - else if (di_card->cntl_register & CNTL_PACK) { /* packed transfer? */ + else if (di_card->cntl_register & CNTL_PACK) { /* is this a packed transfer? */ if (!(signal_set & ioCLF)) /* and CLF not given? */ - di_card->edt = SET; /* set EDT flip-flop */ + di_card->edt = SET; /* set the EDT flip-flop */ } - else /* unpacked transfer */ - if (data & DATA_LBO) /* and last byte out? */ - di_card->edt = SET; /* set EDT flip-flop */ + else /* it's an unpacked transfer */ + if (data & DATA_LBO) /* is the last byte out? */ + di_card->edt = SET; /* set the EDT flip-flop */ - if (di_card->cntl_register & CNTL_DIAG) { /* DIAG loopback? */ - data = fifo_unload (card, diag_access); /* unload data from FIFO */ - fifo_load (card, data, diag_access); /* and load back in */ + if (di_card->cntl_register & CNTL_DIAG) { /* set for DIAG loopback? */ + data = fifo_unload (card, diag_access); /* unload data from the FIFO */ + fifo_load (card, data, diag_access); /* and load it back in */ } - else { /* normal mode */ - fifo_load (card, data, cpu_access); /* load data word into FIFO */ + else { /* the card is set for normal operation */ + fifo_load (card, data, cpu_access); /* load the data word into the FIFO */ if (FIFO_FULL && (di_card->bus_cntl & BUS_NRFD)) { /* FIFO full and listener not ready? */ if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS)) @@ -566,12 +566,12 @@ while (working_set) { dptrs [card]->name); di_card->srq = CLEAR; /* clear SRQ */ - update_required = FALSE; /* card state does not change */ + update_required = FALSE; /* the card state does not change */ } } } - else { /* control clear = write control word */ + else { /* the card is in control mode */ assert = 0; /* initialize bus control assertions */ deny = 0; /* and denials */ @@ -580,39 +580,39 @@ while (working_set) { if (data & CNTL_TALK) { /* talking enables ATN and EOI outputs */ if ((data & (CNTL_PPE | CNTL_CIC)) /* if parallel poll is enabled */ - == (CNTL_PPE | CNTL_CIC)) /* and card is CIC */ - assert = BUS_PPOLL; /* then conduct parallel poll */ + == (CNTL_PPE | CNTL_CIC)) /* and the card is CIC */ + assert = BUS_PPOLL; /* then conduct a parallel poll */ else if ((di_card->cntl_register /* if PP was enabled */ & (CNTL_PPE | CNTL_CIC)) /* but is not now */ == (CNTL_PPE | CNTL_CIC)) - deny = BUS_PPOLL; /* then end the parallel poll */ + deny = BUS_PPOLL; /* then end the parallel poll */ else if ((data /* if packed mode */ - & (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* and card is CIC */ - == (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* then ATN control output */ + & (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* and the card is CIC */ + == (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* then the ATN control output */ assert = BUS_ATN; /* is coupled to the bus */ else /* if none of the above */ - deny = BUS_ATN; /* ATN is not driven */ + deny = BUS_ATN; /* then ATN is not driven */ } - else /* not talking */ + else /* the card is not talking */ deny = BUS_ATN | BUS_EOI; /* so ATN and EOI are disabled */ - if (data & CNTL_NRFD) /* card not ready set explicitly? */ - assert |= BUS_NRFD; /* assert NRFD on bus */ + if (data & CNTL_NRFD) /* is card not ready set explicitly? */ + assert |= BUS_NRFD; /* assert NRFD on the bus */ else if (di_card->cntl_register & CNTL_NRFD) /* NRFD was set but is not now? */ - deny |= BUS_NRFD; /* deny NRFD on bus */ + deny |= BUS_NRFD; /* deny NRFD on the bus */ - if (FIFO_FULL) /* is FIFO full? */ + if (FIFO_FULL) /* is the FIFO full? */ if (data & CNTL_LSTN) /* is card now listening? */ - assert |= BUS_NRFD; /* listener and full FIFO asserts NRFD */ + assert |= BUS_NRFD; /* listener and a full FIFO asserts NRFD */ - else if (di_card->cntl_register & CNTL_LSTN) /* was listener but is not now? */ - deny |= BUS_NRFD; /* deny NRFD on bus */ + else if (di_card->cntl_register & CNTL_LSTN) /* was card a listener but is not now? */ + deny |= BUS_NRFD; /* deny NRFD on the bus */ if (SW8_SYSCTL) { /* system controller drives REN and IFC */ @@ -621,35 +621,35 @@ while (working_set) { else /* coupled to */ deny |= BUS_REN; /* the bus */ - if (data & CNTL_IFC) { /* IFC set? */ - assert |= BUS_IFC; /* assert IFC on bus */ + if (data & CNTL_IFC) { /* is IFC set? */ + assert |= BUS_IFC; /* assert IFC on the bus */ di_card->status_register = di_card->status_register & ~(STAT_LSTN | STAT_TALK) /* clear listen and talk status */ | STAT_IFC; /* and set IFC status */ - di_card->ifc_timer = /* start IFC timer by calculating */ - sim_gtime () + IFC_TIMEOUT; /* IFC stop time (100 microseconds) */ + di_card->ifc_timer = /* start the IFC timer by calculating */ + sim_gtime () + IFC_TIMEOUT; /* the IFC stop time (now + 100 microseconds) */ } } - if ((data & (CNTL_SRQ | CNTL_CIC)) == CNTL_SRQ) /* service request and not controller? */ - assert |= BUS_SRQ; /* assert SRQ on bus */ + if ((data & (CNTL_SRQ | CNTL_CIC)) == CNTL_SRQ) /* if service request and not the controller */ + assert |= BUS_SRQ; /* then assert SRQ on the bus */ else /* else */ - deny |= BUS_SRQ; /* deny SRQ on bus */ + deny |= BUS_SRQ; /* deny SRQ on the bus */ - di_card->cntl_register = data; /* save control word */ - di_bus_control (card, CONTROLLER, assert, deny); /* update bus control state */ + di_card->cntl_register = data; /* save the control word */ + di_bus_control (card, CONTROLLER, assert, deny); /* update the bus control state */ } - if (update_required && !(signal_set & ioCLF)) /* if update and CLF not present, */ - update_state (card); /* update state, else ioCLF will update */ + if (update_required && !(signal_set & ioCLF)) /* if update required and CLF is not present, */ + update_state (card); /* update the state, else ioCLF will update it */ break; case ioPOPIO: /* power-on preset to I/O */ - di_card->flag = SET; /* set flag */ + di_card->flag = SET; /* set the flag */ di_card->flagbuf = SET; /* and flag buffer */ if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) @@ -666,19 +666,19 @@ while (working_set) { di_card->status_register &= /* clear listen and talk status */ ~(STAT_LSTN | STAT_TALK); - deny = BUS_SRQ | BUS_REN | BUS_ATN | BUS_EOI; /* clear lines driven by control register */ + deny = BUS_SRQ | BUS_REN | BUS_ATN | BUS_EOI; /* clear the lines driven by the control register */ if (di_card->cntl_register & (CNTL_NRFD | CNTL_LSTN)) /* if asserting NRFD or listening */ - deny |= BUS_NRFD; /* deny because we're clearing */ + deny |= BUS_NRFD; /* then deny because we're clearing */ - di_card->cntl_register = 0; /* clear control word register */ + di_card->cntl_register = 0; /* clear the control word register */ di_card->control = CLEAR; /* clear control */ - di_card->srq = CLEAR; /* clear srq */ + di_card->srq = CLEAR; /* clear SRQ */ - master_reset (card); /* master reset */ + master_reset (card); /* perform a master reset */ - di_bus_control (card, CONTROLLER, 0, deny); /* update bus control state */ - update_state (card); /* update card state */ + di_bus_control (card, CONTROLLER, 0, deny); /* update the bus control state */ + update_state (card); /* update the card state */ break; @@ -689,14 +689,14 @@ while (working_set) { fprintf (sim_deb, ">>%s cmds: [CLC%s] Control cleared (configure mode)", dptrs [card]->name, hold_or_clear); - if (signal_set & ioCLF) /* if ioCLF given, */ - fputs (", master reset\n", sim_deb); /* then report master reset */ + if (signal_set & ioCLF) /* if ioCLF is given, */ + fputs (", master reset\n", sim_deb); /* then report a master reset */ else fputc ('\n', sim_deb); } - if (signal_set & ioCLF) /* if ioCLF given, */ - master_reset (card); /* then do master reset */ + if (signal_set & ioCLF) /* if ioCLF is given, */ + master_reset (card); /* then do a master reset */ break; /* (ioCLF will call update_state for us) */ @@ -717,16 +717,16 @@ while (working_set) { case ioSIR: /* set interrupt request */ - setstdPRL (di [card]); /* set standard PRL signal */ - setstdIRQ (di [card]); /* set standard IRQ signal */ + setstdPRL (di [card]); /* set the standard PRL signal */ + setstdIRQ (di [card]); /* set the standard IRQ signal */ - setSRQ (dibptr->select_code, /* set SRQ signal from control and SRQ */ + setSRQ (dibptr->select_code, /* set the SRQ signal if control and SRQ are set */ di_card->srq == SET && di_card->control == SET); break; case ioIAK: /* interrupt acknowledge */ - di_card->flagbuf = CLEAR; /* clear flag buffer */ + di_card->flagbuf = CLEAR; /* clear the flag buffer */ break; @@ -734,7 +734,7 @@ while (working_set) { break; /* are ignored */ } - working_set = working_set & ~signal; /* remove current signal from set */ + working_set = working_set & ~signal; /* remove the current signal from the set */ } return stat_data; @@ -745,7 +745,7 @@ return stat_data; During a hardware PRESET, POPIO sets the flag buffer and flag flip-flops, and CRS clears the control flip-flop and Control Word Register. In addition, CRS - asserts a master reset on the card. + performs a master reset on the card. PON is not used by the card. @@ -754,33 +754,33 @@ return stat_data; 1. During a power-on reset, a pointer to the FIFO simulation register is saved to allow access to the "qptr" field during FIFO loading and - unloading. This enables the SCP to view the FIFO as a circular queue, so + unloading. This enables SCP to view the FIFO as a circular queue, so that the bottom word of the FIFO is always displayed as FIFO[0], regardless of where it is in the actual FIFO array. */ t_stat di_reset (DEVICE *dptr) { -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ -const CARD_ID card = (CARD_ID) (dibptr->card_index); /* card number */ +DIB *dibptr = (DIB *) dptr->ctxt; /* get the DIB pointer */ +const CARD_ID card = (CARD_ID) (dibptr->card_index); /* get the card number */ -if (sim_switches & SWMASK ('P')) { /* power-on reset? */ +if (sim_switches & SWMASK ('P')) { /* is this a power-on reset? */ di [card].fifo_reg = find_reg ("FIFO", NULL, dptr); /* find the FIFO register entry */ - if (di [card].fifo_reg == NULL) /* not there? */ - return SCPE_IERR; /* is a programming error! */ + if (di [card].fifo_reg == NULL) /* if not there */ + return SCPE_IERR; /* then this is a programming error! */ else /* found it */ - di [card].fifo_reg->qptr = 0; /* reset the FIFO bottom index */ + di [card].fifo_reg->qptr = 0; /* so reset the FIFO bottom index */ di [card].status_register = 0; /* clear the status word */ di [card].bus_cntl = 0; /* deny the HP-IB control lines */ - di [card].listeners = 0; /* clear map of listeners */ - di [card].talker = 0; /* clear map of talker */ - di [card].poll_response = 0; /* clear map of parallel poll responses */ + di [card].listeners = 0; /* clear the map of listeners */ + di [card].talker = 0; /* clear the map of talker */ + di [card].poll_response = 0; /* clear the map of parallel poll responses */ - di [card].ifc_timer = 0.0; /* clear IFC timer */ + di [card].ifc_timer = 0.0; /* clear the IFC timer */ } IOPRESET (dibptr); /* PRESET the device */ @@ -814,9 +814,9 @@ return SCPE_OK; Also, an address cannot be set that duplicates the address of a disabled unit (which cannot be displayed without enabling it). - An alternate method would be to set the new assignments into a "shadow - array" that is set into the unit flags (and checked for validity) only - when a power-on reset is done. This does follow the disc and tape + An alternate implementation would be to set the new assignments into a + "shadow array" that is set into the unit flags (and checked for validity) + only when a power-on reset is done. This would follow the disc and tape controller hardware, which reads the HP-IB address switch settings only at power-up. */ @@ -828,19 +828,19 @@ uint32 index, new_address; uint32 old_address = GET_BUSADR (uptr->flags); DEVICE *dptr = (DEVICE *) desc; -if (cptr == NULL) /* if address not given */ +if (cptr == NULL) /* if the address is not given */ return SCPE_ARG; /* report a missing argument */ new_address = get_uint (cptr, 10, 7, &status); /* parse the address value */ -if (status == SCPE_OK) { /* parse OK? */ - if (value) /* setting the card address? */ - dptr->flags = dptr->flags & ~DEV_BUSADR /* store new address in the device flags */ +if (status == SCPE_OK) { /* is the parse OK? */ + if (value) /* are we setting the card address? */ + dptr->flags = dptr->flags & ~DEV_BUSADR /* store the new address in the device flags */ | SET_DIADR (new_address); - else { /* setting a unit address */ - for (index = 0; index < dptr->numunits; index++) /* look through units */ - if (new_address != old_address /* to ensure address is unique */ + else { /* we are setting a unit address */ + for (index = 0; index < dptr->numunits; index++) /* look through the units */ + if (new_address != old_address /* to ensure that the address is unique */ && new_address == GET_BUSADR (dptr->units [index].flags)) { printf ("Bus address conflict: DA%d\n", index); @@ -850,8 +850,8 @@ if (status == SCPE_OK) { /* parse OK? */ return SCPE_NOFNC; /* a duplicate address gives an error */ } - uptr->flags = uptr->flags & ~UNIT_BUSADR /* address is valid; change */ - | SET_BUSADR (new_address); /* the address in the unit flags */ + uptr->flags = uptr->flags & ~UNIT_BUSADR /* the address is valid; change it */ + | SET_BUSADR (new_address); /* in the unit flags */ } } @@ -869,10 +869,10 @@ t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc) { DEVICE *dptr = (DEVICE *) desc; -if (value) /* card address? */ - fprintf (st, "address=%d", GET_DIADR (dptr->flags)); /* get from device flags */ -else /* unit address */ - fprintf (st, "bus=%d", GET_BUSADR (uptr->flags)); /* get from unit flags */ +if (value) /* do we want the card address? */ + fprintf (st, "address=%d", GET_DIADR (dptr->flags)); /* get it from the device flags */ +else /* we want the unit address */ + fprintf (st, "bus=%d", GET_BUSADR (uptr->flags)); /* get it from the unit flags */ return SCPE_OK; } @@ -898,14 +898,14 @@ return SCPE_OK; t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc) { -if (value) { /* diagnostic cable selected? */ - ((DEVICE *) desc)->flags |= DEV_DIAG; /* set diagnostic flag */ - dc_dev.flags &= ~DEV_DIS; /* enable dummy device */ +if (value) { /* is the diagnostic cable selected? */ + ((DEVICE *) desc)->flags |= DEV_DIAG; /* set the diagnostic flag */ + dc_dev.flags &= ~DEV_DIS; /* enable the dummy device */ dc_dev.flags |= DEV_DIAG; /* and set its flag as well */ } -else { /* peripheral cable selected */ - ((DEVICE *) desc)->flags &= ~DEV_DIAG; /* clear diagnostic flag */ - dc_dev.flags |= DEV_DIS; /* disable dummy device */ +else { /* the peripheral cable is selected */ + ((DEVICE *) desc)->flags &= ~DEV_DIAG; /* clear the diagnostic flag */ + dc_dev.flags |= DEV_DIS; /* disable the dummy device */ dc_dev.flags &= ~DEV_DIAG; /* and clear its flag */ } @@ -921,9 +921,9 @@ return SCPE_OK; t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc) { -if (((DEVICE *) desc)->flags & DEV_DIAG) /* is cable connected for diagnostics? */ +if (((DEVICE *) desc)->flags & DEV_DIAG) /* is the cable connected for diagnostics? */ fputs ("diagnostic cable", st); /* report it */ -else /* cable is connected for normal use */ +else /* the cable is connected for device use */ fputs ("HP-IB cable", st); /* report the condition */ return SCPE_OK; @@ -936,13 +936,13 @@ return SCPE_OK; In hardware, the HP-IB bus consists of eight control lines and eight data lines. Signals are asserted on the control lines to establish communication between a source and one or more acceptors. For commands, the source is - always the controller (the 12821A card), and the acceptors are all connected - devices. For data, the source is the current talker, and the acceptors are - one or more current listeners. A three-wire interlocking handshake enables - communication at the rate of the slowest of the multiple acceptors. The - controller conducts a parallel poll by asserting ATN and EOI together. - Devices whose parallel poll responses are enabled each assert one of the data - lines to indicate that service is required. + always the controller (the 12821A card), and the acceptors are all of the + connected devices. For data, the source is the current talker, and the + acceptors are one or more current listeners. A three-wire interlocking + handshake enables communication at the rate of the slowest of the multiple + acceptors. The controller conducts a parallel poll by asserting ATN and EOI + together. Devices whose parallel poll responses are enabled each assert one + of the data lines to indicate that service is required. In simulation, a disabled or detached unit logically is not connected to the bus. The card maintains a bitmap of acceptors (all devices currently @@ -970,18 +970,18 @@ return SCPE_OK; listeners) and FALSE if it was not. Called by the controller to send commands to devices, and called by the current talker to send data to the listener(s). ATN - and EOI should be set as required in the control word - before calling. + and EOI should be asserted as required on the bus before + calling. *_bus_accept -- Accept a data byte from the bus. Returns TRUE if the byte was accepted and FALSE if it was not. Called by di_bus_source to handshake between source and acceptor. - If ATN is set in the control word, the byte is a - command; otherwise, it is data. If EOI is set for a - data byte, it is the last byte of a transmission. + If ATN is asserted on the bus, the byte is a command; + otherwise, it is data. If EOI is asserted for a data + byte, it is the last byte of a transmission. di_bus_control -- Set the control lines on the bus. Called by the system - controller to assert or deny REN or IFC, by the + controller to assert or deny REN or IFC, by the current controller to assert or deny SRQ, NRFD, or ATN and EOI (to conduct or conclude a parallel poll), and by the current listener to assert or deny NRFD. All connected @@ -1008,8 +1008,8 @@ return SCPE_OK; card is not in diagnostic mode, then the byte is sent to all acceptors (if a command) or to all listeners (if data) on the bus. - An indication is returned showing whether or not there were any acceptors on - the bus. + The return value indicates whether or not there were any acceptors on the + bus. Implementation notes: @@ -1032,29 +1032,29 @@ if (DEBUG_PRJ (dptrs [card], DEB_XFER)) { fprint_bus (sim_deb, "[%s]\n", di [card].bus_cntl); } -if (dptrs [card]->flags & DEV_DIAG) /* diagnostic run? */ - for (other = first_card; other <= last_card; other++) { /* look through list of cards */ +if (dptrs [card]->flags & DEV_DIAG) /* is this a diagnostic run? */ + for (other = first_card; other <= last_card; other++) { /* look through the list of cards */ if (other != card && dptrs [other] /* for the other card */ - && (dptrs [other]->flags & DEV_DIAG) /* that is configured for diagnostic */ + && (dptrs [other]->flags & DEV_DIAG) /* that is configured for diagnostic mode */ && (di [other].cntl_register & CNTL_LSTN)) /* and is listening */ - accepted = di_bus_accept (other, data); /* call interface acceptor for other card */ + accepted = di_bus_accept (other, data); /* call the interface acceptor for the other card */ } -else if ((di [card].bus_cntl & BUS_PPOLL) != BUS_PPOLL) { /* normal run; not a fake poll? */ - if (di [card].cntl_register & CNTL_LSTN) /* is card a listener? */ - accepted = di_bus_accept (card, data); /* call interface acceptor for this card */ +else if ((di [card].bus_cntl & BUS_PPOLL) != BUS_PPOLL) { /* this is a normal run; not a fake poll? */ + if (di [card].cntl_register & CNTL_LSTN) /* is the card a listener? */ + accepted = di_bus_accept (card, data); /* call the interface acceptor for this card */ - acceptors = di [card].acceptors; /* get map of acceptors */ + acceptors = di [card].acceptors; /* get the map of acceptors */ if (!(di [card].bus_cntl & BUS_ATN) /* if a data transfer, */ || (data & BUS_COMMAND) == BUS_ACG) /* or an addressed command, e.g., SDC */ acceptors = di [card].listeners; /* then limit just to listeners */ - for (unit = 0; acceptors; unit++) { /* loop through units */ - if (acceptors & 1) /* is current unit accepting? */ - accepted |= (*bus_accept [card]) (unit, data); /* call acceptor for this card */ + for (unit = 0; acceptors; unit++) { /* loop through the units */ + if (acceptors & 1) /* is the current unit accepting? */ + accepted |= (*bus_accept [card]) (unit, data); /* call the acceptor for this card */ - acceptors = acceptors >> 1; /* move to next acceptor */ + acceptors = acceptors >> 1; /* move to the next acceptor */ } } @@ -1114,13 +1114,13 @@ uint32 acceptors, responder; t_bool responded; uint8 new_state, new_assertions, new_denials; -new_state = di [card].bus_cntl & ~deny | assert; /* set up new control state */ +new_state = di [card].bus_cntl & ~deny | assert; /* set up the new control state */ -if (new_state == di [card].bus_cntl) /* if control state did not change */ +if (new_state == di [card].bus_cntl) /* if the control state did not change */ return; /* return now */ -new_assertions = ~di [card].bus_cntl & assert; /* get changing assertions */ -new_denials = di [card].bus_cntl & deny; /* get changing denials */ +new_assertions = ~di [card].bus_cntl & assert; /* get the changing assertions */ +new_denials = di [card].bus_cntl & deny; /* get the changing denials */ di [card].bus_cntl = new_state; /* establish the new control state */ @@ -1140,31 +1140,31 @@ if (DEBUG_PRJ (dptrs [card], DEB_XFER)) { fprint_bus (sim_deb, ", bus is [%s]\n", new_state); } -if ((dptrs [card]->flags & DEV_DIAG) /* diagnostic mode? */ - || (new_assertions & ASSERT_SET) /* or changed signals in the */ - || (new_denials & DENY_SET)) { /* set that must be broadcast? */ - responded = FALSE; /* assume no response */ +if ((dptrs [card]->flags & DEV_DIAG) /* is the card in diagnostic mode? */ + || (new_assertions & ASSERT_SET) /* or are changed signals in the */ + || (new_denials & DENY_SET)) { /* set that must be broadcast? */ + responded = FALSE; /* assume no response was received */ - if (dptrs [card]->flags & DEV_DIAG) { /* diagnostic run? */ - for (other = first_card; other <= last_card; other++) /* look through list of cards */ + if (dptrs [card]->flags & DEV_DIAG) { /* is this a diagnostic run? */ + for (other = first_card; other <= last_card; other++) /* look through the list of cards */ if (other != card && dptrs [other] /* for the other card */ - && (dptrs [other]->flags & DEV_DIAG)) { /* that is configured for diagnostic */ - di_bus_respond (other, new_state); /* notify other card of new control state */ + && (dptrs [other]->flags & DEV_DIAG)) { /* that is configured for diagnostic */ + di_bus_respond (other, new_state); /* notify the other card of the new control state */ responded = TRUE; /* and note that there was a responder */ } } - else { /* normal run */ - update_state (card); /* update card for new control state */ + else { /* this is a normal run */ + update_state (card); /* update the card for the new control state */ - acceptors = di [card].acceptors; /* get map of acceptors */ - responded = (acceptors != 0); /* set if there are any acceptors */ + acceptors = di [card].acceptors; /* get the map of acceptors */ + responded = (acceptors != 0); /* set response if there are any acceptors */ - for (responder = 0; acceptors; responder++) { /* loop through units */ - if ((acceptors & 1) && responder != unit) /* is current unit accepting? */ - (*bus_respond [card]) (card, responder, new_state); /* call responder for this card */ + for (responder = 0; acceptors; responder++) { /* loop the through units */ + if ((acceptors & 1) && responder != unit) /* is the current unit accepting? */ + (*bus_respond [card]) (card, responder, new_state); /* call the responder for this card */ - acceptors = acceptors >> 1; /* move to next acceptor */ + acceptors = acceptors >> 1; /* move to the next acceptor */ } } @@ -1173,7 +1173,7 @@ if ((dptrs [card]->flags & DEV_DIAG) /* diagnostic mo dptrs [card]->name); } -if ((new_state & BUS_PPOLL) == BUS_PPOLL) /* parallel poll requested? */ +if ((new_state & BUS_PPOLL) == BUS_PPOLL) /* was a parallel poll requested? */ di_bus_poll (card); /* conduct the poll */ return; @@ -1192,14 +1192,14 @@ void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response) const uint32 address = GET_BUSADR (dptrs [card]->units [unit].flags); uint32 previous_response = di [card].poll_response; -if (response == SET) { /* enable PPR? */ - di [card].poll_response |= PPR (address); /* set response bit */ +if (response == SET) { /* enable the poll response? */ + di [card].poll_response |= PPR (address); /* set the response bit */ - if ((di [card].bus_cntl & BUS_PPOLL) == BUS_PPOLL) /* is parallel poll in progress? */ - di_bus_poll (card); /* conduct with new response */ + if ((di [card].bus_cntl & BUS_PPOLL) == BUS_PPOLL) /* is a parallel poll in progress? */ + di_bus_poll (card); /* conduct again with the new response */ } -else /* disable PPR */ - di [card].poll_response &= ~PPR (address); /* clear response bit */ +else /* disable the poll response */ + di [card].poll_response &= ~PPR (address); /* by clearing the response bit */ if (DEBUG_PRJ (dptrs [card], DEB_XFER) && previous_response != di [card].poll_response) @@ -1218,11 +1218,11 @@ return; A controller asserting ATN and EOI simultaneously on the bus is conducting a parallel poll. In hardware, each device whose poll response is enabled - asserts one of the data lines corresponding to its bus address. The - controller terminates the poll by denying ATN and EOI. + asserts the data line corresponding to its bus address. The controller + terminates the poll by denying ATN and EOI. Setting the CIC (controller in charge) and PPE (parallel poll enable) bits in - the Control Word Register directs the disc interface to conduct a poll. + the Control Word Register direct the disc interface to conduct a poll. Setting PPE without CIC enables the poll response for the interface. In the diagnostic mode, one card is set to conduct the poll, and the other is @@ -1243,30 +1243,30 @@ CARD_ID other; uint8 response; if ((di [card].cntl_register - & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) /* card poll response enabled? */ - response = di [card].poll_response /* add card's response */ + & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) /* is the card's poll response enabled? */ + response = di [card].poll_response /* add the card's response */ | PPR (GET_DIADR (dptrs [card]->flags)); /* to the devices' responses */ else - response = di [card].poll_response; /* card disabled, so just use devices */ + response = di [card].poll_response; /* the card response is disabled, so just use devices */ -if (dptrs [card]->flags & DEV_DIAG) /* diagnostic run? */ - for (other = first_card; other <= last_card; other++) /* look through list of cards */ +if (dptrs [card]->flags & DEV_DIAG) /* is this a diagnostic run? */ + for (other = first_card; other <= last_card; other++) /* look through the list of cards */ if (other != card && dptrs [other] /* for another card */ - && (dptrs [other]->flags & DEV_DIAG) /* that is configured for diagnostic */ - && (di [other].cntl_register /* and has PPE asserted */ + && (dptrs [other]->flags & DEV_DIAG) /* that is configured for the diagnostic */ + && (di [other].cntl_register /* and has PPE asserted */ & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) response |= /* merge its poll response */ PPR (GET_DIADR (dptrs [other]->flags)); -if (response) { /* poll response indicated? */ +if (response) { /* is a poll response indicated? */ if (DEBUG_PRJ (dptrs [card], DEB_XFER)) fprintf (sim_deb, ">>%s xfer: HP-IB parallel poll DIO %03o\n", dptrs [card]->name, response); - while (di [card].fifo_count != FIFO_SIZE) /* fill card FIFO with responses */ + while (di [card].fifo_count != FIFO_SIZE) /* fill the card FIFO with the responses */ fifo_load (card, (uint16) response, diag_access); /* (hardware feature) */ - update_state (card); /* update card state */ + update_state (card); /* update the card state */ } return; @@ -1278,7 +1278,7 @@ return; The indicated card accepts a byte that has been sourced to the bus. The byte is loaded into the FIFO, and the card state is updated to reflect the load. - Bus acceptors return TRUE to indicate if the byte was accepted. A card + Bus acceptors return TRUE to indicate that the byte was accepted. A card always accepts a byte, so the routine always returns TRUE. */ @@ -1288,9 +1288,9 @@ if (DEBUG_PRJ (dptrs [card], DEB_XFER)) fprintf (sim_deb, ">>%s xfer: HP-IB card %d accepted data %03o \n", dptrs [card]->name, card, data); -fifo_load (card, data, bus_access); /* load data byte into the FIFO */ +fifo_load (card, data, bus_access); /* load the data byte into the FIFO */ update_state (card); /* and update the card state */ -return TRUE; /* indicate the byte was accepted */ +return TRUE; /* indicate that the byte was accepted */ } @@ -1303,8 +1303,8 @@ return TRUE; /* indicate the byte was static void di_bus_respond (CARD_ID card, uint8 new_cntl) { -di [card].bus_cntl = new_cntl; /* update bus control */ -update_state (card); /* update card state */ +di [card].bus_cntl = new_cntl; /* update the bus control lines */ +update_state (card); /* update the card state */ return; } @@ -1320,11 +1320,11 @@ return; The primary use, other than during a PRESET, is to clear the FIFO in preparation to changing the card from a listener to a talker or vice versa. This ensures that unneeded FIFO data is not transmitted inadvertently to the - bus or the CPU. It is also used when changing the data mode from unpacked to - packed to release the byte pointer flip-flops, which are held in the "lower - byte" position during unpacked transfers. + bus or to the CPU. It is also used when changing the data mode from unpacked + to packed to release the byte pointer flip-flops, which are held in the + "lower byte" position during unpacked transfers. - In hardware, master reset: + In hardware, a master reset: - clears the EDT, EOR, IRL, LBO, LBI, and IFC flip-flops - clears the Input Data Register - clears the FIFO @@ -1339,11 +1339,11 @@ di [card].edt = CLEAR; /* clear the EDT flip-fl di [card].eor = CLEAR; /* clear the EOR flip-flop */ if (di [card].cntl_register & CNTL_PACK) /* if packed mode is set, */ - di [card].ibp = di [card].obp = upper; /* MR sets selectors to the upper byte */ + di [card].ibp = di [card].obp = upper; /* MR sets the selectors to the upper byte */ else /* otherwise, unpacked mode overrides */ di [card].ibp = di [card].obp = lower; /* and sets the selectors to the lower byte */ -di [card].status_register &= /* clear status flip-flops */ +di [card].status_register &= /* clear the status flip-flops */ ~(STAT_IRL | STAT_LBO | STAT_LBI | STAT_IFC); di [card].input_data_register = 0; /* clear the input data register */ @@ -1368,31 +1368,31 @@ return; In simulation, this routine must be called whenever the FIFO, card control, or bus control state changes. It determines whether: - 1. the next word from the FIFO should be unloaded into the IDR. If the card - is listening, and the IDR is empty, and the FIFO contains data, then a - word is unloaded and stored in the IDR, and the Input Register Loaded + 1. ...the next word from the FIFO should be unloaded into the IDR. If the + card is listening, and the IDR is empty, and the FIFO contains data, then + a word is unloaded and stored in the IDR, and the Input Register Loaded status bit is set. - 2. the next word from the FIFO should be unloaded and sourced to the bus. + 2. ...the next word from the FIFO should be unloaded and sourced to the bus. If the card is talking (but not polling), and the listener is ready to accept data, and the last byte has not been sent, and the FIFO contains data, then a word is unloaded and sourced to the bus. This occurs regardless of whether or not there are any listeners. - 3. an interface clear operation has completed. If IFC is asserted, and the - current simulation time is later than the IFC expiration time, then IFC - is denied, and the timer is reset. + 3. ...an interface clear operation has completed. If IFC is asserted, and + the current simulation time is later than the IFC expiration time, then + IFC is denied, and the timer is reset. - 4. the card should assert NRFD to prevent FIFO overflow. If the card is + 4. ...the card should assert NRFD to prevent FIFO overflow. If the card is listening, and the FIFO is full, or the last byte has been received, or a pause has been explicitly requested, then NRFD is asserted. - 5. the SRQ flip-flop should be set or cleared. If the card is listening and - the Input Data Register has been loaded, or the card is talking and the - FIFO is not full, then SRQ is asserted to request a DCPC transfer. + 5. ...the SRQ flip-flop should be set or cleared. If the card is listening + and the Input Data Register has been loaded, or the card is talking and + the FIFO is not full, then SRQ is asserted to request a DCPC transfer. - 6. the flag flip-flop should be set or cleared. If the Input Data Register - has been loaded or the Last Byte Out flip-flop is set and the + 6. ...the flag flip-flop should be set or cleared. If the Input Data + Register has been loaded or the Last Byte Out flip-flop is set and the corresponding Control Word Register IRL or LBO bits are set, or the End of Record flip-flop is set and the Input Data Register has been unloaded, or SRQ is asserted on the bus and the corresponding Control Word Register @@ -1424,55 +1424,55 @@ uint8 deny = 0; uint16 data; FLIP_FLOP previous_state; -if (di_card->cntl_register & CNTL_LSTN) { /* is card a listener? */ - if (!(di_card->status_register & STAT_IRL) /* is IDR empty? */ - && ! FIFO_EMPTY) { /* and more in FIFO? */ - data = fifo_unload (card, cpu_access); /* unload FIFO */ - di_card->input_data_register = data; /* into IDR */ - di_card->status_register |= STAT_IRL; /* set input register loaded status */ +if (di_card->cntl_register & CNTL_LSTN) { /* is the card a listener? */ + if (!(di_card->status_register & STAT_IRL) /* is the IDR empty? */ + && ! FIFO_EMPTY) { /* and data remains in the FIFO? */ + data = fifo_unload (card, cpu_access); /* unload the FIFO */ + di_card->input_data_register = data; /* into the IDR */ + di_card->status_register |= STAT_IRL; /* set the input register loaded status */ } } -else if ((di_card->cntl_register /* is card a talker? */ +else if ((di_card->cntl_register /* is the card a talker? */ & (CNTL_TALK | CNTL_PPE)) == CNTL_TALK) /* and not polling? */ while (! FIFO_EMPTY /* is data remaining in FIFO? */ - && !(di_card->bus_cntl & BUS_NRFD) /* and NRFD denied? */ - && !(di_card->status_register & STAT_LBO)) { /* and last byte not sent? */ - data = fifo_unload (card, bus_access); /* unload FIFO byte */ - di_bus_source (card, (uint8) data); /* source it to bus */ + && !(di_card->bus_cntl & BUS_NRFD) /* and NRFD is denied? */ + && !(di_card->status_register & STAT_LBO)) { /* and the last byte has not been sent? */ + data = fifo_unload (card, bus_access); /* unload a FIFO byte */ + di_bus_source (card, (uint8) data); /* source it to the bus */ } -if (di_card->bus_cntl & BUS_IFC /* IFC in progress? */ +if (di_card->bus_cntl & BUS_IFC /* is an IFC in progress? */ && di_card->ifc_timer != 0.0 /* and I am timing? */ - && sim_gtime () > di_card->ifc_timer) { /* and timeout has elapsed? */ - deny = BUS_IFC; /* deny IFC on bus */ - di_card->ifc_timer = 0.0; /* clear IFC timer */ - di_card->status_register &= ~STAT_IFC; /* clear IFC status */ + && sim_gtime () > di_card->ifc_timer) { /* and has the timeout elapsed? */ + deny = BUS_IFC; /* deny IFC on the bus */ + di_card->ifc_timer = 0.0; /* clear the IFC timer */ + di_card->status_register &= ~STAT_IFC; /* and clear IFC status */ } -if (di_card->cntl_register & CNTL_LSTN) /* is card a listener? */ +if (di_card->cntl_register & CNTL_LSTN) /* is the card a listener? */ if (di_card->cntl_register & CNTL_NRFD /* if explicitly requested */ - || di_card->status_register & STAT_LBI /* or last byte is in */ - || FIFO_FULL) /* or FIFO is full */ + || di_card->status_register & STAT_LBI /* or the last byte is in */ + || FIFO_FULL) /* or the FIFO is full */ assert = BUS_NRFD; /* then assert NRFD */ - else /* otherwise card is ready for data */ + else /* otherwise the card is ready for data */ deny |= BUS_NRFD; /* so deny NRFD */ -if (assert != deny) /* any change in bus state? */ - di_bus_control (card, CONTROLLER, assert, deny); /* update bus control */ +if (assert != deny) /* was there any change in bus state? */ + di_bus_control (card, CONTROLLER, assert, deny); /* update the bus control */ -previous_state = di_card->srq; /* save current SRQ state */ +previous_state = di_card->srq; /* save the current SRQ state */ -if (di_card->cntl_register & CNTL_LSTN /* if card is a listener */ - && di_card->status_register & STAT_IRL /* and input register is loaded, */ - || di_card->cntl_register & CNTL_TALK /* or card is a talker */ - && ! FIFO_FULL) /* and FIFO is not full */ +if (di_card->cntl_register & CNTL_LSTN /* if the card is a listener */ + && di_card->status_register & STAT_IRL /* and the input register is loaded, */ + || di_card->cntl_register & CNTL_TALK /* or the card is a talker */ + && ! FIFO_FULL) /* and the FIFO is not full */ di_card->srq = SET; /* then request a DCPC cycle */ else - di_card->srq = CLEAR; /* else DCPC service is not needed */ + di_card->srq = CLEAR; /* otherwise, DCPC service is not needed */ if (DEBUG_PRJ (dptrs [card], DEB_CMDS) @@ -1481,27 +1481,27 @@ if (DEBUG_PRJ (dptrs [card], DEB_CMDS) dptrs [card]->name, di_card->srq == SET ? "set" : "cleared"); -if (di_card->status_register & STAT_IRL /* input register loaded */ - && di_card->cntl_register & CNTL_IRL /* and notification wanted? */ - || di_card->status_register & STAT_LBO /* or last byte out */ - && di_card->cntl_register & CNTL_LBO /* and notification wanted? */ - || di_card->eor == SET /* or end of record seen */ - && !(di_card->status_register & STAT_IRL) /* and input register unloaded? */ - || di_card->bus_cntl & BUS_SRQ /* or SRQ is asserted on the bus */ - && di_card->cntl_register & CNTL_SRQ /* and notification wanted */ - && di_card->cntl_register & CNTL_CIC /* and card is not controller? */ - || !SW8_SYSCTL /* or card is not system controller */ +if (di_card->status_register & STAT_IRL /* is the input register loaded */ + && di_card->cntl_register & CNTL_IRL /* and notification is wanted? */ + || di_card->status_register & STAT_LBO /* or is the last byte out */ + && di_card->cntl_register & CNTL_LBO /* and notification is wanted? */ + || di_card->eor == SET /* or was the end of record seen */ + && !(di_card->status_register & STAT_IRL) /* and the input register was unloaded? */ + || di_card->bus_cntl & BUS_SRQ /* or is SRQ asserted on the bus */ + && di_card->cntl_register & CNTL_SRQ /* and notification is wanted */ + && di_card->cntl_register & CNTL_CIC /* and the card is not controller? */ + || !SW8_SYSCTL /* or is the card not the system controller */ && di_card->bus_cntl & BUS_REN /* and REN is asserted on the bus */ - && di_card->cntl_register & CNTL_REN /* and notification wanted? */ - || !SW8_SYSCTL /* or card is not system controller */ + && di_card->cntl_register & CNTL_REN /* and notification is wanted? */ + || !SW8_SYSCTL /* or is the card not the system controller */ && di_card->status_register & STAT_IFC /* and IFC is asserted on the bus */ - && di_card->cntl_register & CNTL_IFC) { /* and notification wanted? */ + && di_card->cntl_register & CNTL_IFC) { /* and notification is wanted? */ if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) fprintf (sim_deb, ">>%s cmds: Flag set\n", dptrs [card]->name); - di_io (dibptr, ioENF, 0); /* set flag and recalculate interrupts */ + di_io (dibptr, ioENF, 0); /* set the flag and recalculate interrupts */ } else if (di_card->srq != previous_state) /* if SRQ changed state, */ @@ -1610,70 +1610,70 @@ if (FIFO_FULL) { /* is the FIFO already f fprintf (sim_deb, ">>%s buf: Attempted load to full FIFO, data %0*o\n", dptrs [card]->name, (access == bus_access ? 3 : 6), data); - return; /* return with load ignored */ + return; /* return with the load ignored */ } -if (di_card->cntl_register & CNTL_LSTN) { /* is card receiving? */ - tag = (di_card->bus_cntl /* set tag from bus signals */ - & (BUS_ATN | BUS_EOI)) << BUS_SHIFT; /* shifted to tag locations */ +if (di_card->cntl_register & CNTL_LSTN) { /* is the card receiving? */ + tag = (di_card->bus_cntl /* set the tag from the bus signals */ + & (BUS_ATN | BUS_EOI)) << BUS_SHIFT; /* shifted to the tag locations */ - if ((di_card->cntl_register & CNTL_EOI /* EOI detection enabled, */ + if ((di_card->cntl_register & CNTL_EOI /* EOI detection is enabled, */ && di_card->bus_cntl & BUS_EOI) /* and data was tagged with EOI? */ - || (di_card->cntl_register & CNTL_LF /* or LF detection enabled, */ - && GET_LOWER (data) == LF)) { /* and byte is a line feed? */ - tag = tag | TAG_LBR; /* tag as last byte received */ - di_card->status_register |= STAT_LBI; /* set last byte in status */ + || (di_card->cntl_register & CNTL_LF /* or LF detection is enabled, */ + && GET_LOWER (data) == LF)) { /* and the byte is a line feed? */ + tag = tag | TAG_LBR; /* tag as the last byte received */ + di_card->status_register |= STAT_LBI; /* set the last byte in status */ } - else /* neither termination condition seen */ - di_card->status_register &= ~STAT_LBI; /* so clear last byte in status */ + else /* neither termination condition was seen */ + di_card->status_register &= ~STAT_LBI; /* so clear the last byte in status */ } -else /* card is transmitting */ - tag = (data & (DATA_ATN | DATA_EOI)) << DATA_SHIFT; /* set tag from data shifted to tag location */ +else /* the card is transmitting */ + tag = (data & (DATA_ATN | DATA_EOI)) << DATA_SHIFT; /* set the tag from the data shifted to the tag location */ -if (di_card->edt == SET) /* end of data transfer? */ - tag = tag | TAG_EDT; /* set EDT tag */ +if (di_card->edt == SET) /* is this the end of the data transfer? */ + tag = tag | TAG_EDT; /* set the EDT tag */ -index = (di_card->fifo_reg->qptr /* calculate index */ - + di_card->fifo_count) % FIFO_SIZE; /* of next available location */ +index = (di_card->fifo_reg->qptr /* calculate the index */ + + di_card->fifo_count) % FIFO_SIZE; /* of the next available location */ -if (access == bus_access) { /* bus access? */ - if (di_card->ibp == upper) { /* packed and this is the upper byte? */ - di_card->ibp = lower; /* set lower byte as next */ +if (access == bus_access) { /* is this a bus access */ + if (di_card->ibp == upper) { /* in packed mode for the upper byte? */ + di_card->ibp = lower; /* set the lower byte as next */ if (tag & TAG_LBR) /* is this the last byte? */ - di_card->fifo [index] = /* copy to both bytes of FIFO */ - tag | SET_BOTH (data); /* and store with tag */ - else { /* more bytes expected */ + di_card->fifo [index] = /* copy to both bytes of the FIFO */ + tag | SET_BOTH (data); /* and store with the tag */ + else { /* more bytes are expected */ di_card->fifo [index] = /* so position this byte */ - tag | SET_UPPER (data); /* and store with tag */ - add_word = FALSE; /* wait for second byte before adding */ + tag | SET_UPPER (data); /* and store it with the tag */ + add_word = FALSE; /* wait for the second byte before adding */ } } else /* this is the lower byte */ - if (di_card->cntl_register & CNTL_PACK) { /* packed mode? */ - di_card->ibp = upper; /* set upper byte as next */ + if (di_card->cntl_register & CNTL_PACK) { /* is the card in packed mode? */ + di_card->ibp = upper; /* set the upper byte as next */ - di_card->fifo [index] = /* merge in data and tag */ + di_card->fifo [index] = /* merge the data and tag values */ tag | di_card->fifo [index] | SET_LOWER (data); } - else /* unpacked mode */ + else /* the card is in unpacked mode */ di_card->fifo [index] = /* position this byte */ - tag | SET_LOWER (data); /* and store with tag */ + tag | SET_LOWER (data); /* and store with the tag */ } -else if (access == cpu_access) /* cpu access? */ - di_card->fifo [index] = tag | data; /* store tag and full word in FIFO */ +else if (access == cpu_access) /* is this a cpu access? */ + di_card->fifo [index] = tag | data; /* store the tag and full word in the FIFO */ -else { /* diag access */ - data = SET_BOTH (GET_LOWER (data)); /* copy lower byte to upper byte */ - di_card->fifo [index] = tag | data; /* and store tag and full word in FIFO */ +else { /* must be diagnostic access */ + data = SET_BOTH (GET_LOWER (data)); /* copy the lower byte to the upper byte */ + di_card->fifo [index] = tag | data; /* and store the tag and full word in the FIFO */ } if (add_word) /* did we add a word to the FIFO? */ - di_card->fifo_count = di_card->fifo_count + 1; /* increment count of words stored */ + di_card->fifo_count = di_card->fifo_count + 1; /* increment the count of words stored */ if (DEBUG_PRJ (dptrs [card], DEB_BUF)) { fprintf (sim_deb, ">>%s buf: Data %0*o tag ", @@ -1746,10 +1746,10 @@ return; listening, or asserts the bus EOI line if talking; in packed mode, the tag is ignored). - ATN and EOI tag handling is a bit complex. If the card is listening in - the unpacked mode, the ATN tag substitutes for bit 8 of the data word, - and the EOI tag substitutes for bit 9. In the packed mode, bits 8 and 9 - are as stored in the FIFO (they are upper-byte data bits). + ATN and EOI tag handling is complex. If the card is listening in the + unpacked mode, the ATN tag substitutes for bit 8 of the data word, and + the EOI tag substitutes for bit 9. In the packed mode, bits 8 and 9 are + as stored in the FIFO (they are upper-byte data bits). If the card is talking in the unpacked mode, the ATN tag asserts or denies ATN on the bus if the card is the CIC, and the EOI tag asserts or @@ -1800,7 +1800,7 @@ if (FIFO_EMPTY) { /* is the FIFO already e return 0; /* return with no data */ } -data = di_card->fifo [di_card->fifo_reg->qptr]; /* get tag and data from the FIFO */ +data = di_card->fifo [di_card->fifo_reg->qptr]; /* get the tag and data from the FIFO */ tag = data & TAG_MASK; /* mask the tag to just the tag bits */ data = data & DMASK; /* and the data to just the data bits */ @@ -1811,9 +1811,9 @@ if (tag & TAG_EDT /* is this the end of a di_card->status_register |= STAT_LBO; /* set the last byte out status */ -if (access == cpu_access) { /* cpu access? */ - if (!(di_card->cntl_register & CNTL_PACK)) /* unpacked data format? */ - data = data & ~(DATA_ATN | DATA_EOI) /* substitute ATN/EOI tag values */ +if (access == cpu_access) { /* is this a cpu access? */ + if (!(di_card->cntl_register & CNTL_PACK)) /* in unpacked mode? */ + data = data & ~(DATA_ATN | DATA_EOI) /* substitute the ATN/EOI tag values */ | (tag & (TAG_ATN | TAG_EOI)) >> DATA_SHIFT; /* into the data word */ if (tag & TAG_LBR) /* is this the last byte? */ @@ -1822,7 +1822,7 @@ if (access == cpu_access) { /* cpu access? */ di_card->eor = CLEAR; /* the end-of-record flip-flop */ } -else if (access == bus_access) /* bus access? */ +else if (access == bus_access) /* is this a bus access? */ if (di_card->obp == upper) { /* is this the upper byte? */ di_card->obp = lower; /* set the lower byte as next */ data = GET_UPPER (data); /* mask and position the upper byte in the data word */ @@ -1832,11 +1832,11 @@ else if (access == bus_access) /* bus access? */ else { /* this is the lower byte */ data = GET_LOWER (data); /* mask and position it in the data word */ - if (di_card->cntl_register & CNTL_PACK) /* in packed mode? */ + if (di_card->cntl_register & CNTL_PACK) /* is the card in the packed mode? */ di_card->obp = upper; /* set the upper byte as next */ } -else /* diagnostic access */ +else /* must be a diagnostic access */ data = GET_LOWER (data); /* access is to the lower byte only */ @@ -1857,15 +1857,15 @@ if (DEBUG_PRJ (dptrs [card], DEB_BUF)) { if (di_card->cntl_register & CNTL_TALK) /* is the card talking? */ - if (di_card->cntl_register & CNTL_PACK) /* in packed mode? */ + if (di_card->cntl_register & CNTL_PACK) /* is it in the packed mode? */ if (di_card->status_register & STAT_LBO /* yes, is the last byte out? */ - && di_card->cntl_register & CNTL_EOI) /* and EOI control enabled? */ - di_card->bus_cntl |= BUS_EOI; /* assert EOI */ + && di_card->cntl_register & CNTL_EOI) /* and is EOI control enabled? */ + di_card->bus_cntl |= BUS_EOI; /* assert EOI on the bus */ else - di_card->bus_cntl &= ~BUS_EOI; /* deny EOI */ + di_card->bus_cntl &= ~BUS_EOI; /* deny EOI on the bus */ - else { /* in unpacked mode */ - if (di_card->cntl_register & CNTL_CIC) /* is card the controller in charge? */ + else { /* the card is in the unpacked mode */ + if (di_card->cntl_register & CNTL_CIC) /* is the card the controller in charge? */ di_card->bus_cntl = /* assert or deny the ATN bus line */ di_card->bus_cntl & ~BUS_ATN /* from the ATN tag value */ | (tag & TAG_ATN) >> BUS_SHIFT; @@ -1908,7 +1908,7 @@ static const char *cntl_names [] = { uint32 signal; char mnemonics [40]; -if (cntl == 0) /* any control signal asserted? */ +if (cntl == 0) /* are any control signals asserted? */ strcpy (mnemonics, "---"); /* no; use dashes in lieu of an empty string */ else { /* one or more signals are asserted */ diff --git a/HP2100/hp2100_di.h b/HP2100/hp2100_di.h index 79d742ab..08171b21 100644 --- a/HP2100/hp2100_di.h +++ b/HP2100/hp2100_di.h @@ -1,4 +1,4 @@ -/* hp2100_di.h: HP 12821A HP-IB Disc Interface simulator common definitions +/* hp2100_di.h: HP 12821A HP-IB Disc Interface simulator definitions Copyright (c) 2010-2012, J. David Bryan @@ -41,8 +41,8 @@ only the DA device is implemented. However, as the 12821A diagnostic requires two cards to test I/O fully, a dummy DC device is provided by the DA simulator. It is enabled only when the DA card is configured for - diagnostic mode. This dummy device may be removed when either the DC or - MA device is implemented. + diagnostic mode. This dummy device should be removed when either the DC + or MA device is implemented. */ @@ -51,19 +51,21 @@ #define FIFO_SIZE 16 /* FIFO depth */ -typedef enum { da, dc, ma, /* card IDs */ - first_card = da, /* first card ID */ - last_card = ma, /* last card ID */ - card_count } CARD_ID; /* count of card IDs */ +typedef enum { + da, dc, ma, /* card IDs */ + first_card = da, /* first card ID */ + last_card = ma, /* last card ID */ + card_count /* count of card IDs */ + } CARD_ID; -/* Device flags and accessors (leaves space for disc/tape flags) */ +/* Device flags and accessors (bits 7-0 are reserved for disc/tape flags) */ -#define DEV_V_BUSADR (DEV_V_UF + 8) /* bits 10-8: HP-IB address */ +#define DEV_V_BUSADR (DEV_V_UF + 8) /* bits 10-8: interface HP-IB address */ #define DEV_V_DIAG (DEV_V_UF + 11) /* bit 11: diagnostic mode */ #define DEV_V_W1 (DEV_V_UF + 12) /* bit 12: DCPC pacing jumper */ -#define DEV_M_BUSADR 7 /* bus address mask */ +#define DEV_M_BUSADR 07 /* bus address mask */ #define DEV_BUSADR (DEV_M_BUSADR << DEV_V_BUSADR) #define DEV_DIAG (1 << DEV_V_DIAG) @@ -73,11 +75,11 @@ typedef enum { da, dc, ma, /* card IDs */ #define SET_DIADR(f) (((f) & DEV_M_BUSADR) << DEV_V_BUSADR) -/* Unit flags and accessors (leaves space for disc/tape flags) */ +/* Unit flags and accessors (bits 7-0 are reserved for disc/tape flags) */ -#define UNIT_V_BUSADR (UNIT_V_UF + 8) /* bits 10-8: HP-IB address */ +#define UNIT_V_BUSADR (UNIT_V_UF + 8) /* bits 10-8: unit HP-IB address */ -#define UNIT_M_BUSADR 7 /* bus address mask */ +#define UNIT_M_BUSADR 07 /* bus address mask */ #define UNIT_BUSADR (UNIT_M_BUSADR << UNIT_V_BUSADR) @@ -95,10 +97,10 @@ typedef enum { da, dc, ma, /* card IDs */ #define DEB_SERV (1 << 5) /* unit service scheduling calls */ -/* HP-IB control state bit flags. +/* HP-IB control line state bit flags. NOTE that these flags align with the corresponding flags in the DI status - register, so don't change the order! + register, so don't change the numerical values! */ #define BUS_ATN 0001 /* attention */ @@ -128,7 +130,7 @@ typedef enum { da, dc, ma, /* card IDs */ #define BUS_UCG 0020 /* universal command group */ #define BUS_ACG 0000 /* addressed command group */ -#define BUS_UNADDRESS 0037 /* unlisten and untalk */ +#define BUS_UNADDRESS 0037 /* unlisten and untalk addresses */ #define PPR(a) (uint8) (1 << (7 - (a))) /* parallel poll response */ @@ -146,8 +148,10 @@ typedef enum { da, dc, ma, /* card IDs */ #define SET_LOWER(b) (b) #define SET_BOTH(b) (SET_UPPER (b) | SET_LOWER (b)) -typedef enum { upper, /* byte selector */ - lower } SELECTOR; +typedef enum { + upper, /* upper byte selected */ + lower /* lower byte selected */ + } SELECTOR; /* Per-card state variables */ @@ -170,9 +174,9 @@ typedef struct { uint32 fifo_count; /* FIFO occupancy counter */ REG *fifo_reg; /* FIFO register pointer */ - uint32 acceptors; /* unit bitmap of bus acceptors */ - uint32 listeners; /* unit bitmap of bus listeners */ - uint32 talker; /* unit bitmap of bus talker */ + uint32 acceptors; /* unit bitmap of the bus acceptors */ + uint32 listeners; /* unit bitmap of the bus listeners */ + uint32 talker; /* unit bitmap of the bus talker */ uint8 bus_cntl; /* HP-IB bus control state (ATN, EOI, etc.) */ uint8 poll_response; /* address bitmap of parallel poll responses */ @@ -183,7 +187,7 @@ typedef struct { /* Disc interface VM global register definitions. - Include these definitions before any device-specific registers. + These definitions should be included before any device-specific registers. Implementation notes: @@ -222,7 +226,7 @@ typedef struct { /* Disc interface VM global modifier definitions. - Include these definitions before any device-specific modifiers. + These definitions should be included before any device-specific modifiers. */ #define DI_MODS(dev) \ diff --git a/HP2100/hp2100_di_da.c b/HP2100/hp2100_di_da.c index 24b1766d..005a6215 100644 --- a/HP2100/hp2100_di_da.c +++ b/HP2100/hp2100_di_da.c @@ -25,7 +25,7 @@ DA 12821A Disc Interface with Amigo disc drives - 21-Feb-12 JDB First release + 29-Mar-12 JDB First release 04-Nov-11 JDB Created DA device References: @@ -45,13 +45,14 @@ connected via an 12821A disc interface and provided 20MB, 50MB, and 120MB capacities. The drives were identical to the 7906M, 7920M, and 7925M Multi-Access Controller (MAC) units but incorporated internal two-card - controllers in each drive and connected to the CPU interface via HP-IB. Each + controllers in each drive and connected to the CPU interface via the + Hewlett-Packard Interface Bus (HP-IB), HP's implementation of IEEE-488. Each controller was dedicated to a single drive and operated similarly to the 12745 Disc Controller to HP-IB Adapter option for the 13037 Disc Controller - box. The 7906H was introduced in 1980 (there was no 7905H version, as the - 7905 was obsolete by that time). Up to four ICD drives could be connected to - a single 12821A card. The limitation was imposed by the bus loading and the - data transfer rate. + chassis. The 7906H was introduced in 1980 (there was no 7905H version, as + the 7905 was obsolete by that time). Up to four ICD drives could be + connected to a single 12821A card. The limitation was imposed by the bus + loading and the target data transfer rate. The ICD command set essentially was the MAC command set modified for single-unit operation. The unit number and CPU hold bit fields in the opcode @@ -61,12 +62,12 @@ controller did not support ECC. Controller status values 02B (Unit Available) and 27B (Unit Unavailable) were dropped as the controller supported only single units, 12B (I/O Program Error) was reused to indicate - HP-IB sequence errors, 13B (Sync Not Received) was added, and 17B (Possibly + HP-IB protocol errors, 13B (Sync Not Received) was added, and 17B (Possibly Correctable Data Error) was removed as error correction was not supported. Some minor redefinitions also occurred. For example, status 14B (End of Cylinder) was expanded to include an auto-seek beyond the drive limits, and - 37B (Drive Attention) was restricted from head loads and unloads to just head + 37B (Drive Attention) was restricted just head unloads from head loads and unloads. The command set was expanded to include several commands related to HP-IB @@ -76,12 +77,6 @@ sequences, Read and Write Loopback channel tests, and controller Self Test commands. - Unfortunately, the primary reference for the ICD controller (the HP 13365 - Integrated Controller Programming Guide) does not indicate parallel poll - responses for these HP-IB commands. Therefore, the responses have been - derived from the sequences in the 7910 and 12745 manuals, although they - sometimes conflict. - This simulator implements the Amigo disc protocol. It calls the 12821A Disc Interface (DI) simulator to send and receive bytes across the HP-IB to and from the CPU, and it calls the HP Disc Library to implement the controller @@ -89,8 +84,15 @@ Four units are provided, and any combination of 7906H/20H/25H drives may be defined. - The drives respond to the following commands; numeric values are in hex, and - bus addressing is indicated by U [untalk], L [listen], and T [talk]: + Unfortunately, the primary reference for the ICD controller (the HP 13365 + Integrated Controller Programming Guide) does not indicate parallel poll + responses for these HP-IB commands. Therefore, the responses have been + derived from the sequences in the 7910 and 12745 manuals, although they + sometimes conflict. + + The drives respond to the following commands; the secondary and opcode + numeric values are in hex, and the bus addressing state is indicated by U + [untalk], L [listen], and T [talk]: Bus Sec Op Operation --- --- -- -------------------------------- @@ -410,18 +412,15 @@ static const IF_STATE next_state [] = { typedef enum { invalid = 0, /* invalid = default for reset */ - disc_command, /* MLA 08 */ crc_listen, /* MLA 09 */ amigo_clear, /* MLA 10 */ write_loopback, /* MLA 1E */ initiate_self_test, /* MLA 1F */ - crc_talk, /* MTA 09 */ device_specified_jump, /* MTA 10 */ read_loopback, /* MTA 1E */ return_self_test_result, /* MTA 1F */ - amigo_identify /* UNT MSA */ } IF_COMMAND; @@ -429,18 +428,15 @@ typedef enum { static const char *if_command_name [] = { "invalid", - "disc command", "CRC listen", "Amigo clear", "write loopback", "initiate self-test", - "CRC talk", "device specified jump", "read loopback", "return self-test result", - "Amigo identify" }; @@ -488,7 +484,7 @@ static void complete_write (uint32 unit); static void complete_abort (uint32 unit); static uint8 get_buffer_byte (CVPTR cvptr); static void put_buffer_byte (CVPTR cvptr, uint8 data); -static t_stat activate_unit (UNIT *uptr); +static t_stat activate_unit (UNIT *uptr); @@ -514,6 +510,14 @@ static t_stat activate_unit (UNIT *uptr); 2. The CNVARS register is included to ensure that the controller state variables array is saved by a SAVE command. It is declared as a hidden, read-only byte array of a depth compatible with the size of the array. + + There does not appear to be a way to expose the fields of the four + controller state variables as arrayed registers. Access to an array + always assumes that elements appear at memory offsets equal to the + element size, i.e., a 32-bit arrayed register has elements at four-byte + offsets. There's no way to specify an array of structure elements where + a given 32-bit field appears at, say, 92-byte offsets (i.e., the size of + the structure). */ DEVICE da_dev; @@ -523,10 +527,10 @@ DIB da_dib = { &di_io, DI_DA, da }; #define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD) UNIT da_unit [] = { - { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (0), D7906_WORDS) }, /* bus address 0 */ - { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (1), D7906_WORDS) }, /* bus address 1 */ - { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (2), D7906_WORDS) }, /* bus address 2 */ - { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (3), D7906_WORDS) } /* bus address 3 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (0), D7906_WORDS) }, /* drive unit 0 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (1), D7906_WORDS) }, /* drive unit 1 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (2), D7906_WORDS) }, /* drive unit 2 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (3), D7906_WORDS) } /* drive unit 3 */ }; REG da_reg [] = { @@ -535,8 +539,8 @@ REG da_reg [] = { { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) }, { BRDATA (DSJ, if_dsj, 10, 2, DA_UNITS) }, - { BRDATA (IFSTAT, if_state, 10, sizeof (IF_STATE) * CHAR_BIT, DA_UNITS), PV_LEFT }, - { BRDATA (IFCMD, if_command, 10, sizeof (IF_COMMAND) * CHAR_BIT, DA_UNITS), PV_LEFT }, + { BRDATA (ISTATE, if_state, 10, sizeof (IF_STATE) * CHAR_BIT, DA_UNITS), PV_LEFT }, + { BRDATA (ICMD, if_command, 10, sizeof (IF_COMMAND) * CHAR_BIT, DA_UNITS), PV_LEFT }, { BRDATA (CNVARS, icd_cntlr, 10, CHAR_BIT, sizeof (CNTLR_VARS) * DA_UNITS), REG_HRO }, @@ -594,14 +598,14 @@ DEVICE da_dev = { /* Service an Amigo disc drive I/O event. - The service routine is called to start commands and control the transfer of + The service routine is called to execute commands and control the transfer of data to and from the HP-IB card. The actions to be taken depend on the current state of the ICD interface. The possibilities are: 1. A command is pending on the interface. This occurs only when a command is received while a Seek or Recalibrate command is in progress. - 2. A command is ready for execution. + 2. A command is executing. 3. Data is being sent or received over the HP-IB during command execution. @@ -640,7 +644,7 @@ DEVICE da_dev = { into the sector buffer, a data phase that transfers bytes from the buffer to the card, and an end phase that schedules the intersector gap time and resets to the start phase. Data phase transfers are performed in the - read_exec or write_exec interface states. + read_xfer or write_xfer interface states. The results of the disc library service are inferred by the controller state. If the controller is busy, then the command continues in a new @@ -675,8 +679,8 @@ DEVICE da_dev = { has already stored the received byte in the sector buffer and has asserted NRFD to hold off the card. If the buffer is now full, or the byte was tagged with EOI, then we terminate the transfer and move to the end phase - of the command. Otherwise, we deny NRFD and exit, as we will be - rescheduled when the next byte arrives. + of the command. Otherwise, we deny NRFD and exit; we will be rescheduled + when the next byte arrives. error_source ============ @@ -692,13 +696,14 @@ DEVICE da_dev = { If an error occurred during the data transfer phase of a write command, dummy bytes are sunk from the bus until EOI is seen or the card is unaddressed. This allows the OS driver to complete the command as expected - and to determine the failure by requesting the controller's status. + and then determine the cause of the failure by requesting the controller's + status. Implementation notes: 1. The disc library sets the controller state to idle for a normal End, - Seek, or Recalibrate command and to Wait for all other commands that end + Seek, or Recalibrate command and to wait for all other commands that end normally. So we determine command completion by checking if the controller is not busy, rather than checking if the controller is idle. @@ -720,7 +725,7 @@ DEVICE da_dev = { that was started by the ICD boot loader ROM. In hardware, if the LSTN control bit is cleared, e.g., by CRS, - transmission stops because the card denies NDAC and NRFD (the GPIB + transmission stops because the card denies NDAC and NRFD (the HP-IB handshake requires NDAC and NRFD to be asserted to start the handshake sequence; TACS * SDYS * ~NDAC * ~NRFD is an error condition). In simulation, we handle this by terminating a read transfer if the card @@ -733,15 +738,15 @@ t_stat da_service (UNIT *uptr) { uint8 data; CNTLR_CLASS command_class; -const uint32 unit = uptr - da_dev.units; /* disc unit number */ -const CVPTR cvptr = &icd_cntlr [unit]; /* pointer to controller */ +const int32 unit = uptr - da_unit; /* get the disc unit number */ +const CVPTR cvptr = &icd_cntlr [unit]; /* get a pointer to the controller */ t_stat result = SCPE_OK; t_bool release_interface = FALSE; -switch (if_state [unit]) { /* dispatch interface state */ +switch (if_state [unit]) { /* dispatch the interface state */ case command_wait: /* command is waiting */ - release_interface = TRUE; /* release interface at end if idle */ + release_interface = TRUE; /* release the interface at then end if it's idle */ /* fall into the command_exec handler to process the current command */ @@ -751,50 +756,50 @@ switch (if_state [unit]) { /* dispatch interfac case disc_command: /* execute a disc command */ result = dl_service_drive (cvptr, uptr); /* service the disc unit */ - if (cvptr->opcode == clear) /* Clear command? */ - if_dsj [unit] = 2; /* indicate self test complete */ + if (cvptr->opcode == clear) /* is this a Clear command? */ + if_dsj [unit] = 2; /* indicate that the self test is complete */ if (cvptr->state != cntlr_busy) { /* has the controller stopped? */ if_state [unit] = idle; /* idle the interface */ - if (cvptr->status == normal_completion || /* normal completion? */ + if (cvptr->status == normal_completion || /* do we have normal completion */ cvptr->status == drive_attention) /* or drive attention? */ break; /* we're done */ - else { /* if status is abnormal */ + else { /* if the status is abnormal */ if_dsj [unit] = 1; /* an error has occurred */ - command_class = dl_classify (*cvptr); /* classify command */ + command_class = dl_classify (*cvptr); /* classify the command */ - if (command_class == class_write) { /* write command failed? */ - if_state [unit] = error_sink; /* sink remaining bytes */ + if (command_class == class_write) { /* did a write command fail? */ + if_state [unit] = error_sink; /* sink the remaining bytes */ uptr->wait = cvptr->cmd_time; /* activate to complete processing */ } - else if (command_class != class_control) { /* read or status command failed? */ + else if (command_class != class_control) { /* did a read or status command fail? */ if_state [unit] = error_source; /* source an error byte */ uptr->wait = cvptr->cmd_time; /* activate to complete processing */ } } } - else if (uptr->PHASE == data_phase) { /* starting the data phase? */ - cvptr->length = cvptr->length * 2; /* convert buffer length to bytes */ + else if (uptr->PHASE == data_phase) { /* are we starting the data phase? */ + cvptr->length = cvptr->length * 2; /* convert the buffer length to bytes */ - if (dl_classify (*cvptr) == class_write) /* write command? */ - if_state [unit] = write_xfer; /* set for write data transfer */ - else /* read or status command */ - if_state [unit] = read_xfer; /* set for read data transfer */ + if (dl_classify (*cvptr) == class_write) /* is this a write command? */ + if_state [unit] = write_xfer; /* set for a write data transfer */ + else /* it is a read or status command */ + if_state [unit] = read_xfer; /* set for a read data transfer */ } break; case amigo_identify: /* Amigo Identify */ - buffer [0] = 0x0003; /* store response in buffer */ + buffer [0] = 0x0003; /* store the response in the buffer */ cvptr->length = 2; /* return two bytes */ - if_state [unit] = read_xfer; /* ready to transfer data */ + if_state [unit] = read_xfer; /* we are ready to transfer the data */ uptr->wait = cvptr->cmd_time; /* schedule the transfer */ if (DEBUG_PRI (da_dev, DEB_RWSC)) @@ -805,11 +810,11 @@ switch (if_state [unit]) { /* dispatch interfac case initiate_self_test: /* Initiate a self test */ sim_cancel (&da_unit [unit]); /* cancel any operation in progress */ - dl_clear_controller (cvptr, /* hard clear the controller */ + dl_clear_controller (cvptr, /* hard-clear the controller */ &da_unit [unit], hard_clear); - if_dsj [unit] = 2; /* set DSJ for self test */ - if_state [unit] = idle; /* command is complete */ + if_dsj [unit] = 2; /* set DSJ for self test completion */ + if_state [unit] = idle; /* the command is complete */ di_poll_response (da, unit, SET); /* with PPR enabled */ break; @@ -817,7 +822,7 @@ switch (if_state [unit]) { /* dispatch interfac case amigo_clear: /* Amigo clear */ dl_idle_controller (cvptr); /* idle the controller */ if_dsj [unit] = 0; /* clear the DSJ value */ - if_state [unit] = idle; /* command is complete */ + if_state [unit] = idle; /* the command is complete */ di_poll_response (da, unit, SET); /* with PPR enabled */ break; @@ -830,23 +835,23 @@ switch (if_state [unit]) { /* dispatch interfac case error_source: /* send data after an error */ - if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) { /* is card ready for data? */ + if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) { /* is the card ready for data? */ di [da].bus_cntl |= BUS_EOI; /* set EOI */ - di_bus_source (da, 0); /* send a dummy byte to the card */ - if_state [unit] = idle; /* command is complete */ + di_bus_source (da, 0); /* and send a dummy byte to the card */ + if_state [unit] = idle; /* the command is complete */ } break; case read_xfer: /* send read data */ - if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) /* is card ready for data? */ + if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) /* is the card ready for data? */ switch (if_command [unit]) { /* dispatch the interface command */ case disc_command: /* disc read or status commands */ data = get_buffer_byte (cvptr); /* get the next byte from the buffer */ - if (di_bus_source (da, data) == FALSE) /* send data to card; is it listening? */ - cvptr->eod = SET; /* no, so terminate read */ + if (di_bus_source (da, data) == FALSE) /* send the byte to the card; is it listening? */ + cvptr->eod = SET; /* no, so terminate the read */ if (cvptr->length == 0 || cvptr->eod == SET) { /* is the data phase complete? */ uptr->PHASE = end_phase; /* set the end phase */ @@ -858,7 +863,7 @@ switch (if_state [unit]) { /* dispatch interfac uptr->wait = cvptr->cmd_time; /* and reschedule the service */ } - else /* data phase continues */ + else /* the data phase continues */ uptr->wait = cvptr->data_time; /* reschedule the next transfer */ break; @@ -872,13 +877,13 @@ switch (if_state [unit]) { /* dispatch interfac if (cvptr->length == 0) /* is the transfer complete? */ di [da].bus_cntl |= BUS_EOI; /* set EOI */ - if (di_bus_source (da, data) /* send data to card; is it listening? */ - && cvptr->length > 0) /* and more to transfer? */ + if (di_bus_source (da, data) /* send the byte to the card; is it listening? */ + && cvptr->length > 0) /* and is there more to transfer? */ uptr->wait = cvptr->data_time; /* reschedule the next transfer */ - else { /* transfer is complete */ - if_state [unit] = idle; /* command is complete */ - di_poll_response (da, unit, SET); /* enable PPR */ + else { /* the transfer is complete */ + if_state [unit] = idle; /* the command is complete */ + di_poll_response (da, unit, SET); /* enable the PPR */ } break; @@ -886,7 +891,7 @@ switch (if_state [unit]) { /* dispatch interfac case device_specified_jump: di [da].bus_cntl |= BUS_EOI; /* set EOI */ di_bus_source (da, if_dsj [unit]); /* send the DSJ value to the card */ - if_state [unit] = idle; /* command is complete */ + if_state [unit] = idle; /* the command is complete */ break; @@ -904,10 +909,10 @@ switch (if_state [unit]) { /* dispatch interfac case error_sink: /* absorb data after an error */ - cvptr->index = 0; /* absorb data until EOI */ + cvptr->index = 0; /* absorb data until EOI asserts */ if (cvptr->eod == SET) /* is the transfer complete? */ - if_state [unit] = idle; /* command is complete */ + if_state [unit] = idle; /* the command is complete */ di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ break; @@ -934,7 +939,7 @@ switch (if_state [unit]) { /* dispatch interfac case write_loopback: if (cvptr->eod == SET) { /* is the transfer complete? */ cvptr->length = 16 - cvptr->length; /* set the count of bytes transferred */ - if_state [unit] = idle; /* command is complete */ + if_state [unit] = idle; /* the command is complete */ } di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ @@ -957,8 +962,8 @@ switch (if_state [unit]) { /* dispatch interfac if (uptr->wait) /* is service requested? */ activate_unit (uptr); /* schedule the next event */ -if (result == SCPE_IERR && DEBUG_PRI (da_dev, DEB_RWSC)) { /* internal error? */ - fprintf (sim_deb, ">>DA rwsc: Unit %d ", unit); +if (result == SCPE_IERR && DEBUG_PRI (da_dev, DEB_RWSC)) { /* did an internal error occur? */ + fprintf (sim_deb, ">>DA rwsc: Unit %d ", unit); /* report it if debugging */ if (if_state [unit] == command_exec && if_command [unit] == disc_command) @@ -988,7 +993,7 @@ if (if_state [unit] == idle) { /* is the command no fprintf (sim_deb, ">>DA rwsc: Unit %d %s command completed\n", unit, if_command_name [if_command [unit]]); - if (release_interface) /* if next command is already pending */ + if (release_interface) /* if the next command is already pending */ di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ } @@ -1015,20 +1020,20 @@ t_stat status; status = di_reset (dptr); /* reset the card */ -if (status == SCPE_OK && (sim_switches & SWMASK ('P'))) /* card OK and power-on reset? */ - for (unit = 0; unit < dptr->numunits; unit++) { /* loop through units */ - sim_cancel (dptr->units + unit); /* cancel activation */ +if (status == SCPE_OK && (sim_switches & SWMASK ('P'))) /* is the card OK and is this a power-on reset? */ + for (unit = 0; unit < dptr->numunits; unit++) { /* loop through the units */ + sim_cancel (dptr->units + unit); /* cancel any current activation */ dptr->units [unit].CYL = 0; /* reset the head position */ dptr->units [unit].pos = 0; /* to cylinder 0 */ - dl_clear_controller (&icd_cntlr [unit], /* hard clear the controller */ + dl_clear_controller (&icd_cntlr [unit], /* hard-clear the controller */ dptr->units + unit, hard_clear); if_state [unit] = idle; /* reset the interface state */ if_command [unit] = invalid; /* reset the interface command */ - if_dsj [unit] = 2; /* set DSJ for power up */ + if_dsj [unit] = 2; /* set the DSJ for power up complete */ } return status; @@ -1037,18 +1042,18 @@ return status; /* Attach a unit to a disc image file. - The simulator considers an attached unit to be connected to the bus, and an + The simulator considers an attached unit to be connected to the bus and an unattached unit to be disconnected, so we set the card's acceptor bit for the selected unit if the attach is successful. An attached unit is ready if the - heads are loaded and not ready of not. + heads are loaded or not ready if not. This model is slightly different than the MAC (DS) simulation, where an - unattached unit is considered "connected but not ready" -- the same indication - returned by an attached unit whose heads are unloaded. Therefore, the - situation when the simulator is started is that all DS units are "connected to - the controller but not ready," whereas all DA units are "not connected to the - controller." This eliminates the overhead of sending HP-IB messages to unused - units. + unattached unit is considered "connected but not ready" -- the same + indication returned by an attached unit whose heads are unloaded. Therefore, + the situation when the simulator is started is that all DS units are + "connected to the controller but not ready," whereas all DA units are "not + connected to the bus." This eliminates the overhead of sending HP-IB + messages to unused units. In tabular form, the simulator responses are: @@ -1082,11 +1087,11 @@ return status; t_stat da_attach (UNIT *uptr, char *cptr) { t_stat result; -const uint32 unit = uptr - da_unit; /* calculate the unit number */ +const int32 unit = uptr - da_unit; /* calculate the unit number */ result = dl_attach (&icd_cntlr [unit], uptr, cptr); /* attach the drive */ -if (result == SCPE_OK) /* attach successful? */ +if (result == SCPE_OK) /* was the attach successful? */ di [da].acceptors |= (1 << unit); /* set the unit's accepting bit */ return result; @@ -1096,18 +1101,18 @@ return result; /* Detach a disc image file from a unit. As explained above, detaching a unit is the hardware equivalent of - disconnecting the drive from the bus, so we clear the unit's acceptor bit is + disconnecting the drive from the bus, so we clear the unit's acceptor bit if the detach is successful. */ t_stat da_detach (UNIT *uptr) { t_stat result; -const uint32 unit = uptr - da_unit; /* calculate the unit number */ +const int32 unit = uptr - da_unit; /* calculate the unit number */ result = dl_detach (&icd_cntlr [unit], uptr); /* detach the drive */ -if (result == SCPE_OK) { /* detach successful? */ +if (result == SCPE_OK) { /* was the detach successful? */ di [da].acceptors &= ~(1 << unit); /* clear the unit's accepting bit */ di_poll_response (da, unit, CLEAR); /* and its PPR, as it's no longer present */ } @@ -1118,8 +1123,8 @@ return result; /* Boot an Amigo disc drive. - The ICD disc bootstrap prorgam is loaded from the HP 12992H Boot Loader ROM - into memory, the I/O instructions are configured from the interface card + The ICD disc bootstrap program is loaded from the HP 12992H Boot Loader ROM + into memory, the I/O instructions are configured for the interface card's select code, and the program is run to boot from the specified unit. The loader supports booting the disc at bus address 0 only. Before execution, the S register is automatically set as follows: @@ -1204,11 +1209,11 @@ static const BOOT_ROM da_rom = { t_stat da_boot (int32 unitno, DEVICE *dptr) { -if (GET_BUSADR (da_unit [unitno].flags) != 0) /* boot supported on bus address 0 only */ +if (GET_BUSADR (da_unit [unitno].flags) != 0) /* booting is supported on bus address 0 only */ return SCPE_NOFNC; /* report "Command not allowed" if attempted */ if (ibl_copy (da_rom, da_dib.select_code)) /* copy the boot ROM to memory and configure */ - return SCPE_IERR; /* return an internal error if failed */ + return SCPE_IERR; /* return an internal error if the copy failed */ SR = SR & (IBL_OPT | IBL_DS_HEAD) /* set S to a reasonable value */ | IBL_DS | IBL_MAN | (da_dib.select_code << IBL_V_DEV); /* before boot execution */ @@ -1252,13 +1257,13 @@ return SCPE_OK; t_stat da_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) { -const uint32 unit = uptr - da_unit; /* calculate the unit number */ -const t_bool load = (value != UNIT_UNLOAD); /* true if heads are loading */ +const int32 unit = uptr - da_unit; /* calculate the unit number */ +const t_bool load = (value != UNIT_UNLOAD); /* true if the heads are loading */ t_stat result; result = dl_load_unload (&icd_cntlr [unit], uptr, load); /* load or unload the heads */ -if (result == SCPE_OK && ! load) { /* unload successful? */ +if (result == SCPE_OK && ! load) { /* was the unload successful? */ icd_cntlr [unit].status = drive_attention; /* set Drive Attention status */ if (uptr->OP == end) /* is the controller in idle state 2? */ @@ -1283,20 +1288,21 @@ return result; addressed (applying only to those acceptors that have been addressed to listen). Data bytes are accepted only if the unit has been addressed to listen. As we are called for a data transfer or an addressed command only if - we are currently listening, the only bytes that we do not accept are talk or - listen commands directed to another address, or secondary commands when we - are not addressed to listen. + we are currently listening, the only bytes that we do not accept are primary + talk or listen commands directed to another address, or secondary commands + when we are not addressed to listen. This routine handles the HP-IB protocol. The type of byte passed is - determined by the state of the ATN signal and, if asserted, by the high-order - bits of the value. Most of the work involves decoding secondary commands and - their associated data parameters. The interface state is changed as needed - to track the command protocol. The states processed in this routine are: + determined by the state of the ATN signal and, if ATN is asserted, by the + high-order bits of the value. Most of the work involves decoding secondary + commands and their associated data parameters. The interface state is + changed as needed to track the command protocol. The states processed in + this routine are: opcode_wait =========== - A receive disc command secondary has been received, and the interface is + A Receive Disc Command secondary has been received, and the interface is waiting for the opcode that should follow. parameter_wait @@ -1309,19 +1315,19 @@ return result; ========== A disc write command has been received, and the interface is waiting for - the receive write data secondary that should follow. + the Receive Write Data secondary that should follow. read_wait ========= A disc read command has been received, and the interface is waiting for the - send read data secondary that should follow. + Send Read Data secondary that should follow. status_wait =========== A disc status command has been received, and the interface is waiting for - the send disc status secondary that should follow. + the Send Disc Status secondary that should follow. write_xfer ========== @@ -1338,18 +1344,18 @@ return result; Disc commands and parameters are assembled in the sector buffer before being passed to the disc library to start the command. Once the command is - started, then the interface state is set either to execute the command or to - wait for the receipt of a data transfer secondary before executing, depending - on the command. + started, the interface state is set either to execute the command or to wait + for the receipt of a data transfer secondary before executing, depending on + the command. Two disc command protocol errors are detected. First, an Illegal Opcode is - identified during the check for the expected number of disc command opcode + identified during the check for the expected number of disc command parameters. This allows us to sink an arbitrary number of parameter bytes. - Second, an I/O Program Error occurs if an unsupported secondary is received, + Second, an I/O Program Error occurs if an unsupported secondary is received or the HP-IB sequence is incorrect. The latter occurs if a command has the - wrong number of parameters, or a secondary data transfer sequence is invalid. + wrong number of parameters or a secondary data transfer sequence is invalid. - Disc commands that require data transfers (e.g., read, write, request status) + Disc commands that require data transfers (e.g., Read, Write, Request Status) involve a pair of secondaries. The first transmits the command, and the second transmits or receives the data. If one occurs without the other, an I/O Program Error occurs. @@ -1360,26 +1366,27 @@ return result; - An unsupported talk secondary sends a single data byte tagged with EOI. - An unsupported listen secondary accepts and discards any accompanying data - bytes until EOI or unlisten. + bytes until EOI is asserted or an Unlisten is received. - A supported command with too few parameter bytes or for which the last parameter byte is not tagged with EOI (before unlisten) does nothing. - A supported command with too many parameter bytes accepts and discards - excess parameter bytes until EOI or unlisten. + excess parameter bytes until EOI is asserted or an Unlisten is received. - - A read or status command that is not followed by a send data or send - status secondary does nothing. The unexpected secondary is executed - normally. + - A read or status command that is not followed by a Send Read Data or a + Send Disc Status secondary does nothing. The unexpected secondary is + executed normally. - - A write command that is not followed by a receive data secondary does - nothing. The unexpected secondary is executed normally. + - A write command that is not followed by a Receive Write Data secondary + does nothing. The unexpected secondary is executed normally. - - A send data or send status secondary that is not preceded by a read or - status command sends a single data byte tagged with EOI. + - A Send Read Data or a Send Disc Status secondary that is not preceded by a + read or status command sends a single data byte tagged with EOI. - - A receive data secondary that is not preceded by a write command accepts - and discards data bytes until EOI or unlisten. + - A Receive Write Data secondary that is not preceded by a write command + accepts and discards data bytes until EOI is asserted or an Unlisten is + received. The Amigo command sequence does not provide a byte count for disc read and write commands, so the controller continues to source or accept data bytes @@ -1387,22 +1394,22 @@ return result; Untalk. However, per IEEE-488, a listening device may be unaddressed by IFC, by an Unlisten, or by addressing the device to talk, and a talking device may be unaddressed by IFC, by addressing another device to talk (or no device via - Untalk), or by addressing the device to listen. Therefore, we keep track of - whether the unit stopped talking or listening, and if it has, we check for - command termination. + Untalk), or by addressing the device to listen. Therefore, we must keep + track of whether the unit stopped talking or listening, and if it has, we + check for command termination. If the controller is unaddressed in the middle of a sector transfer, the read or write must be terminated cleanly to ensure that the disc image is - coherent. It is also permissable to untalk the controller before all of the + coherent. It is also permissible to untalk the controller before all of the requested status bytes are returned. In addition, the controller has no way to inform the host that an error has - occurred that prevents the command from continuing. For example, a data - error encountered while reading, or a protected track encountered while - writing must still source or sink data bytes until the command is terminated - by the host. The controller handles read errors by sourcing a single data - byte tagged with EOI, and write errors by sinking data bytes until EOI is - seen or the unit is unaddressed. + occurred that prevents the command from continuing. For example, if a data + error is encountered while reading or a protected track is encountered while + writing, the controller must still source or sink data bytes until the + command is terminated by the host. The controller handles read errors by + sourcing a single data byte tagged with EOI and write errors by sinking data + bytes until EOI is seen or the unit is unaddressed. Therefore, if the unit is unaddressed while a read, write, or status command is transferring data, the unit service must be scheduled to end the current @@ -1418,11 +1425,6 @@ return result; 2. It is not necessary to check for listening when processing addressed commands, as only listeners are called by the bus source. - - 3. The dl_prepare_command routine returns FALSE if the command accesses a - busy unit. However, we check for a busy unit during addressing and hold - off the CPU if it is. Therefore, the unit will never be busy when the - routine is called, so a FALSE return will indicate a rejected command. */ t_bool da_bus_accept (uint32 unit, uint8 data) @@ -1469,28 +1471,28 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma case BUS_LAG: /* listen address group */ my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ - if (message_address == my_address) { /* my listen address? */ + if (message_address == my_address) { /* is it my listen address? */ di [da].listeners |= (1 << unit); /* set my listener bit */ di [da].talker &= ~(1 << unit); /* clear my talker bit */ addressed = TRUE; /* unit is now addressed */ - stopped_talking = TRUE; /* MLA stops unit from talking */ + stopped_talking = TRUE; /* MLA stops the unit from talking */ if (DEBUG_PRI (da_dev, DEB_XFER)) sprintf (action, "listen %d", message_address); } - else if (message_address == BUS_UNADDRESS) { /* unlisten? */ - di [da].listeners = 0; /* clear all listeners */ + else if (message_address == BUS_UNADDRESS) { /* is it an Unlisten? */ + di [da].listeners = 0; /* clear all of the listeners */ - stopped_listening = TRUE; /* UNL stops unit from listening */ + stopped_listening = TRUE; /* UNL stops the unit from listening */ if (DEBUG_PRI (da_dev, DEB_XFER)) strcpy (action, "unlisten"); } - else /* other listen address */ - accepted = FALSE; /* is not accepted */ + else /* other listen addresses */ + accepted = FALSE; /* are not accepted */ break; @@ -1498,26 +1500,26 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma case BUS_TAG: /* talk address group */ my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ - if (message_address == my_address) { /* my talk address? */ - di [da].talker = (1 << unit); /* set my talker bit and clear others */ + if (message_address == my_address) { /* is it my talk address? */ + di [da].talker = (1 << unit); /* set my talker bit and clear the others */ di [da].listeners &= ~(1 << unit); /* clear my listener bit */ - addressed = TRUE; /* unit is now addressed */ - stopped_listening = TRUE; /* MTA stops unit from listening */ + addressed = TRUE; /* the unit is now addressed */ + stopped_listening = TRUE; /* MTA stops the unit from listening */ if (DEBUG_PRI (da_dev, DEB_XFER)) sprintf (action, "talk %d", message_address); } - else { /* some other talker (or untalk) */ - di [da].talker &= ~(1 << unit); /* clear talker */ + else { /* it is some other talker (or Untalk) */ + di [da].talker &= ~(1 << unit); /* clear my talker bit */ - stopped_talking = TRUE; /* UNT or OTA stops unit from talking */ + stopped_talking = TRUE; /* UNT or OTA stops the unit from talking */ - if (message_address != BUS_UNADDRESS) /* other talk address? */ - accepted = FALSE; /* is not accepted */ + if (message_address != BUS_UNADDRESS) /* other talk addresses */ + accepted = FALSE; /* are not accepted */ - else /* untalk */ + else /* it's an Untalk */ if (DEBUG_PRI (da_dev, DEB_XFER)) strcpy (action, "untalk"); } @@ -1529,7 +1531,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma icd_cntlr [unit].index = 0; /* reset the buffer index */ if (di [da].listeners & (1 << unit)) { /* is it a listen secondary? */ - if (if_state [unit] == write_wait /* if waiting for a write data secondary */ + if (if_state [unit] == write_wait /* if we're waiting for a write data secondary */ && message_address != 0x00) /* but it's not there, */ abort_command (unit, io_program_error, /* then abort the pending command */ idle); /* and process the new command */ @@ -1540,8 +1542,8 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma if (if_state [unit] != write_wait) /* if we're not expecting it */ abort_command (unit, io_program_error, /* abort and sink any data */ error_sink); - else { /* sequence is correct */ - if_state [unit] = command_exec; /* now ready to execute */ + else { /* the sequence is correct */ + if_state [unit] = command_exec; /* the command is ready to execute */ da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ di_bus_control (da, unit, BUS_NRFD, 0); /* assert NRFD to hold off the card */ } @@ -1550,36 +1552,36 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma break; case 0x08: /* disc commands */ - if_command [unit] = disc_command; /* set the command */ - if_state [unit] = opcode_wait; /* opcode must follow */ + if_command [unit] = disc_command; /* set the command and wait */ + if_state [unit] = opcode_wait; /* for the opcode that must follow */ break; case 0x09: /* CRC (Listen) */ - if_command [unit] = crc_listen; /* set the command */ + if_command [unit] = crc_listen; /* set up the command */ if_state [unit] = error_sink; /* sink any data that will be coming */ initiated = TRUE; /* log the command initiation */ break; case 0x10: /* Amigo Clear */ - if_command [unit] = amigo_clear; /* set the command */ + if_command [unit] = amigo_clear; /* set up the command */ if_state [unit] = parameter_wait; /* a parameter must follow */ - icd_cntlr [unit].length = 1; /* expect one (unused) byte */ + icd_cntlr [unit].length = 1; /* set to expect one (unused) byte */ break; case 0x1E: /* Write Loopback */ - if_command [unit] = write_loopback; /* set the command */ + if_command [unit] = write_loopback; /* set up the command */ if_state [unit] = write_xfer; /* data will be coming */ icd_cntlr [unit].length = 16; /* accept only the first 16 bytes */ initiated = TRUE; /* log the command initiation */ break; case 0x1F: /* Initiate Self-Test */ - if_command [unit] = initiate_self_test; /* set the command */ + if_command [unit] = initiate_self_test; /* set up the command */ if_state [unit] = parameter_wait; /* a parameter must follow */ - icd_cntlr [unit].length = 1; /* expect the test ID byte */ + icd_cntlr [unit].length = 1; /* set to expect the test ID byte */ break; - default: /* an unsupported listen secondary */ + default: /* an unsupported listen secondary was received */ abort_command (unit, io_program_error, /* abort and sink any data */ error_sink); /* that might accompany the command */ initiated = TRUE; /* log the abort initiation */ @@ -1592,7 +1594,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* these are always scheduled and */ initiated = TRUE; /* logged as initiated */ - if (if_state [unit] == read_wait /* if waiting for a send data secondary */ + if (if_state [unit] == read_wait /* if we're waiting for a send data secondary */ && message_address != 0x00 /* but it's not there */ || if_state [unit] == status_wait /* or a send status secondary, */ && message_address != 0x08) /* but it's not there */ @@ -1604,42 +1606,42 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma case 0x00: /* Send Read Data */ if (if_state [unit] != read_wait) /* if we're not expecting it */ abort_command (unit, io_program_error, /* abort and source a data byte */ - error_source); /* tagged with EOI */ + error_source); /* tagged with EOI */ else - if_state [unit] = command_exec; /* now ready to execute */ + if_state [unit] = command_exec; /* the command is ready to execute */ break; case 0x08: /* Read Status */ - if (if_state [unit] != status_wait) /* if we're not expecting it */ + if (if_state [unit] != status_wait) /* if we're not expecting it, */ abort_command (unit, io_program_error, /* abort and source a data byte */ - error_source); /* tagged with EOI */ + error_source); /* tagged with EOI */ else /* all status commands */ if_state [unit] = read_xfer; /* are ready to transfer data */ break; case 0x09: /* CRC (Talk) */ - if_command [unit] = crc_talk; /* set the command */ + if_command [unit] = crc_talk; /* set up the command */ if_state [unit] = read_xfer; /* data will be going */ break; case 0x10: /* Device-Specified Jump */ - if_command [unit] = device_specified_jump; /* set the command */ + if_command [unit] = device_specified_jump; /* set up the command */ if_state [unit] = read_xfer; /* data will be going */ break; case 0x1E: /* Read Loopback */ - if_command [unit] = read_loopback; /* set the command */ + if_command [unit] = read_loopback; /* set up the command */ if_state [unit] = read_xfer; /* data will be going */ break; case 0x1F: /* Return Self-Test Result */ - if_command [unit] = return_self_test_result; /* set the command */ + if_command [unit] = return_self_test_result; /* set up the command */ if_state [unit] = read_xfer; /* data will be going */ icd_cntlr [unit].length = 1; /* return one byte that indicates */ buffer [0] = 0; /* that the self-test passed */ break; - default: /* an unsupported talk secondary */ + default: /* an unsupported talk secondary was received */ abort_command (unit, io_program_error, /* abort and source a data byte */ error_source); /* tagged with EOI */ break; @@ -1652,14 +1654,14 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma if (di [da].talker == 0 && di [da].listeners == 0 /* if there are no talkers or listeners */ && message_address == my_address) { /* and this is my secondary address, */ - if_command [unit] = amigo_identify; /* then this is an Amigo ID sequence */ - if_state [unit] = command_exec; /* set up execution */ + if_command [unit] = amigo_identify; /* then this is an Amigo ID sequence */ + if_state [unit] = command_exec; /* set up for execution */ da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ initiated = TRUE; /* log the command initiation */ } - else /* an unaddressed secondary */ - accepted = FALSE; /* is not accepted */ + else /* unaddressed secondaries */ + accepted = FALSE; /* are not accepted */ } @@ -1675,7 +1677,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma } - if (addressed && sim_is_active (&da_unit [unit])) { /* is the unit being addressed while busy? */ + if (addressed && sim_is_active (&da_unit [unit])) { /* is the unit being addressed while it is busy? */ if_state [unit] = command_wait; /* change the interface state to wait */ di_bus_control (da, unit, BUS_NRFD, 0); /* and assert NRFD to hold off the card */ @@ -1683,7 +1685,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma fprintf (sim_deb, ">>DA rwsc: Unit %d addressed while controller is busy\n", unit); } - if (stopped_listening) { /* was the unit unlistened? */ + if (stopped_listening) { /* was the unit Unlistened? */ if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy, */ complete_write (unit); /* then check for write completion */ @@ -1695,8 +1697,8 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma abort_command (unit, io_program_error, idle); /* then abort the pending command */ } - else if (stopped_talking) { /* was the unit untalked? */ - if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy */ + else if (stopped_talking) { /* was the unit Untalked? */ + if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy, */ complete_read (unit); /* then check for read completion */ else if (if_command [unit] == invalid) /* if a command was aborting, */ @@ -1705,10 +1707,10 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma } /* end of bus command processing */ -else { /* it is bus data (ATN denied) */ +else { /* it is bus data (ATN is denied) */ switch (if_state [unit]) { /* dispatch the interface state */ - case opcode_wait: /* wait for an opcode */ + case opcode_wait: /* waiting for an opcode */ if (DEBUG_PRI (da_dev, DEB_XFER)) sprintf (action, "opcode %02XH", data & DL_OPCODE_MASK); @@ -1716,8 +1718,8 @@ else { /* it is bus data (A if (dl_prepare_command (&icd_cntlr [unit], /* is the command valid? */ da_unit, unit)) { - if_state [unit] = parameter_wait; /* set up to get pad byte */ - icd_cntlr [unit].index = 0; /* reset the word index for byte 1 */ + if_state [unit] = parameter_wait; /* set up to get the pad byte */ + icd_cntlr [unit].index = 0; /* reset the word index for the next byte */ icd_cntlr [unit].length = /* convert the parameter count to bytes */ icd_cntlr [unit].length * 2 + 1; /* and include the pad byte */ } @@ -1730,7 +1732,7 @@ else { /* it is bus data (A break; - case parameter_wait: /* wait for a parameter */ + case parameter_wait: /* waiting for a parameter */ if (DEBUG_PRI (da_dev, DEB_XFER)) sprintf (action, "parameter %02XH", data); @@ -1748,13 +1750,13 @@ else { /* it is bus data (A break; - case write_xfer: /* transfer write data */ + case write_xfer: /* transferring write data */ if (icd_cntlr [unit].length > 0) /* if there is more to transfer */ put_buffer_byte (&icd_cntlr [unit], data); /* then add the byte to the buffer */ /* fall into error_sink handler */ - case error_sink: /* sink data after an error */ + case error_sink: /* sinking data after an error */ if (DEBUG_PRI (da_dev, DEB_XFER)) sprintf (action, "data %03o", data); @@ -1767,7 +1769,7 @@ else { /* it is bus data (A break; - default: /* data was received in wrong state */ + default: /* data was received in the wrong state */ abort_command (unit, io_program_error, /* report the error */ error_sink); /* and sink any data that follows */ @@ -1782,7 +1784,7 @@ if (accepted && DEBUG_PRI (da_dev, DEB_XFER)) fprintf (sim_deb, ">>DA xfer: HP-IB address %d accepted %s\n", GET_BUSADR (da_unit [unit].flags), action); -if (da_unit [unit].wait > 0) /* is service requested? */ +if (da_unit [unit].wait > 0) /* was service requested? */ activate_unit (&da_unit [unit]); /* schedule the unit */ if (initiated && DEBUG_PRI (da_dev, DEB_RWSC)) @@ -1811,14 +1813,13 @@ return accepted; /* indicate the acceptan has asserted NRFD must deny it before a talker may send data. If the interface is sending data and both ATN and NRFD are denied, then we reschedule the service routine to send the next byte. - */ void da_bus_respond (CARD_ID card, uint32 unit, uint8 new_cntl) { if (new_cntl & BUS_IFC) { /* is interface clear asserted? */ - di [da].listeners = 0; /* unlisten */ - di [da].talker = 0; /* untalk */ + di [da].listeners = 0; /* perform an Unlisten */ + di [da].talker = 0; /* and an Untalk */ if (icd_cntlr [unit].state == cntlr_busy) { /* is the controller busy? */ complete_write (unit); /* check for write completion */ @@ -1831,13 +1832,13 @@ if (new_cntl & BUS_IFC) { /* is interface clear as else if (if_command [unit] == invalid) /* if a command was aborting, */ complete_abort (unit); /* then complete it */ - else if (if_state [unit] == opcode_wait /* if waiting for an opcode */ + else if (if_state [unit] == opcode_wait /* if we're waiting for an opcode */ || if_state [unit] == parameter_wait) /* or a parameter, */ abort_command (unit, io_program_error, idle); /* then abort the pending command */ } -if (! (new_cntl & (BUS_ATN | BUS_NRFD)) /* in data mode and card is ready for data? */ - && (if_state [unit] == read_xfer /* is interface waiting to send data */ +if (!(new_cntl & (BUS_ATN | BUS_NRFD)) /* is the card in data mode and ready for data? */ + && (if_state [unit] == read_xfer /* is the interface waiting to send data */ || if_state [unit] == error_source)) /* or source error bytes? */ da_service (&da_unit [unit]); /* start or resume the transfer */ } @@ -1849,57 +1850,58 @@ if (! (new_cntl & (BUS_ATN | BUS_NRFD)) /* in data mode and card /* Start a command with parameters. - A command that has been pending until all of its parameters were received is + A command that has been waiting for all of its parameters to be received is now ready to start. If this is a disc command, call the disc library to validate the parameters and, if they are OK, to start the command. Status commands return the status values in the sector buffer and the number of words that were returned in the buffer length, which we convert to a byte count. - If the disc command was accepted, the controller will be busy. In this case, + If the disc command was accepted, the library returns a pointer to the unit + to be scheduled. For an ICD controller, the unit is always the one currently + addressed, so we simply test if the return is not NULL. If it isn't, then we set the next interface state as determined by the command that is executing. For example, a Read command sets the interface to read_wait status in order - to wait until the accompanying Send Read Data secondary is received. If the - controller is not busy, then the command was rejected, so we set DSJ = 1 and - leave the interface state in parameter_wait; the controller status will have - been set to the reason for rejection. + to wait until the accompanying Send Read Data secondary is received. - If the interface state is command_exec, then the disc command is ready for - execution, and we return TRUE to schedule the unit service. Otherwise, we - return FALSE, and the appropriate action will be taken by the caller. + If the return is NULL, then the command was rejected, so we set DSJ = 1 and + leave the interface state in parameter_wait; the controller status will have + been set to the reason for the rejection. + + If the next interface state is command_exec, then the disc command is ready + for execution, and we return TRUE to schedule the unit service. Otherwise, + we return FALSE, and the appropriate action will be taken by the caller. For all other commands, execution begins as soon as the correct parameters are received, so we set command_exec state and return TRUE. (Only Amigo - Clear and Inititate Self Test require parameters, so they will be the only + Clear and Initiate Self Test require parameters, so they will be the only other commands that must be started here.) -set wait = 0 if not executing (e.g., for read wait) Implementation notes: - 1. The ICD implemenation does not need to differentiate between unit and + 1. As the ICD implementation does not need to differentiate between unit and controller commands, the return value from the dl_start_command routine - is not used. + is not used other than as an indication of success or failure. */ static t_bool start_command (uint32 unit) { -if (if_command [unit] == disc_command) { /* starting a disc command? */ - dl_start_command (&icd_cntlr [unit], da_unit, unit); /* ask the controller to start the command */ - - icd_cntlr [unit].length = icd_cntlr [unit].length * 2; /* convert return length from words to bytes */ - - if (icd_cntlr [unit].state == cntlr_busy) /* was the command accepted? */ +if (if_command [unit] == disc_command) { /* are we starting a disc command? */ + if (dl_start_command (&icd_cntlr [unit], da_unit, unit)) { /* start the command; was it successful? */ + icd_cntlr [unit].length = icd_cntlr [unit].length * 2; /* convert the return length from words to bytes */ if_state [unit] = next_state [icd_cntlr [unit].opcode]; /* set the next interface state */ + } + else /* the command was rejected */ if_dsj [unit] = 1; /* so indicate an error */ - if (if_state [unit] == command_exec) /* if command is executing */ + if (if_state [unit] == command_exec) /* if the command is executing */ return TRUE; /* activate the unit */ else { /* if we must wait */ - da_unit [unit].wait = 0; /* for another secondary */ - return FALSE; /* skip the activation */ + da_unit [unit].wait = 0; /* for another secondary, */ + return FALSE; /* then skip the activation */ } } @@ -1926,7 +1928,7 @@ static void abort_command (uint32 unit, CNTLR_STATUS status, IF_STATE state) if_command [unit] = invalid; /* indicate an invalid command */ if_state [unit] = state; /* set the interface state as directed */ if_dsj [unit] = 1; /* set DSJ to indicate an error condition */ -dl_end_command (&icd_cntlr [unit], status); /* place the disc controller into a wait state */ +dl_end_command (&icd_cntlr [unit], status); /* place the disc controller into the wait state */ return; } @@ -1967,8 +1969,8 @@ static void complete_read (uint32 unit) if ((if_state [unit] == command_exec /* is a command executing */ || if_state [unit] == read_xfer) /* or is data transferring */ && (dl_classify (icd_cntlr [unit]) == class_read /* and the controller is executing */ - || dl_classify (icd_cntlr [unit]) == class_status)) { /* a read or status? */ - icd_cntlr [unit].eod = SET; /* set the end of data */ + || dl_classify (icd_cntlr [unit]) == class_status)) { /* a read or status command? */ + icd_cntlr [unit].eod = SET; /* set the end of data flag */ if_state [unit] = command_exec; /* set to execute */ da_unit [unit].PHASE = end_phase; /* the completion phase */ @@ -2016,7 +2018,7 @@ static void complete_write (uint32 unit) if ((if_state [unit] == command_exec /* is a command executing */ || if_state [unit] == write_xfer) /* or is data transferring */ && dl_classify (icd_cntlr [unit]) == class_write) { /* and the controller is executing a write? */ - icd_cntlr [unit].eod = SET; /* set the end of data */ + icd_cntlr [unit].eod = SET; /* set the end of data flag */ if_state [unit] = command_exec; /* set to execute */ da_unit [unit].PHASE = end_phase; /* the completion phase */ @@ -2049,7 +2051,7 @@ return; static void complete_abort (uint32 unit) { if (if_state [unit] != idle) { /* is the interface busy? */ - icd_cntlr [unit].eod = SET; /* set the end of data */ + icd_cntlr [unit].eod = SET; /* set the end of data flag */ da_service (&da_unit [unit]); /* and process the abort completion */ } @@ -2083,7 +2085,7 @@ else /* the lower byte is nex The supplied byte is stored in the sector buffer. The determination of which byte of the 16-bit buffer word to store is made by the polarity of the buffer - byte count. The count always begins with an even number, as it is set by + byte count. The count always begins with an even number, as it is set by doubling the word count returned from the disc library. Therefore, because we decrement the count first, the upper byte is indicated by an odd count, and the lower byte is indicated by an even count. The buffer index is @@ -2110,7 +2112,7 @@ return; static t_stat activate_unit (UNIT *uptr) { -uint32 unit; +int32 unit; t_stat result; if (DEBUG_PRI (da_dev, DEB_SERV)) { diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt index 358e0bb5..c9382484 100644 --- a/HP2100/hp2100_diag.txt +++ b/HP2100/hp2100_diag.txt @@ -1,6 +1,6 @@ SIMH/HP 21XX DIAGNOSTICS PERFORMANCE ==================================== - Last update: 2012-02-20 + Last update: 2012-03-30 The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation. @@ -70,7 +70,7 @@ The results of the diagnostic runs are summarized below: 103116 12967 Synchronous Interface 1438 - No simulation 103017 12966 Asynchronous Data Set 1519 3.8-0 Passed 103121 12968 Asynchronous Comm. Interface 1602 - No simulation -103024 12821 ICD Disc Interface 1928 3.8-2 Passed +103024 12821 ICD Disc Interface 1928 3.9-0 Passed 104000 2600 Keyboard Display Terminal 1615 - No simulation 104003 Teleprinter 1509 3.2-3 Partial @@ -128,8 +128,9 @@ offline diagnostics: Part Number Diagnostic Name Code Op. Sys. Code Vers. Result ----------- ------------------------------- ---- -------- ---- ----- ---------- 12824-16002 Vector Instruction Set Firmware 2026 RTE-IVB 5010 3.8-0 Passed -91711-12032 ICD/MAC Disc Diagnostic 2201 RTE-IVB 5010 3.8-2 Partial +91711-12032 ICD/MAC Disc Diagnostic 2201 RTE-IVB 5010 3.9-0 Partial 92067-16013 Extended Memory Area Firmware 1805 RTE-IVB 5010 3.8-0 Passed + 12829-16006 Vector Instruction Set Firmware 2226 RTE-6/VM 6200 3.8-0 Passed 92084-16423 Virtual Memory Area Firmware 2121 RTE-6/VM 6200 3.8-0 Passed 92835-16006 SIGNAL/1000 Firmware Diagnostic 2040 RTE-6/VM 6200 3.8-0 Passed @@ -3527,7 +3528,9 @@ BINARY FILE: 91711-12032 Rev. 2201 HOST SYSTEM: RTE-IVB Rev. 5010 -CONFIGURATION: sim> set DS0 FORMAT +CONFIGURATION: sim> set DA1 7906H + sim> set DA1 FORMAT + sim> attach DA1 scratch.U1.7906H.disc sim> go TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC @@ -3540,12 +3543,12 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : Start trace at what step ? 0 DIAG : Trace operations which are not part of the test steps ? NO DIAG : Stop after first failure ? NO - DIAG : Disc LU ? 41 - DIAG : Disc address ? 0 + DIAG : Disc LU ? 14 + DIAG : Disc address ? 1 DIAG : Drive model number ? 06 DIAG : Do you want to run the interactive part of the test ? YES - DIAG : LU 41 address 0 select code 25 7906 drive + DIAG : LU 14 address 1 select code 12 7906 drive DIAG : CHECK THAT ALL SWITCHES ARE SET CORRECTLY. DIAG : THE RUN/STOP SWITCH SHOULD BE IN THE RUN POSITION. @@ -3569,7 +3572,7 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 1 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : REQUEST STATUS drive type 0 0 0 50 0 + DIAG : REQUEST STATUS drive type 0 0 0 40 0 DIAG : IDENTIFY result 3 0 0 40 0 DIAG : STEP 3 PASSED @@ -3580,19 +3583,19 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : cylinders: 0 - 410 heads: 0 - 3 sectors: 0 - 47 DIAG : First and last tracks on LU: DIAG : cylinder 0 head 0 (track 0) - DIAG : cylinder 199 head 1 (track 399) + DIAG : cylinder 49 head 1 (track 99) DIAG : First and last spares on LU: - DIAG : cylinder 200 head 0 (track 400) - DIAG : cylinder 202 head 1 (track 405) + DIAG : cylinder 50 head 0 + DIAG : cylinder 49 head 1 (track 99) DIAG : Heads on LU (first - last): 0 - 1 DIAG : Searching entire LU for file directory: DIAG : NO DIRECTORY OR UNABLE TO READ DIRECTORY ON TEST LU DIAG : First and last tracks available for testing: DIAG : cylinder 0 head 0 (track 0) - DIAG : cylinder 199 head 1 (track 399) + DIAG : cylinder 49 head 1 (track 99) DIAG : Default test tracks: - DIAG : cylinder 199 head 0 (track 398) - DIAG : cylinder 199 head 1 (track 399) + DIAG : cylinder 49 head 0 (track 98) + DIAG : cylinder 49 head 1 (track 99) DIAG : Use default test tracks ? YES DIAG : Checking test track preambles. @@ -3601,11 +3604,11 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : Beginning part 2 of diagnostic. DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : STEP 4 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : REQUEST DISC ADDR cy 199 hd 0 sec 0 0 0 40 0 + DIAG : REQUEST DISC ADDR cy 49 hd 0 sec 0 0 0 40 0 DIAG : STEP 5 PASSED DIAG : operation parameters/results spd cs ds DSJ @@ -3614,8 +3617,8 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 6 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : REQUEST SECTOR ADDR sec 2 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : REQUEST SECTOR ADDR sec 6 0 0 40 0 DIAG : STEP 7 PASSED DIAG : operation parameters/results spd cs ds DSJ @@ -3626,153 +3629,153 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 8 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 138 0 0 40 0 - DIAG : decode preamble cy 199 hd 0 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 0 sec 0 spd 0 DIAG : STEP 9 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : WRITE FULL SECTOR length 138 0 0 40 0 DIAG : STEP 10 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : VERIFY sector count 1 0 0 40 0 DIAG : STEP 11 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : READ length 128 0 0 40 0 DIAG : STEP 12 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : READ WITH OFFSET length 128 offset 55 0 0 40 0 DIAG : STEP 13 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : READ WITHOUT VERIFY length 128 0 0 40 0 DIAG : STEP 14 FAILED DIAG : operation parameters/results spd cs ds DSJ DIAG : SET FILE MASK mask 0 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 47 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 47 0 37 40 0 DIAG : READ FULL SECTOR length 140 0 14 40 1 DIAG : STEP 16 PASSED DIAG : operation parameters/results spd cs ds DSJ DIAG : SET FILE MASK mask 2 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 47 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 47 0 37 40 0 DIAG : READ FULL SECTOR length 140 0 0 40 0 DIAG : STEP 17 PASSED DIAG : operation parameters/results spd cs ds DSJ DIAG : SET FILE MASK mask 2 0 0 40 0 - DIAG : SEEK cy 199 hd 3 sec 47 0 37 40 0 + DIAG : SEEK cy 49 hd 3 sec 47 0 37 40 0 DIAG : READ FULL SECTOR length 140 0 14 40 1 DIAG : STEP 18 PASSED DIAG : operation parameters/results spd cs ds DSJ DIAG : SET FILE MASK mask 3 0 0 40 0 - DIAG : SEEK cy 199 hd 3 sec 47 0 37 40 0 + DIAG : SEEK cy 49 hd 3 sec 47 0 37 40 0 DIAG : READ FULL SECTOR length 140 0 0 40 0 - DIAG : REQUEST DISC ADDR cy 200 hd 0 sec 1 0 0 40 0 + DIAG : REQUEST DISC ADDR cy 50 hd 0 sec 1 0 0 40 0 DIAG : STEP 19 PASSED DIAG : operation parameters/results spd cs ds DSJ DIAG : SET FILE MASK mask 11 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 47 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 47 0 37 40 0 DIAG : READ FULL SECTOR length 140 0 0 40 0 - DIAG : REQUEST DISC ADDR cy 198 hd 0 sec 1 0 0 40 0 + DIAG : REQUEST DISC ADDR cy 48 hd 0 sec 1 0 0 40 0 DIAG : STEP 20 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 1 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 1 1 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 0 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 0 sec 0 spd 0 DIAG : STEP 21 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 0 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 4 4 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : STEP 22 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 1 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 2 2 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : STEP 25 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 0 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 6 6 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : STEP 26 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 1 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 3 3 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : STEP 28 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 0 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 4 4 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : STEP 30 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 0 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 0 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 0 sec 0 spd 0 DIAG : SET FILE MASK mask 0 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : READ length 128 0 0 40 0 DIAG : STEP 31 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 1 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : SET FILE MASK mask 0 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ length 128 0 0 40 0 DIAG : STEP 32 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : WRITE length 128 0 0 40 0 DIAG : STEP 35 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : READ length 128 0 0 40 0 DIAG : test data read test passed DIAG : STEP 36 PASSED @@ -3801,19 +3804,19 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 40 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : VERIFY sector count 1 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : VERIFY sector count 2 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : VERIFY sector count 4 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : VERIFY sector count 8 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : VERIFY sector count 16 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : VERIFY sector count 32 0 0 40 0 - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : VERIFY sector count 48 0 0 40 0 DIAG : STEP 45 PASSED @@ -3854,38 +3857,38 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 50 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 198 hd 1 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 48 hd 1 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : STEP 52 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 0 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 0 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : STEP 54 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 1 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 0 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : SET FILE MASK mask 0 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ length 128 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 5 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 5 0 37 40 0 DIAG : READ FULL SECTOR length 138 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : WRITE FULL SECTOR length 138 0 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 1 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 1 0 37 40 0 DIAG : READ length 128 0 0 40 0 DIAG : STEP 55 FAILED @@ -3912,7 +3915,7 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 60 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 4 sec 0 0 23 44 1 + DIAG : SEEK cy 49 hd 4 sec 0 0 23 44 1 DIAG : SEEK cy 0 hd 0 sec 0 0 37 40 0 DIAG : STEP 72 PASSED @@ -3922,7 +3925,7 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 73 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 49 0 23 44 1 + DIAG : SEEK cy 49 hd 1 sec 49 0 23 44 1 DIAG : SEEK cy 0 hd 0 sec 0 0 37 40 0 DIAG : STEP 74 PASSED @@ -3948,12 +3951,12 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 81 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 - DIAG : ADDRESS RECORD cy 199 hd 1 sec 0 0 0 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 + DIAG : ADDRESS RECORD cy 49 hd 1 sec 0 0 0 40 0 DIAG : INITIALIZE length 6144 spd 2 2 0 40 0 - DIAG : SEEK cy 199 hd 1 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 40 0 DIAG : READ FULL SECTOR length 3 0 0 40 0 - DIAG : decode preamble cy 199 hd 1 sec 0 spd 0 + DIAG : decode preamble cy 49 hd 1 sec 0 spd 0 DIAG : STEP 82 FAILED @@ -3965,17 +3968,17 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : STEP 83 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 0 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 0 0 DIAG : WRITE length 1 0 0 0 0 DIAG : STEP 84 FAILED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 0 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 0 0 DIAG : WRITE FULL SECTOR length 1 0 23 0 1 DIAG : STEP 85 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 1 sec 0 0 37 0 0 + DIAG : SEEK cy 49 hd 1 sec 0 0 37 0 0 DIAG : INITIALIZE length 1 spd 0 0 23 0 1 DIAG : STEP 86 PASSED @@ -3992,21 +3995,21 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : Type , DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 140 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 140 0 DIAG : STEP 89 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 140 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 140 0 DIAG : WRITE length 1 0 23 140 1 DIAG : STEP 90 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 140 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 140 0 DIAG : WRITE FULL SECTOR length 1 0 23 140 1 DIAG : STEP 91 PASSED DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 140 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 140 0 DIAG : INITIALIZE length 1 spd 0 0 23 140 1 DIAG : STEP 92 PASSED @@ -4015,7 +4018,7 @@ TEST REPORT: DIAG : HP-IB DISC DIAGNOSTIC DIAG : Type , DIAG : operation parameters/results spd cs ds DSJ - DIAG : SEEK cy 199 hd 0 sec 0 0 37 40 0 + DIAG : SEEK cy 49 hd 0 sec 0 0 37 40 0 DIAG : STEP 97 PASSED DIAG : Part 3 of diagnostic completed. diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index f244d356..c26d16e6 100644 --- a/HP2100/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -859,7 +859,7 @@ t_stat dpc_svc (UNIT *uptr) int32 da, drv, err; err = 0; /* assume no err */ -drv = uptr - dpc_dev.units; /* get drive no */ +drv = uptr - dpc_unit; /* get drive no */ if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ dpc.command = CLEAR; /* clr cch cmd */ @@ -1052,7 +1052,7 @@ return detach_unit (uptr); /* detach unit */ t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) { -uint32 drv; +int32 drv; if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to load */ @@ -1060,7 +1060,7 @@ if (value == UNIT_UNLOAD) /* unload heads? */ uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */ else { /* load heads */ uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */ - drv = uptr - dpc_dev.units; /* get drive no */ + drv = uptr - dpc_unit; /* get drive no */ dpc_sta[drv] = dpc_sta[drv] | STA_ATN | STA_1ST; /* update status */ if (dpc_poll) /* polling enabled? */ dpcio (&dpc_dib, ioENF, 0); /* set flag */ diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index 3f4062f8..06c92b2b 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -678,7 +678,7 @@ t_stat dqc_svc (UNIT *uptr) int32 da, drv, err; err = 0; /* assume no err */ -drv = uptr - dqc_dev.units; /* get drive no */ +drv = uptr - dqc_unit; /* get drive no */ if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ dqc.command = CLEAR; /* clr cch cmd */ dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c index 79552417..29df4589 100644 --- a/HP2100/hp2100_ds.c +++ b/HP2100/hp2100_ds.c @@ -26,7 +26,7 @@ DS 13037D/13175D disc controller/interface - 02-Mar-12 JDB Rewritten to use the MAC/ICD disc controller library + 29-Mar-12 JDB Rewritten to use the MAC/ICD disc controller library ioIOO now notifies controller service of parameter output 14-Feb-12 JDB Corrected SRQ generation and FIFO under/overrun detection Corrected Clear command to conform to the hardware @@ -60,15 +60,14 @@ The 13037D multiple-access (MAC) disc controller supports from one to eight HP 7905 (15 MB), 7906 (20MB), 7920 (50 MB), and 7925 (120 MB) disc drives accessed by one to eight CPUs. The controller hardware consists of a 16-bit - microprogrammed processor constructed from 74S181 bit slices and operating at - 5 MHz, a device controller providing the interconnections to the drives and - CPU interfaces, and error correction circuitry that enables the controller to - correct up to a 32-bit error burst. 1024 words of 24-bit firmware are stored - in ROM. + microprogrammed processor constructed from 74S181 bit slices operating at 5 + MHz, a device controller providing the interconnections to the drives and CPU + interfaces, and an error correction controller that enables the correction of + up to 32-bit error bursts. 1024 words of 24-bit firmware are stored in ROM. - The 13175D disc interface is used to connect the CPU to the 13037 device - controller. In a multiple-CPU system, one interface is strapped to reset the - controller when the CPU's front panel PRESET button is pressed. + The 13175D disc interface is used to connect the HP 1000 CPU to the 13037 + device controller. In a multiple-CPU system, one interface is strapped to + reset the controller when the CPU's front panel PRESET button is pressed. This module simulates a 13037D connected to a single 13175D interface. From one to eight drives may be connected, and drive types may be freely @@ -134,7 +133,7 @@ #define FIFO_STOP (ds.fifo_count >= 5) /* FIFO stop filling test */ #define FIFO_FULL (ds.fifo_count == FIFO_SIZE) /* FIFO full test */ -#define PRESET_ENABLE TRUE /* Preset Jumper (W4) enabled */ +#define PRESET_ENABLE TRUE /* Preset Jumper (W4) is enabled */ /* Debug flags */ @@ -223,7 +222,7 @@ static t_stat activate_unit (UNIT *uptr); 1. The validation routine does not allow the model number or autosizing option to be changed when the unit is attached. Therefore, specifying - UNIT_ATT in the mask field has no deleterious effect. + UNIT_ATT in the mask field has no adverse effect. 2. The modifier DEVNO is deprecated in favor of SC but is retained for compatibility. @@ -237,14 +236,14 @@ static DIB ds_dib = { &ds_io, DS }; #define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD) static UNIT ds_unit [] = { - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 0 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 1 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 2 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 3 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 4 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 5 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 6 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* unit 7 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 0 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 1 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 2 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 3 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 4 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 5 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 6 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 7 */ { UDATA (&ds_service_controller, UNIT_DIS, 0) }, /* controller unit */ { UDATA (&ds_service_timer, UNIT_DIS, 0) } /* timer unit */ }; @@ -252,8 +251,8 @@ static UNIT ds_unit [] = { static REG ds_reg [] = { { FLDATA (CMFOL, ds.cmfol, 0) }, { FLDATA (CMRDY, ds.cmrdy, 0) }, - { BRDATA (FIFO, ds.fifo, 8, 16, FIFO_SIZE), REG_CIRC }, { DRDATA (FCNT, ds.fifo_count, 5) }, + { BRDATA (FIFO, ds.fifo, 8, 16, FIFO_SIZE), REG_CIRC }, { ORDATA (FREG, ds.fifo_reg, 32), REG_HRO }, { ORDATA (CNTYPE, mac_cntlr.type, 2), REG_HRO }, @@ -375,13 +374,13 @@ DEVICE ds_dev = { The control path consists of the usual control, flag buffer, flag, and SRQ flip-flops, although flag and SRQ are decoupled to allow the full DCPC transfer rate through the FIFO (driving SRQ from the flag limits transfers to - only every other cycle). SRQ is based on the FIFO level: if data or room in - the FIFO is available, SRQ is set to transfer it. The flag is only used to - signal an interrupt at the end of a command. + every other cycle). SRQ is based on the FIFO level: if data or room in the + FIFO is available, SRQ is set to initiate a transfer. The flag is only used + to signal an interrupt at the end of a command. One unusual aspect is that SFC and SFS test different things, rather than - complementary states of the same thing. SFC tests the busy flip-flop, and - SFS tests the flag flip-flop. + complementary states of the same thing. SFC tests the controller busy state, + and SFS tests the flag flip-flop. In addition, the card contains end-of-data-transfer, command-follows, and command-ready flip-flops. EDT is set when the DCPC EDT signal is asserted @@ -397,16 +396,16 @@ DEVICE ds_dev = { 1. In hardware, SRQ is enabled only when the controller is reading or writing the disc (IFIN or IFOUT functions are asserted) and set when the FIFO is not empty (read) or not full (write). In simulation, SRQ is set - by the unit service read/write data phase transfers and cleared below - when the FIFO is empty (read) or full (write). + by the unit service read/write data phase transfers and cleared in the + IOI and IOO signal handlers when the FIFO is empty (read) or full + (write). 2. The DCPC EDT signal cannot set the controller's end-of-data flag directly because a write EOD must occur only after the FIFO has been drained. - 3. Polling the interface or drives must be deferred to the end of the I/O - signal service. If they are performed in the IOO/STC handlers - themselves, an associated CLF might clear the flag that was set by the - poll. + 3. Polling the interface or drives must be deferred to the end of I/O signal + handling. If they are performed in the IOO/STC handlers themselves, an + associated CLF might clear the flag that was set by the poll. 4. Executing a CLC sets the controller's end-of-data flag, which will abort a read or write data transfer in progress. Parameter transfers are not @@ -417,7 +416,7 @@ DEVICE ds_dev = { 5. The hardware Interface Function and Flag Buses are not implemented explicitly. Instead, interface functions and signals are inferred by the - interface by the current command operation and phase. + interface from the current command operation and phase. */ uint32 ds_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) @@ -512,7 +511,7 @@ while (working_set) { if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS)) fprintf (sim_deb, ">>DS cmds: [OTx%s] SRQ cleared\n", hold_or_clear); - ds.srq = CLEAR; /* clear SRQ */ + ds.srq = CLEAR; /* clear SRQ to stop filling */ } } break; @@ -622,7 +621,7 @@ return stat_data; overrun error. Write transfers set the initial SRQ to request words from the CPU. As each - arrives, it is unloaded from the FIFO into the sector buffer, and SRQ is + word arrives, it is unloaded from the FIFO into the sector buffer, and SRQ is enabled. If the current sector transfer is complete, the controller is moved to the end phase. If the FIFO underflows, the write terminates with a data overrun error. @@ -639,12 +638,12 @@ return stat_data; Implementation notes: - 1. Every command except Seek, Recalibrate, and End set the flag when the + 1. Every command except Seek, Recalibrate, and End sets the flag when the command completes. A command completes when the controller is no longer - busy (it becomes idle for Seek, Recalibrate, and End, and becomes waiting - for all others). Seek and Recalibrate may generate errors (e.g., heads - unloaded), in which case the flag must be set. But in these cases, the - controller state is waiting, not idle. + busy (it becomes idle for Seek, Recalibrate, and End, or it becomes + waiting for all others). Seek and Recalibrate may generate errors (e.g., + heads unloaded), in which case the flag must be set. But in these cases, + the controller state is waiting, not idle. However, it is insufficient simply to check that the controller has moved to the wait state, because a seek may complete while the controller is @@ -653,8 +652,9 @@ return stat_data; completes, another command is issued that attempts to access unit 1, which is not ready. The command fails with a Status-2 error, and the controller moves to the wait state. When the seek completes, the - controller is waiting with error status. We must determine if the seek - completed successfully or not, as we must interrupt in the latter case. + controller is waiting with error status. We must determine whether the + seek completed successfully or not, as we must interrupt in the latter + case. Therefore, we determine seek completion by checking if the Attention status was set. Attention sets only if the seek completes successfully. @@ -663,31 +663,31 @@ return stat_data; command terminated before the seek ever started. Also, a seek may complete while the controller is busy, waiting, or idle.) - 2. For debug printouts, we want to print the name of the command that has - completed when the controller returns to the idle or wait state. - Normally, we would use the controller's "opcode" field to identify the - command that completed. However, while waiting for Seek or Recalibrate - completion, "opcode" may be set to another command if that command does - not access this drive. For example, it might be set to a Read of - another unit, or a Request Status for this unit. So we can't rely on - "opcode" to report the correct positioning command completion. + 2. For debug printouts, we want to print the name of the command that has + completed when the controller returns to the idle or wait state. + Normally, we would use the controller's "opcode" field to identify the + command that completed. However, while waiting for Seek or Recalibrate + completion, "opcode" may be set to another command if that command does + not access this drive. For example, it might be set to a Read of another + unit, or a Request Status for this unit. So we can't rely on "opcode" to + report the correct name of the completed positioning command. - However, we cannot rely on "uptr->OP" either, as it can be changed - during the course of a command. For example, Read Without Verify is - changed to Read after a track crossing. + However, we cannot rely on "uptr->OP" either, as that can be changed + during the course of a command. For example, Read Without Verify is + changed to Read after a track crossing. - Instead, we have to determine whether a seek is completing. If it is, - then we report "uptr->OP"; otherwise, we report "opcode". + Instead, we have to determine whether a seek is completing. If it is, + then we report "uptr->OP"; otherwise, we report "opcode". - 3. The initial write SRQ must set only at the transition from the start - phase to the data phase. If a write command begins with an auto-seek, - the drive service will be entered twice in the start phase (the first - entry performs the seek, and the second begins the write). In hardware, - SRQ does not assert until the write begins. + 3. The initial write SRQ must set only at the transition from the start + phase to the data phase. If a write command begins with an auto-seek, + the drive service will be entered twice in the start phase (the first + entry performs the seek, and the second begins the write). In hardware, + SRQ does not assert until the write begins. - 4. The DCPC EDT signal cannot set the controller's end-of-data flag - directly because a write EOD must only occur after the FIFO has been - drained. + 4. The DCPC EDT signal cannot set the controller's end-of-data flag + directly because a write EOD must only occur after the FIFO has been + drained. */ t_stat ds_service_drive (UNIT *uptr) @@ -695,9 +695,10 @@ t_stat ds_service_drive (UNIT *uptr) static const char completion_message [] = ">>DS rwsc: Unit %d %s command completed\n"; t_stat result; t_bool seek_completion; -FLIP_FLOP entry_srq = ds.srq; /* SRQ state on entry */ -CNTLR_PHASE entry_phase = (CNTLR_PHASE) uptr->PHASE; /* operation phase on entry */ -uint32 entry_status = uptr->STAT; /* drive status on entry */ +int32 unit; +FLIP_FLOP entry_srq = ds.srq; /* get the SRQ state on entry */ +CNTLR_PHASE entry_phase = (CNTLR_PHASE) uptr->PHASE; /* get the operation phase on entry */ +uint32 entry_status = uptr->STAT; /* get the drive status on entry */ result = dl_service_drive (&mac_cntlr, uptr); /* service the drive */ @@ -764,7 +765,7 @@ if ((CNTLR_PHASE) uptr->PHASE == data_phase) /* is the drive in the d break; - default: /* entered with an invalid state */ + default: /* we were entered with an invalid state */ result = SCPE_IERR; /* return an internal (programming) error */ break; } /* end of data phase operation dispatch */ @@ -774,13 +775,13 @@ if (DEBUG_PRI (ds_dev, DEB_CMDS) && entry_srq != ds.srq) fprintf (sim_deb, ">>DS cmds: SRQ %s\n", ds.srq == SET ? "set" : "cleared"); -if (uptr->wait) /* is service requested? */ +if (uptr->wait) /* was service requested? */ activate_unit (uptr); /* schedule the next event */ seek_completion = ~entry_status & uptr->STAT & DL_S2ATN; /* seek is complete when Attention sets */ if (mac_cntlr.state != cntlr_busy) { /* is the command complete? */ - if (mac_cntlr.state == cntlr_wait && !seek_completion) /* is it command and not seek completion? */ + if (mac_cntlr.state == cntlr_wait && !seek_completion) /* is it command but not seek completion? */ ds_io (&ds_dib, ioENF, 0); /* set the data flag to interrupt the CPU */ poll_interface (); /* poll the interface for the next command */ @@ -788,22 +789,22 @@ if (mac_cntlr.state != cntlr_busy) { /* is the command co } -if (DEBUG_PRI (ds_dev, DEB_RWSC)) +if (DEBUG_PRI (ds_dev, DEB_RWSC)) { + unit = uptr - ds_unit; /* get the unit number */ + if (result == SCPE_IERR) /* did an internal error occur? */ fprintf (sim_deb, ">>DS rwsc: Unit %d %s command %s phase service not handled\n", - uptr - ds_dev.units, - dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP), + unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP), dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); else if (seek_completion) /* if a seek has completed */ fprintf (sim_deb, completion_message, /* report the unit command */ - uptr - ds_dev.units, - dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP)); + unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP)); else if (mac_cntlr.state == cntlr_wait) /* if the controller has stopped */ fprintf (sim_deb, completion_message, /* report the controller command */ - uptr - ds_dev.units, - dl_opcode_name (MAC, mac_cntlr.opcode)); + unit, dl_opcode_name (MAC, mac_cntlr.opcode)); + } return result; /* return the result of the service */ } @@ -862,11 +863,11 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current case clear: case set_file_mask: case wakeup: - ds_io (&ds_dib, ioENF, 0); /* complete the operation with the flag set */ + ds_io (&ds_dib, ioENF, 0); /* complete the operation and set the flag */ break; - default: /* entered with an invalid state */ + default: /* we were entered with an invalid state */ result = SCPE_IERR; /* return an internal (programming) error */ break; } /* end of operation dispatch */ @@ -917,7 +918,7 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current break; - default: /* entered with an invalid state */ + default: /* we were entered with an invalid state */ result = SCPE_IERR; /* return an internal (programming) error */ break; } /* end of operation dispatch */ @@ -976,7 +977,7 @@ return result; /* return the result of 1. During a power-on reset, a pointer to the FIFO simulation register is saved to allow access to the "qptr" field during FIFO loading and - unloading. This enables the SCP to view the FIFO as a circular queue, so + unloading. This enables SCP to view the FIFO as a circular queue, so that the bottom word of the FIFO is always displayed as FIFO[0], regardless of where it is in the actual FIFO array. @@ -992,7 +993,7 @@ if (sim_switches & SWMASK ('P')) { /* is this a power-on re ds.fifo_reg = find_reg ("FIFO", NULL, dptr); /* find the FIFO register entry */ if (ds.fifo_reg == NULL) /* if it cannot be found, */ - return SCPE_IERR; /* report a programming error! */ + return SCPE_IERR; /* report a programming error */ else { /* found it */ ds.fifo_reg->qptr = 0; /* so reset the FIFO bottom index */ @@ -1064,7 +1065,7 @@ return result; /* Boot a MAC disc drive. The MAC disc bootstrap program is loaded from the HP 12992B Boot Loader ROM - into memory, the I/O instructions are configured from the interface card + into memory, the I/O instructions are configured for the interface card's select code, and the program is run to boot from the specified unit. The loader supports booting from cylinder 0 of drive unit 0 only. Before execution, the S register is automatically set as follows: @@ -1166,7 +1167,7 @@ if (unitno != 0) /* boot supported on return SCPE_NOFNC; /* report "Command not allowed" if attempted */ if (ibl_copy (ds_rom, ds_dib.select_code)) /* copy the boot ROM to memory and configure */ - return SCPE_IERR; /* return an internal error if failed */ + return SCPE_IERR; /* return an internal error if the copy failed */ SR = SR & (IBL_OPT | IBL_DS_HEAD) /* set S to a reasonable value */ | IBL_DS | IBL_MAN | (ds_dib.select_code << IBL_V_DEV); /* before boot execution */ @@ -1193,7 +1194,7 @@ return SCPE_OK; t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) { -const t_bool load = (value != UNIT_UNLOAD); /* true if heads are loading */ +const t_bool load = (value != UNIT_UNLOAD); /* true if the heads are loading */ return dl_load_unload (&mac_cntlr, uptr, load); /* load or unload the heads */ } @@ -1265,7 +1266,7 @@ if (uptr) { /* did the command start time = uptr->wait; /* save the activation time */ if (time) /* was the unit scheduled? */ - activate_unit (uptr); /* activate it (clears "wait") */ + activate_unit (uptr); /* activate it (and clear the "wait" field) */ if (DEBUG_PRI (ds_dev, DEB_RWSC)) { unit = uptr - ds_unit; /* get the unit number */ @@ -1337,8 +1338,8 @@ return; void poll_drives (void) { -if (mac_cntlr.state == cntlr_idle && ds.control == SET) /* controller is idle and OK to interrupt? */ - if (dl_poll_drives (&mac_cntlr, ds_unit, DL_MAXDRIVE)) /* poll drives; was Attention seen? */ +if (mac_cntlr.state == cntlr_idle && ds.control == SET) /* is the controller idle and interrupts are allowed? */ + if (dl_poll_drives (&mac_cntlr, ds_unit, DL_MAXDRIVE)) /* poll the drives; was Attention seen? */ ds_io (&ds_dib, ioENF, 0); /* request an interrupt */ return; } @@ -1455,7 +1456,7 @@ return; static t_stat activate_unit (UNIT *uptr) { -uint32 unit; +int32 unit; t_stat result; if (DEBUG_PRI (ds_dev, DEB_SERV)) { diff --git a/HP2100/hp2100_mpx.c b/HP2100/hp2100_mpx.c index 65aa65c2..a4d91dd9 100644 --- a/HP2100/hp2100_mpx.c +++ b/HP2100/hp2100_mpx.c @@ -1658,7 +1658,7 @@ return SCPE_OK; t_stat mpx_line_svc (UNIT *uptr) { -const uint32 port = uptr - mpx_unit; /* port number */ +const int32 port = uptr - mpx_unit; /* port number */ const uint16 rt = mpx_rcvtype [port]; /* receive type for port */ const uint32 data_bits = 5 + GET_BPC (mpx_config [port]); /* number of data bits */ const uint32 data_mask = (1 << data_bits) - 1; /* mask for data bits */ diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index bc3acca6..c78c5e0c 100644 --- a/HP2100/hp2100_ms.c +++ b/HP2100/hp2100_ms.c @@ -690,7 +690,7 @@ int32 unum; t_mtrlnt tbc; t_stat st, r = SCPE_OK; -unum = uptr - msc_dev.units; /* get unit number */ +unum = uptr - msc_unit; /* get unit number */ if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) { /* offline? */ msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */ @@ -905,7 +905,7 @@ else t_stat ms_map_err (UNIT *uptr, t_stat st) { -int32 unum = uptr - msc_dev.units; /* get unit number */ +int32 unum = uptr - msc_unit; /* get unit number */ if (DEBUG_PRI (msc_dev, DEB_RWS)) fprintf (sim_deb, diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index 144db5de..72066de9 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -25,6 +25,7 @@ MT 12559A 3030 nine track magnetic tape + 25-Mar-12 JDB Removed redundant MTAB_VUN from "format" MTAB entry 10-Feb-12 JDB Deprecated DEVNO in favor of SC 28-Mar-11 JDB Tidied up signal handling 29-Oct-10 JDB Fixed command scanning error in mtcio ioIOO handler @@ -220,7 +221,7 @@ REG mtc_reg[] = { MTAB mtc_mod[] = { { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_VUN, 0, "FORMAT", "FORMAT", + { MTAB_XTD | MTAB_VDV, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev }, diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index 82740889..92208b00 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -985,7 +985,7 @@ return SCPE_OK; t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) { -int32 u = uptr - tty_dev.units; +int32 u = uptr - tty_unit; if (u > TTO) return SCPE_NOFNC; if ((u == TTI) && (val == TT_MODE_7P)) @@ -997,7 +997,7 @@ return SCPE_OK; t_stat tty_set_alf (UNIT *uptr, int32 val, char *cptr, void *desc) { -int32 u = uptr - tty_dev.units; +int32 u = uptr - tty_unit; if (u != TTI) return SCPE_NOFNC; return SCPE_OK; diff --git a/HP2100/hp_disclib.c b/HP2100/hp_disclib.c index 14e3aaa7..f5218ff6 100644 --- a/HP2100/hp_disclib.c +++ b/HP2100/hp_disclib.c @@ -24,7 +24,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. - 20-Mar-12 JDB First release + 28-Mar-12 JDB First release 09-Nov-11 JDB Created disc controller common library from DS simulator References: @@ -65,6 +65,11 @@ disc heads, classify commands, and provide opcode and phase name strings for debugging. + Autosizing is supported when attaching a disc image. If enabled, the model + of the drive is set to match the disc image size. For example, if a 50 MB + disc image is attached to a unit set for autosizing, the unit's model will be + set to a 7920(H). + The interface simulator declares a structure that contains the state variables for a controller. A MAC controller may handle multiple disc units. An ICD controller handles only a single disc unit, but multiple controllers @@ -79,7 +84,7 @@ stored in the controller state structure. The controller maintains the current index into the buffer, as well as the length of valid data stored there. Other than setting the length when the controller places data into - the buffer, and resetting the index at the start of a sector read or write, + the buffer and resetting the index at the start of a sector read or write, the interface simulator is free to manipulate these values as desired. In general, a user of the library is free to read any of the controller state @@ -87,16 +92,16 @@ with controller operations, with these exceptions: Field Name Description - =========== ======================== + =========== ============================ status controller status eod end of data flag index data buffer index length data buffer length - seek_time seek delay time + seek_time per-cylinder seek delay time sector_time intersector delay time - cmd_time command start delay time - data_time data transfer delay time - wait_time command wait timeout + cmd_time command response time + data_time data transfer response time + wait_time command wait time In hardware, the controller executes in three basic states: @@ -121,10 +126,10 @@ 3. In command execution, which processes the current command. - During command execution, waits for input parameters, seek completion, - data transfers, and output status words are handled internally. Each - wait is governed by the 1.8 second timer; if it expires, the command is - aborted. + During command execution, the waits for input parameters, seek + completion, data transfers, and output status words are handled + internally. Each wait is governed by the 1.8 second timer; if it + expires, the command is aborted. In simulation, these states are represented by the values cntlr_idle, cntlr_wait, and cntlr_busy, respectively. @@ -134,14 +139,15 @@ unit of a contiguous array is passed, and the unit number present in the command is used to index to the target unit. - A MAC controller emulation requires an array of two contiguous auxiliary - units containing a controller unit and a command wait timeout unit. Commands + A MAC controller emulation also requires an array of two contiguous auxiliary + units containing a controller unit and a command wait timeout unit. Commands that do not access the drive, such as Address Record, are scheduled on the controller unit to allow controller commands to execute while drive units are - seeking. The command wait timer limits the amount of time the controller will - wait for the interface to supply a command or parameter. A pointer to the - auxiliary unit array is set up during controller state variable - initialization. + seeking. The command wait timer limits the amount of time the controller + will wait for the interface to supply a command or parameter. A pointer to + the auxiliary unit array is set up during controller state variable + initialization. The auxiliary array may be separate or an extension of the + drive unit array. An ICD controller manages a single unit corresponding to the drive in which the controller is integrated. An interface declares a unit array @@ -179,9 +185,9 @@ the caller uses this feature, the field should be reset to zero before the next service call. - The MAC timer unit is activated by the library, and the "wait" field is not + The MAC timer unit is activated by the library, and its "wait" field is not used. The timer starts when a command other than End, Seek, or Recalibrate - completes, and when the controller is waiting for the interface to supply or + completes, or when the controller is waiting for the interface to supply or accept a parameter during command execution. It stops when an End, Seek, or Recalibrate command completes, a command is prepared for execution, or the final parameter has been supplied or accepted by the interface during command @@ -190,7 +196,7 @@ The controller maintains six variables in each drive's unit structure: wait -- the current service activation time - pos -- the current file offset + pos -- the current byte offset into the disc image file u3 (CYL) -- the current drive cylinder u4 (STAT) -- the drive status (Status-2) u5 (OP) -- the drive operation in process @@ -247,32 +253,32 @@ -/* Command accessors (16-bit word) */ +/* Command accessors */ #define DL_V_OPCODE 8 /* bits 12- 8: general opcode */ #define DL_V_HOLD 7 /* bits 7- 7: general hold flag */ #define DL_V_UNIT 0 /* bits 3- 0: general unit number */ -#define DL_V_SPD 13 /* bits 15-13: initialize S/P/D flags */ -#define DL_V_CHEAD 6 /* bits 7- 6: cold load head */ -#define DL_V_CSECT 0 /* bits 5- 0: cold load sector */ -#define DL_V_FRETRY 4 /* bits 7- 4: file mask retry count */ -#define DL_V_FDECR 3 /* bits 3- 3: file mask seek decrement */ -#define DL_V_FSPEN 2 /* bits 2- 2: file mask sparing enable */ -#define DL_V_FCYLM 1 /* bits 1- 1: file mask cylinder mode */ -#define DL_V_FAUTSK 0 /* bits 0- 0: file mask auto seek */ +#define DL_V_SPD 13 /* bits 15-13: Initialize S/P/D flags */ +#define DL_V_CHEAD 6 /* bits 7- 6: Cold Load Read head number */ +#define DL_V_CSECT 0 /* bits 5- 0: Cold Load Read sector number */ +#define DL_V_FRETRY 4 /* bits 7- 4: Set File Mask retry count */ +#define DL_V_FDECR 3 /* bits 3- 3: Set File Mask seek decrement */ +#define DL_V_FSPEN 2 /* bits 2- 2: Set File Mask sparing enable */ +#define DL_V_FCYLM 1 /* bits 1- 1: Set File Mask cylinder mode */ +#define DL_V_FAUTSK 0 /* bits 0- 0: Set File Mask auto seek */ -#define DL_V_FMASK 0 /* bits 3- 0: file mask (combined) */ +#define DL_V_FMASK 0 /* bits 3- 0: Set File Mask (flags combined) */ -#define DL_M_OPCODE 037 -#define DL_M_UNIT 017 +#define DL_M_OPCODE 037 /* opcode mask */ +#define DL_M_UNIT 017 /* unit mask */ -#define DL_M_SPD 007 -#define DL_M_CHEAD 003 -#define DL_M_CSECT 077 -#define DL_M_FRETRY 017 -#define DL_M_FMASK 017 +#define DL_M_SPD 007 /* S/P/D flags mask */ +#define DL_M_CHEAD 003 /* Cold Load Read head number mask */ +#define DL_M_CSECT 077 /* Cold Load Read sector number mask */ +#define DL_M_FRETRY 017 /* Set File Mask retry count mask */ +#define DL_M_FMASK 017 /* Set File Mask flags mask */ #define GET_OPCODE(c) (CNTLR_OPCODE) (((c) >> DL_V_OPCODE) & DL_M_OPCODE) @@ -290,13 +296,13 @@ #define DL_FAUTSK (1 << DL_V_FAUTSK) -/* Parameter accessors (16-bit word) */ +/* Parameter accessors */ #define DL_V_HEAD 8 /* bits 12- 8: head number */ #define DL_V_SECTOR 0 /* bits 7- 0: sector number */ -#define DL_M_HEAD 0017 -#define DL_M_SECTOR 0377 +#define DL_M_HEAD 0017 /* head number mask */ +#define DL_M_SECTOR 0377 /* sector number mask */ #define GET_HEAD(p) (((p) >> DL_V_HEAD) & DL_M_HEAD) #define GET_SECTOR(p) (((p) >> DL_V_SECTOR) & DL_M_SECTOR) @@ -310,15 +316,15 @@ In hardware, drives report their Drive Type numbers to the controller upon receipt of a Request Status tag bus command. The drive type is used to determine the legal range of head and sector addresses (the drive itself will - validate the cylinder during seeks). + validate the cylinder address during seeks). In simulation, we set up a table of drive properties and use the model ID as an index into the table. The table is used to validate seek parameters and to provide the mapping between CHS addresses and the linear byte addresses required by the host file access routines. - The 7905/06/06H drives consist of removable and fixed platters, whereas the - 7920/20H/25/25H drives have only removable multi-platter packs. As a result, + The 7905/06(H) drives consist of removable and fixed platters, whereas the + 7920(H)/25(H) drives have only removable multi-platter packs. As a result, 7905/06 drives are almost always accessed in platter mode, i.e., a given logical disc area is fully contained on either the removable or fixed platter, whereas the 7920/25 drives are almost always accessed in cylinder @@ -332,12 +338,12 @@ The simulator maps the tracks on the 7905/06 removable platter (heads 0 and 1) to the first half of the disc image, and the tracks on the fixed platter (heads 2 and, for the 7906 only, 3) to the second half of the image. For the - 7906/06H, the cylinder-head order of the tracks is 0-0, 0-1, 1-0, 1-1, ..., + 7906(H), the cylinder-head order of the tracks is 0-0, 0-1, 1-0, 1-1, ..., 410-0, 410-1, 0-2, 0-3, 1-2, 1-3, ..., 410-2, 410-3. The 7905 order is the same, except that head 3 tracks are omitted. - For the 7920/20H/25/25H, all tracks appear in cylinder-head order, e.g., 0-0, - 0-1, 0-2, 0-3, 0-4, 1-0, 1-1, ..., 822-2, 822-3, 822-4 for the 7920/20H. + For the 7920(H)/25(H), all tracks appear in cylinder-head order, e.g., 0-0, + 0-1, 0-2, 0-3, 0-4, 1-0, 1-1, ..., 822-2, 822-3, 822-4 for the 7920(H). This variable-access geometry is accomplished by defining additional "heads per cylinder" values for the fixed and removable sections of each drive that @@ -430,7 +436,7 @@ static const DRIVE_PROPERTIES drive_props [] = { /* Command properties table. - The validity of each command for a given type of controller is checked + The validity of each command for a specified controller type is checked against the command properties table when it is prepared. The table also includes the count of inbound and outbound properties, the class of the command, and flags to indicate certain common actions that should be taken. @@ -440,10 +446,10 @@ typedef struct { uint32 params_in; /* count of input parameters */ uint32 params_out; /* count of output parameters */ CNTLR_CLASS classification; /* command classification */ - t_bool valid [TYPE_COUNT]; /* per-type command validity */ - t_bool clear_status; /* command clears status */ + t_bool valid [type_count]; /* per-type command validity */ + t_bool clear_status; /* command clears the controller status */ t_bool unit_field; /* command has a unit field */ - t_bool unit_check; /* command checks unit number validity */ + t_bool unit_check; /* command checks the unit number validity */ t_bool unit_access; /* command accesses the drive unit */ t_bool seek_wait; /* command waits for seek completion */ } DS_PROPS; @@ -606,7 +612,7 @@ if (props->clear_status) { /* clear the prior contr cvptr->spd_unit = SET_S1UNIT (unit); /* save the unit number for status requests */ } -if (cvptr->type <= last_type /* is the controller type legal? */ +if (cvptr->type <= last_type /* is the controller type legal, */ && props->valid [cvptr->type]) /* and the opcode defined for this controller? */ if (props->unit_check && unit > DL_MAXUNIT) /* if the unit number is checked and is illegal, */ dl_end_command (cvptr, unit_unavailable); /* end with a unit unavailable error */ @@ -617,13 +623,13 @@ if (cvptr->type <= last_type /* is the controller typ cvptr->length = props->params_in; /* set the inbound parameter count */ cvptr->index = 1; /* point at the first parameter element (if any) */ - if (cvptr->type == MAC && cvptr->length) { /* MAC controller and inbound parameters? */ + if (cvptr->type == MAC && cvptr->length) { /* is this a MAC controller with inbound parameters? */ cvptr->aux [controller].OP = opcode; /* save the opcode */ cvptr->aux [controller].PHASE = data_phase; /* and set the phase for parameter pickup */ set_timer (cvptr, SET); /* start the timer to wait for the first parameter */ } - return TRUE; /* command is now prepared for execution */ + return TRUE; /* the command is now prepared for execution */ } else /* the opcode is undefined */ @@ -649,8 +655,8 @@ return FALSE; /* the preparation has f If a seek is in progress on a drive when a command accessing that drive is started, the unit pointer is returned but the unit's "wait" field is set to zero. In this case, the unit must not be activated (as it already is). - Instead, the unit's opcode and phase fields are set to start the command - automatically when the seek completes. + Instead, the unit's opcode and phase fields will have been set to start the + command automatically when the seek completes. For commands that return status from the controller, the buffer will contain the returned value(s), the buffer index will be zero, and the buffer length @@ -671,9 +677,9 @@ return FALSE; /* the preparation has f permanently offline. 2. Commands that check for a valid unit do some processing before failing - with a Status-2 (not ready) error. For example, the Seek command accepts - its parameters from the CPU and sets the CHS values into the controller - before failing. + with a Status-2 (not ready) error if the unit is invalid. For example, + the Seek command accepts its parameters from the CPU and sets the CHS + values into the controller before failing. 3. In hardware, read, write, and recalibrate commands wait in an internal loop for a pending seek completion and clear the resulting Attention @@ -692,7 +698,7 @@ return FALSE; /* the preparation has f a seek command with a Seek Check error. The firmware does not test explicitly for Access Not Ready before executing the command, so the parameters (e.g., controller CHS addresses) are still set as though the - command succeeded. + command had succeeded. A Seek command will return to the Poll Loop with Seek Check status set. When the seek in progress completes, the controller will interrupt with @@ -723,8 +729,8 @@ return FALSE; /* the preparation has f 8. The activation time is set to the intersector time (latency) for read and write commands, and to the controller processing time for all others. - This time cannot be shorter than 20 instructions, or DVR32 will be unable - to start DCPC in time to avoid an over/underrun. + The read/write start time cannot be shorter than 20 instructions, or + DVR32 will be unable to start DCPC in time to avoid an over/underrun. */ UNIT *dl_start_command (CVPTR cvptr, UNIT *units, uint32 unit_limit) @@ -752,11 +758,11 @@ if (cvptr->type == MAC) { /* is this a MAC control else { /* for an ICD controller, */ unit = 0; /* the unit value is ignored */ - uptr = units + unit_limit; /* and we use the indicated unit */ + uptr = units + unit_limit; /* and we use the indicated unit */ } if (props->unit_check && !uptr /* if the unit number is checked and is invalid */ - || props->seek_wait && (drive_status (uptr) & DL_S2STOPS)) { /* or if waiting for an offline drive */ + || props->seek_wait && (drive_status (uptr) & DL_S2STOPS)) { /* or if we're waiting for an offline drive */ dl_end_command (cvptr, status_2_error); /* then the command ends with a Status-2 error */ uptr = NULL; /* prevent the command from starting */ } @@ -788,16 +794,16 @@ cvptr->eod = CLEAR; /* clear the end of data switch (cvptr->opcode) { /* dispatch the command */ case cold_load_read: - cvptr->cylinder = 0; /* set cylinder to 0 */ - cvptr->head = GET_CHEAD (cvptr->buffer [0]); /* get the head */ + cvptr->cylinder = 0; /* set the cylinder address to 0 */ + cvptr->head = GET_CHEAD (cvptr->buffer [0]); /* set the head */ cvptr->sector = GET_CSECT (cvptr->buffer [0]); /* and sector from the command */ if (is_seeking) { /* if a seek is in progress, */ uptr->STAT |= DL_S2SC; /* a Seek Check occurs */ - cvptr->file_mask = DL_FSPEN; /* set sparing enabled */ - uptr->OP = read; /* start the read on seek completion */ + cvptr->file_mask = DL_FSPEN; /* enable sparing */ + uptr->OP = read; /* start the read on the seek completion */ uptr->PHASE = start_phase; /* and reset the command phase */ - return uptr; /* to allow the seek to complete normally */ + return uptr; /* to allow the seek to complete normally */ } else /* the drive is not seeking */ @@ -809,7 +815,7 @@ switch (cvptr->opcode) { /* dispatch the command case seek: cvptr->cylinder = cvptr->buffer [1]; /* get the supplied cylinder */ cvptr->head = GET_HEAD (cvptr->buffer [2]); /* and head */ - cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector */ + cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector addresses */ if (is_seeking) { /* if a seek is in progress, */ uptr->STAT |= DL_S2SC; /* a Seek Check occurs */ @@ -824,10 +830,13 @@ switch (cvptr->opcode) { /* dispatch the command cvptr->buffer [0] = /* set the Status-1 value */ cvptr->spd_unit | SET_S1STAT (cvptr->status); /* into the buffer */ - if (unit > unit_limit) /* if the unit number is invalid */ - rptr = NULL; /* it does not correspond to a unit */ - else /* otherwise, the unit is valid */ - rptr = &units [unit]; /* so get the address of the referenced unit */ + if (cvptr->type == MAC) /* is this a MAC controller? */ + if (unit > unit_limit) /* if the unit number is invalid */ + rptr = NULL; /* it does not correspond to a unit */ + else /* otherwise, the unit is valid */ + rptr = &units [unit]; /* so get the address of the referenced unit */ + else /* if not a MAC controller */ + rptr = uptr; /* then the referenced unit is the current unit */ cvptr->buffer [1] = drive_status (rptr); /* set the Status-2 value */ @@ -878,7 +887,7 @@ switch (cvptr->opcode) { /* dispatch the command case address_record: cvptr->cylinder = cvptr->buffer [1]; /* get the supplied cylinder */ cvptr->head = GET_HEAD (cvptr->buffer [2]); /* and head */ - cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector */ + cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector addresses */ cvptr->eoc = CLEAR; /* clear the end-of-cylinder flag */ break; @@ -886,8 +895,8 @@ switch (cvptr->opcode) { /* dispatch the command case set_file_mask: cvptr->file_mask = GET_FMASK (cvptr->buffer [0]); /* get the supplied file mask */ - if (cvptr->type == MAC) /* if a MAC controller */ - cvptr->retry = GET_FRETRY (cvptr->buffer [0]); /* the retry counter is supplied too */ + if (cvptr->type == MAC) /* if this is a MAC controller, */ + cvptr->retry = GET_FRETRY (cvptr->buffer [0]); /* the retry count is supplied too */ break; @@ -904,7 +913,7 @@ switch (cvptr->opcode) { /* dispatch the command default: /* the remaining commands */ - break; /* are handled in the service routines */ + break; /* are handled by the service routines */ } @@ -926,7 +935,7 @@ else /* Complete a command. - The current command is terminated with the indicated status. The command + The current command is completed with the indicated status. The command result status is set, the controller enters the command wait state, and the CPU timer is restarted. */ @@ -940,14 +949,14 @@ return; } -/* Poll the drives for attention status. +/* Poll the drives for Attention status. If interrupts are enabled on the interface, this routine is called to check if any drive is requesting attention. The routine returns TRUE if a drive is - requestion attention and FALSE if not. + requesting attention and FALSE if not. Starting with the last unit requesting attention, each drive is checked in - sequence. If a drive has its Attention status set, the controller sets its + sequence. If a drive has its Attention status set, the controller saves its unit number, sets the result status to Drive Attention, and enters the command wait state. The routine returns TRUE to indicate that an interrupt should be generated. The next time the routine is called, the poll begins @@ -970,12 +979,12 @@ for (unit = 0; unit <= unit_limit; unit++) { /* check each unit i units [cvptr->poll_unit].STAT &= ~DL_S2ATN; /* clear the Attention status */ cvptr->spd_unit = SET_S1UNIT (cvptr->poll_unit); /* set the controller's unit number */ cvptr->status = drive_attention; /* and status */ - cvptr->state = cntlr_wait; /* and wait for a command */ + cvptr->state = cntlr_wait; /* and wait for a command */ return TRUE; /* tell the caller to interrupt */ } } -return FALSE; /* no requests, so no interrupt */ +return FALSE; /* no requests, so do not generate an interrupt */ } @@ -989,7 +998,7 @@ return FALSE; /* no requests, so n service routine accesses these six variables in the UNIT structure: wait -- the current service activation time - pos -- the current file offset + pos -- the current byte offset into the disc image file u3 (CYL) -- the current drive cylinder u4 (STAT) -- the drive status (Status-2) u5 (OP) -- the drive operation in process @@ -1026,13 +1035,13 @@ return FALSE; /* no requests, so n An operation in the data phase is in the process of transferring data between the CPU and sector buffer. Because this process is interface-specific, the - service routine does nothing (other than validate) with this phase. It is up + service routine does nothing (other than validate) in this phase. It is up to the caller to transition from the data phase to the end phase when the transfer is complete. If an operation is completed, or an error has occurred, the controller state on return will be either idle or waiting, instead of busy. The caller should - check the controller state to determine if normal completion or error + check the controller status to determine if normal completion or error recovery is appropriate. If the command is continuing, the service activation time will be set @@ -1072,7 +1081,7 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case seek: if (start_seek (cvptr, uptr, opcode, end_phase) /* start the seek; if it succeeded, */ && (cvptr->type == MAC)) /* and this a MAC controller, */ - dl_idle_controller (cvptr); /* idle until the seek completes */ + dl_idle_controller (cvptr); /* then go idle until it completes */ break; @@ -1101,7 +1110,7 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ result = start_read (cvptr, uptr); /* start the sector read */ if (uptr->PHASE == data_phase) { /* did the read start successfully? */ - uptr->PHASE = end_phase; /* skip the data phase for Verify */ + uptr->PHASE = end_phase; /* skip the data phase */ uptr->wait = cvptr->sector_time /* reschedule for the intersector time */ + cvptr->data_time * DL_WPSEC; /* plus the data read time */ } @@ -1131,11 +1140,11 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case request_disc_address: case end: case wakeup: - dl_service_controller (cvptr, uptr); /* call the controller for service */ + dl_service_controller (cvptr, uptr); /* the controller service handles these */ break; - default: /* entered with an invalid state */ + default: /* we were entered with an invalid state */ result = SCPE_IERR; /* return an internal (programming) error */ break; } /* end of operation dispatch */ @@ -1167,7 +1176,7 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case recalibrate: case seek: if (cvptr->type == ICD) /* is this an ICD controller? */ - dl_end_command (cvptr, drive_attention); /* seek ends with drive attention status */ + dl_end_command (cvptr, drive_attention); /* seeks end with Drive Attention status */ else /* if not an ICD controller, */ uptr->STAT |= DL_S2ATN; /* set Attention in the unit status */ break; @@ -1182,7 +1191,7 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case read_without_verify: if (cvptr->sector == 0) /* have we reached the end of the track? */ - uptr->OP = read; /* begin verifying next time */ + uptr->OP = read; /* begin verifying the next time */ end_read (cvptr, uptr); /* end the sector read */ break; @@ -1192,7 +1201,7 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ cvptr->verify_count = /* decrement the count */ (cvptr->verify_count - 1) & DMASK; /* modulo 65536 */ - if (cvptr->verify_count == 0) /* more sectors to verify? */ + if (cvptr->verify_count == 0) /* are there more sectors to verify? */ cvptr->eod = SET; /* no, so terminate the command cleanly */ end_read (cvptr, uptr); /* end the sector read */ @@ -1209,11 +1218,11 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case request_status: case request_sector_address: case request_disc_address: - dl_service_controller (cvptr, uptr); /* call the controller for service */ + dl_service_controller (cvptr, uptr); /* the controller service handles these */ break; - default: /* entered with an invalid state */ + default: /* we were entered with an invalid state */ result = SCPE_IERR; /* return an internal (programming) error */ break; } /* end of operation dispatch */ @@ -1241,9 +1250,10 @@ return result; /* return the result of to indicate that it is ready for the second word. For ICD controllers, the controller unit is not used, and all commands are - scheduled on the drive unit. To reduce code duplication, however, the drive - unit service calls the controller service directly to handle controller - commands. + scheduled on the drive unit. This is possible because ICD controllers always + wait for seeks to complete before executing additional commands. To reduce + code duplication, however, the drive unit service calls the controller + service directly to handle controller commands. The service routine validates phase assignments and returns SCPE_IERR (Internal Error) if entry is made with an illegal operation phase or a phase @@ -1268,13 +1278,13 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case end_phase: switch (opcode) { /* dispatch the current operation */ case request_status: - dl_end_command (cvptr, cvptr->status); /* command is complete with no status change */ + dl_end_command (cvptr, cvptr->status); /* the command completes with no status change */ break; case clear: dl_clear_controller (cvptr, uptr, soft_clear); /* clear the controller */ - dl_end_command (cvptr, normal_completion); /* command is complete */ + dl_end_command (cvptr, normal_completion); /* the command is complete */ break; @@ -1284,21 +1294,21 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case set_file_mask: case load_tio_register: case request_disc_address: - dl_end_command (cvptr, normal_completion); /* command is complete */ + dl_end_command (cvptr, normal_completion); /* the command is complete */ break; case end: - dl_idle_controller (cvptr); /* command is complete with controller idle */ + dl_idle_controller (cvptr); /* the command completes with the controller idle */ break; case wakeup: - dl_end_command (cvptr, unit_available); /* command is complete with unit available */ + dl_end_command (cvptr, unit_available); /* the command completes with Unit Available status */ break; - default: /* entered with an invalid state */ + default: /* we were entered with an invalid state */ result = SCPE_IERR; /* return an internal (programming) error */ break; } /* end of operation dispatch */ @@ -1331,7 +1341,7 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - default: /* entered with an invalid state */ + default: /* we were entered with an invalid state */ result = SCPE_IERR; /* return an internal (programming) error */ break; } /* end of operation dispatch */ @@ -1346,7 +1356,7 @@ return result; /* return the result of The command wait timer service routine is called if the command wait timer expires. This indicates that the CPU did not respond to a parameter transfer - or did not issue a new command within the 1.8 second timeout period. The + or did not issue a new command within the ~1.8 second timeout period. The timer is used with the MAC controller to ensure that a hung CPU does not tie up the controller, preventing it from servicing other CPUs or drives. ICD controllers do not use the command wait timer; they will wait forever, as @@ -1368,7 +1378,7 @@ return result; /* return the result of t_stat dl_service_timer (CVPTR cvptr, UNIT *uptr) { -sim_cancel (cvptr->aux); /* cancel the controller */ +sim_cancel (cvptr->aux); /* cancel any controller activation */ dl_idle_controller (cvptr); /* idle the controller */ cvptr->file_mask = 0; /* clear the file mask */ @@ -1393,8 +1403,8 @@ return SCPE_OK; The first two conditions, called "hard clears," are equivalent and cause a firmware restart with the PWRON flag set. The 13175 interface for the HP - 1000 asserts CLEAR in response to the backplane CRS signal if the PRESET - ENABLE jumper is not installed (which is the usual case). The third + 1000 asserts the CLEAR signal in response to the backplane CRS signal if the + PRESET ENABLE jumper is not installed (which is the usual case). The third condition also causes a firmware restart but with the PWRON flag clear. The last condition is executed in the command handler and therefore returns to the Command Wait Loop instead of the Poll Loop. @@ -1406,7 +1416,7 @@ return SCPE_OK; - issue a Controller Preset to clear all connected drives - clear the clock offset - clear the file mask - - enter the Poll Loop (clears the controller status) + - enter the Poll Loop (which clears the controller status) For a timeout clear, the 13037 controller will: @@ -1414,7 +1424,7 @@ return SCPE_OK; - clear the hold bits of any drives held by the interface that timed out - clear the clock offset - clear the file mask - - enter the Poll Loop (clears the controller status) + - enter the Poll Loop (which clears the controller status) For a programmed "soft" clear, the 13037 controller will: @@ -1447,7 +1457,7 @@ return SCPE_OK; Implementation notes: 1. The specific 13365 controller actions on hard or soft clears are not - documented. Therefore, an ICD controller clear is handled as a MAC + documented. Therefore, an ICD controller clear is handled as a MAC controller clear, except that only the current drive is preset (as an ICD controller manages only a single drive). @@ -1459,7 +1469,7 @@ return SCPE_OK; aborted for a hard or timeout clear, whereas in hardware it would complete normally. This is OK, however, because an internal seek always clears the drive's Attention status on completion, so aborting the - simulated seek is equivalent to seek completion. + simulated seek is equivalent to an immediate seek completion. 4. In simulation, a Controller Preset only resets the specified status bits, as the remainder of the hardware actions are not implemented. @@ -1482,7 +1492,7 @@ if (cvptr->type == ICD) /* is this an ICD contro else { /* a MAC controller clears all units */ dptr = find_dev_from_unit (uptr); /* find the associated device */ - if (dptr == NULL) /* device doesn't exist?!? */ + if (dptr == NULL) /* the device doesn't exist?!? */ return SCPE_IERR; /* this is an impossible condition! */ else /* the device was found */ unit_count = dptr->numunits; /* so get the number of units */ @@ -1534,7 +1544,7 @@ return; In simulation, the unit must be attached before the heads may be unloaded or loaded. As the heads should be automatically loaded when a unit is attached and unloaded when a unit is detached, this routine must be called after - attaching or before detaching. + attaching and before detaching. Implementation notes: @@ -1550,7 +1560,7 @@ return; t_stat dl_load_unload (CVPTR cvptr, UNIT *uptr, t_bool load) { -if ((uptr->flags & UNIT_ATT) == 0) /* must be attached to [un]load */ +if ((uptr->flags & UNIT_ATT) == 0) /* the unit must be attached to [un]load */ return SCPE_UNATT; /* return "Unit not attached" if not */ else if (!(sim_switches & SIM_SW_REST)) /* modify the flags only if not restoring */ @@ -1585,11 +1595,11 @@ return SCPE_OK; CNTLR_CLASS dl_classify (CNTLR_VARS cntlr) { -if (cntlr.type <= last_type /* if the controller type is legal, */ +if (cntlr.type <= last_type /* if the controller type is legal */ && cntlr.opcode <= last_opcode /* and the opcode is legal */ && cmd_props [cntlr.opcode].valid [cntlr.type]) /* and is defined for this controller, */ return cmd_props [cntlr.opcode].classification; /* then return the command classification */ -else /* type or opcode is illegal */ +else /* the type or opcode is illegal */ return class_invalid; /* so return an invalid classification */ } @@ -1603,11 +1613,11 @@ else /* type or opcode is ill const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode) { -if (controller <= last_type /* if the controller type is legal, */ +if (controller <= last_type /* if the controller type is legal */ && opcode <= last_opcode /* and the opcode is legal */ && cmd_props [opcode].valid [controller]) /* and is defined for this controller, */ return opcode_name [opcode]; /* then return the opcode name */ -else /* type or opcode is illegal, */ +else /* the type or opcode is illegal, */ return invalid_name; /* so return an error indication */ } @@ -1622,7 +1632,7 @@ const char *dl_phase_name (CNTLR_PHASE phase) { if (phase <= last_phase) /* if the phase is legal, */ return phase_name [phase]; /* return the phase name */ -else /* phase is illegal, */ +else /* the phase is illegal, */ return invalid_name; /* so return an error indication */ } @@ -1636,9 +1646,9 @@ else /* phase is illegal, */ The file specified by the supplied filename is attached to the indicated unit. If the attach was successful, the heads are loaded on the drive. - If the drive is set to auto-type, the size of the image file is compared to - the table of drive capacities to determine which type of drive was used to - create it. If the image file is new, then the previous drive type is + If the drive is set to autosize, the size of the image file is compared to + the table of drive capacities to determine which model of drive was used to + create it. If the image file is new, then the previous drive model is retained. */ @@ -1654,13 +1664,13 @@ if (result != SCPE_OK) /* did the attach fa dl_load_unload (cvptr, uptr, TRUE); /* if the attach succeeded, load the heads */ -if (uptr->flags & UNIT_AUTO) { /* is auto-typing desired? */ +if (uptr->flags & UNIT_AUTO) { /* is autosizing enabled? */ size = sim_fsize (uptr->fileref) / sizeof (uint16); /* get the file size in words */ - if (size > 0) /* a new file retains the current drive type */ - for (id = 0; id < PROPS_COUNT; id++) /* find the best fit to the drive types */ + if (size > 0) /* a new file retains the current drive model */ + for (id = 0; id < PROPS_COUNT; id++) /* find the best fit to the drive models */ if (size <= drive_props [id].words /* if the file size fits the drive capacity */ - || id == PROPS_COUNT - 1) { /* or this is the largest drive */ + || id == PROPS_COUNT - 1) { /* or this is the largest available drive */ uptr->capac = drive_props [id].words; /* then set the capacity */ uptr->flags = (uptr->flags & ~UNIT_MODEL) /* and the model */ | SET_MODEL (id); @@ -1668,7 +1678,7 @@ if (uptr->flags & UNIT_AUTO) { /* is auto-typing de } } -return SCPE_OK; /* unit was successfully attached */ +return SCPE_OK; /* the unit was successfully attached */ } @@ -1694,7 +1704,7 @@ return detach_unit (uptr); /* and detach the unit t_stat dl_set_model (UNIT *uptr, int32 value, char *cptr, void *desc) { -if (uptr->flags & UNIT_ATT) /* cannot alter the disc model */ +if (uptr->flags & UNIT_ATT) /* we cannot alter the disc model */ return SCPE_ALATT; /* if the unit is attached */ if (value != UNIT_AUTO) /* if we are not autosizing */ @@ -1760,12 +1770,12 @@ uint32 count, offset; t_bool verify; const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; -if (cvptr->eod == SET) { /* end of data indicated? */ +if (cvptr->eod == SET) { /* is the end of data indicated? */ dl_end_command (cvptr, normal_completion); /* complete the command */ return SCPE_OK; } -if (opcode == read_full_sector) { /* starting a Read Full Sector command? */ +if (opcode == read_full_sector) { /* are we starting a Read Full Sector command? */ if (cvptr->type == ICD) /* is this an ICD controller? */ cvptr->buffer [0] = 0100377; /* ICD does not support ECC */ else @@ -1773,30 +1783,30 @@ if (opcode == read_full_sector) { /* starting a Read Full set_address (cvptr, 1); /* set the current address into buffer 1-2 */ offset = 3; /* start the data after the header */ - verify = FALSE; /* no address verification */ + verify = FALSE; /* set for no address verification */ } else { /* it's another read command */ offset = 0; /* data starts at the beginning */ - verify = (opcode != read_without_verify); /* verify unless RWV */ + verify = (opcode != read_without_verify); /* set for address verification unless it's a RWV */ } if (! position_sector (cvptr, uptr, verify)) /* position the sector */ - return SCPE_OK; /* seek in progress or an error occurred */ + return SCPE_OK; /* a seek is in progress or an error occurred */ count = sim_fread (cvptr->buffer + offset, /* read the sector from the image */ - sizeof (uint16), DL_WPSEC, /* into the sector buffer */ + sizeof (uint16), DL_WPSEC, /* into the sector buffer */ uptr->fileref); -for (count = count + offset; count < cvptr->length; count++) /* pad sector as needed */ +for (count = count + offset; count < cvptr->length; count++) /* pad the sector as needed */ cvptr->buffer [count] = 0; /* e.g., if reading from a new file */ if (ferror (uptr->fileref)) /* did a host file system error occur? */ - return io_error (cvptr, uptr); /* set up data error status and stop the simulation */ + return io_error (cvptr, uptr); /* set up the data error status and stop the simulation */ next_sector (cvptr, uptr); /* address the next sector */ -uptr->PHASE = data_phase; /* set up data transfer phase */ +uptr->PHASE = data_phase; /* set up the data transfer phase */ cvptr->index = 0; /* reset the data index */ return SCPE_OK; /* the read was successfully started */ @@ -1823,7 +1833,7 @@ return SCPE_OK; /* the read was successf static void end_read (CVPTR cvptr, UNIT *uptr) { -if (cvptr->eod == SET) /* end of data indicated? */ +if (cvptr->eod == SET) /* is the end of data indicated? */ dl_end_command (cvptr, normal_completion); /* complete the command */ else { /* reading continues */ @@ -1839,7 +1849,8 @@ return; The current sector indicated by the controller address is positioned for writing from the sector buffer to the disc image file after data transfer - from the CPU. + from the CPU. If the end of the track had been reached, and the file mask + permits, an auto-seek is scheduled instead to allow the write to continue. On entry, if writing is not permitted, or formatting is required but not enabled, the command is terminated with an error. Otherwise, the disc image @@ -1866,14 +1877,14 @@ return; static void start_write (CVPTR cvptr, UNIT *uptr) { -const t_bool verify = (CNTLR_OPCODE) uptr->OP == write; /* only Write verifies the sector */ +const t_bool verify = (CNTLR_OPCODE) uptr->OP == write; /* only Write verifies the sector address */ -if ((uptr->flags & UNIT_WPROT) /* is the unit write protected? */ +if ((uptr->flags & UNIT_WPROT) /* is the unit write protected, */ || !verify && !(uptr->flags & UNIT_FMT)) /* or is formatting required but not enabled? */ dl_end_command (cvptr, status_2_error); /* terminate the write with an error */ -else if (position_sector (cvptr, uptr, verify)) { /* write OK; position the sector */ - uptr->PHASE = data_phase; /* position OK; set up data transfer phase */ +else if (position_sector (cvptr, uptr, verify)) { /* writing is permitted; position the sector */ + uptr->PHASE = data_phase; /* positioning succeeded; set up data transfer phase */ cvptr->index = 0; /* reset the data index */ } @@ -1884,17 +1895,16 @@ return; /* Finish a write operation on the current sector. The current sector is written from the sector buffer to the disc image file - at the current file position. If the end of the track had been reached, and - the file mask permits, an auto-seek is scheduled instead to allow the write - to continue. + at the current file position. The next sector address is then updated to + allow writing to continue. On entry, the drive is checked to ensure that it is ready for the write. Then the sector buffer is padded appropriately if a full sector of data was not transferred. The buffer is written to the disc image file at the position corresponding to the controller address as set when the sector was started. The write begins at a buffer offset determined by the command (a - Write Full Sector leaves room at the start of the buffer for the sector - header). + Write Full Sector has header words at the start of the buffer that are not + written to the disc image). If the image write failed with a file system error, SCPE_IOERR is returned from the service routine to cause a simulation stop; resumption is handled as @@ -1929,14 +1939,14 @@ if (cvptr->index < DL_WPSEC + offset) { /* was a partial sector pad = cvptr->buffer [cvptr->index - 1]; /* pads with the last word written */ for (count = cvptr->index; count < DL_WPSEC + offset; count++) - cvptr->buffer [count] = pad; /* pad the sector buffer */ + cvptr->buffer [count] = pad; /* pad the sector buffer as needed */ } sim_fwrite (cvptr->buffer + offset, sizeof (uint16), /* write the sector to the file */ DL_WPSEC, uptr->fileref); if (ferror (uptr->fileref)) /* did a host file system error occur? */ - return io_error (cvptr, uptr); /* set up data error status and stop the simulation */ + return io_error (cvptr, uptr); /* set up the data error status and stop the simulation */ next_sector (cvptr, uptr); /* address the next sector */ @@ -1952,16 +1962,16 @@ return SCPE_OK; } -/* Position the disc image file to the current sector. +/* Position the disc image file at the current sector. - The image file is positioned to the byte address corresponding to the + The image file is positioned at the byte address corresponding to the controller's current cylinder, head, and sector address. Positioning may - involve an auto-seek if the prior read or write addressed the final sector in - a cylinder. If a seek is initiated or an error is detected, the routine + involve an auto-seek if a prior read or write addressed the final sector in a + cylinder. If a seek is initiated or an error is detected, the routine returns FALSE to indicate that the positioning was not performed. If the file was positioned, the routine returns TRUE. - On entry, if the controller's end-of-cylinder flag is set, the prior read or + On entry, if the controller's end-of-cylinder flag is set, a prior read or write addressed the final sector in the current cylinder. If the file mask does not permit auto-seeking, the current command is terminated with an End of Cylinder error. Otherwise, the cylinder is incremented or decremented as @@ -1970,8 +1980,8 @@ return SCPE_OK; If the increment or decrement resulted in an out-of-bounds value, the seek will return Seek Check status, and the command is terminated with an error. If the seek is legal, the routine returns with the disc service scheduled for - seek completion and the command state unchanged. When the service is called, - the read or write will continue on the new cylinder. + seek completion and the command state unchanged. When the service is + reentered, the read or write will continue on the new cylinder. If the EOC flag was not set, the drive position is checked against the controller position. If they are different (as may occur with an Address @@ -2003,34 +2013,34 @@ static t_bool position_sector (CVPTR cvptr, UNIT *uptr, t_bool verify) uint32 block; uint32 model = GET_MODEL (uptr->flags); -if (cvptr->eoc == SET) /* positioned at the end of a cylinder? */ +if (cvptr->eoc == SET) /* are we at the end of a cylinder? */ if (cvptr->file_mask & DL_FAUTSK) { /* is an auto-seek allowed? */ - if (cvptr->file_mask & DL_FDECR) /* decremental seek? */ - cvptr->cylinder = (cvptr->cylinder - 1) & DMASK; /* decrease cylinder with wraparound */ - else /* incremental seek */ - cvptr->cylinder = (cvptr->cylinder + 1) & DMASK; /* increase cylinder with wraparound */ + if (cvptr->file_mask & DL_FDECR) /* is a decremental seek requested? */ + cvptr->cylinder = (cvptr->cylinder - 1) & DMASK; /* decrease the cylinder address with wraparound */ + else /* an incremental seek is requested */ + cvptr->cylinder = (cvptr->cylinder + 1) & DMASK; /* increase the cylinder address with wraparound */ start_seek (cvptr, uptr, /* start the auto-seek */ (CNTLR_OPCODE) uptr->OP, /* with the current operation */ - (CNTLR_PHASE) uptr->PHASE); /* and phase unchanged */ + (CNTLR_PHASE) uptr->PHASE); /* and phase unchanged */ if (uptr->STAT & DL_S2SC) /* did a seek check occur? */ - if (cvptr->type == ICD) /* ICD controller? */ - dl_end_command (cvptr, end_of_cylinder); /* report as end of cylinder error */ - else /* MAC controller? */ - dl_end_command (cvptr, status_2_error); /* report as Status-2 error */ + if (cvptr->type == ICD) /* is this ICD controller? */ + dl_end_command (cvptr, end_of_cylinder); /* report it as an End of Cylinder error */ + else /* it is a MAC controller */ + dl_end_command (cvptr, status_2_error); /* report it as a Status-2 error */ } - else /* file mask does not permit auto-seek */ + else /* the file mask does not permit an auto-seek */ dl_end_command (cvptr, end_of_cylinder); /* so terminate with an EOC error */ else if (verify && (uint32) uptr->CYL != cvptr->cylinder) { /* is the positioner on the wrong cylinder? */ start_seek (cvptr, uptr, /* start a seek to the correct cylinder */ (CNTLR_OPCODE) uptr->OP, /* with the current operation */ - (CNTLR_PHASE) uptr->PHASE); /* and phase unchanged */ + (CNTLR_PHASE) uptr->PHASE); /* and phase unchanged */ if (uptr->STAT & DL_S2SC) /* did a seek check occur? */ - dl_end_command (cvptr, status_2_error); /* report as Status-2 error */ + dl_end_command (cvptr, status_2_error); /* report a Status-2 error */ } else if (((uint32) uptr->CYL >= drive_props [model].cylinders) /* is the cylinder out of bounds? */ @@ -2043,10 +2053,10 @@ else if (((uint32) uptr->CYL >= drive_props [model].cylinders) /* is the cylind else if (uptr->flags & UNIT_UNLOAD) /* is the drive ready for positioning? */ dl_end_command (cvptr, access_not_ready); /* terminate the command with an access error */ -else { /* ready to position the image file */ +else { /* we are ready to position the image file */ block = TO_BLOCK (uptr->CYL, cvptr->head, /* calculate the new block position */ cvptr->sector, model); /* (for inspection only) */ - uptr->pos = TO_OFFSET (block); /* and then convert to a byte offset */ + uptr->pos = TO_OFFSET (block); /* and then convert to a byte offset */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set the image file position */ @@ -2071,7 +2081,7 @@ return FALSE; /* report that positioni The new cylinder address is not set here, because cylinder validation must only occur when the next sector is actually accessed. Otherwise, reading or writing the last sector on a track or cylinder with auto-seek disabled would - cause an End of Cylinder error even if the transfer ended with that sector. + cause an End of Cylinder error, even if the transfer ended with that sector. Instead, we set the EOC flag to indicate that a cylinder update is pending. As a result of this deferred update method, the state of the EOC flag must be @@ -2084,7 +2094,7 @@ const uint32 model = GET_MODEL (uptr->flags); /* get the disc model */ cvptr->sector = cvptr->sector + 1; /* increment the sector number */ -if (cvptr->sector < drive_props [model].sectors) /* at the end of the track? */ +if (cvptr->sector < drive_props [model].sectors) /* are we at the end of the track? */ return; /* no, so the next sector value is OK */ cvptr->sector = 0; /* wrap the sector number */ @@ -2092,7 +2102,7 @@ cvptr->sector = 0; /* wrap the sector numbe if (cvptr->file_mask & DL_FCYLM) { /* are we in cylinder mode? */ cvptr->head = cvptr->head + 1; /* yes, so increment the head */ - if (cvptr->head < drive_props [model].heads) /* at the end of the cylinder? */ + if (cvptr->head < drive_props [model].heads) /* are we at the end of the cylinder? */ return; /* no, so the next head value is OK */ cvptr->head = 0; /* wrap the head number */ @@ -2132,7 +2142,7 @@ return; /* indicate that an up Implementation notes: 1. EOC is not reset for recalibrate so that a reseek will return to the same - location as was pending when the recalibrate was done. + location as was current when the recalibrate was done. 2. Calculation of the file offset is performed here simply to keep the unit position register available for inspection. The actual file positioning @@ -2150,14 +2160,14 @@ uint32 block, target_cylinder; const uint32 model = GET_MODEL (uptr->flags); /* get the drive model */ if (uptr->flags & UNIT_UNLOAD) { /* are the heads unloaded? */ - dl_end_command (cvptr, status_2_error); /* seek ends with Status-2 error */ - return FALSE; /* drive was not ready */ + dl_end_command (cvptr, status_2_error); /* the seek ends with Status-2 error */ + return FALSE; /* as the drive was not ready */ } if ((CNTLR_OPCODE) uptr->OP == recalibrate) /* is the unit recalibrating? */ - target_cylinder = 0; /* seek to cylinder 0 and don't reset EOC */ + target_cylinder = 0; /* seek to cylinder 0 and don't reset the EOC flag */ -else { /* Seek command or auto-seek request */ +else { /* it's a Seek command or an auto-seek request */ target_cylinder = cvptr->cylinder; /* seek to the controller cylinder */ cvptr->eoc = CLEAR; /* clear the end-of-cylinder flag */ } @@ -2167,12 +2177,12 @@ if (target_cylinder >= drive_props [model].cylinders) { /* is the cylinder out o uptr->STAT = uptr->STAT | DL_S2SC; /* and set Seek Check status */ } -else { /* cylinder value is OK */ +else { /* the cylinder value is OK */ delta = abs (uptr->CYL - target_cylinder); /* calculate the relative movement */ uptr->CYL = target_cylinder; /* and move the positioner */ if ((cvptr->head >= drive_props [model].heads) /* if the head */ - || (cvptr->sector >= drive_props [model].sectors)) /* or sector is out of bounds, */ + || (cvptr->sector >= drive_props [model].sectors)) /* or the sector is out of bounds, */ uptr->STAT = uptr->STAT | DL_S2SC; /* set Seek Check status */ else { /* the head and sector are OK */ @@ -2184,14 +2194,14 @@ else { /* cylinder value is OK } } -if ((uptr->STAT & DL_S2SC) && cvptr->type == ICD) /* Seek Check and ICD controller? */ - dl_end_command (cvptr, status_2_error); /* command ends with Status-2 error */ +if ((uptr->STAT & DL_S2SC) && cvptr->type == ICD) /* did a Seek Check occur for an ICD controller? */ + dl_end_command (cvptr, status_2_error); /* the command ends with a Status-2 error */ -else { /* seek OK or this is a MAC controller */ - if (delta == 0) /* if seek is to the same cylinder */ - delta = 1; /* schedule as a one-cylinder seek */ +else { /* the seek was OK or this is a MAC controller */ + if (delta == 0) /* if the seek is to the same cylinder, */ + delta = 1; /* then schedule as a one-cylinder seek */ - uptr->wait = cvptr->seek_time * delta; /* seek delay is based on the relative movement */ + uptr->wait = cvptr->seek_time * delta; /* the seek delay is based on the relative movement */ } uptr->OP = next_opcode; /* set the next operation */ @@ -2202,7 +2212,7 @@ return TRUE; /* and report that t /* Report an I/O error. - Errors indicated by the host file system are reported to the console and + Errors indicated by the host file system are reported to the console, and simulation is stopped with an "I/O error" message. If the simulation is continued, the CPU will receive an Uncorrectable Data Error indication from the controller. @@ -2228,7 +2238,7 @@ return SCPE_IOERR; /* return an I/O error t The controller's current cylinder, head, and sector are packed into two words and stored in the sector buffer, starting at the index specified. If the end-of-cylinder flag is set, the cylinder is incremented to reflect the - auto-seek that will be attempted when the next disc access is made. + auto-seek that will be attempted when the next sequential access is made. Implementation notes: @@ -2240,7 +2250,7 @@ return SCPE_IOERR; /* return an I/O error t static void set_address (CVPTR cvptr, uint32 index) { -cvptr->buffer [index] = cvptr->cylinder + (cvptr->eoc == SET ? 1 : 0); /* update the cylinder if EOC */ +cvptr->buffer [index] = cvptr->cylinder + (cvptr->eoc == SET ? 1 : 0); /* update the cylinder if EOC is set */ cvptr->buffer [index + 1] = SET_HEAD (cvptr) | SET_SECTOR (cvptr); /* merge the head and sector */ return; } @@ -2253,7 +2263,7 @@ return; interfaces supply an auxiliary timer unit that is activated when the command wait timer is started and cancelled when the timer is stopped. - ICD interfaces do not use the command wait timer. + ICD interfaces do not use the command wait timer or supply an auxiliary unit. Implementation notes: @@ -2265,10 +2275,10 @@ return; static void set_timer (CVPTR cvptr, FLIP_FLOP action) { if (cvptr->type == MAC) /* is this a MAC controller? */ - if (action == SET) /* start the timer? */ + if (action == SET) /* should we start the timer? */ sim_activate_abs (cvptr->aux + timer, /* activate the auxiliary unit */ cvptr->wait_time); - else /* stop the timer */ + else /* we stop the timer */ sim_cancel (cvptr->aux + timer); /* by canceling the unit */ return; } @@ -2292,15 +2302,15 @@ return; Implementation notes: - 1. The Attention, Drive Fault, First Status, and Seek Check flags are stored - in the unit status word. The other status flags are determined + 1. The Attention, Drive Fault, First Status, and Seek Check bits are stored + in the unit status word. The other status bits are determined dynamically. 2. The Drive Busy bit is set if the unit service is scheduled. In hardware, this bit indicates that the heads are not positioned over a track, i.e., that a seek is in progress. In simulation, the only time a Request Status command is allowed is either when the controller is waiting for - seek completion or for another command. In the latter case, unit service + seek completion or for a new command. In the latter case, unit service will not be scheduled, so activation can only be for seek completion. */ @@ -2312,7 +2322,7 @@ uint32 model; if (uptr == NULL) /* if the unit is invalid */ return DL_S2ERR | DL_S2NR; /* then it does not respond */ -model = GET_MODEL (uptr->flags); /* get the drive type */ +model = GET_MODEL (uptr->flags); /* get the drive model */ status = drive_props [model].type | uptr->STAT; /* start with the drive type and unit status */ if (uptr->flags & UNIT_WPROT) /* is the write protect switch set? */ diff --git a/HP2100/hp_disclib.h b/HP2100/hp_disclib.h index 52c4a161..315fc6ec 100644 --- a/HP2100/hp_disclib.h +++ b/HP2100/hp_disclib.h @@ -24,7 +24,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. - 19-Mar-12 JDB First release + 30-Mar-12 JDB First release 09-Nov-11 JDB Created disc controller common library from DS simulator @@ -66,7 +66,7 @@ #define CYL u3 /* current drive cylinder */ #define STAT u4 /* current drive status (Status 2) */ #define OP u5 /* current drive operation in process */ -#define PHASE u6 /* current command phase */ +#define PHASE u6 /* current drive operation phase */ /* Unit flags and accessors */ @@ -78,7 +78,7 @@ #define UNIT_V_AUTO (UNIT_V_UF + 5) /* bits 5-5: autosize */ #define DL_V_UF (UNIT_V_UF + 6) /* first free unit flag bit */ -#define UNIT_M_MODEL 3 /* model ID mask */ +#define UNIT_M_MODEL 03 /* model ID mask */ #define UNIT_MODEL (UNIT_M_MODEL << UNIT_V_MODEL) #define UNIT_WLK (1 << UNIT_V_WLK) @@ -96,9 +96,9 @@ #define DL_V_S1SPD 13 /* bits 15-13: S/P/D flags */ #define DL_V_S1STAT 8 /* bits 12- 8: controller status */ -#define DL_V_S1UNIT 0 /* bits 7- 0: last unit number */ +#define DL_V_S1UNIT 0 /* bits 3- 0: last unit number */ -#define DL_M_S1UNIT 15 /* unit mask */ +#define DL_M_S1UNIT 017 /* unit number mask */ #define GET_S1UNIT(v) (((v) >> DL_V_S1UNIT) & DL_M_S1UNIT) @@ -107,7 +107,7 @@ #define SET_S1UNIT(v) ((v) << DL_V_S1UNIT) -/* Status-2 accessors (+ = kept in unit status, - = determined dynamically */ +/* Status-2 accessors (+ = kept in unit status, - = determined dynamically) */ #define DL_V_S2ERR 15 /* bits 15-15: (-) any error flag */ #define DL_V_S2DTYP 9 /* bits 12- 9: (-) drive type */ @@ -116,7 +116,7 @@ #define DL_V_S2FMT 5 /* bits 5- 5: (-) format enabled flag */ #define DL_V_S2FAULT 4 /* bits 4- 4: (+) drive fault flag */ #define DL_V_S2FS 3 /* bits 3- 3: (+) first status flag */ -#define DL_V_S2SC 2 /* bits 2- 2: (+) seek error flag */ +#define DL_V_S2SC 2 /* bits 2- 2: (+) seek check flag */ #define DL_V_S2NR 1 /* bits 1- 1: (-) not ready flag */ #define DL_V_S2BUSY 0 /* bits 0- 1: (-) drive busy flag */ @@ -195,8 +195,9 @@ typedef enum { MAC = 0, - ICD, last_type = ICD, /* last valid type */ - TYPE_COUNT /* count of controller types */ + ICD, + last_type = ICD, /* last valid type */ + type_count /* count of controller types */ } CNTLR_TYPE; @@ -224,7 +225,8 @@ typedef enum { load_tio_register = 023, request_disc_address = 024, end = 025, - wakeup = 026, last_opcode = wakeup /* last valid opcode */ + wakeup = 026, + last_opcode = wakeup /* last valid opcode */ } CNTLR_OPCODE; #define DL_OPCODE_MASK 037 @@ -235,7 +237,8 @@ typedef enum { typedef enum { start_phase = 0, data_phase, - end_phase, last_phase = end_phase /* last valid phase */ + end_phase, + last_phase = end_phase /* last valid phase */ } CNTLR_PHASE; @@ -324,22 +327,22 @@ typedef struct { uint32 verify_count; /* count of sectors to verify */ uint32 poll_unit; /* last unit polled for attention */ uint16 *buffer; /* data buffer pointer */ - uint32 index; /* data buffer index */ - uint32 length; /* data buffer length */ - UNIT *aux; /* auxiliary units (controller and timer) */ - int32 seek_time; /* seek delay time (per cylinder) */ + uint32 index; /* data buffer current index */ + uint32 length; /* data buffer valid length */ + UNIT *aux; /* MAC auxiliary units (controller and timer) */ + int32 seek_time; /* per-cylinder seek delay time */ int32 sector_time; /* intersector delay time */ - int32 cmd_time; /* command start delay time */ - int32 data_time; /* data transfer delay time */ - int32 wait_time; /* command wait timeout */ + int32 cmd_time; /* command response time */ + int32 data_time; /* data transfer response time */ + int32 wait_time; /* command wait time */ } CNTLR_VARS; typedef CNTLR_VARS *CVPTR; /* pointer to controller state variables */ -/* Controller state variables initialiation. +/* Controller state variables initialization. - Parameters are: + The parameters are: ctype - type of the controller (CNTLR_TYPE) bufptr - pointer to the data buffer diff --git a/doc/hp2100_doc.doc b/doc/hp2100_doc.doc index 987acf0319adb6a4f6ae7fc7066b166db9c6a543..5a1ee52276d8995f04bf7deedda07d6caef6ebec 100644 GIT binary patch delta 39185 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 Date: Tue, 10 Apr 2012 05:38:12 -0700 Subject: [PATCH 047/112] Extensive Control Flow Enhancements: Added Message Suppression flag for status values, including providing a -Q option to the RETURN command to return with a message suppressed status Added Do command file default extension of .sim (from Dave Bryan) Added -O option to DO command file invocation which causes the caller's ON state and actions to be inherited in the newly called DO command file Added Command Line expansion to include a %* which expands to the whole set of arguments (%1 ... %9) Relaxed Command Line argument substitution (delimited by %'s) which cause environment variable lookups to first lookup the literal name provided and if that fails, lookup the name upcased. Added a SIM_VERIFY special Command Line expansion variable which expands to "-V" when command echoing is active Added a SIM_MESSAGE special Command Line expansion variable which expands to "-Q" when error message display is suppressed Added Command Aliasing, which causes the initial token on a command line to be looked up in the environment variable table, and if it exists to substitute the expansion for the initial token. Changed environment variable defining (with SET ENV variable=value) to always upcase the variable name. Added SHIFT command which shifts the numbered argument variables %1 ... %9 to the left by one (%1 becomes what was %2, etc.) Added CALL command which will call a routine (label) in the currently executing command file Added SET VERIFY and SET NOVERIFY commands which enable or disable DO command echoing Added SET MESSAGE and SET NOMESSAGE commands which globally enable or disable the display of status messages when commands (or Do Commands) return with unsuccessful status Added SET ON INHERIT and SET ON NOINHERIT to globally enable inheritance of ON state and actions when DO commands are invoked Added PROCEED and IGNORE commands which are do nothing but return success. These can be used in specific ON actions to possibly ignore particular return status values Added DO command file line number to error messages which are displayed while processing DO command files Expanded the DO command nesting level to 20 to potentially allow for more nesting due to the extensive use of CALL commands are used --- scp.c | 379 +++++++++++++++++++++++++++++++++++++++++++++-------- scp.h | 3 + sim_defs.h | 5 +- 3 files changed, 328 insertions(+), 59 deletions(-) diff --git a/scp.c b/scp.c index 779345c2..ace333cc 100644 --- a/scp.c +++ b/scp.c @@ -99,6 +99,7 @@ 27-Sep-04 RMS Fixed comma-separation options in set (David Bryan) 09-Sep-04 RMS Added -p option for RESET 13-Aug-04 RMS Qualified RESTORE detach with SIM_SW_REST + 17-Jul-04 JDB DO cmd file open failure retries with ".sim" appended 17-Jul-04 RMS Added ECHO command (Dave Bryan) 12-Jul-04 RMS Fixed problem ATTACHing to read only files (John Dundas) @@ -238,7 +239,7 @@ #define SSH_SH 1 /* show */ #define SSH_CL 2 /* clear */ -#define MAX_DO_NEST_LVL 10 /* DO cmd nesting level */ +#define MAX_DO_NEST_LVL 20 /* DO cmd nesting level */ #define SRBSIZ 1024 /* save/restore buffer */ #define SIM_BRK_INILNT 4096 /* bpt tbl length */ #define SIM_BRK_ALLTYP 0xFFFFFFFF @@ -400,8 +401,12 @@ t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr, UNIT *uptr, int32 dfltinc); t_stat step_svc (UNIT *ptr); void sub_args (char *instr, char *tmpbuf, int32 maxstr, char *do_arg[]); +t_stat shift_args (char *do_arg[], size_t arg_count); t_stat set_on (int32 flag, char *cptr); +t_stat set_verify (int32 flag, char *cptr); +t_stat set_message (int32 flag, char *cptr); t_stat set_asynch (int32 flag, char *cptr); +t_stat do_cmd_label (int32 flag, char *cptr, char *label); /* Global data */ @@ -438,11 +443,15 @@ FILEREF *sim_log_ref = NULL; /* log file file referen FILE *sim_deb = NULL; /* debug file */ FILEREF *sim_deb_ref = NULL; /* debug file file reference */ static FILE *sim_gotofile; /* the currently open do file */ +static int32 sim_goto_line; /* the current line number in the currently open do file */ static int32 sim_do_echo = 0; /* the echo status of the currently open do file */ +static int32 sim_show_message = 1; /* the message display status of the currently open do file */ +static int32 sim_on_inherit = 0; /* the inherit status of on state and conditions when executing do files */ int32 sim_do_depth = 0; static int32 sim_on_check[MAX_DO_NEST_LVL+1]; static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1]; +static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE]; static t_stat sim_last_cmd_stat; /* Command Status */ @@ -604,7 +613,9 @@ static CTAB cmd_table[] = { "set console DEL specify console delete char\n" "set console PCHAR specify console printable chars\n" "set console TELNET=port specify console telnet port\n" - "set console TELNET=LOG specify console telnet logging\n" + "set console TELNET=LOG=log_file\n" + " specify console telnet logging to the\n" + " specified destination {LOG,STDOUT,DEBUG or filename)\n" "set console TELNET=NOLOG disables console telnet logging\n" "set console TELNET=BUFFERED[=bufsize]\n" " specify console telnet buffering\n" @@ -613,10 +624,19 @@ static CTAB cmd_table[] = { "set console TELNET=UNBUFFERED\n" " disables console telnet buffering\n" "set console NOTELNET disable console telnet\n" - "set console LOG enable console logging\n" + "set console LOG=log_file enable console logging to the\n" + " specified destination {STDOUT,DEBUG or filename)\n" "set console NOLOG disable console logging\n" - "set console DEBUG enable console debugging\n" + "set console DEBUG=dbg_file\n" + " enable console debugging to the\n" + " specified destination {LOG,STDOUT or filename)\n" "set console NODEBUG disable console debugging\n" + "set log log_file specify the log destination\n" + " (STDOUT,DEBUG or filename)\n" + "set nolog disables any currently active logging\n" + "set debug debug_file specify the debug destination\n" + " (STDOUT,LOG or filename)\n" + "set nodebug disables any currently active debug output\n" "set break set breakpoints\n" "set nobreak clear breakpoints\n" "set throttle {x{M|K|%}}|{x/t}\n" @@ -625,6 +645,14 @@ static CTAB cmd_table[] = { "set asynch enable asynchronous I/O\n" "set noasynch disable asynchronous I/O\n" "set environment name=val set environment variable\n" + "set on enables error checking after command execution\n" + "set noon disables error checking after command execution\n" + "set on inherit enables inheritance of ON state and actions into do command files\n" + "set on noinherit disables inheritance of ON state and actions into do command files\n" + "set verify re-enables display of command file processed commands\n" + "set noverify disables display of command file processed commands\n" + "set message re-enables display of command file error messages\n" + "set nomessage disables display of command file error messages\n" "set OCT|DEC|HEX set device display radix\n" "set ENABLED enable device\n" "set DISABLED disable device\n" @@ -634,8 +662,6 @@ static CTAB cmd_table[] = { "set ENABLED enable unit\n" "set DISABLED disable unit\n" "set arg{,arg...} set unit parameters (see show modifiers)\n" - "set on enables error checking after command execution\n" - "set noon disables error checking after command execution\n" }, { "SHOW", &show_cmd, 0, "sh{ow} br{eak} show breakpoints\n" @@ -659,15 +685,25 @@ static CTAB cmd_table[] = { "sh{ow} {arg,...} show unit parameters\n" "sh{ow} on show on condition actions\n" }, { "DO", &do_cmd, 1, - "do {arg,arg...} process command file\n" }, + "do {-V} {-O} {-E} {arg,arg...}\b" + " process command file\n" }, { "GOTO", &goto_cmd, 1, "goto diff --git a/Visual Studio Projects/swtp6800mp-a2.vcproj b/Visual Studio Projects/swtp6800mp-a2.vcproj new file mode 100644 index 00000000..d7c86620 --- /dev/null +++ b/Visual Studio Projects/swtp6800mp-a2.vcproj @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/descrip.mms b/descrip.mms index e02bd0e3..9a5414b1 100644 --- a/descrip.mms +++ b/descrip.mms @@ -38,7 +38,8 @@ # PDP15 Just Build The DEC PDP-15. # S3 Just Build The IBM System 3. # SDS Just Build The SDS 940. -# SWTP Just Build The SWTP. +# SWTP6800MP-A Just Build The SWTP6800MP-A. +# SWTP6800MP-A2 Just Build The SWTP6800MP-A2. # VAX Just Build The DEC VAX. # VAX780 Just Build The DEC VAX780. # CLEAN Will Clean Files Back To Base Kit. @@ -573,13 +574,28 @@ SDS_SOURCE = $(SDS_DIR)SDS_CPU.C,$(SDS_DIR)SDS_DRM.C,$(SDS_DIR)SDS_DSK.C,\ SDS_OPTIONS = /INCL=($(SIMH_DIR),$(SDS_DIR))/DEF=($(CC_DEFS)) # -# SWTP 6800 +# SWTP 6800MP A # -SWTP_DIR = SYS$DISK:[.SWTP] -SWTP_LIB = $(LIB_DIR)SWTP-$(ARCH).OLB -SWTP_SOURCE = $(SWTP_DIR)SWTP_CPU.C,$(SWTP_DIR)SWTP_DSK.C,$(SWTP_DIR)SWTP_SIO.C,\ - $(SWTP_DIR)SWTP_SYS.C -SWTP_OPTIONS = /INCL=($(SIMH_DIR),$(SWTP_DIR))/DEF=($(CC_DEFS)) +SWTP6800MP_A_DIR = SYS$DISK:[.SWTP6800.SWTP6800] +SWTP6800MP_A_COMMON = SYS$DISK:[.SWTP6800.COMMON] +SWTP6800MP_A_LIB = $(LIB_DIR)SWTP6800MP-A-$(ARCH).OLB +SWTP6800MP_A_SOURCE = $(SWTP6800MP_A_COMMON)mp-a.c,$(SWTP6800MP_A_COMMON)m6800.c,\ + $(SWTP6800MP_A_COMMON)m6810.c,$(SWTP6800MP_A_COMMON)bootrom.c,$(SWTP6800MP_A_COMMON)dc-4.c,\ + $(SWTP6800MP_A_COMMON)mp-s.c,$(SWTP6800MP_A_DIR)mp-a_sys.c,$(SWTP6800MP_A_COMMON)mp-b2.c,\ + $(SWTP6800MP_A_COMMON)mp-8m.c +SWTP6800MP_A_OPTIONS = /INCL=($(SIMH_DIR),$(SWTP6800MP_A_DIR))/DEF=($(CC_DEFS)) + +# +# SWTP 6800MP A2 +# +SWTP6800MP_A2_DIR = SYS$DISK:[.SWTP6800.SWTP6800] +SWTP6800MP_A2_COMMON = SYS$DISK:[.SWTP6800.COMMON] +SWTP6800MP_A2_LIB = $(LIB_DIR)SWTP6800MP-A2-$(ARCH).OLB +SWTP6800MP_A2_SOURCE = $(SWTP6800MP_A2_COMMON)mp-a2.c,$(SWTP6800MP_A2_COMMON)m6800.c,\ + $(SWTP6800MP_A2_COMMON)m6810.c,$(SWTP6800MP_A2_COMMON)bootrom.c,$(SWTP6800MP_A2_COMMON)dc-4.c,\ + $(SWTP6800MP_A2_COMMON)mp-s.c,$(SWTP6800MP_A2_DIR)mp-a2_sys.c,$(SWTP6800MP_A2_COMMON)mp-b2.c,\ + $(SWTP6800MP_A2_COMMON)mp-8m.c,$(SWTP6800MP_A2_COMMON)i2716.c +SWTP6800MP_A2_OPTIONS = /INCL=($(SIMH_DIR),$(SWTP6800MP_A2_DIR))/DEF=($(CC_DEFS)) # # Digital Equipment VAX Simulator Definitions. @@ -657,14 +673,15 @@ I7094_OPTIONS = /INCL=($(SIMH_DIR),$(I7094_DIR))/DEF=($(CC_DEFS)) .IFDEF ALPHA_OR_IA64 ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 \ ID32 NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 VAX VAX780 SDS \ - I7094 SWTP + I7094 SWTP6800MP-A SWTP6800MP-A2 $! No further actions necessary .ELSE # # Else We Are On VAX And Build Everything EXCEPT the 64b simulators # ALL : ALTAIR ALTAIRZ80 GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ - NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 VAX VAX780 SDS SWTP + NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 VAX VAX780 SDS SWTP6800MP-A \ + SWTP6800MP-A2 $! No further actions necessary .ENDIF @@ -1036,11 +1053,22 @@ $(SDS_LIB) : $(SDS_SOURCE) $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -$(SWTP_LIB) : $(SWTP_SOURCE) +$(SWTP6800MP_A_LIB) : $(SWTP6800MP_A_SOURCE) $! $! Building The $(SWTP_LIB) Library. $! - $ $(CC)$(SWTP_OPTIONS) - + $ $(CC)$(SWTP6800MP_A_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(SWTP6800MP_A2_LIB) : $(SWTP6800MP_A2_SOURCE) + $! + $! Building The $(SWTP_LIB) Library. + $! + $ $(CC)$(SWTP6800MP_A2_OPTIONS) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - LIBRARY/CREATE $(MMS$TARGET) @@ -1435,16 +1463,28 @@ $(BIN_DIR)SDS-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(SDS_LIB) $(BLD_DIR)SCP.OBJ,$(SDS_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -SWTP : $(BIN_DIR)SWTP-$(ARCH).EXE - $! SWTP done +SWTP6800MP-A : $(BIN_DIR)SWTP6800MP-A-$(ARCH).EXE + $! SWTP6800MP-A done -$(BIN_DIR)SWTP-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(SWTP_LIB) +$(BIN_DIR)SWTP6800MP-A-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(SWTP6800MP_A_LIB) $! - $! Building The $(BIN_DIR)SWTP-$(ARCH).EXE Simulator. + $! Building The $(BIN_DIR)SWTP6800MP-A-$(ARCH).EXE Simulator. $! $ $(CC)$(SWTP_OPTIONS)/OBJ=$(BLD_DIR) SCP.C - $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)SWTP-$(ARCH).EXE - - $(BLD_DIR)SCP.OBJ,$(SWTP_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)SWTP6800MP-A-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(SWTP6800MP_A_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +SWTP6800MP-A2 : $(BIN_DIR)SWTP6800MP-A2-$(ARCH).EXE + $! SWTP6800MP-A2 done + +$(BIN_DIR)SWTP6800MP-A2-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(SWTP6800MP_A2_LIB) + $! + $! Building The $(BIN_DIR)SWTP6800MP-A2-$(ARCH).EXE Simulator. + $! + $ $(CC)$(SWTP_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)SWTP6800MP-A2-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(SWTP6800MP_A2_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* VAX : $(BIN_DIR)VAX-$(ARCH).EXE diff --git a/makefile b/makefile index a0debfc0..cd253954 100644 --- a/makefile +++ b/makefile @@ -598,10 +598,15 @@ SDS = ${SDSD}/sds_cpu.c ${SDSD}/sds_drm.c ${SDSD}/sds_dsk.c ${SDSD}/sds_io.c \ ${SDSD}/sds_stddev.c ${SDSD}/sds_sys.c SDS_OPT = -I ${SDSD} -SWTPD = swtp -SWTP = ${SWTPD}/swtp_cpu.c ${SWTPD}/swtp_dsk.c ${SWTPD}/swtp_sio.c \ - ${SWTPD}/swtp_sys.c -SWTP_OPT = -I ${SWTPD} +SWTP6800D = swtp6800/swtp6800 +SWTP6800C = swtp6800/common +SWTP6800MP-A = ${SWTP6800C}/mp-a.c ${SWTP6800C}/m6800.c ${SWTP6800C}/m6810.c \ + ${SWTP6800C}/bootrom.c ${SWTP6800C}/dc-4.c ${SWTP6800C}/mp-s.c ${SWTP6800D}/mp-a_sys.c \ + ${SWTP6800C}/mp-b2.c ${SWTP6800C}/mp-8m.c +SWTP6800MP-A2 = ${SWTP6800C}/mp-a2.c ${SWTP6800C}/m6800.c ${SWTP6800C}/m6810.c \ + ${SWTP6800C}/bootrom.c ${SWTP6800C}/dc-4.c ${SWTP6800C}/mp-s.c ${SWTP6800D}/mp-a2_sys.c \ + ${SWTP6800C}/mp-b2.c ${SWTP6800C}/mp-8m.c ${SWTP6800C}/i2716.c +SWTP6800_OPT = -I ${SWTP6800D} # @@ -610,7 +615,7 @@ SWTP_OPT = -I ${SWTPD} ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ vax vax780 nova eclipse hp2100 i1401 i1620 s3 \ altair altairz80 gri i7094 ibm1130 id16 \ - id32 sds lgp h316 swtp + id32 sds lgp h316 swtp6800mp-a swtp6800mp-a2 all : ${ALL} @@ -799,8 +804,14 @@ ${BIN}sds${EXE} : ${SDS} ${SIM} ${MKDIRBIN} ${CC} ${SDS} ${SIM} ${SDS_OPT} $(CC_OUTSPEC) ${LDFLAGS} -swtp : ${BIN}swtp${EXE} +swtp6800mp-a : ${BIN}swtp6800mp-a${EXE} -${BIN}swtp${EXE} : ${SWTP} ${SIM} +${BIN}swtp6800mp-a${EXE} : ${SWTP6800MP-A} ${SIM} ${MKDIRBIN} - ${CC} ${SWTP} ${SIM} ${SWTP_OPT} $(CC_OUTSPEC) ${LDFLAGS} + ${CC} ${SWTP6800MP-A} ${SIM} ${SWTP6800_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +swtp6800mp-a2 : ${BIN}swtp6800mp-a2${EXE} + +${BIN}swtp6800mp-a2${EXE} : ${SWTP6800MP-A2} ${SIM} + ${MKDIRBIN} + ${CC} ${SWTP6800MP-A2} ${SIM} ${SWTP6800_OPT} $(CC_OUTSPEC) ${LDFLAGS} diff --git a/swtp/6800boot.dsk b/swtp/6800boot.dsk deleted file mode 100644 index 132cd56935e98384e1a2f7f9fdbcc441ac45ceb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1474560 zcmeFa3w#^JwLd<)dU*Bn`;|D5@k6_LKkQ(m1c+r@N$l8`v7N**4o*tKJ28*&ytZtW zL=ciCO`sBww4jt)w3UH?v4Lb0(i;8yYcDFaT${GHQqod8yi%Z$ghH*~cUE!|+H(Kg z-|v1t|J&=oY^`=@XU?2+=FFKhXU@((@I*HiIF6_vk7=+cS1y-Z;A`5_VozUe>vN- zT1QJUlA6{w5yEj?4#^<|65wcTbT%R>o}SB5V&GYNrL%syqn?l|do%LqbA<#Q3hB6Z zFvyj4RY))5tb|w7?M=vhHeKXI0^NiB&CP3@8~_o|FL5&x`KziM&&xlPo0Uj!XsoVB z_5?n&x!DOg4QlQQICHo;iS)|Kc>aoN)X&Z3N=TAgFZ((FQ|WA2%dX>iEaEOE5D?(E zth&CM)fZ2x_;$3ILo+Y2|OHCDwst6<$N~DRrA}M z>d@g5aQGa4KADn$)5NNc=jRvjB}A*HH#+L=b>OgCFTaRiGy%WS&ax-cFXBrR{Hk+S zIqFI;PNbLd4w9n6A%dFy?4haFv8ova#o;c~EFdLnzNUuSy0dUK3$+)L(l4dgRs((Q zbnOC?em1?)VXum(FVvPL_{HF?X{>IJr(dkSG{LWB)wK?YSG->BW!mzD961x1srYE^ z+KL1{4u}=|#M3MFdIC0q?-TN1s&P78sx1fGO5H29uYI;MJqxLL*!i54&&@+K| zJb%8BpJ=zHW_x4vs)hud0-<0+ZW~rLJ0Joo-a?@;Gr`9RdQ^ObS;DMD{t5i!>9d82 zeqnEDaMXimaX52?c?o=oaf0&rZzb!;_{8(g7ZxV+)iqVvo2n}l>BR;enMMeob`^S+ zWBEjWgWizD+6U<>kbi~)ns-uv%#)gWLM)S<{^UtcKZe0c{YjnF)Dx06$?1o=HmN@_ z11I$-b5c`JNY*5$AJdgd{egR9Qh(rnnA9J*Stj)d?vY9T$(z*F6XwR5)Sn9`HT8sC zILYasKFR5)lbrtiNlt&kB&WY{lG9%_$?3OFa{9$dPQNtC>7Oyl>7O~t>7O;p>7PBx z>7O&n>7P5v>7O^r>7PHz>0dC(>0da>>1V;dllg=2)=B+YG^wd4)p0gWqA znFE1zxu`pE0r1$Yk#yHHs<1PIur0LGWsDzwCieWRGQF zrpUF{KMn>{m8X9ZeySY2Cg7SR^m58`TU>n|;U{`x!A#s?sT$YwE60PG*k1|!Kz$;e6KycbRi8tFUHnyn?ol#der>bhs+O;#6QY{}O z2ZY?kxeZ!uBofPGn@}V^eb@))Z$In1W7vG#~q%GT90?bhHQY<%#op|0Q` zX6w3oE|`7N7Lz}o^+k8^4}-{7D)aHI6GXWB)_}dPz877`gX;equH$dGp2>1O)8=~m za@W%V*R#`IPyfR8>}9ULk6q7R=Xx&Lbs)!e;0xC?&$*t}yPo^Nb>KGFvl`cdS6t73 z$Mv)&{{O%e-Qi%p+Rne|4yGynq&ql6dH$~~9U}C^3P@2nKw?j%hXX0GCkT2Vx*|GZ zcd%AoHxNua5adO^Z{LuvGnhrQyMi-Vs~=GMHDZ4_xF#+@$^p)8;q*i&{Q&~d8MG+R zUT4h-2lvTKCBt|yT@vI{QG1fxLX_ve6Ard}vIc_`MS&1#9`DP5?2h+YAj;jr!tP)} zcQC&@D0T;nY_Z^_;isy4iMzd!@1e1veLQ%npNM$^Zfqu^Wjtu_<&ah<7S#M;^*itLTqtiRG!H?5agr_5AaW~9|{tQx-F6gJ-^sJy>M*T6EW%caVh?-EgZZ; zw$j&jJ<%h50*Os>3!>nm$}jpuhrZZSwT-p^Z5HnbvTKRj_0%Szgn?g05K$4Wc^kP&| zb2@l|M>`m-W4pD5gFldsf^c`RPCT7ME4qU#{luD5pgqo64ad0sq%*jZeo#8VKXYOz zxKd2*3f73GuHXfd$wTD=3bCt^(~4~}C-f3o+e@gn3ZHE$I~TZZh5XJW^bhv}YbGwT z+;*$k-CAgIZ?J0JcNgj`gTXYLnaL28)IczIFo@w~Fqn&`XJRdxAw`*PDr)^i8if$i z0Z&$d^TaU7XgkahYL74&Tq!TI&J$DQdDa=C;ZSg?bgf)ixN$tVbhB1kw^=g_je7(8}%$?zxiI-7f0ZiGQ@%)=95-;08S%3oZpIkUA=A1a`^b zg1{xCW^q32D+exjn+mMiEqU3>fiFUuUXp+dN?F$lFp|Lyd#m{NcyNggdst!nAneeC zEqSmXSA~6LQ)MG`bA`PU+hsNI2W}c_Y<8|{Za*E&I~|+`%&b%{v}Tuuw08!l-4)Dh z6;GEO3{D#iPHW?g#6XWT<7`#?E6?q0XRzJ^ zXTsZ3${>1qr-IX3s@Y#0@aMs4FR68w;A{s$<%7Yzk~aENu;BAx`RQPJ5yTPPSPFT& zKrY7~gIVexgQbJP3+07_!Ra1uFn9s|qiije3xFg4+@hgrp9S*`vf1}|+DKcW;h`yL`+Y)zGuI-w)C z(~r7?dELQjoQW9Gq_xnGefU4_;pKe!gz{YSDG0M}Jb2+2DA!FMx2tcol-2a?b;Z`H z?BqZWj_N@BTvHL0s}B;m#0J$1ITe_kGH4dG^3qEfho8C_goR9KZRNm1Rs{q*F`kR)4zy$cNCYV>}H9T~Nwk zDQ*V14$`hX^BiMvIJgt(^pm(rfSVz0%{JIWKVMoSem+*fbjy(P3}+^$Hm33t7|@@F zgJ9M>#U+Em%G1HBBSA-Zkah-VxcZJ@3>pts9u7KA1^MR>6;h@jzYsO9W3Mwj^8zq7 zprbm@+bWKK{;$;aL*nW$b@gBA>hC^psMoQL)!2vczi22HKK$*FAm@hr4I!hP7ACq_ ze@3i7tGj<{xIZs6wS(;i`4?BftON|>{RZjX&@^l{`9-YXq`Z8h=!5ZoQwOgE%%K=` z?H7^;xyo>_gBvAc{wOa^Im%0^$_u|kJ}cDu7oyZ&Vp9e_peI9|g_zUnl%v^&+7L(6 zT3f>XZz?a`bCUECuqnLhXpBST&#bC!g+5MyKnype~kUlyA0bL+LbYw9qwBIL;*#3la;; zZY+?06(}!h6Y~?<_!pF+At&w&lyODOo3#$ zu>kz;1wdI-^gc`MEg!Ytm@o1-(mGMIPMR9HaBO-h#IvASPA>uqKq!^!Lk7x+1axf) zMU=z4tSNG`a=1r?sw$K7N{T*GL0vdHogZ)ym4(VtNr}xl*q=7opKg0KRZIgdg{S(t z6q20Qb~H)So$gPgnce+qr~1>|j$%wb-Jh;P-oY$i`F|y9q4<^il*9Lk=7Ii;B%N~D z!>W9>Tr`x)!IGk5wh)bzwq*82Q25DhV@r;9i)Lz;jYTIgCQy3HY%4vA<^|6z9)p}x zY&DevYVVScB{E+;(MA_E7fl^4II0!(rE+1h)uO!6TO{yA-+CbV^`iUy|IO&ZL?ZrlTNftkP_2FAHfXWH$>6;Z%P{*{S|a+#j=-jFory=Z45wfr@p3Sf~ul zw=zC<_2-I4Z`ELbuGcZxKgE+8DCmV41m=$|=q(5=4CTi9Q_7TqsU_q6DFH2)Mp9Af zpUkSbEDRK=_j|Qv%HT|vgWYot9A-Fa0)+$pIbHoz#RUOP9HU(@p3QQ8A^+lQLl=$r z19S%c6U$o|(9B9!l#i{8Wk1hxlkCpT;3@oxKgZspMIp2C=NDo+`0_gRw6Vwy7TP_-_ zReTRU?Zw%Q7fHwzN(FyVPJYjN=3J>fY|D$xjQ(|8I!R+7P?8D6uJsv8C0PP4EPS=S){ylwe=l(KT9QWVUUg` z9ug>k-mzLbNEL?uf%zdVqlx9<-B1i3O@L?cG+-8*bIh6?zojYQ zQ?~br=@WfV@bE|ru$rKtkeiw4=`Iv5IR zEVhtYZ4zt--JjO09la=U(U?}ayFX22BHU{hjj&LeO$tCru*tt-Rp><>E>Nj9UN{!e z0(m5XS-fpR-()~f@&|u6BtVNBRV{9U92hO2Y@T(qa_|}JwX6jP(QzSoToxv`khFB(k4Bgb!n>7la=Dnx;fi|EWV|=!1 zz*4XWRhzjil8JE)3Zm`!C54(0SL@FZQ;uhfrrt7lOw!c`%Fv_G7R3zI;+-0CD$DFo z6Sc?FCH|0qNE^xl0BF0w#bY)|*T9)+n6lQDaaqferZYYH3inMiOXE`B2+*;7 zHp-fp73n)jZw`75MhJ{(jBT5#n6x<`#+veyqWqingtHxH=hpXlE}LZSAWVnw%BCOo zoBXt3fmM4vzi1Xyeu7Xs(4STdL2x%qN$#hLrE2<%GR6te%it_7DW->y1jqh6YAcI(Mmt2ZO8Matk4vQSuUC#_h8VOLRH|3O4T_b zRr`~s)~zi{324wi4)4Y+`S4!r30o-DV&f0@47mds|I#S^}vetFvHrJ5={yFkg z`Lv|CX-UZO;PE$lv_0uhkSEfQz5c`s`7+Ng_%J1IDVKsB#FZo1;5hq<5cV5CyZd-H zHJ#giT=(iUxFX{v;+vQMS>1&^9lMY#N1jl(A;)i-{O={ok&x@i6Y_CS@Jki^9dJx$ zd-BkE-jSbrwGF^MyZ9qjo4;H}-oquonrn+4_Q^T%P1%)DVijayU5 zIpwTVJyXU2GIQ|ow`I(>2YaTNsU>{)kyD4iEwSGIg-to~J>^I*E5Q|pLOo#Kk$$06 z3BFzI>I0*4()lB=Eb(M1eYv*Mfy3X%X6oAednmt66FYLcOwOICKu%Vnmy91dU5riF zZQ&!I(Z?C1vl*0s(hrCIf4He<<>jB0ivM%8xkCShYzXQ zQAgoBa#S`u8`mb>>2pC9dmR9c-~UP&Dh7WGq6zz=t9)3tsef}2isU&TUuWhEn}%2AI_`PFa}-6!6M zo9)f3K>dG01en%=^VSZHQH7;1tZ*&=&&UufUR`g8(gN$gZkL^)9`a9#euDjR3gTJ_ z`@lmBel^kOAh1_3F!iC9uB>%7{b#TTm?l-}&^mhqb*^?aE~|B}0UfF^H9MWO$+5i7 z0TujJ4N&i_pR4LgWP-w~bT&fu#UC2_+?9G)c&Z=xdsElniZ@|s_(j}u3!ES zVXSGy8#w3+dt=oad!yQYmsKxc)%bOrkHd=wDvJ{jfpR_Cc)R8{{DaloynhfXO=;dl z099W6MID6XZH)sVd3PmFEE6vo_%FA!mi$AWB&z*7KU^VuVZlG^=l_;^mF|Dg)c>sf z_|N0bSrPx@Cqq~XB_zIjvx2SORLb+M)NL-n0#>qIWX-~wYZ?o)m|``$uPV?Z)B@{8 zSoR1_#R@^+Qd}r~E3D>q65fKP8SrbF(^%;%f=epwf3ikW7q&ka=%?~5tV;Lgb|X_T zWzeq;`!(%KpDpZvTuz183MqIQ7GT)`u@@0G$ScrOwmEd6jnvrdSJ@lal4XvHM)jo5 z-iVja*r6Y4Nu7Ny?;k29HLL0!IMl8s_EpPQ;msjUjs~b_jHtv3>yG`_L(i%SRSp*Y z%EvFV{r`FH{f{VduKnekrBbC&a<9Rvio2x1vQ3lC5;ZwYn%s6^vq3!NiP3k${$pwoLtH#QvBigAv_GY)J;cV5 zLhTx7Fk~92SrKmT-`q^6TTyjhH{l zCZA+|@8KBeA5t^YU&~R3?+W;=mPtmJ{|dDz)#0auQCIXiJt!YyS(yBUZkMIC&_H}7_OQk zbXO!X|GGbE&~Fa=&91&n@OC_?f?iad3kMB53hZ5Z;r$QM9QpU>=SSZ+jS*L$t(V__ zUk(dXnP_2pDb+gbwa#VB{;moCuR0-Ks1ee@aLV<7yzqVxlm4f^6*4IMOO*Xf!~6G!1e}JS z+Sg0kPw#(raQ}hu{%2W#*#Bta&i7DyKST?q_p7D-A@GMOPW*dxgZp1#E6e%-8Q9;C z5DYbVZGV#|iJ_vdegn%UT=Z(;t3AQm-;H=XlvTy9O05N`c;UO41p{IXtgv+^vIqgcu_dlofUD7HE zp1G_g>BlyxX@t<^;_jzd-(yineYvglQ=3fGQyaq%u?bj~?pvBbZU4=nHh%s$lOHyJ znulmNwEw(jd#!Uho6>6OYG>`LItKy`SqL6XP1R;@qP31?%`{=N{cX?w+G4?-9}oBU zv2gVNEf(%;SM=XBBa{C}DaQ>Ubijbd3guyOp)#(R9n2Oe?+zlQ>}|JA%)sr5V2lhF z@S*fAP=c?7gKr}i&ef+!J8MND?EeOum#O}xh`3{-=)aSGP@tOe^Ps8=R2x4YzF5#u zKJlc4>{PU7DTv zy#U`$`0mBG3||+%zu{aw?(2H+-GMLe>B9Jq;(L0vOP`9b72n19HsgCOzW3n!6i;sA zG(5Qr0k%B3rzK4O#iQ}vG!UG9Dmdqr@^2zoRTv|}-Q*_mBNiv&yLsf6$jujp$z9Pq zP7+Dz;3Ibk=xAYqP;=x)obr(yeOpF4Mu`x;@icjBxMQ3nTL{mQA+Cknz}?Jsayz)a z+;_OAxC5NR{XbloJH{algZqLv^6C6+yhrb1-p*ge-@(Gl*-D) zH~;pQM{Z^u{_f2Tn2TG07rgzrrJ7a!9`^&{;)jb%Uhmiox=_0(wba?Z;A+j)+Uv<| zW0Cef{s-K$)%4`Tg$s*IkVBsCy=fa)T!L80E7)b~!iA;Yn?OAh#rKiYO>U~=`TK@u z={m_x@)AHyD_zj5n`OF{+%&3}X9aX)dS|N%A&FKUgp{T}rx!T+OwLpQ)&^gj3gY z*AXPp59C*XOl1=e3<`eOsu_M3a0`i+tuHc?XX!^e9__H$*wJiTz>@cD5&1VdZ1TsF zjV_Yk7kN$XPzjwU|H3+#&XE6Cp+pPhpA_UH_(dtoquFxUnnhFPpBAQ2qx|Cn1J%lh ziZtz5XylyWY~;o*WObN8n&Xmwv<5qKIx;a8ir-z{nP*Z>}|S!Aai3 zh3+^`r1Z#^_<%R_tWxpt6KPpcI~sA+V^*_>zhle1^cV_{az}3y^`Tf~%h(dNwb6eW zOl^SIrVgo?-Wy;Hm_X|3z=2?u|)kV+j7ma=HZxDiHchs0tRX7B+OCM=+8W9MkaH zH;4A~Dw-#G491_j+Yo+~f^5vPU}_k{^cXBJ_csu9BhcCItMO~5h3+k)7B2$Tdn`21 z-6rL@CA{&tKuU4nDb02-n5%V{&DR=wi7liVxv9NpK}!qbVxXlEfeKjh`|lWXY#|=E z<4GU6ZSynT_POu4m(4f2H_ScmzIxv8dT39QS~^kuHTuid3r02abQNWs6i=L37Vx@< zhsuytxZqu~5XsJ=?xP##YLDJMKl!K~zpeB2N82U7-4^0(?B0U8pB%N#|CpX+5Qn;* ziOkw|lua~hJl#I`eH4D5j!tBxQuL@r`Yi^9q@zY@jrYCT&q+ zF#A`G^lA?9mC}eBajf*^7wO&eBt3l{q1HbEvY2>=Oz{>|b8vV;EHW6wPsA8bPqLu$ zESSoEAR$==^taYopHex@kq&-+)xcvvA77UHy0f2BFNC?(!!~2o^{LHrGjr<`$pFm7V?`Y>_GK-yvoH zDA-|53P0&WRHz-?pbx3KN#pXr=JLy^UJzKoYoATE@KFVVNT(#MeK{3aJo%UmzJC*$ z*rbYxysBa#uYblOIzx#oBO2hT*%tGsj{C8~jhR{UxIdK_yGllK{HsiZl%w&1YrM;F>KU~ zk%?8RB0vu?R1*Q!W&|B@{FA9en3g8FHBz!`|M$aB2I7pc*uayJMcMyW_{kqL(Zv|B zR(vP?gE6QQ*JTzUn=~c>3{DAW=|Vs zVz5SI=D`hvc($~4(b?WPZcV|b==TAQuPB_^c(#3MICCp5!W@F+)IPbCjoWNCtO^4H z;?vf36EU1QdbWtB6W3YOCaPFr{TR>wNF&kt-UT(jg}y~TJmKfN$dlR)@K{JxRWdlXZ|G)J)8=SIyamJVCR_Jqw{T(vJJ`m5lcRh7N`^ccONt$ul?5Pd(!S zJv4;Tn;%FTE{ICuwAbXNqa-42P7;lL+I>SuxdMIbn4yjGIG_SidlWHiN3%pjZHNPK z46`gY+Vgqf0?+AyDbyot1K$k=qqBcIXJigyzRB#!Y#XQ1B^h|FUND+0DQOwz^rFvmqN@fHno8mF(&m+vc(v&GB0Nuf7?xImr)YSKZ? zNC7m-GIdhL(|GDY)n!BJg-KAicOD{Vak zamnzddyxD_fhfp_eV2?}N-t(ry0Vnm6~j7Wh7j3<9m(%(ckNN>SCmAC{LwQj~! zRyXp9{~nIbiOwCK=L~0KoM7fvIBOmYI{yhWAt+THZwDs^-lxNv3L~4#V%-kn`yBswr0TX*0fdV zWGlG{b5Pg$3#s;Rw6417dwv{4z7|h5sq3-vTlI;e+GSWUubo(Gthz*JR$|x3DwdduS7(uwDL~k+TC6LWd1~HzwiFsSAoU2$sN>grL81}-;@x$FVJOS|C`L)Ag9t3@j%7TYy*BB{N(a{&n`5(Tm$Fwo9D$jy8MWG zWN$x%`34DlNB-AWr->)S{RLKu<8`;*KyTf2)z*$%=q;NzY@B5RsisAkTLH8WX7b7riVx#`Y1Gwd^Oz3RH_KAJP5VdjSG zwrr)hUUkc+OYfU}t}E@ox9!q8UT>0KXCCpzYjia7VY1-I*;~2KaTggZw&0pUo2HstGmc z5~@UlqPaA2w^=lBl|-XxS`!IP?Cvdz3p>DSA7@Y+F!J#(oP|?f8Q`x7Xa@K;UNdtj za3N|7OlLz2v(N$P1jdv<0sC&grCrhZyZ9E-hzRC)2l*=i6*vDHzo}^MXZQ4je4Coi zoBlSPQD93j0iKLbzJ<f_*xt#}+fKx}2FdbC5F^jV4e z;5x!BIEIWZ`yaby{ws$Xw*J!s{SPM(bAgnzH6AQ{W8rdQ0xvFriAc_NbTMCjz{xST zY@&TKdO3GF9*i+zrAS>0S?|Ol6lmQZ-ukD*;z+SEfx4yu3#aHB;|3;($|u-pH({90oU;v zH%V@(!q?H#fFL=Nc^OV{T!v^zVtQ;DzRT?mBwMoralD94N&k2SzSZ?jj>cwUeyAE> zEP@hKaUFtINZOC;0Q^Vwjx{9b-Fin$Gci3J5B6&!#!&q#c0dw~BdoQrC8?h}@r|#Y z8EFGCB0$hyMRH~}I^v~>fU%#iz$FoIY^X)hGUz{ZCV5pONnX`tN1a*jCTt>-@x7*I zX9MtP!nfI8LDB>2^)*1@8dO)kY%MXFSL3V3?vkuMYw&F$ru>k5hh&p$}m?NUGG`u^ErK6eO>dD z_bp$MkNWb*gR`Rty$9WQ6ly(p_zn&q8ksdRCmVx6s&A(EV2y8fIQKhDmYY3T)h`K| z!?{mH=Z2>oi_VYCWfPLQk@+zCqVrotG`8kX$enOiNhY{>G#{RU2B_>LMO2C}gI>ax zLCeBZe#d|&sX!@!7AtyvVuf?c?^t0h}ky`Ly!?_I%Ec{36?ji6Z?PHk|j-$RfoQ0~*dWQbs9O~j; zmzEApIfiZvFJ*j=WSyRvBU!WAV_*kzpDVCfbsyzEU!)J`ZbLO*UPH7+k}0fl;;NH; zi|RXh?TIslDmj?=(r$8N@$nBmg>LeWo?UI-8@f*^f0R(^;Qt@3cb z8&QLz-{SP$?vtZ6kt#)>6|F+N4V>FmVe`$jMoEf+r$$Q4qvc^fJ-QFB@|oB&1G`Va zb83!ML2XB?BKrjT_PMQ8r0Is}zDPNePLf^bheWNn2Qd$ZpNUhQzFU1;v9*DY*Am_D z!W*!a3L7}6 zgn1&bXRA3E>>`RZ({MN0eQrAzo^8#7-1N6>TNg95yq2xzbdudRr|(9au#0nupLtl0 z1duHf)6_>LFwQ|W)xOn(>X}e;mjnvSos5b)d#qFY? z7>-NR6~nLCZw~tv)`S1jhu*E~J#5ZGdTg>&-W;jHEyM*WNvDuaDhOGy>IX;d$6k*Z z5%xVQi3Xg#X@~<5bLg*FPT~44a3a2agU$O5-yZK(zP&ccvl_zY;fA{;^DN$z`q+b0d=J7v@Nn&q z?VaM=oAbz?DZV{6@16kh?hSC>2k}&BFY)c^<$Qa4dEbLJ#k3{za5w1!3*{H(5ykML zcdPWNcbml7T*j4NdA0^Ef`;fOHxGA;=&CnI+iW3Av^LrnsgJJiC6QWiEPu}nQof%^ z7j%&=BK%x8iv>cot+Y%LrYK48l@u5L7UgY1v=-$ftA%|Hd=e3)6#C;x8(Na(DcsKs zKRrW_4R=ZcD^`NXmLqMja?l|W$K;-0m}g$fb2+2ZMNy2jSp(>_Ojyca!_Y z-wU!AcR!EMBcmC7OhbXyQ8g6-vb7G zMhTV_4WpW)*yyH~e(2lHA_Jo>N=gno;SJa*34QL7D0HYzp3ijL_6XdmJEJT1J;a== zJLP=uPRZnzr9T-A$VgA9xfN3n^b%u$^ob3+)qB0Dm$MKBqLH%=Oy@9N3YGGSV1vcV z8_YKE_0l}~&mrF2OSXS#<+0vuJY=D~jF`z+$0hyt6r}0oX)NhA-aw2(tCTcr#B-^O zH((CJ^Trp?7%cQ>6FU~s_ponA(rjZlxtY@RR#eKS%*vdiHZ&52Zn1A{YHlr zj|IE6phuYF`s7pef8S7GYYxoYa5_`Ito;~BeQ!Edg{)#a% za^)_!Lu3V~(R7IC{lRLY~T}%?H;)>MZo+ajVk~?V%lql1h7_WYX*3x#8 zyP!RM9necR*??Y(w*$)OCf{Cm-z2{c6=;ksbLqDO9)j{1d#bvLtCMW+B;DTIM2Z%B zND(gTB;WMz_TA%3-lg8>O$1^Bo}tq1Y_KH?Z+_~GclW+3Nn0b(GdnfD-OLI=dwaVj zz4ulrlUf1C+asAEl1c3&dq(!s4Ct#-9vaKo9(i=%!;BfV(H3vFI0tFEZt@_V=5>j= z-UmnSdGsF1g2E8^2cfLHC$SndJbRk=YKt1jAjqcXto+32d+fBIvE+)K0REDGtSOm6+^=9r>Ul)P*faS&NoK zT}XOH5!LW!V(C;ze)+OUIl8kjgSR|!hV|R>2%xh853!cGg3>stWM1RlE@Gg{$rq3_$6 zTsi8UtCp{zjZSABMC6;QR#9a+oYJI1xiP`JKY<94@QHefwMnd!rre?Ec?(I_)2pDL zWGO2?=EjBM->6-fv1Y zvI0F4tv(-OVuI8#DX4Lo-;dTn6v4H~3b4k)dTn_)SThYaU<_b&Zo^if;0y%D<}sv(A$?NqLC zROQE?zd3Jt6Lwv^?W*`>k`jMFP#d4rQ751BtuxEw%cltdTD3Q!gThFX(3l!m>RX+} zqa=CTv385J2`l5H=+z_lvIJ&kpm8BZ80i+ORkLKBcw^hheSnY*Jz!MKO&GkR z8|mwvD15D?MX$Om+7W4k@O4T6^1#S$7AsEw0)3j2GkmX9sHU+DiiJ-hsUyR?BMr=c zE|0W<(R}KCXQFM__Urg%=A3t+YOD-0(Q!ZWd!i54D=9FFefk`tIz6T zj!n_)-11cKE}x9<(h8;0f=SXtY{*CNQAbFOHOzF^Z-+cj?IyQ(lRKaxwHQ3KUfH*c z8Sof0K<)2gOF+yg`mp$ciY-8vM;^i&8(<(!l#jR1FXSqP>*WwjjrI+?>ysm$L&ri zdM8w;;YE6^$+@br5^-*-Z=r!b7TSchCiOWxZJ2x)6Rr5Hjfww!b)q6A70g3FprdRa zQq|5zv+TAqj8`R?Iqn++_xJ50&q+Le)fw4`)k)*8(c$qJ4 zw84Hr(|w{6ej1uoWv`e4rm|)>IcrNHD8=F#-@ibCGM;T$mFEL6nBxi)1~X9c{)?!G zvAmm>Ww%PxRJ?%FC()LX-DSX_#6uJH=U@ygSMRgw;HeQ7Vki=`+Kp9JK#i=| z#jju3-lc?g*wP~dZr>-KKKSgGGjRQ=Zs53Q3Xvly3ReUCLHWMIaP}#v znsXkiD)AeLVu~_fnXe$6dqZ3=BaD~XY-jBb)w^6|l-I=lX0%wYgEYdKhl=9fW-kPr zVVVg?m{u~ti)Lb8v|omE@1U>28@|-ZvIFU6J02{a*e+m3^V}-76>~&Fjot#bdn!nw zP_Fr~*Hv38Vx`xEUGUq1`$jIsI|zO$S)W3I@Yy5>jaZI}A)FPDK;K39oQ5-x0z{lw zduA5BNVR)r7d?ltnE1bv^9p)u9^!kG8MAX3Pt$!xG#R_{{sH1fBkZ6s$%#G+)ygvI zlx!zW^1g_Qxnx*!I{06NI(7&16jLis&>eX5m)Z?}LvRBgN%ruJD|?Y=sw=y8Lhx2Z zTQO0>1PQIeTy%H@OZ#D@m9g~ij57$jw+IfDM?s7x?%1;>9(u>DD>rWIuqAyh3mW5d zSFB2Gy`fD6jbUfim8%-!`DU!0ThI8d#+N1H04DroEKQ5&uyi!`&M|meK$l_LLT*h!MLrVGuy8>Zt+m<)D4TuPs^{po(LnSEPTzCB z@B4ZI0>17e7{{BV-e_NBWiMfYDghD_08i4vLk#o&@mnHJLpQ-BLNS&`@AkIB&PuBH zuE*rc#C4GsxHN?#cYCjbEpa(iD{`atkv+0HdS_&@fRLuMCDWCpm)Yu9fb?>+bWlV3 zgDRjTehT5=^gbqKd#~mBSPZ>JfuhT*^j-@!br@A-FZ5mu(bQbwy$9a2*WU1j#nC4@t-V!(u^^YjJqOkS?Z@;7oYo{aN2dHK$S-h%JB_6yKvn zi&|esq10y>rus+1TBD-BU&(kbveFRUiiD6ZvK5+MnpqaoGlB(1F#L}=H$8|OI3l0v zz7j}4MyvQs`t!0-67qae65R?R`>{*&VK=$f#s5Uf{XN15qMhDN@Nsw#N}qcli`>bU zq@#DD{U3{T?%OMk!MC_Wz=_aF9>e+lLbMYD(7yqXZnCM1*hCYm!atu!w1_`vh1y-P9e9)3*9@$SG$E1DS@@N4nz#4k0(!QklP^{(7gVcmK~ zzo(mQ2Yd3IwLtk5AE ziA7#vS0e1Q+tGz$^XhY%oDJ%xOHFI4vH6CU)uRScC6H-CR0{&W zW@?$#z*u0*)6tt`ZR95U5mv3e&)52%cP}o0`{5d!EA<)dyyx5DyWh9dw^1?8FD~`% zF76^5L_;Vx(%(g3#laajyi3&hcG-sc3y5CEsciE-V6(;JTWYK8s^M8^sdP9H`=u=_ z4dwFs&tu+wh`o3ihr7sk?;_v1i|j*$cyWm>Oj^6iGri0>qkk z(roWD?iu2k2U2s;+X{F26>yig1$ghefW~`eKrQZAe*!H@Z9xLwE_;#GsZXxyxd!AXaS5@vXuf>zCJ8`V9+J<9O?F#cf z_NK<==6fnCD~rs@6_rg^937WSI4*b0VaMiqIIgHJV8HjecU5yytwSvWS@DUMBzGLEY&XRu?_OmlK&g+0wIRMu9S%>qB2;H)~C zT{k+-_f*!dHsZXl!EIiPD5pxKG_>q8udTA%rjrWXdrN@^bS%_09&) zETGen6yj{O-)~;)Y+O!KUTLu7=xbZb1^S2u700+Af)mEGD!M0S(aBQw# zVip>kn`~yGse-4(U{7UdmESb4Mfjry=Z@+Wc3f@3v7wSAzm8X;_{?qCi|lcBY>DEy zs-lNCoQa{#n(C!y0b@fpJ2vQXtgz?c*kDh>v8lPvd{1*z%L1G?*MfrPmZpo$!Ww(^ zWoE(KB-G6MBI=1gjKOrh?>ZmM)B>mPG2ejiKHo+koC>}Nd>f*VNBt2Gn*G+8m#)``MVi`0rGi1!qeMKMj0>f1-w1N_G5e4t5@P@-utAa zs7KKUBOcobZ#*3vu#F7J)1>$4F=l+YlHT;)M@JI%AV%v`8#~A1s2k5o5E^X_QwkT; zl{TzFu@MUY)QEHT%i}k?8fP|nimz49@?9aP`PyWQZ=G!LT`B8)?KS~RXWP276K_!X zDDeh`cd!!0-k@-N;X*(^lmmi!E+&5k-OD(>m(TY@8fy8@RZZhyYWDX zYMbYrj#TreQ!zESC-J<H~z-r+_ zkA^QKW@xYoyi)fwW#?|euFD*nssPf)Q#PZXBT-y0#FS^QK>q}!l7N)=Uf=zSd4o6u z&!U=^^m1y+Oaajo=1*hD{_n{C7EMC+sUtgV9s$|(K|ID9xt*Dfz8j*hxXgvRM{bDR zj)k*1rAZN2^!5_Hl)6r|40{lX2=EQwd+GcHkjU*orcj!IDMW7{-l5W+#d3=0BW7Ac zvl+!2m-$Hyfr(p;kwAeV&`B<4Hq_n-Uqmc^Ad{gjTFZFN>X;+e3*LK22|ALf^<5nT z1EZaasWQ@81B=VI3B&6F+>Lg2k*h`hM5f5zF{JHP^W9B&%O|l-;_sM2=G(;jR>XxO z%qmNO!id4yMpRfx2C&H9G;F(qmwaII7~Q*zCsKwAiylXD2FE5}jTO6(*_8=W0{lBk z87efsfX0AvR;eOy!7eFtB%N9yjw%?1JdwTLd(T3CiN3CquNZkNNqzy0LHQ+LD$k=r zl;?d1&X)IJFupgy!KuyAqpx+7jo_>mhHt(X<1aI(!NTEtMLg~ci_&|IsNs|U9K!-K z43lnhoz0cM%0fe|(}F|eli#E(2i& zaN9COffbl#gsAC3?=$oRTWxhyjJ#A2{}*`)ia16TERbL`7Z{H*@^ZbiiIA6g4&QHS-p-z z*Rd;|Cke=6iWPN0rB0~Rh{JpDuxCskNQ&?&AICf_?{4Iav*2}z;Z-VhP!WfAX(zb^ z3S%RL6MUTqz(2ywGI~?Q523V3DFTLpn^+s(#3q{WcxZ&3NO+?F+ad`tpi+j{cvmYX z1ueRofdULW=3U|?%t7OTgQhg%hnqxoxy&uL77X$dNe!k&9Pvao3aYP!={qdnT-Qlf zMDC7O+gv%P(R5|QhcN!6*)T`K%%;rgd){{_q`~U4I!^+oY`&wDyvwlzL>dAg@24f* z1a+pk4FwuZF9w2q>PN9;T!vbu&0aH=|k3;kOu)mF7iqPq8?)jow zO=jt@(c}=*asot;Meryi9R`?<{%&#~n#yjK5`huZ5g3sd-G)IuffCobUPJ`nfv20?3yJe?38#0hz-$bYMD}Kn z$n7Zozqxx8@TjV6U;GR;r83VU3CYP&r$XkFK(LfKVGsfV0tgX=5W>_5$fVNANeV+L zLxF&tY6a9{NE|>#C25DFM$>79w(Pd;&`MjSw{3CgRzMBf_D$Yzol^-VYwx}G+H0*nt&R2LwRt=@jERw>VjdO^lrv+Yq}y_Hm`9 zXFDiL4pj$TphqUK&Btu(j%wv6WrvJ}eRLzpt#lbI4=m@F^EKi{9A$Pv$RnP=1;TB6 zkL!F(z||d%R3jBv&%F?OHVZkpn6LYhHf$BYidzLk1=wlwZ(3p)p1CobJ7>i*x2Hw9 z+q2!`aOVN9x%RKzf6W#~QgPfich-gN=eIxD;%RXYDXqEy*ZJ+97K`u~2em^>6SEx_ zXzpUR-_5i*+MeM*o0rTalJ^zHsFI2v?>_-T%Rni{v;pQ*<6(mRLt zgamR>C()k+6BgP2?111G12{mpPr&k7*1n8P%z?yy)gR|n<88JCHLl+;sB!-Y2!}Jl z{o!?qya-+(^ROU(5DX3aDE9j^JWYzYU+~C1S--a_nftT%$uQW^WJ^}E_hljr+rF%9 zi$B{v%Ae`J!7l`|g(OAThXY(Voo7dgz~wP|FnRBVO5GgwS*_@9&tER{JTFBzPavUflLSL zj1SRr7*nP04B^{rQ3I$MYAn2hSX|sc`gQhiu{a2E^mF)yZVL<%=^!p5<4iwI=z~-~ zcYi>>?)Q)u72Aa3%iSjbCXx)B{5aernk)esE0_-Dc6*qQZ&LX?RQ_HptNZUd{J0rv z>f>}`fy-y&t(Jn(?>tTPhZw_!a*jqfSJL|=21=UKbu(Pr~b4fS!2%x~7$x~nDB5`t%5pbaOd-7|g3cPV#a9DR2i=Syw~ zD1N2qkg~&FP{S243D|SA(=FCu?r)bnJ)mgwO4n-mtzJXLZ3rmBKeT$D*qt&CJ3CI; zb4CJi8=r8_fcdK=AI)f;KLM|Rve?!2B=p7G}=_)@e@>=W_EbicOuH>Es~>r1^Sknhi>s^t3f zQHel4jwAX~o4Gu9b=EXdv%nmyP znZ6-@z{WxfZV!Y4y+BN-1i_uYQ8*&bC4SLw5Kd#l$K)IG2RU&)7D4pI89PzETs^C~xI@%aa zxrZxal2mt@4(JU4`bLMZ?|U9f`<|0ElD2w%Bqh%~}q6(}d1U$;<^ zc-58cFF!n<8f66ZmQ*a1M0$oJiy;uJke1&GQ5Z!17Ofz>-iCvqBka9_Sq{Jf%2D=L z{N*I>aUB)bHy`YA;4pB~=lu(P%#EZ6a5$9o5C5;Q@dEN-5o9puUgZ*SRAOPL#n$VF z;TX6=ZM}_5yFE+~a4#UwM&<@FvXL2yov??T*a_<{7vfw3)+2^!Ng|PWgmQxz;ZDO< zsye_SHfXLlG%+Ko*mg2*2U8rHI{_KPPGJ(362FG}jxP*tMXt2eF@Y(pWQwa9X);qX zhbf)GI2JHv70hI2z{>EzRNsKL^TCP2!3C9{p5z}mw_jPo4f!lez~y(afhi2E!u;>9 zsc;h3KfE~qml3Kj&GggJ|1jPC(B_T*<<>T3=I-owuX!#(@{W zo&ip^PqBRjJAgz=IEO}`f572Qid8^6h|!a>UlT4-hx!uKKSMNjcum43oHm0aQh@0~ z(c9ro7W|FgNPDPy?BANav97WX*k%|!m;%{!^hNd9K^XA)(HlngKdySiUhu;FWaw#c zh|Qc?eA#Qw%scHhXPRx+%U+8O10xu7?DNLI>`jEFABHPoI2F}m@c+)z(=^fso9bTcso7v&bC;_QN5O`CAHwsvly|17@q?1o_qc_1;- zm9o{FA;dL$huWhXyqUe;OvE#9^=1m3ixDa*eLM;*Ml^ZT8<2KI979a6f;ZgmMGQT@^y;TxBLQ*W?Q8Bdm6 zw0RkAv6z-ekG=@x^m`K#A|${G?t*x`oBG8b_)@FGN(m(m-chLS*Y+I;i5rfB71R0g zek#&CxQJ_7T< za_oxw|LAMyzw)me1PW9);>oz|5hfc8Y?0LW^z$kh3u*+1=l@D>KjkU^&%d~`ApbMa zK|7cwCbB|B?`ZJyuxw-T9nD2^3ZDnh2Z^-<7@4ek->@(6dHb~ng5l2z(6WwNumb4q z02OKC{5juIa0C+Y^obppN6FNOaF~#&OL_bKgAyI)V#V)~D?DT}jyhWSqi#n8R|#wE zr5o%D8Y@VoM*Oau*ZklEKC0W^YzP0lzYQ$MV3%5Xa5*}qhfBb{tQdh65o;OF!+V($ zOgn8w6wPYw?#EDRZk%>4xNrdyJt%B44VePS>1XB%VBBB|?KZ`Y7*!btoIaa4qnfS? zq02vTcSeQ2B>?sdu*#+#Iumdy$lQtlXAQRgAEp@Y2DCqe#^>6zCNIcILGLMAs ziCONx$rpO}KtuXM7h$^6U{8z|)4yV&cAbI>GaQYpMG-C#4+!n1cK$uIL*b7uzN49O z&BDXc+sxc@i}u9Ba0`q~u#R@^&j?*A+qdY^kt(~WG&{om52sPIAZM_3Ar_wVOKp}A zvA0INK>Oyi9WooEva_>)RN18tgpy-9Yz8HjILZ$39v-ie0l~)=614W zG|J8nQ;P44@)Rr5eHk99gmW+)MpGaAh0+ojRa4ou*l-Uy$SxNyH!?-oOt^wpM`ISKa$kzNWV6L84dLshkBU+)5`cFw-FBs z@#EB3WV85pnCKYmGQd~kEh=}R+w2R!9EkLVe-wyTxg1~ky9BSy7xq5hFup?oP8EOn}{L%A__GS=zt#Zcsk%ame4xT zMlyFJ!?Q8n*bMEW0=%mg0QSEk_t57B?bGpaxGr8T0n!Wo81OzR2x# z(=%Gh3iYpVkjWAO#iu=y7b1An2; z#b7!-<_-{ott4bik-G~N)5LHv^V7tXXo%kr#QP#%r`qtoh;!PP7v)4CCa1Gh{va^a z#PHoSQK2R#&xJiL+2SzSXz*l_w{@geRfLpMKolklYanxs28|kpk5xXJ47^x;;TRRA z33p(17OH{?l)9106P7Ajrz83>Ih{2XZ!rmNg%xV{Ne+rAH$;o3WXXm_+$ctCDTT^u zMP1(O;ybVb8I8BSH?sK;G{4DyAsd#e+>J_BrB-e&HL??p8VHq}i#`~vJ!%JgL3;U- zP^*Ggew^q-`M;EnuLlc`s=Tfjk`sQXXT=F`Xt2?5&dPUT-#`M-cRwKnq`X{f>2 z1)Q&nQu%KJM!z{2fSvDX-8})c%U^`|eUW5GaofO&R8B|_cCzn(-pN#MG-EQ1k&PCI z%)JF-A~awIF|Cow$FUnjIQo|n#}@LiH71-C8;2i+vpaIDSn7%es?l_Qd^XvK5ZeH0 zp0c!|&kGk_3>*j$dx1D#M87K`U<8o!|Q0i=ghIPYgd0yr@OzA_hQxe7o* zrd-*yL<0h%=f>dvcQB_2su#+qF(@p1VOvZi0!&$wzG>hM(duy1Am=00~1N>Q^ z)5r{c6}2I(U@Ph+!l)4&4g`w=US$@#2y4q-P%DzOY0_e?wb8*<%KJOa8?dVOP>KOX zk?_DNDs%%7RTE?Ai0CWti0D^MpAB*XGvGO~ZBj8*dJGU8fAxj`iV)1r6-FTiQEG^4 zI)&0!3NJP?xuS^WV)hX&JvWv?^Jasd2nMmQJR#H>Z~qH`0o0#x8>TPnHz1qH?K*3; z_@cUXPRW@+=^}OwZW-mf#w}s~32YPz7(GFlRzD{Lqfr7-j62I6zNpu`ac=}DPM>Db zbn&K0W+O99wcJg?bZi;cs+t(P58IfpH`oZ;H~N@JAyK!}$iOn&pq<8WM;K&F0cMvt zPcACdZ9H%29;Ne3I=*VKkLtDxUsF}f#V9n47|M-fLN+o*oaM2uGGD~AKwF73Ui?dy zYM$T73=`uto|X&j`NE432%LrN*9vITgpjxa7Ti>eLo7$3HT#cOfS*RjE@lKmQ1n2k zKXf;fX2;eO3)~^Pp+}!35F&i4n$Lm&2M(TF1v?QP?nh21argxx^m=g!#GpZC%g021 zda1x^ArHZNNzUo)mJ34@kpZ)h$p;G#yAp`* z#&OIX5~RNHVbet(N?;(8vwqv<3rCOW1`o(VG#xNTn6%kq0p^~Kbqx6XZZL~T;_KQ} zc)%Qp6rP5BCkY2xssu$TZ}mm|VGu&71_3>{Nca;-f4HOE`rIt;pR18(vOYat@u3NcQn7(e^hUM$lZL)?B zMiYd2^&2*>TDMjxDJ3!667uHAV1 zs*PG2&4yH6{rXJ+5RS;R5P5d}rp+7H3Y*pmlPV|9C*RqcZ(ThZmRb%NUx-m z8t|9{k2&=lZeO*wc8zfRx@B6dx$vBLSAE@PSg5KMCatNzYrw1&!I+NF@|Cq~SJVsT zv&)OhSJv14V&mr9QT4EfE$g@nCR~Ry3GuYD!vfUWjmzsd01?aTk^LIjk0L-dh)}U= zwdBDBNhVU_`E4g`x_qt-ZZoC>SFc z^78TwT-enRp;`kW6ma1BY=hP^9g!o=^+;mFrdjM%~JFRQhs3sG5QEwd3!s zUA1Y|+7-g8wRi&+GsaKDzSKFZZm(ard6SUEh0jbi%&ymvxlCBLdHtGIb+y1w(4rT@ zZwKZKKrJ_siCBiZmXDu-##>Xr4Bo+nKlPlkPQWH`0VEIvQlMLzLwpTuT8jf~IU9!w z8#mY0)o>oyB_ z)*>4ae6W>Qp_n-fsL(Tp5mo5)!v0?{_;YQTi^2b7jDK0o|5h0=k)s*BflV>o+JbHH zk@Be+nJh1tVZbJzN`YvVPnF7;X?)%!pPE+2pA0*ha4O_fj7mz~uaC64s5{BE`sXYkpU^qsHKUJ}fx``8h?*~xaC zL)JVQ_$6=@EzhgM2%qqPnqJz@a=VJv z^o2CoRnu#Hwm-mA3w>PW-b6vjo$ZIGYb>IvX{Ve*VJIeHKWUV>DGYZS<^(_V+4f@K z6N9^cq!*kunIQ>fuZ^3pvMD9BU@p9(vT3T}kv_J(U7FIy^sy7$rJL#PXom$%wq2Um z#`Uoy+imA?SBvd;Z7f1s*$!!HE7u`SYq$Ltacpl=oN`D+Y05eRL9UzEF)l-gbgWUD zEJ}SWc2a$c6cew~U{{*d$BrhC)6zuIcv+f+nP_QZuQchj?Ja!UaA>eWnv6v4wzt~Y zUfbD=oCAf_vEvgy?3XH0^FBP&OR-9I$$^@;OC9AMQitwrFYn-4hL_s)&yxr_>Clk1 zi7=QR(v7oc2|oJ|{Zg~fcC}xUefIbJrEM*&FdswQPn{f0KM&JF#XGgow-74a2;<0S zp*+U<^0Y7-?1~q!g{MKydCD0gKIkjZ!tDzNA-nov?KHAOdhDw7q{Am2QNu#Au)*M; z!Z&@=BmL5vKIurmv|0@7lh#0E0^9+N-+Xl@iN0 z^Mq@Fb)YI+461FCp3u=Mp=`eFbSmL>$;31b=Xzk+&jZIh+(UiCp|54zBB1WEc1>es z3+VVnQiF8b(J$TBD4oX9E$KAkX=4_IV%Uliz)gM9Z4O__zbJLImKq;4E~J63N!)FU>%3 zp9HHbP8<@@(^}N@dH7GA{Cq2m`OP7%oYx@6x~2!iVef@v%ojd%&AFCD_=0kpF_8ai z#PLaMwC6IE1%ZuHJ1!cUNHOq1gI(z)JZ9=1E|i#R(Jnof%eg`{-k>Gw5G}3=dK@s4 zCh3f?gf}pze+}S_5J3$!STEDKpVli5i7~B`4r3{UHT#oRvlOjn@mkIF7=v}Ypw(?K z8O(Z64y!HDma`utf{;+dX};`d$W4P?s_V2qX_*E47Bt%SNx^#eNx7AB>WM3BXrcNyRP?55p zy#C{rera}}G#i^uc-fL~!I!hhp6ncjBjeI)EGUk_e7=TU;eC`uc+Z#hDsN&eFH5sU zGl4e%D6*E860H@#)GsZ8??^RnMxR83-8q=jpyEgms_E0)r9(T%H49EcWhS7tOAod* z^+`*xU}SL0FcMpc!7de=Ezv-CP3Bo05>oJHCS+v4w6&MLxwAqn>}98RmW%e?w!hkq zyKNW6p{`I>h-{Zm>@sTaR=pKi2$o18r<=BY2$2}mU+t5&?zUYJYm)8P{nuN@pVl_0kLpqM>1%9FM%_6LqGGf9);d5s*3}S_N&>EK0s7$zQ{qt#C zz<%Jg?Sg$zuha@pF?EssMc%?#w@R(;QcJJ2{SrHU8)S0JRcX7=_E$kT4Gd&;Mr5Wo z48-`6oxWo*29-zHCWkEVl}?ScCjrZRG&2ER%?b6t^zqmVtQ z?(#lqDRlvM8d_9C>P)>K^+_`^0nsnb?33ouDQsEFriGZH2WfZk?)nN zFLDP>aZ)2SKT=03%W zr`1V=-RL~OGokQxHVl1QAH=4WY@j zp9oDgXwwl0WiuzQ_=j}FSx-?d8~Ky8qo z0TZJ=x$eBoT$( z+6X};3I5X{+7s8xcsbEPLI;w6$v~C+rH1bGKB+-#<_7Q~vMHMfJ2AwAYQ(=`u-irG za=2==dV1B+o_^^_A0NtuOJ0=Gm))-A`X~y72^^{eRIT+67s%bChCYFYXq27-t8S7G zHc8I})d)?6ki&5)XB$+F)fOD|=&nRLoZpMSc8Log*X6O#B32y~ zpj*MPLHk6WK{+bH3o>*)61MR$J1cnrMN>}*97^BKTm)Sd@L^1ZxMr*55kJKq0qNk+ z%7X(0Uu%-MvQau{pR8p`+NLg%sb&dOvt^_y*0*t_6#f?(iDoSmTCYkX43h=%c1|&TLbtZxsi4Xjj0QaqAU@!XBOCAOLI=jOunAOqp1h5l%932QS#VF zYE8IQ>p};$Rso9m?QT#XR+VkuQ zt{S)p$(sm8lq1%Nl*E*M-h!=&&Q|^i(lF0TF*KKfjN)l} z^d=bIi)xTgQ7lV?gv)aA0U*@R!t@-o8l|V~X};o%1h4oTHB6&=33@0jg6r*YA7UC``e?*c(yX^16f0UdrNX=KJ+74-n zMv?Yga4G7@go+j!&D6y=LjSe47r)ff2a04NM(=H96Ds&9CZ?jIqC?t|_`LLFhqM#X zLy+x|5E6?k;wT-^#J$DEP9p6ZiZ@k5*&lUg_SN%aRLg zJ#jOHD-g7wGFK&cyR;LV4IPcrF1yq&-RBf?a}!%|dX9_!bC>fz2<_N$i7k;%Q=Y|X z$-CkV%l#^`<&tv=KAZFY>U=FXfa+qHjd-)2yci#XF%3RVm=$0IXkVYQa_l-RI}as) zqa7IcIx7my;`y!8LE+uR#duK!BQlBs5kHn^#<+YGfFaWkX@6o1AI-!@bx3;>Tb2L~ zz{5V=-k9Dl?ZL?^Gi5stx1;^g8DakpMsm!Zyl9#(enCwTDO#r6KWdcri5Iw-!(E-0 zynookJ45XkJHzZo(wR%O2jU^?(9ST?kRZn{>kJpo2@qj&?5fTX(MnFeh@I$c3BotR ztysufgP}?%mp4Lt!AHcyCuR={s(Oo6oSgens(XR-;uRgza=p_; zG)iqEFa^DAg_^+j7QZYcIIZ@p8>NSuBo{atm=hS(QbDW|_!uS*g8PWGQnaAWLb%u^ zU9F5@)UN&;08J#-Kw|F!Ic`R~gr;u#QS$6S`##bkJ=`Zf+{yrVJICRJnqDC z7z#7KN%D3`M+8SF&N72PH_xAfwgIP+yn+qL$RO0DXC`+~xQfC@W@0Rk`H@H4rH7HD zYjy`0m)#{j92{YxzD?4vQG76$Ac}l21cI3}iH~LC+je2|oH;Pfe$#4``z5f<3)M`rxW` zfpj$JAjE&Lww|;uZC!emkO{Z|0YD$&s>?6UJD4AB-7naF(;>~jDlI@D36rJZ4Z&t= z;Nm{(l3b0_1NIQoUuh6F4>eocE`fI((hG!n2>Tf9biyr~_OPs6%rzK3HrTmL0jCE# zr;A`+^A`(|oi$=8Twp<+(?oVL*bX1ZB$U#qgnojG5XV*NaS)KbSYto7IUz#qhDHy-q0tl z1j()J<>F6vA@|v06qseNG)qkwX)~%(XR-pQ(HsDzJ{%0d8I1Ui@CDP<^td^I(<`|y zOOM+>MediSL!w`fU(}9as#NP9Zj<_?O^A4rbiPd?A%v1NGD`Y!P+!c7YK0zlk;Ace zz76_5j=S{n@l2w${$**CJsP6h{4p!?;et8K0Azd-hRMx`oYP=TR{FIa8p^MInB<|E ziqAFiGlNT5kNH-bkAd)Sk}9_ne|KpJvs*fG-U!tsoeOIH9I)Va!r5F@IJ;QWPJ9yP ze5PSZAA{%OzYzs$9=`040A3?b&%o3T6dQXvFflbmc#hyt!`z=VM^37si6FaPte*hV z%SnK+(5_8wkZ`Tk>oY-5Kp(UD1SZLz?qa#b;iwBn@vcgH9N01EGNQ<&eWgz)#qE0y ze4|up4;v^f<)P0Oo$8mKYnPtskj}Ihf8!+6CB@J`XbPrX%F@22H2oVQ)*cRpWrju= zOVp%@2I<#m`I+`G2v@BO&VZ-hNmG2;SCLH9KL>LS&IFO}ff=l}Ch2+1W1&b;Oi1i= ziQjj{1oiWvib=Ct7<6a~!W?R89E13jJuNMvuF5AeLu&0YSz)IoY{0%ORoP8i&c3xZvv4f9T7q_1lX4q9}x~9D@laual=aZOZsZwWWh>x)AlDzg) zfTw{%7shEAueGtb1O;O@uFcRceb5G4fn2!IX6hiF+CR0;tdHq1=_2x%rC(&4xFOA5 z9n$KnqzSDdzuU7AdCgVnc2Ji#Rt;iHJdDBtAE4C_s7(?9_q0?cMj~^{7^C#*7Y)MW z_|%z}1(DaILxI_7qag&)FcCjA+Tef)gLixalc=;j1e4R~*dn9}KZHs7HTCm618$hf z_Z2?{JcI1PXRs$EeYz_j&Fi8zt`R`f(;KCSa=GM+E?!QnL3=yLixIwJq5~gv!}Mvw zmrk%iU-21gtpKLoBYfGHw9u6l`nC&FXJI2IYja7vwCP$)8d?Q1n7A0Jk3dd!rgZ>y zxG*xMfV3#Cpx0?Ayka*tNQ&@fujK8lF8BoU&RGsa>XqXAzKP@erALI1JFBrl1RDl; zpKVerV;==nVlRBUGsB*SGnP5dTd@%ZSH3wHiCl`Mi%(`!(bshvwg^3m!nXtcTdU9K zK$-A~oK{VX5#S~i6Q${u+*klX(a`C3*{A55-GY%_mv9F`)sHsc3%0ihl>-v(50`dD zLgohpjzWqL$b45mGyLEd*QJf9z%G{1o_T6Fi)E1*pyV)1BBxGjloT=CH3}-mKc$Xb zYKit@K7|>o^IobhVqp72_PldZnFE&Wx^Mh~Fq3wa00o+ohxUhKi^MP$s+> zj+TYT7&+w|Ii(M3sYqFV>&ik@t-Z=2QqoU{{u^oN$%}G%F7^H{ zd1!W5`fsA_5!mLQzVPg&nO%`MRvrZmG)a3jvJn#-r4Af)$51OMKU~FdVpk$jtDc2c z)JExk;Df+ymF^dNd!>EXH3Xl^r0I>p4U9=k8>PKSK+8Q_rM+TrqqGOvEW#&>s(;*y z4;0AMAnlb?dpa?t2bXXex*ELhCoi77?iVg|L+5mL((ShJ!2-A8CUTZzQ;pCx-(6SA#F+vZN z@5t+^89~Aw*yRPf?E@8{xMqGRlkUnvb%d{-r0=KpK*L6n2(x40jpXvs9nR3)(FyHb zT2hyEUrS_#KEqEGrbE{dk1t>G%V<#QtX6xpP9{OYz8u6wJZGvn0y`WjCUF={R$*o% zJ<9~mibKN{BBUnwb41LIpk)hfwU(B07J}8d!@!^2<_?W}J4U*fYjfM~#VMuO9yhQS zXQHJx%!Q4l6|n*zmcxQFC_m*S)|fR-V}x|4ko6Z7ArW(u0`?<@ zfs{iVrDsKgCbK=5Rx5S5j|Qh;1pBv`>BOOS?2wJdcq*ZgZ#H8v{RGYJu|4i#s1->6 zs)NQ;+7&;JEL`y;M7yy@=>7ts!sqVq+&IfpHnN+$sx2a-#42vvl%AlhN*p80DEDd< zP{@OV@S>Xjt}0|w>BgeSm#1R_#A^S?>62#rXI%QDT^JW#%pKNkoNABjj-G0d>`t6& zw|1vZwZn(&mRtfrxEH!7UzT1h{1&EAN--QggTqUh_g~1TGa0?o3+RjHUg^con7nk% z8wBUZa0Hnqrq1Z$rdOmba^gp&C4JID0C>(Gt^rWlczB@DjneZ2UQ&hbh2>EfhM7;O zEWkX`B)y18Pk_kSo>!#1wg#R0I~{XyoUp8mf(>I3n^f=!tV+^kNVlH#065B=*I_!! zaqPc(^Lp%Hsa{jRdDBW^o>XX{txOX(FB4|gZrqqJl&@QRH+C=O3zNqe3gwdHhEhXt zQ_fgnIWI7o*n+XLe$9FVgY7%@8)|8r61LO?Z>HOLBlhrA2t~p?p#Zny0b>2_OV`vF zZCO=+r?776YHR^P)MfREHL0Nfu2tF=k4cqWMo!nn`S6^Dq}YOltsxukF2b&oRm-ta zQ-*ZpEmjzs6+nj(Xh8<&^Jy6x4B#oZ9>8FHLKPObsN@g+*mMx z$qm7cR4DC4J$z&R`dTzYeZiXArPxrW@3TViOg(u0x{cWMv~FzyYF3Y3Im_y?@9bKv znu1`?PQZnM^i7PcGQFzP^syrgrmPxZ{wv z6Rldie)Fax?5DzO0H2iwYgTQf24A~r!@4zyvV7f!+ck;-kQoJZ@gKFsHA1;tZ%>3) zX`#W}0oSanT{hUX)q|O9S!#I+v{?+P=4+`2HdhT0iGks=Hg##+^9qZFLP;nr5eiF% z!r?;U2%)e{C>$vm3U3e!9YW!Fp>TpwSS}P+2!#`c!bvzJRxFj24j)lA(r|-gJfFqb zCX`o9oMb4f-c-9`Q_<*AMHAO9D;hnfX#D7mqVmyMMN>xS6x}>}Skctcxkb}P=M`1g zZCG103l}gJ&D>DGrDz5=Ton=V771e+Vdl!(jrD@rAXHt$n^qU(dov;QTJ7L7UPCsQ zeM1)z9_*C{VP?*HkSd6MSiUeJXX(04E8&=v0}pNAA3kQ}tX(JQEi;TNG`j4D;^Lx` zq8suha!N&|`6Z*vMiiIikD%`n`3`zH5Ov*J{4HN@5VYEkHt^Yu2yU=!v_Y6hJq_>q z*u{p|1hkOex*4breQ7-tA3V-G84bC41|C+&jM)YrL{Bf+K{ImM|LQX2&n%y9fEBXp zMY;Lo^C#GDt(-VMcTrAG_9XlYax#Vu%aevtB-^cXCe22q3fryYAuSe_NK4IdFNgMU?}zq8?%+P*y9^UUd-Q)s z-p1Jdku2ZLKhJ$_9u417VNQcNa!1%Hp0mBy)fN%P{Zsl^+RN#ig~`RP;)iqQ%)7b3 zF@OFrLvnL-a~k%N(ZOLlIz^YfhT)HXmgW#sh$ZyCu-C%=9QH}nYtc)i&qjY1!^EtN zWn!(dIkDqncg8Vs&2gW^Hz(m1)|Bj&B`F`IGQzlwaT$~HKAF}$%~ic*&L_1@Ew}8G z+sEB8W8+5++gg6Veg1*h4*dDRCkL5dHUG->;J72q5$;IEk=Gs__vn&Gn~yWcUpxL; zEA#7dAtvPg=cw+ePotN{aAHf>%GlY+F)2=ocg44+m{Ke$F)8^eOHz4}$tg}P$(WR} zK4Sy&bxnI_+Ot~DTy1e}$+Ax<-)-DB;U4ZDLCZPjpop9&JvimT*~q*2NXet?AKh^L zQY+UgwoVAv`jcSJrkI$RnKAQGYcX~bO0Zlj!?w7?ai5?JF~M3FYc7tGsA%I!pK2Yxy^~{9*fo>*~B7*ha1oFZ7-`{u#rJXUdss zW+pR-na?ahn~!HEz^A;tg1MQgM95ste+E;+lrr-WenPv-@WBP~3;xFbBiiZR%;ki2 zc^6%N`|={`ZD~>M+qJ)mUJy;xL%)wRK8O1b{IP?6GZJR_3YV9;(#q0YlT4YWd1dol zQ@2cj5w0<&T+@xF%U-ARboA+r&CVa3r=m|~oPNC1$v)m$d+PBccmI3shqYb}(yHhO z@m8aUM8`+Jz~?Zz(Rbr}d-QjB)<%0XDECzv58|z649SSkcp>9%xVL9~hi7fZQ6q(~ zHa>*+E5>AF%;xsZTShQk&hNXJZ6kV(JB>??$LO+G<`?`SykF&0_}Gmd8}BS-n0rdE z^1Jvt{)4#XacAQ$%!!CAiBoXnpd4q4dm_#nx9<3C(}5O-`5~)K zvqG~D-1^5`4;=gBv0?1a6@)2<*~wX99C{zS(-6Ya_bxsZxD!n~@1ie+FSRaZm=Wx* zjr#Yly3jg?*~pu;^vRrwdl=~-WKD)6NT0%+`A2w$%bnlFq?t@X7^bBU1IB6A9E4%6 zd!&xxbD4Zl=54`p+{SGK95;KL!3j9)_{ID^C`X~`wjhk#mTm)#(d^BqBoZu|o_f95d-OjF&Rb-zT3W*8=E<(R=u;${QJ zDt3}#E?`vgllf}E$TUp~)??Dr*{FwuogA#k!z7rVqV!zeM_qV5wR9<9oME31!g#u_4lrH~Ssd~|`+LQDoArP8H`O!)oT0=N zV@fbhFeRJP#I&+W;0O!!GlkqvP|sR?Z{a?`^EPgu#wY5d z-FSPW!=raZABnyl?#kMc##Czri)#04 zd}6tA58g+O5#S3C8`r|U#rOf9w;A`DH5g_$-d=OKd58Ik`F6NBo8QNCk@<1<6flPt z`cHnp8UOLDpL+j^oy(qK7qBm|C)k5X^C9aqEHyl9SZ%Nx3Ju#p7aI(m;UR+wuGuCR zo<6kDv)pRF0EeHfTp{TGb*^A#7q@}qxQEc6wsJD(;?8pKpyi(9e}Vp3gud_wzmey` z*UX@)CjMUj9RH4`&hnh)7nV>wuC8=R-oTh{Dzg;57-%| z*``9!0I0!4a-+s{n`tVj19F2eWQrj>%1rxD>_4-A`~HJZIG=JpvG1vU;QlNNe6Fp1 zP-}-HXnFLA=!1Blf#iseJ{`RoZfEp|c-BTA$?+6@p-1b$I+&c8?VRsW|Q350|~Mfa-$V;WBJjY+@7OnkNO}t zUXS<9CAqN&5@c(uD~|2r z_Z~ZU%m>-=dUog>$d2qi*(d|#Ml0mTUYJ_k`vA%Snelq2bvDV2J&+z-Av0PbGxp3r z%N0G}HG9wgv-^FJ8?W1}b4hOOfdttKxzP%_v1jhtxqA+tJ@^jf#v4Jou@@5LmyjE6 zkQ;le&sFa|aPC0$mW-k;nKy08O4*W~zQs0qi{%bz{G=h=tPKKsb>xyP2DIms6@C40_1b@t5D zE2^Jc@!ZRMpL^xpbFc1g@$K2>Kf5ikXZu%Yw|~9&p1yPU^#9@Wu`3SWvtsw|mgWvzNp9^Y4Rt|2Rm82n+|cpV4TxkXpy$Pya!-47$mO zW%X~0aV>=7$e(3-{+b_!gCDaxoY2t7@bE}JlIJ2LBf|&sGZ;)-etH}Yd@%l?&wp_6 z!x@e7B7ie!wy*v}l>a@C2@B@n&h3iXGiO)9&iWkTKY{k&7BZMdHlD-<#xUQ)OpuMA zvJmk($^>?*8g^GJ<7pPiW0dw$<};jBoN$(SnZhV78a@;!mSZDs$F-P`D9u=AGODK2 z0zZN=yoC8~e7qq%OKVP?v9DjXZxSANhQc@GW#LgdyOC8x^97GH3_jL(ggwr1a{M4{ zcSc|p!ukbDHnxdbqAYQ;MXbXOQ;16hSfpFBl_^)seFjD^m9hjDSgBOFAjPmy^YheV zcT^gpA(B$ANAoe0l_gUs-a4j@6>KPKhEm?ld4iBW#T_PPBL`!ZmRv+MhZ==5?*DS_ z@=SNV<(Z+HaicDL%vG*t_`I(9pwEO-Yoz9GU?$>!6EjorDz}JP{%Le8 zX`)t@=3``s~Wl(s~{oxCifa4mIy%&y+^Qe=705Tgb;d2V8<%ARM-+IQ!z@J;aM-+ z%YZAv;9@;hN>vNHi}OrWt!rVuuY~ZkCfLLx5>9k-`QsF{ww)c@Gg+B(XzKenpP%Nb zR3-s>n4J12_Ry5~Cu=^zW>%)PF$xyi6`a6Q%6DNW?o-z=CYlG397MX-Hgd-AT~pNP zPh2qN{RvCCiIK8>DmzFO86PT>P)w6&q8#=t>vDOf^EWVNSGQ*dkZM$;*9mta4Qf71 zpj~w#t`ZIT!cxxiV?S^g<|-xdC3pz4v5*Gq!|$n~9|@DNcBZ?(#_2c0E8+1Yp>PnV zUkjN7I2|&8&nWaBa?*RQy{MbN&DnX#h&j zV18c;sRQ|iaj>zdLH{xcJq%|9(JVk0=yJYti_fr|num8_-p(^ineQ_k)|+d#G7AmX zGaC;q5N4y@*s<7y5&E7oe-{_>&wh(%J{HNstjaCG<1K1faRW0S|536~u~4}M&qSBc zGo5+@D9H5=oaiucI-G1_34+!m2z{(v_$!c};h!uH)oK-nE0xwGDg`-QRfK>?)vy;F zYRD#sQtqkH*@!ZcnAlyQxS0+m=-0~Z!oDWezH*>Tq75y^~^;E3yZgT@ATYmk_v@Eo8YG(XD3Q;84Sx zlv^P>d1 ztvZ};yd!cQ&OO2RUi~d+oIpYUfozZ_2c>o4{8KRB2rIIzLRGZv5k4$fG=4M_X4Rsh zWsub22JCKhIK8{|ED*zS@eVG`LZ`!j2X5kF;KAY$Du-|3vw@fj7v9@H5NJKLAjq_Z z8%1lEOxA?+@aj&G- zQTBxHOy?LoKZXg9>dtZw$BKEjbA;Wn7`=Aj8Zy{tPq4``jE|Xs!oxVnCGmST{YMq% zJF?1Hvf1^3kDVO2pNu8X@i9?>NBeN&!FT=l1?trV*mvIM3hyv7Y6|{;tl9)(5o*k8 zWjjpFUsYqO;3$HLlEgo%sb)Dl8_nKsyo0DLJDXyHV!|b@(sD$L9C@q8#h?t~sr$sBrnQ_$LFw7ZBzBB1D>9m2unyve) z@R}~BD^r|Y7Vr~w`0&l}>1lQ~baHl>Aych$<)~I=3gO0r7%rb`&Fz_Tz8WmoL^<4=Ck8tyV6*jLxa_ z(X16*Lx>RwfzL!J!A32L%g05114)q!zfg#z-D-3(^1=-XaXnM);pm_1J$H2S`6kt_ zT}-ljP&OhKq_v!SgaoNTzOgJzI%xY&;A;lT7X8zzGOV{l<}c9K$}T>G}gB z0x0@ub&D=bVGb{JA{ZaFjc8F8ptU&kK7KqC1&#>Cl0edn^mt;wM1rYiFjHj?*r_rX z57&)qDlB+~jfJcb9A&!1DsfmeG2!17xWfUWCt*>&7q5d9< zTLADaXB?tP4xgc4*#RTQPK(={$9wJrzg#ikO~6**s02HkBfm=}d8<>^26yh_CIjIPy!tPb>rGl>({)YNb!TpA-wYXcEZB&JYFdo4yaPj3#%q33^uJ|~E zSTz{EImhQmIE(Y)aNw(fxfeG6Joh?!w!c;k1hIDRHS_sj^ej{sOmMhayW}LKrPC4pl6h9=VCAQAJ*CeC$f#MQe=-pL3%@Y)0QkE zGQFwzG*_jNy05{(47``y1&cn=rEYX#Y(>_ya``;~n(vOSMmzyJU~+P#%4aLVv!@P`ta z5Xe@h>{?c!8M!Fjzf&%X_l@Iv9#9Ty`S0_fDijOg;lWR2;wX%ABCqogcn1C8#k!IJCxHh{(Hm6lRZS zFN*B&>{C2#T$RJWGw_&?!BtGRD);!tP^-JDQQNR9-7{SRJRqy-=1w(XI>fM?az#!Z zrH54EjDr#955IS?^3Y!g>il*5Bqkm-6{rKzmDY?DFPF+g-^4KzHHLA>L&BUpz+i{` zT~2C{6QPj2B`5As<4;i_{?v%oAh26C&c(|~6Xe9bI`!WOs_xaP+I7WKqbB^ZfoXNk z#p&CD@;bn+BRUb_nv1j8A+CxxF5w^j3>1#AOD>^}*~+xa$=PcBT(q?UrUSx@MLxKf zUdEjPNLGRR4*8QB&j2s-ke3Du?1%17rNcp4lbSdK<%ZS>*Ah8thn)J-K=A9edb*If*pVX80rxmn)V~nIQFt`~V)u z%ZZnf8-2+`z9as#9ZU>I$aWwD@E4C4vGYOha&nZe1_}17Fwj6upLj;D-GF@PB;!W zUlUA6-4|#9h%1O0&S3VV1&$&4{1he;L-StxI4lft-Ummr5rgNQ6~N!z;Jq z{$vtSR|pRN(D(xi={8-LhNo{VqZ|b}_WVkDkb0Cl>~s9bEx*4~lTXQ+>41X!rJVPO zak#Sip`gE-jCR5G8L8xlkFCtntz6QV{mjt;aOg$9a;Wh~iIp8jTq=m1u+_O;&lqqH zs|iQ6;(d)^d_Ro*9KNy5$}uX%#rvV9}0kWsVKNMX??pfC=|uIYDu#Id7AWgupFN{o2%op@HLiK#nYogL+&8GK~Qc_!>B72;p-W znmdL80Y!8I6RGgorTav~xm(1HX4^nGG0(@8$H5MjHdNzL#j920F|8U(oAVnHI}T3V z%^atoLnq!pe*RH8@wbFbC`V1q25opP49BkPoX!4pCF?P;;x~luAH$IG12_fj#DO%1#Gb_1-eoR#+m3?P6Tv@~{KDja8UC0uR=P zQHyC@WbiQ~&X=jVE0i+mo+CVEu42y!2MeG|86J?Bhn^nddD_K1_|y>3Q&jV(@o)(m zau_h#r*Ok8%cXpVP9OY{hR|+YFBi6H9(wsecYjk+C^dDcn*R_cQV9Z#VXL`|OB@rI z2)JKWkn(bu2(!DR)grf=^18vmq{u~z4g-l3W~#%6JJ@bBT{=J_fn)`KfU2f$hZ;gc zV?ba42UlFV-3E2&yWN~R^!E@w$l6?`rgR0BO(YaQ^N*43rrA=#sZG&LPm1Yi~c#5z#RWG)3q@F%?PoqRw{d@$(E(W0l3tQ{R^+twP?_xb5J|f zQjL|8muKOCXY7EdRe_oY^-+%9;2{MPOxIv!Qth%}mt!|;ASnY%sHwx+0B3u1u_vhS zm5n5gulPy!a|nh3wQn#o$~km8K&z>L4eIJ|YVRhdMvj^4yk9iBaYJ;2oOG9RjAkq_ zF+vRHVU59{b2-{m8Zq_VkWiT;AnRASqn@r0Jp105c zPIv1RYywwS>ocYp2Pms6J*%C3!D|pb!mlx>7osfE#3nXs zhcE&pA2hLaBz{D;jziW9-T5Yc~nprd+hL;o8;*(N!7#HQF zk4U{tdfmNB)BG?A>{KvYndJ1~Ib?9&7HY(Yn6JU8xk}CMCvB+Rkn2npqkAUQoS&ek z>H-Tmj&sMjDztWR*)Y>aiveL{ff0SuR-24*Ck-f>zXBXrvL1#UK1JpaidI+3fRCE} zgBBGNwR;zVo?nZ?&0m=x_opHPv`gdR5-ldCl--%KEe=zVT({9#WC&$4;W9Z7;2C*+ z9sYtG3Xp?gAO{)OJeW$-1OI;Goe+NTac@xbu)=@s zM-x_JsH+EcWwbQ|mohlPh=c^h^e^Aev$*%|7Bsy1jBI`}=-JXGd>(Y(_om=SYr4uc z%qdkgbziNy0pq%5+4R9>R4(hIeoS0kTS}eOz)Yg0)L3PrA&kiyST_2Pi;BT%bIW^j z_6=AflCjidmU*|D%Qz>ZJ-}RuoLuLx)yOkgqk-jLIXf*l1Lwk04yb}A$guRd9>WvO ziA7V{x|U{d)r?D+!^1kGNzKY77j~$rSy=2pi3LKq=8!9iT=$Y|2)WwGl}xU~8J;K*8WVmcTQ+ zOR&4ZeH&9_CrmJ|m{)xu|?(4zGI_CTqo@q!2g|AV_X0dK3i_Qm%(8Z5|M%XXk68Qcd9S_p8uzd?ApaXy%`XnxOuWLy z7OK#Orm4ck781YCi`h)l0p3$FUrS(*LK#k}mxGT?X8CAqm2{h0>gKJ+SEbrSb7)Jt zGv3Mzk_p-r`avN7i)#KCrQ5=-kzZpx_yV#;s^3t}nVVhYmEsZX= z3@onW=@q(Lus2uda9ygwVHpDck30HJObz63lm!Y)vBD(S`+1vkmN+5 z^l|J2W-Z#I@m5lTdlZu>|9hghH(<W{Rl1mbe6dVmP&fct-hHK>2O3 z#SQ}m5EzyOQZor=7)MTKC@p+Qc|VY2fDtRF2+?HlDA)`G0_;S4$lfw;dASjBbFwLp zOZT0DIYXW7>F^;rQ&SbI4rR6Qe26B={xAEC2?h<^hz4eTyLS{S*BSWX3kJDaCLmi- zD;^1ciiEVJM_}gP(V+4!W3a`j zhO5=GkH|o#oFT>DUKJ?Vj{@Y!n1kD!{-PMWp}oSt1zPce_EY8kG2t9=Pz!fV)U3#Q z4}DG=61WCX2o>>0U-+lc=%5xB-wCB|?vB9R9iyflvS@RthLFucVZkvvx9gA{*bsh1 zmV+5c7%=QpCPf}m4L4rJ9+A&b^Kj4OW;(l!0#MNQ%ANHx@G&1FgDP38y`6_Ux*Y7dlT3n7duQ2bzo1&a3t4E=Go zxO^MK^8m)UIkYk&hSTg}u~8msm*3Txt+5EQtF;U#jCYoU-byF!Rl#h#ucN$f<5%#k za-Q+7v{%eu#qG}(m1yS9Wiu?E^MPd^;qjv!-vQ8vjyp)%@)Ij+z=4HObbAOdljC`E_9_8T( zFI0g-`v2I0wCEda@eibG(KiB%t`US^6ecp&T{CAKC2op0_B z!b<{kALGA3z_2|~Sp5%RtzL}klm+up_0Mv9OYPzfw^mOWWEVEx|((zG>OGW z6W_s-J!rZr=zuDXJsZ{m(^Uu!n7(t+v;%kg0)0P(l9x#49xz>j#fgTn;sQmR z${%1AB(9fM21?2@Gn?C5C1apul^na3)?y_EahGu>D^ZK4!jjZOUf+^8VkNe?3o#^Fc+{fySc#K=511~;Y5J1E1Z7f- z44_)2*YHS;1}3?SlBI4>mih|+j+I==f7RE%i33u3jqm|*xo-d%u(sHu7R01TZ zHBh>e(}+^O5hqaUBN<400m;ftfVIa!1uo>ua-j4}d@9rucF@#J&J^{vCjvzVWCN`! zek@izJy2YWVLV~D9riddObn7cI0J@V2!dWB(Kw5h2Ik^gH+5clVEPO`dzT|AV7N7v z{j6d4O?1}B5uhq4Q7nBaan|sC#0Id9k*m}?l_xYTfwN#Hi4qyHm5KOddYpTeBjQD| z;B$fWTJGx#%qS*HFboN6?18dx9gaa7S_paOXe{yv$U$U8ixK!GPfhB)QLP)C0yGR+eHY;PW&UcLt=r8mb{LSzy6pSX|9&*}Y`BntvPb23JkN z_rTUCIOHB8~gmfC}5n8M*`Q-{_g~}49Hh>gv6oYuVRKAS4aD*vnQB z3O_oqaW|^1Z^d7uv(00+JA#1Ust6WVC?ASiD9A!BL2rutT&|1Ny`e!yY$ z|H2>RTxP=?7>U^Hd5OEHcAK_$n|5@YF7Gy7(cN%rV1Et?CF+49wc&?>x{;uG(6k-Y zz7rW5&UQB>y1gvs#RE-vCw=T4Q~pF_@>MJOuSiZbjKmsUiH1?Nz8-;X8QU_q;T2^C zVqO>Cfu4z%oUC{$3Q6?vDjrW&upRCqJ;N3}>1aZK@GSI3+^ExVN;=W&!4^#cy^vnR zT~kKv8a#ztsM4r!S4h9@twod|or=}HqBdNHvl^L`{^7&hT_9#g*!Z#18(l#r)+O-X zQzhM1OfSNj=uTq?c%VTp?`k+DXUFOqi7wzd_(LJsLidXP`W!ulqcx6SQIn(MU{eRvkGyWwL; zZvuPOo>EQ+XQ~aE0}Y?>zkd%jWWr+f1{`aNhBJe!!mA%@_;9%4jJ&zGCvSaM!^Z%S zC}-h<$AE0@cwN8zan-?wkAh;zi@F8MVmR3FNoZA{m<<0tgg4U;HhkRK@XEU|{C5R}ZZhTq^7?s2-S#kAq$@<`p{dwlm(5Mqb-VHJxY=2FFwPFu#yK#FaGHd4)=N+c+mw z>vuNN>sRAVk=Tk1s6#>@O08nE6L~!7NsH9v^EVQ!LwYkLXpftoU-o-yF(OI^$0bo3 ztP>fKQtS0q;}NY3oc?-ewbx@@z(g7pGCSR+G?W&P2k$(4^oxe@+?$l^bYI|XLIrr# z*+*cY{xwqFwQcooPp(ws^Gi<2?P+xay{H*CBy4{@KY%FtY9x=-RY$+56^SXZ@y4j3 z6xf>D8mobwdPZuC+ChQFHj?Era$SCKOHPbR!e+v1Oq&ZC@Jd)qtFwtRp(`GYhKLM_ z`>l2LEyz%VegSCI7&7`XYqeZ@gur6VWd=YWl{OIsKLs6vZYx(t=vDP{si39JMH4|i z@cW$`TMDHXJc;c^ac_%nVkeO)*&Av#g-}WI*HSEbN^3a)%AFPE<#o%JBfr~)X-O_k zIw_`9D9dR=%AHFWBa1}oejFZ^3My^og}|Ct4;34usVQXrbQ~#Hgv3-=YT8>;&@?V& zM)bZ0xWZ>W)kEZ655`GD(y?a(6xy1+fE;o(L;3Q!ffyWvC7-{(w!W#cs@rO$f(qNx6mZI&u5w!vavq=8Rp(DajS@UO!I;NPUa6%K56#u_ z#A2z%jdlsT2yXN^CzPqENLJ=`wzL9bjpNl-EKVgs18v26fIPe${c}|;O(wY7{HYEU z1G_yJq`oj8zBnjy}YKT4pUE&HNdM>Y%HhD4)kOmUkoiA zbng0=2C3dhu%hZV)VPvGmE{sj)wqoL%v?PN?Nl~Ti=K@zke6#~(jzKU5jDw(#iDV3QCXFzuDIOkF0ZV^GJ?qixKV-iK~w0e8^dHwJU6)b znsA(4VHU!5Vm5ehkuve+*$V6&YrzHn0(7bMP;5~dTBul3H{LX$ zc65^sHN+dK@%tc$BpZRDW@01yFuZQPF8g?0R!g#dy@1~SQnb$ph(-V%GWvigG!tJ& z|9N1n`{&fW6g4Z7fa-baP>{Q)Y^~otD^u%RoV`RNQDu2*O@JWs+2XPZ=C1`X`V5i8(CA@TCxmA%tR@T5x`jx)p>=F<6BjPW zJ3S{KPAcsm4pgs;545uKoJHfVZPll-Sn?W+S*E+C*_Gtv;|m$mW zm{nZwN8%>N#R*Rf%*;vA3B;h423dnNFKUHUZb)*J6KA1XiXHI}WGYn%1o6Knw2a4V+RH{BS8ZbA&k0LmM3ZTN=|X9B-Ms!ok=B`Zwk(fZ5U6A@Bgzkt5=|ds-=}r zVGZyKEskN8v5aMx6@emhtRoJdY#cd0#b0e4EQCftaN=(m*11HEa3hJ?PWL~VE6VpN z>_vV)SBpuoNHwfGb3U~aKYv01@A{?-oZfnOa^n7zQ(`P2mSOp2*L~Bo1CpNyRuwyzVgy@@bBQo}k~=i_7g3 z`i-615FLPz|44MO8qj0jhn7~Nwsp|SQ<5deAI`8F$29Cy8nKMH|L33E ze^TnRZUai^l5>hML8UhRkC=XVD-dXLeA0s_(4Agr+es^iQx`gjgZh0?(8rvdWO-4@ zK%hvUF`4ML2xR!QHNuGde_)W+4HC=#cbXfl7OX1W_T|T1kUU%h0hPr8n}`mC8Co_#+K};XPn}F zZin;+sd~MA9Vlbp$;KzP%4NP1T;)YlpboPM@BxK0LQ@8Q_%{|y1-j{~ki;z#!3YJA zAt`8a+s@|*Vn!qG|7qRWOmjnqzX=vkw1o1XV^@Hl2(K%(uIpQ5S0*)w)OHBFPVagc z#*kXyR99aOM;tc~rP|i#ltwf*rJoBdT}&n5{09?=Ec$$&J9$>ixtIbA!Wg7=$#A(< z1O+kT{+|gDBYPL|@HTE<`Y&P9XF8J2r_yRcD@jl!6;uKk;Y_NJO&ps^q)3S=9OooHVQBR15x7Na0c8cAuBU+b&JmbI0Mw1 z`R{PR^}xXYJO?x`Vf0thxS27a-o+O*+ zVhc>{W6+++Gyl)=OTB-e&o9?kw-Ue93CFn%GsPr9+PR7VzDYc^)M_dMfi;8aQQRJ@5^MjD5d2SZ6ys`K&$*ZV8n;L4J8q`-O3DYl zW!TcV?-#iL!GfQG{TVyUd&*_dp{`=ff` zyx4uaqE>a^4eGwzV*BDz3xcux_Vlri)AuYocu#Tco<%CorSChDOt}Z8_ig5--{YnC zMj0~jh`%F(0{5*6n(^k|J!Sm{+T4PE^##+YFSMzJf8wLhh|6EZy}$nTTfI0G7&u^v z-RI_Qpd)xz>Of8uG2Udy?(^Y=`5wg>TrY{nHB8^Tfv7cza!X^M5g2dWbHl=$!*=~I*PO*^w^OQ)ZkG`F8s z;;M?jR-U~F`#V-_!qsuK&%+`Oi~Fv>4;w<1H2T~mf8c0G8tpN`fn@&cpiyI=4~}0P zSWN@o_ap#@fRx(r*03d(q?9Wgx=zDVecAT zQJxy?$i-7Obk#8aBTWK(Lj3T8(|>L#n=KS*so#{Wz@zUKnYs5 zqBBtB1Tcu^bfACk!Mz5hqR((}ud#2+@u_F~XYUo{$*+s@B>TW#<6dUNHr1<;Wis|i zS%CjH-E`j??3cYSTY5DpIC6cte4`0>HKcZ%_^_2jY9?Qbud&gIX%d^Tt-CEtxr*8jKT zh0%@qH(i0#qE`meUnkW52miU2m6w-Ge*V`>fAQ6t{B_fB3H~v7JY0T{n>K<<_4W1A z1uabywpo>zz*Hu=O7ZxZ4QA)d@UGCs(uH`K%X!5W+b+5kZ(Us>6*2wwF}z0B@{MiV zOG`^xGd+Vuk9PSlx#F8!FS(fFT$kbbD@4^?df6pcP=x35%TeUguS*Osoo(GpwU!_} zRvA8u%J2pnD*7g#zQW!Esugc2;oYWU$>?FC=i*Bd+9sMWPh2iJzqsx4Z>*Ns`U~;M z*4MvGEu;ua%SJeDHjI5Hac1nh(dYJzedyPZkA0HJH2&fALtGjE#72txCMQ6~ur;#2 zk@oINjrA}nG}W@C->;_4>t*nP5dqVqa3vp}+H9NE!XZvXrwyGS-0pabN#J%8mU!V%m;G9XGZxlJa5cgtdcl%;uYcV7eIV zI*;XJ19^oz53b4j3+h`p>V_ePO+x<8K>p zPq)S}{RhOlsTR9dC{qm<>{vy0Fim;t@AUPJBG8nohPE)h77F(mSw@I&yIlZJA z!*AgcE!z_{vtxDStqn<+1B%5dyZH1}$xh6#sqt*3;O2?lyVGXn_ zWzI}lk~!k45i@IDt!a~M-8GiUKX=zzCO_j)OO#N}K&ph?n+Gg{#v^u|O+U@mjae8pA*E0RrYa1=oKVI8xnX#h5Yo2j~ z*CWo%_12qbD&9u(%#~iBF!Q_KX2Z;fy)A}WKWKD`IrAEQX*mm;Jm#GIrWP@$q^V8J zS?Y5ea=bpTIp+eO&ye#?U$Y@6oK%}z1r&E|S@&fCpii%DSS z*{hoyO|!3TZnn(5tl4j!`&e^}I5*+1H_x;B8_n}A{uZ-1>FbGk#ule}er-#mIKQc- z#V~(kORH)AORY}JdD*QVQR-{;iPHYII#GIIz0177wBBQ0VA-_E&K$yXsqN z8>`_)z!rt(W_ObpTP|AM-qywzH+=uDdT*P{)#i4&*W)$1mR7h;TfME#8BZ<9UeL1O z3kyOEp2&S6_oIdK!r;OmFZ|QO(|Kii-_Lt0?`YoN^YieWL|^{n`OoE_kd5+kIU+x) z+^#&O{8>quuQP|uedeE;pEm!&teM|WGo)pu%}*;$bEa)d`&!z!(@Y{uyE<)m+C6EH zrbW}Vv|)>2$+jq#l@`C{OO`7w-?Kz44;0u6mKUro_-28azBTc)f>#S?6fP-T8#7&D z-NtTW`SKYbga=$m7Jpf7-k??~PYR7clGLhK)aJHeS!8R>+?){Bs52i{%rT1=Xx`n; z?pF&hR+~3>u{}6vIT+umdXL1!v+*I#86Q^dPtsW`)U7$UGPCA?T&b#J6fwGYQjRQt!B?5w)@E9&Yz zwc4+B?70xTjhAdyt6vBg?50;PrAGutbVpo@($TL+06Vl5zb=jNJwf*eH9g5kq+fa*fo9xzaT|44HbgTVR1jx;mz=L%s4iiHwkmbWx6~ztm75f^*1l)6{GQgK+Fy&~ z0I`CRIR=Ck*f?*9njKxjD%mn1tX7+^#rHgiRsvb9`uPqta{xKJ*#VQ0S#fhL_ZiK(U(PJDE37Q_2e5 zp_Y#G&~tIUts!c1XqzQ#pW&KrXioOm_O#2VsB&DhhHDq6XdOJwWMY$&=@-hU!o}Bg zM~cNz2qWsjAz}Fz>2ICvAi6m7 zkVlz($fry?RIQl1*+Gn?iyf5bA=*OG;p^o|;p=3xB!#b6=23?89Ajxg`DFN7`EQaD zmvkPZRfEpY#a)~UVU@PITUZ82bYc`mNEjI~K4dbp^iiRX>R*An=b*`XgV)N2QR9K^ zeCtEPvV3E&DQ`=3zGE;bzbm~pmi8{Cz13^VKZaVQHxBv4tVCinUjW88Q2y7;=I*Guy# zB+VR)Z#a5wyzyvIGR6_o+T)vn_-BPx@gjBcqeNH;vk!LQKHCEcq4KQp!Gy5ntgz+@ z0pPU8V}b1b)&b*zXscSeV8E2dGK@csdMRvtFj~!jABr~PH~gDu3w{Q-;$TR$34h`- ztvBASR$d=kL})yRI8&;R4cROmw6_;MYa9X*4v~^8oarS zg*Y~1dCux>RdRa0%Iw~1WlnDkRzQ=I3%ofk*roGM3zgFB)52nD`e|W_ly%6E`@44K z-;Vx9GHM}{g=NNjsWHX4dz%~@5bO^LmH7uA5|-rOhv~WZtWcRS9ylv3Nf;mGu*KQ{ zFnRB19&+XxqO%=`Hs^i#lyieti)9c$MyY~0<;w}VR6BN(sU=T-{%~8yhid_U=o2vX zH&XTH??kF;ZbhP#FA{8d=}Q@^Mkn`yD&PUOr!A-iAbW8Y)_ zOnO(VJ-IkOf1_;C2tuJjOAXwRY+x3O4y#quQJ$I^Rwh~FBdYy*svU5M zi&MXppd`lGTBH0?2QG8F?X2L#sx;^neNTsC;&fdbOffZW&?^63t-lEQzRq+?N~91- z^Eu>CIYw0y^;rYrw-BgMq|5=m3NLyb*MQ#~E_zH@6$wc*X@P{KEbYQQ9aNKQKZXl> zL#9bAORYGPtU@^-l@y_ZG*q-2l~8VF67s6RONfc{X{!BQoPy2AHRB6#rRQY3x@w&bLd)y;m0~nk zh7RdD$`+M=hR+V^N%|0{U!0haY^UjCItoul;lK5k;=DT|434OwqC&ch^IZe@tWu(pOyHdeZt9*>RhBYtQgOwR@?!0BSh|_@i>*K7}GS+gy~@8GrHM*H0YI0 zQl`4%FOo%F@fg_c$~;pBn*y$jWJ0dGsDOf5C^!QJ=b|7Hk!}|0X15;=OY?E1Foh!0 zG(ChA$-;w?qqlR^rsl(8dpKeb-;T?$k)6uw9a?~T7oc8o#zhGW>Yg7pp%2Sz(YP&g zyDbv2MZ)clNLYG15|K_sZkOKF5gQ#^h<|I8wZP0WV5RE#J!lZnS+y;fMUG4ma&|2` zD6Ae3R^3u`P*{az(2iBoN{;Vo+ROA&&XJx%FHpoX2w0{}HuXX!lXJ!8@(5U?^xlB5 z{2{7o*(1WL{Qge%FxrzRp++l;%I|elK~|}32Uu>!GAabqzEdrlte7CrP~@F~>SwVU zm4)bZN(P$_F2Cu;9l05Y&g5ENELb@CXaSy4eX~ivgWTKr8khdC7!8mBwRS{wv0HF0rS}Mz0N>Sx#t91s7hFvyl8QcL zLt5JjNPDAdbGM8;Sbm^3e--!rXW?Q<(_}WSdAkjF$^rvNz)37vE%IB@X()50{N}@^ z7vz%^dgWo$i}JCU@&5QoXp=SqZg!LD3S0(@%q^Ylv2OOuZuWRLd!n1E-R#M3hMOgR z78Ux+l{rU$*=Lr;qmTDZ#b34WJp6sKZw3B7(btNTW^cJjsjkoCF>~Q z>TQ%)<7teM=-i`+w(B=b@g>#2$>*uUu$QTR8t@I{F6T6;n$ zBs4F45jXu6O~&=Tq)BB$?9aCXF`-dOZ+4s&3afzr5G*0gKQB#187L`;C9REgE?P7x z^5gipK&gz7P^;cO=e$LZxU@=xu2vbOMA*dbf)WD3inYgM$0z1%Ww7 z0<&M#I~>H*a|G4H`f`qSCZB3mudf)fmKNkXW$AaWanT!&}p4Nygt z%r5pUd@^&6MA5@*HP2uHL?T_f^Wr|gR{2l3_3T!<@$Xhhb&&Zy^0R#g+%@>L7PAJu zqzQ?^)_x|=`Im$xh_`+$!NPttR?XW6MRTJuFr@QwVAvSVm2hVr=Wo!$0D2wgh}ShL zuYg;na}kv~DE&^0Jt4SpHI=h?vQH&GQZhFCBO z)Etp@7FjvYY+`1=>WqW`U=+kzUAT#=89b*+Q6Q&Va3uY)4uAlH!XT(-5Hxv()(e`e zx<3Y~6zZfqwTUwK{RMkKg6L{bX&Ti7dZqmSRh=M1joGjIL4UmJRCO}5|tJbX#hcD?X z*e{6xJ-{CWdjNb3i*1aN>*_I8J)H|^Ym_f^u?L`s7AZv}WO3%yNG$B{Nf!1ASXh2K zSPtcTU7WWiVUaY@giiKTsX%R-rDOmBa)=O3i)K2sPb~3IQvB)l4o6Z)r?P+KfHa;I zBvC7hAI5?Nur&`zTGK4J3=2%t+3ZFc@h5PF!QueM5}gD>aef#3sr<@0^*-l=0b{G4 z$JR&!PCD8Lvd_C7*hl%(&O))o8#cJExSa#?vn+6Xev$>|Wq}2z>+BELSVhkq-7(Jp zJ|<9dLK-ff=Q(!IoSdhd>BgHj~3DrYEYzJy3qK% zW4&(toc{+hYXl@Wq^=Cm!VZ$Qglr6U(FmuzVE&TU5!YzmVDnitBAYewyiEyi^&w)0 z6owQ|k0q$W_$G3!=Op{ldnk%rNfHdpPM44k&`rnPT>G?=xM?PvdsutNYT0vAS%d@l zaDKxWRrGTuODmzcSrjLKAjQ?<@2MqIg2F)|TPu-{X@}z_s0lMSi&qJtOm{>rF(KR1 z$F3QYGdAG|uexoL-;=U~l2)?k9i;+y=gGyJ7M|@S-Y`Kn z6daKZ(HV|l!X6W5fIfW#0C#rStH6`LA)ks`#Pc^Mv=Ts@-cQNuEtd^e337=QpYj>4 z1a3)kV8i%=8mM?on9ggcvRio#T1j-0T4kEW=1sRy6*GFvl~EA%WO=yptELAf^hNpD zIv^}iOxB=oJ>wHZW9Lv@QWz7aK>hPT!z;O)n|1V1xi-9w(QSbr0)(ZqxQ&eyPt6l7 zxALliPHDIa4A#Ht)JQt~-v}Em_zV0w0~;jlmTEm_aqGELhpEQsi+(Oj8xok$SzyvY z7O-SO6rQ5ItN$R5P=bHJu*T<+n-))K+8$F5o8PXaPe77R!aw3tT%J!_kkYaIPH-D! zp|*J>U z+Oz@;`%$Gpi|uiu65OsBkA;`+UYtK!JF~~BSgi3gP->)kSFxp6v2tlTBxTC=q8;~X zt$Oq-R-mpvAB&}Auv=WPJ^`X@3qzma5k!Hh$9$wzNQXj~K(B_uND6J+ougKpX0!92 z;hmVQ#UNzvapAsV(xYI*-SI*}P_k|TPQXw{teKP*&?2h8lYO7Z;Poxtc#N6qmGX08 zG0s&ho`O)nLplCpm26d4y%DxY3M44E)LZFAY+0!6%~rB|XJg45!6|dV2=Ji<0YGp7Vvx2x4_OkO3!AfV(tZr z>gNLse#bcwpRr{-A$g7W(V{FzKaHp#mo@!eGtFV=Q_VZ%$tgp%iHy^Sxp6uRBS33! zfEJ8dsnIlVYV9uGq5IF74Czjq&zYLbYQ_5Q7xu*D(>ynUlmiSi5tINSK5a0Afu=yP8WRK|RsiUU8gqH2>W>>U>yklO@ zMOE@~Oz(I>fqrK{wgt=C_@Yf7Y0ss)Ve_YzjSKldAoLxCy4bE`co(}3PeUxdlrWrQ z`&?r2MV5GxnAe)nc3R>)!^-YTWlATx2cDM}ff!JPd_ER~X&zgkSd)w483*ha$dXcD z{Dig2*a-CXMD`=<(4dVQhtkn8A}{FJd(<&NFbO(PagpdD2pG-%qsnY}cVh7~$yGK^ z4LPBKj;-gKuIK7zOZ6OlHDci#2X{y!ANILGBeFMRP}u^IVVQC((-v5nHuD+bKoj#@ z65r|)t{q?apa4(uF6Eo%vs_T0-zy8@YC0cwS5AH=X=f}t=`nXQJn*@+!;wS_EC`UE zH}u7<<8TSLS#rdJxS#)}bGpap1t3ADUT1zfFeL3pTBx*ol6m!6#DaxT1-R<-d=)UsIE^@+7#x%=8abc z1Io=~Gl~g56OTc+iU~`hKHVhL$!EIRRxGRVA9j5R>OXC!b_T02er5~RUfYa+O{ z^Ks$oNEwzhiC4YXf6&b6|{#(KylKBA&k>>KFgDbad*D zK{i8=_k*I44VNZ2D1qEh0@SP)PKyBzf~IUHXyV~Copit(NmGH2OL7_}Vg%VxPS}!6 zPja{9^5Ju4r1?rF^Jcc|%~&^40?Jb^G=mT6eUPC3%%>bcrcr35 zJl9#lO@)`e=>f<<+(ltC^b)djQ`5Kj( zySFJ*p)FdHM!$4evYzdOj*6PBkhZlD+2X2h%DF(6xNezh;UEa`Lh#Zx@*T;1B&b72 zllpl7kD}r~!hJ&ODl}p~D2r(Us8pd3mx5&>IX#scD0nqcu(X@q(9LdygDU0qO1ZBF ze{)Dsat`4kL3bX=>J3uH%wWR%lp*iq=L|=0h+IuYg1Qq8elP9}`=>>2j9lZ;-hr?o zrR_NhdnV8akRHK2jbN#fm4!@13l&q;gxeuuOoZ~ECXF0Aop**@yr(D+WSww4)ijuzH zE#!6!3m_#&vqAb11;h42vgZj^Tu>)H3Wn-Z2=RIFV3a`bUc@EZJ@3d_dpt@JBnk8i zrsy08f|UC&$o)EU|2uNOg4{2m(=m$#LrJ9-O3N3agY@R%zC0lx7w47Y^&&xrHA*^$ zi}et>P{R#>E@4G2oFHSbnbC7Yf=#0>*N0V3W7 zW@-DX_fG%?PVC6j`OlX?{ZwmhsC zw}MmX#i>`OA1*|XF!LB6?#}KxDCDZeuc*a)J23h4=^?*u;x@xsp+Zrho{=sHklB^f zHl*6>@E@KM$*eq-P|VmOY?0o<_3%&{$IC6^<-h^Q%gv_jQ%IAWL>0{K#|*u5!hoUV zJ`Bw&CvRbBO+GA73qndv$cYcf1Sx6>nDSXs$<_%GB{zoV=f9z7)aM1#QL&^U0o3hd z$1NvVzXeD;8*g(GGF$qvMr9)qdeo5_yyFJ8j}av9XS1P%!s#`HclO?@chxvDK)gPk z@Qx#DtkQ;n*swG>J2WyjpTNg37U_v?%z*;2@K!{o{D$D7TCAN*1jdRA5QwC0F+M!_ zO=6Wpg!d4fVZ)$Ffi|EG^C>w=j!1VLOY>*yf+sjNN$PPO@jnk1m}Iu-IU{Poipi9x zSzy%BrBqlAkb#(F{EhgqSh_Yr{>-6dpS9uR)VC?hdoXWIKa{B$wKt?!v|&i`F$ja$ zvl2elBkp>=$GCe(?pxtEd1!mSMmu!g*8U7X1_Z0Ox$Odc|9qH!@=aarZQAZYTUf~E z=zKtz3w5cJluM&lB#F=n4r5COh#{HgU~!6%=(KSvtZCC=wOi0AAJ;8vvtSaFCUXZ6 zx2JQD=cq){%6nLytHK{VZc-SYW{jK;kC4}LG(5U{B>!lxIedEe2l;;pVK>mv$z%^o zsg1(yCzjPGY|GJdnnN3jhhY4M18O)gLpn);zvi6?l&R2<%cb}b9MA1Ec|T8XXHv_j zDfw`0wuis4>tDhhx3u>Pd9Qb|pM&SvkHy=eER*4_+$Q}Vkx;r2GE#OVfMs`tI^rXM z{y9~KR>3%QZjEnHjpkHkUcIu(+6Vw{4An^%Z72?8OV!%mCzuLY$?j3vh>ZuQu?=DO z2wa@@*Q5{d{Q-8}Q(lae_GG~p)-Ips5n_2=0=>~whX~n6tc2ng?)xUn(jkx1XNNZ8 zu#=;9rVW2$lkV#Ub3P9Uq5D6=_ zKVh+wGnd?`W12-LdlZs1nN>`Mtd#b7$-ulvqX`Fgd*y@M)kBhu57pg8+X04dU=iT` zNp^rKFM!7US+(CG{hM7~D^}DdcG<|r4*lVmpVb}UIwaje`Vp5Pp%Rnimuud}VC*=h z_hr0qXg*}roE?rTtt@_6j~`s3;bu;pfmpi>WafkLlI)o@io@};N{3xLxd*Hgb@mI= z2R1y1S^YdjBaY~N$%Hn@#yqQJBc=cwF6>UJVHC z6>=^4r@}Yy74yNZxVrckU^`EEE#FKDxkox+zb130Au7?P1lnHkKIq)75OF~19I#Qf z%PFl$dcXI=d~@%2^TZwrCgRR+*451dp(;S(nyg3wKcQ7}A(8*P0{Ul}JSWmc@v=OH z$9L(Uvt%*S3HD)H#L7dHl@FmnRDPm$lcewHEzh6SyDZOqO%@?#S0((UM2k-VscfNn z;m(<`6dFLA!(C)`oT7&VVx@;R{)~4k($melL$kwOJIf=Tsr^8at}x#Y6baB<(WwF8 z!GmyjPj>#CNOw4}Gdw#I$P+^wP;$-eNLSvm&;@vtx4TD3reC0^FGaejr`wUHv{zo^@n-U9L32@@kIGga3C!ljx@ zn9cq?XxoT<+5%cfM9Ts41=V;23@}M?iTELdPCKzSexb*5$YH$grzu6Klbz! zEL?;p7xjxvTnRB;jC+rXgAPAsQf9zJJkCBjYlq1sm`OMT`c48Fn&zgTc>8g76xGe` z6Cy=@Vq{UDAyUjM;&x_KHf4+tk5vR#fbgDLzH=7ft%^!Pla+)v3m|+tQdsG*SiJ~- zB%LBxDv1$BhpCiR!msly;!2T=i7!Pi3SYdd5aEly$08SjONr4*Hb<2`d~tRv(pKrH zdiCO?7Y|;9%~TgvI(`#Swzd~dvsXd*T0vU)KF|v2_mwu$UY)R4jZ?XpxddLrvqC*q zB;HpD)l^os7nx#a7fu5~sdmOItA5@6l(-?5o{K85c?>bOLs_u7IP*f8+{Owci1UF! zwLd02g49vrmjP!C%q6gPm+p+*{dGrG)DVIL;p0ljxnSa-oKtZT&4I&crZT(`T4e-1 zCGvbtH=t*=0y{l}+d~=gcPOwUWQd=1#E(?H`qI&t2z`%eM*x8Mk@CTp{>&)qDt4q& zI|5;(A?}D@68~}(o1cyG<(Bx$_@(i$MYC10%9%jSYD*jzu;@pW`g=TqLcbpRQyaC@ zPkp>4+_KXcY0+AuYbc_vleNLykI?!~wjSh6Mi%#okt*8WT@>Gmy@D?8D)7VMTKv*s*fLu7DF?_v)rQ()H&IPQXci7)vAGL$X;SHyL(hvn5t#h09j7Lp*V z{n8?``GJPt24+|N7+z$-7UNm4c`EPlIBxVbRWQ4zsBTyUABIcfwr=(?Ekf=`;|z=T z+kh{2fLss|N!U3Vgt7$5#S8`Nw6p*cy#4ttx<2(m)gbmrlkknKWR4uJe04h{ahRn$ zo->^QOwz+eqGNS}h{R4@s+}iZCV>5EN-fFVW_8*6D4vWU`!5bknqJ(V3u}Bp${pO! zg>=B^9Z38;Uf2$ECw9pz!17VaXjPZ>=w?IgHd_|pCSL$Wv5t*saQjg*3rvL0n*f4* z%4A~@aG#Z4A&}~ur81KsEh1xaKA^1?S^3slg7XY=pzzJw=>#@-P@Vzg#-PS+fZ6B+ z<;8X$Y%BvjKYu9VvQ>$HG92!+A`j+oP#sAxNhfBq=4bUb-vJjP%@b-4Ts9T|pYHasr7*Um`#a94lNKbR9ui@yNB0N#H|I>6CKfYG{%#(~*2k$DxCRv1w~#OLTOUE95p!!VP%mDw{v96+;& z2a)-C&;u%N<;77rt~YibuxJidKn;m2mnYEH^JL%Ujp?~*D$OJmLlR!`7!V@72%BfO zr+V-uRPjZ<3WPT3C<(|PfhU%)5LEs#DO(>C{W=^!LUPWqb_DXToxvX{7ZO%{Oe^MN zDh5^v-`$XW8atX_rU*Vxqc$WRbzm=63QVT}`1iQmU=*PZd`>V1-fWUcCM%`Zc(c^L zURxoVIQ35P7U0Vu!0JtktCl6sZ5G>{a!P1xQ%ty@^Zkdx_m38YGC?%qAt##wT)}o6 z>#^sj?XJo-WI(3g9PLX>;_5 zUD&55_Lv+y_0Ucec9-n8SH+Kq?aG|cUw19Z!@G_4(BNH*BUN2&Kh$jAZlz5-K9;kp z_l%Mk`q^De^0UxrI<=v$`f0?DZ9!+G_di`~ut4(!s*Iu2@e&8BJc~^ivwUnR8kgZs@bJ>0yB>(_;)LWZ;89x@#=` z)?~Us#mxr=yb=-g;uwEx)Pp=>(^9tbkz^K;s<0juL{#C#*@sjUwW96IH3#J9K^e5qAtL+Z&EBXgX>epY1dmA4qay#yB$CNE*8O$ zD_O>@ph0oX(u8?taBYmuK&dYFn6hB-7d*rJLYk5jV>!X*(+C-(E!bEvK6V_!;tg9A z^vdG3$Jl&;*9KWKtfcznV5_W@Y^CId$z-jFCqE%fQYI$^zU$rDrxjttwYD>vl0hjM zF;;;h+D@c|?a3;$sJg5e=&G|XY{yLHg=unWk|tBqY%_69IS<99+W%s4Qv>E3y;QYZ-u`Bk!$Yyk zPBBszE{K$e%XeY7`%e)lff`&t>{A^Hpw62RYI67XakF*Dw-gtm|d9! zhtH@FMJplN9gycC)%1dWmh>)6E@JRss;ETemKUoQ9+%#N(c@SZ;&ZtUO($;n5S2*; z2eH}?vrFX`s3csK1~Sve0KM>Ur3ZCwgIWTwMgoM=QTWuH$HMTL|8$o+RK%>;TNS&2TeJ{LYH$2b5YP3PS?*q;UI$2bLd*vSboz=#;fU5%;dfoT}u-3YARi;Tb5)aWbzLzsFH73 zga{Uutr}MOcy;^aZ&42}r;3eXMY%L=TEU!^yA;LAHRt8LSIJh=dIiO>R(i`mv6ob7 zI(2otT1f5y@gW-3d{ivwP@ZXxO7>bvROG9z3|C~+Ns4ZUU3B+!vwOSQkGol4H`|X_ z*twlI4hf9@*G3(oQ&3+r)R!rk&bdw7ZHUYx*&wwa;j zw%rvuj`!6nj36pRUX^D_5=S9A#xIUOc6%A3X0B1ki>WYwd>kC4uB1>SU`#Q&yb zksWGMuz9PYC}XE2L7YTL3>Lxcx64MHVk&e_+Aa?jy&EcekLrXM7>Si+0D{uf74C&G z=X;SJ7|}ZOExBp1x^?BkN7r*LNO1USoO-$DE*PUoq3rBrJ@Qeqo*bqjw(aoOeW>0mqL*4A@ZuaYT#}mRb(<P_7*RbZY8U@{JwOA z_A1uM3$bIGjv375d&}q)LinOyOMV8h8s`pZADDFg;BVC0e7TR#qM6VsYyv?KA`*DU zgUV91)&aW=9hnOjsP)f;JF$N8(*>6Y_T)TcqmRIZk6RF4v{osCesC+#XxG! z1F8VrdQi@yYCV!AJ_;~tqeN#$uv(}mVvQ}450}q!0NJcH3|()_jB4A>X>e>)T~34lW{9!6B2H+vxD_FTm8er2%LM`vWY+#%Mwk zV5g;35Z9&GJoJboMbLuYgOE<_TyH*(=4IkkAMdYXs_3eT!kqw5&l3(vtb=<+`S4x? z{Fl5w@@NpiVyv^Hj}aAzM;-?TLo;FR#*RuJo^%uImS5LK12s=nd?U4qiOZ zL{KqSinSGqcFBk)h8&~DpVG6zwNZSX>2Sn9WYd1v?g0Dx zwUXAwex-;v_R!=Y;wc4Qna62s*dYZf_!Ekm^sCU4F7~uCwTr1rrVX_zX`%CNb`zL~Y?^ zv7bh;I}BUmETL1t*AD4rJVBNoI!x`o5qTO(Mma6?GLTq$6K{p5haROSpN%|&6f;tA z`s5irgf>Y|7wgIsp&wGee;PT2)O4hR_#BcR?468q*I=+FC#zAuANe&>vygft)`fIi zZ<<^>!DeNG#VHP>KR?$6AHjqqGcYqAsQm!*o1@mg5SkXsqm#>U#Qj8hiT+^2t$k)) z-G;d{aUce&fLa%`bzn{&AzoSk40t8>M35g7?%)Kr{PDOUm>?YSFUK!AD_o$62iU0L z!$YS0jI%}qOl7W5TzQaj-0ey|_Ig$6$FVeL(09m5&PF1B38Yd7ru%J3KC4 zs~C5dhvxXaPffz-q_uJyR>8&jCLdyr!ScCa@OQ#5PeY@bGbqMGz}POfOa52_huo#) zs11M0`&ex__^_}M2d*0StKO@mx4YS{0bw1OF82MmDrTGg0FyG$3jUz@W2Ss!v-b-$ z3&vbyuOV+9)i4V+bO{?2>%#(kJ&|3KS+7d_6AZNR*C0-M?^Vp1fZb~jeF8IamRoEn zNm#W@_k2zMYld{fx4;)CW;!xx9q`=D4ew>0BXVUo zgAeQ5-RwKv?5a>r-t@?~LTmCSN4_0emS>54C$uUXzEdW%8Wx zw?K)fhrbP4JURRwP-9E@s=avDZkB_nvSrI5Ngnh$Mh$1GF#gJXGP~hghK7UiU0vGG zRPX(JzNU!rOC8!J^!3P|FXQVHhxWBSmnv!4qu{+i{xyg8nGnN5FwVM;E&vddw8^eBm_GzvP*s*$9Im?3AscA{f}Ms_(hb0uT$p@fK-jn2yb1 z=iC?JRlX2jWs8i>iMNmqGf4I&3rxWLG{biqm5)%mymt=d*@RTUPqW2`Of{@QY+RJk z+ApIG0C8?R)Y`*4v0QKJ7vc4@r^9L7?t@rEXIgL+4W2rFmWsP(*3qe!EQlG|5Hqsj zm9K(V9@460*V-jppUBT3_X+$AvKF%PBb(fRp8v5Hf{TTm<&+&~N9cI+>mj9!{Z;|@ zxCIUq+T%_Kkhu*O5(ilTQw~bl5jIor=F7 z%6(1e0-|FUPXR9|0PJL1k`LuryQ^6n%vW zcc>CCla~d3p+&*WkfJqKs=mI#YZZyI5b%FD(6%SgS`%oU8E7pDv{v%} z*9BVJ0<9YZZLb7cuMYTc2>7D`|9t`f33zJ)>j1wW1e*I*Z zy@W$sfpsfVb(%%ya~E^{Ut13>?KjYEliLKfb+epv8Hr<1_#cAkfw8_0 zr22Xw*;nabgEQdTx;>D;-kTA#rt_N#=StWrw|_b>JE|U70Je5Ok<13xybkuq7P{{6#vt0Q z>|}fNqVu$tz6?CTJH0Pc^vekxX`I|Qxwk>K#H>?MrF4%rgbu(zcc4Un)K@QNj_eJZ zr3@aQX9%o|1O4j=Z~IIQ(JgbsU<5IsS)qY%>SPL#FpyK}s`m zJY)`S$ILVGZ3zB*9ctT&U~@liDs3q9cZ&lk~8Q7oRkNwEVQ-?er zs8>+UA#S7*#dwl3)6`7J?TziDlXcAfev*{-`_x2<-qwf5no+A_b-_j}I0a|ejE)%`vG|IrNh-Z}T2@A-be=X<`d za}FH~J5B4w|AVf+N9)C(jv*rYiYoL^4N#Hs%m0kE{yOe}j@DrPbRP@c+njIsUqWG; zx2WJ}>~Ie6lzl>PcfT!&-iH$4Q7u0O!Cs_`|0LL+qpN?FusPoV0PYmgEITnFfpC4% z|I$M)?^urwk_Rvs6COr3V>BKUf2p0f>!%$N2g~<|{CVae zRRc8UUP*fF7r_`$&2>&RhryG599egjxBBFgXw(g$D$76MARa%0|K5=NUo z5^*3b?JYgyI3pX*hw$8z}mkCxmnrNmQ-r6&G;d*!Z{@$QBwjl0oC=?D0>feEOd3TeF=sqA%aVOG=S-s=Kf;Lh-Q}$W);Pj{~VS1SH@N>i)P(G zKfj9f|JaJE#NDRYitD3`mH{|#-mf2aTpnBTS$VsaZm)=~_!@!k_6d#N9&+bu8S(fp z9(HVojd>+Hvo^Nk$I(T10Sk^RquG~6vzI^YsEy?;P|voT&qBtPv78F^vecT;qL}mh)5U`UJn9RtHc;P$})ra|~j zS05LvY~@y|a;s!Hb$h|rr&fjJ%g1FS_FCO(!Zr8DrO|9H>vwS~e*s_s5W}si%)ZIL zI#CjL*^{eV@HxLK@syi&9b0sD<>ab!&fM3|X-I)wJ=D7TrP0;beJAxqM(&%Bq~4l= zeow9ncy8^uHlQJ`&g?q$0LG9Vcx)7oEy8mUw;J}071m?e!u3c|ETD1W5L7mdHM({V z>9dgwor$o!&Ydn&`1cQqLjU<=i+*g?S&H9*hDE=P|23*|Q&kTJ@ESDm*KTvH3#6bq z)-r$((<_(kIc5h=Ug{@lkRO}fW++>6!2Rm`bT^Rc#_jmRl z?CNRn?lXEj_jUGm_U!F6`VZh=ckb&~)f;;wy*-`11_407_wDWN?Cdex@m}Qc z`n{3vfrCB9hdO&Bw5ziDP6Q=;`(_o2^mG;(b^8qCXk-BOxfckJ3559`x}H>T$vV{9 zcNooUi{FeFmjF5jq6a%D8~ukP=6fF;=FG3^tL)4GH8=sX=a#Rt#>i7jA>eUa|&$YI(V z+s0MKf%Y3a4Py_OMNjSO0T&&L^kTd14#Vi^>h0Xy@6Hgu?xP0w&jwLxNYECn#Lz>$>=WmU{-AfBz{#-x%Z zI2pdWrSP&+qon-EWu;uctiT9i>tpPHY}Id7?#>jcC1_f{Q(A1kv!MV-99@fD+_CMm z5e#Ej=axc@SN@a$09Aei%4^GBk8?X4=^&MAO29H3K31KcRxaHOQH6mOLPh#iF` zl~wDnrEe}@Zk69yx?a9z!BqkPs&{V-HskbPqoJn0u%x7zU#dVoO@*c98#Y#1h0Ti+ zK+v`u2V1r6CJ?wh4ucPea8kBWcXeS2B$)kEQeNQB5@|Tc77bz7?pknv4YmvCclA_@ z;Xo1`!dF{|Qxu5na5yB&8~HUgir2ZIw*0j?aVK^QH+B_<8rS2iwss5JOCA_jt^9l9 zL}LXQhK9XXs*!4&Q;x=vDyZPW0BR1kg?Vp(HIS)JfN8>+C|FHLK;X1;>_aWm(HFD4 ztuW532jU)yef23cdcwTVPL9nj!jEEaJ2B;lP@I6=+1wN~TkW5|_|I$q8WFvF>>{8ikV z5@g{Z4z099IuER~YgODyh)C|eS!4M3)o2a6#$cNSQsOh;y+kaW%~8x~)*IV`I9-%K zb8wm%PmMUAAdHjBgEcrz#rz}$gm%#{cXS`(jV>OU&L*<@8P7 z8p>%lFZ#`kqwZxQQ{Bu9vij}a{z(E?yW|xM4fA7o9+2M|hW}tV-OEMR{4XtQa?SlA z$3#}rPdO{pZO$U|Vxf7lR9(!)u4eq)LW3&wNB>!rxvVMWZQjm#pZxLieX|O=R|o}j z&ijgY@{hQ%@8qAB|2d=jIXLdBG*WSgS1cq&u%)zdErC5yL--S@K)&6cS z6}Z}(mu8`14#*b(cW&eFgn!)^i6wL2d}mM6o9B@bY4g6ja=ChJN($jN%UR9a!PRnq zItvYE@jw1=_I%*FFBVJR8<78az~+B*8Nk)@UYv`D_Y_?BC1Tn9?f(%^=O1#WN?@zd zF#aG3q51zSZr3AhHNBfl0@rN_lQk1nWh5@GE5lfDk-AxMvAVEW*PP_U0#nSr=itT) z(zU=(;=_pcQgCW1f>Tca&eN`P6|VAcK`6@j4+_eic2QJm{ctJ$$;a-B__IoR8c_}1 zW=$2HEcX8_R)C(YNLLX@tmt^Kj6!J-I^n6d1wPAS`KKrb_8>xbXD+Are~O5wj4BS5 zV%K*(`99Wy|EsF~@hNP32Dhec!mQr^P^I#(@F7j|C@5F7KydsOvDe{7tWm_R3Uv&yZf{*A4zr_gReIueI=T+3Z$)^D4F>wTk4J}2~qb$1Un%MI9MHdBP z&H@f>QTLn$6j#KuarYXb#a4cLIybtA;y-1hdAF_}D;Ukio)6fnBzRoZ9v9f4e#dc9 zcU)X`Tx^MEe{ph)-|_x)?mWk}F%iUW6O^QTYq4Bv5zRJeF9O?bSp||ZQ-;^!7cVj& zzB?L3Hp8Noyzy(se~@cEy6DNlRi8x~N7*swihv85aX5m(pEk92A_alg-%_~C_|mjL zCY~Y+tjfptl%KwG2Q%Ipy(*9rGq6D``hoHjO%tB zj`4o(^KH&=`_CI|v7nc#bLR@DtgSv2yFE2>9vEailbTQDcX~D zKAQDA3dCF%&3cOhESJeB&Sm7c=V%Z1-Kwyat5D@CWI1(v!PloM5bdExekL19t`+?7 zV2&-i;La1SRiCA%Z4rh_L>MUkGk=t!vhvuX#j~OeNQrTcq#@}FL`FLLE0xo$W8&K* zzpj|bt_a~F2>*K7)auHq8!4L=*-O(Krb}OQF6Xpf=Nd}ub^1B2_ad3ryVaJ~>kQ0F z>vaYw!8R$SH!$POL0skXSoV|C`M4gH00YK8pN>#Tn7XG2t^J$F8-a&XWa~RL7L=IKC6#KIpwmVc9qAvxq^y%qKjWFn=;Fyvq34hZ)VB;*o&0WZNdf_s$}E~oepvRRS6dnAyK zlCIm2`dy*1U?m2t3!%AJM;eS@5KNTE>RcuBSTC~Yv93^gtd~%!`SMt0X)}*?w&cNz zk}V@exdmgjH;FAHdAY{ecDh)ZyL4;^T`WS5YaLyr=BA8Yg^ST3(p8rM4_mBs)x|53 zu1XtnF40aFBSE#Oa;nswFFf=l?c@eL!Nv#0CyN4*ZljsbGCt+RjN5JDt? z`CvODTonK5p#Yk3{Xk!ToC6s+os^;^RQynHWPfk_L8JZ9q0V*$;1F5iFidx3?+u8& z3>?B?qd2jY3&(HhJle-qap)wn=f*A^Qi_O7N5nvs#Ms}7upa_8T=CvW2O@Ka4|MH4 zK=()EeFq`~-5m(K96&ITnohtd;p27{d}x?J>4_XRjKl4H@va`Dv)8>=_;7wIMff@x zjKf{s-4a}s?d|OA?B}0)I}3XUWE-k`MRAJ%#OZiU#57wdT7>@z=FTIBy4$;Y&{Z@+ zP~lM4f%a}=&p zts+GA6h%ReiTDY(P4OR`KpUp0I=^8ClxEk-Kh785wEbK^mMJZblMYo7!l$q44QGM@5$qHB!eM%Mx`Q3{e5C1P$m| zY1L94qKLMSDjII80yE1xwp*=i4^dbO4eUfjh9fAl#5S&jj+kw3MG}F#SS-9IXl$#h z-f6F=r8%i3G}=YeH}~ z@!|88YeH>}j6GRTBhe}OV@0uKi6%(_s|?qoC?HECrj1L zYRMi3RP{*w5;7F4%%)Z&j^9@12Cy&kOj?MPh*@GpR#!nh z$U5p0(AuM*Hh!s}T?bCdPOhWcT`DqXVGn5_GNucWrSQV_Fai}y66~o;wAt}%AP<70 ztt|0Wj}vsJ_zzd6+9CX?mV%%Y60xe9f<``6Gy*o%06ATQ=dzv_B-p4AQ2~fShD3{$ zt*Qj#gY;>@!Qit)v#LY_bM7*crK)2Vw~hQ3$-kt3gj&OimhAI%kim)i=k4Pgl~6=trkfxu~k2NXD%^W^W#%6 zNYPMo_2d#m{HJTqY3Q!#>YYh$G2GhSVz`~{7Q3)ZY|WStF0s{Z^SQ*_8|V1H#P8rB z%GyZDxLMI?=B55OrpsbkKap1(V~Z9=GY{a5v9;I}ZPAtH^<}X|UFLOVY|-b;>rJ1o z%=;Hug^zu@BJWZBeI&N%AETLher@dX*rFG?)Yui+I~=R1{pAyG+8QLwKb==vKH-mL zFQ)4N_Swq#2W;Y&7tKs9#rmD)lQB^?y(%VtH@#+X*-y+I&~?M^u}iHS&~?$wH&qVk z@||?eIiPFl3NDwm>`DPaqV95`!TGTczmxw6nUVTNY7kD;H;ZoHMNRzG*?Zn zAp)-99L>y0^5kSrMl*j)PL={yZGrUAsN1pR)^Mv_F;fM!nh>S%{!8>e3jP=JXC+kf zE_-q<=g$@-p7PtSW0~WXlLc1(>{`yBU7M6YyLPf5kw3c@EzM0T1x`>MTt4m!;Z%vG z%U;;Xoqz=*qAn?A1y=H5EyoP0cNoL|14aX-tYR zb4=HTTk5KlQ%%Y8oSkespCL?DOF30tWRz51R=N&~H(u>v>#VA;FS54_W@4X8H8q=7 zIfqaYcbQU-{#rVn%YB(Z2Buk@GY@59@_)_$N}_m6sL51e>_zPiHx#*62oiPT2qqQ2P=n#Gg|W5ltY#wKKzSOi+mZQwXr7HtW+})L6$;p zA%7?-_QIvgtQO50w}t9!YNaA*)rA~F+lOkLQ_8(bxS?MnmyJIXx|&ccWwf@{)c~*D z1M+`K_+SF557jrfq%4Ij#l*)l9mB*h5+liYGtp*OL#Y>5DMD2(GJk6D`VMH3%`)}J zj@@D;I&#MGw&u`IjK6uYOR1g)Cu^xv?#qQ|c1hVPh&rcL@_*S|wo1y*n%%Ierxqy~W1+w@{kR)n-E>sdy z$1FwuFOM=ev!<(MV8m0TjWVxe8< zB>&eR7K)V$1*(xc=cZ0$k58>4m1S1-$zfRNziEaU zie2GM(m8Q!*Ew$^f|nrAYUA@pE<3?{I9we>vb{~Q(n*E-}zOL?0RpXH(5SH z1abs(>qm~Dm?yt8vbTV03Id?eKBHRx3b$oPM;BcA?kb^S{f+rnpFs^ukE(jT+x~hz z{GmlgBbM37*Dw5P+IsG9XLr}ZE_O>>u4^3?`{rU?nZ0JxYq%A5Z}V0L8>a~5&E_e9x2@kPPc8XweWNLQfp|&RVC&8L>{c|LA|;fKQy_w z38$&1s+4c(Oz^pCXl7DxO2>{~P4llg%b6a%nmTxPs&@OFSg8O!)8ZUh`R9atI*gULT#ia>D3KX zhBL0ouNC$!+)kb20rsKyt)-WFTI-lS1P}{YFpUnt`@G0 zI_g$4&{$a4i1c|(s4a%-m0m*~P*|u9A=c6C)32(>v#VO6&DYANFiKMLrT=W3%m*jr z)HSvSp{6t0;Fct;D7^(&M8^Vs-5<;fR}m7-w#nDyThKt=W^V_fDXd>bSTT!O{x+Wv zx%7qbmLT_@c|+fcZn$fp|L%m4H&KQ~5weg>I@h5G7E1piL5yb5VtQjM9#-!L9_3Fe z5!}RCJyDkxTTmEo9N)qaVOTkZhz0a|>IQsphRrbWr6Dz*UJNt(cY+4+fj}bd*6XQ@ z^`Y&IHoS)*UZ~NR3a?2a1&|sIW$4JdssHt%DlocY?V75VDxZ&)PcCgf54F03!rju; z+QN*fBZpnRsXUqdVk%^!YQ|&|Zl{4pkiY9YG`X=i(KF^ z_A2X5L}ZJ*Fl?C8sc`wL$|VX>H4zm)>YdCIzD!V8k{+Hl{7N-5JqjCw&D(>%g$R9M zMH?bL;hl9&jJYsP9O-i>jxg2*)dven!jOIzR#OJmG0QRUOT({d zlf4phzH#rsZso+V`ZoH>iVN6d0=|^()PqDsLCym<@2ziP9U(x8PRoZWE3PK`tHLze zQJ9|0_F3!IL^@TDG38qT$Ej72#j9S;lE?H<`!ee#;w>+E!o1gO=%?BKYF}ytv624|B}={1A{^*hLGQn87rL`Jeo+G6`1j*wa_o~`Mvcpbw<_Q+T_b@ zA(~N1CYUZqq;$*EaKeCNRC=+%T9#8`m#SvHg|Mp{sjq@iz_l-}brwAnQ4hU^2%uh& z*vEjV+BQo!GA9RJ$IJ`uue(6k!?c_lL1~}1cc2%GtowahC$vAG*4OEAigX0CBRxJ1 zDyvVEVR#gb^z`>ex_w%I1pf|n>QYOkaCG0%zW&aGMMhhs_Xbu+k&;146MGQd?~e4z zvw5+$_)d*g<6{(hTtbJKm5cq@ zRF&frZB|#W>FH6;*7fvt_R7HifzBgX(!00oAhc%a$Fr$y`1X@PlF@Rt8%im4vVQo61DUpGm4kQa4J-8>*?MXrW_aL%(hws5R5l8)~jPuLOs?zt8CFCpH4xD9cffTcmPP zQr5n%UT_Y-QK<9o4K(Cb+a>Ip2XYQkwh|}Q9Pa8v=2nDwi<;`fD)<8s3%jX+j?^i6 z+uj320PVe;QPg>4ZzmFUs;T4BmLS`jsREWjCXb>i+Ar+uZ|@~p;?wFd@F|6ds;@?N z7vz(@V{@l1HN5q1%KuodgitiX7(F z!G#fKF4_VBy#~*A^$b8PR-uP%`g1*;2E<*{xg~Ja0Mft`U9|8=y-_&WM}r=Ihe)qa zlS3UX>kN{FJ&9fz+$#A?iQ4LhYMM@}JwB0TS(GYMB0r2d!>De!LNW%fuC%V!T36&) z0ORqvM7k1X_I1NMkl$AzWtrp+2&sdZ7B~-(h(IO#jD1MH;vuRt#Z2L;BxL`A-pIgy zPVqB`23IZX?dt>{J5-%|a-F7Rr8$mYA+!@7JMo6hL4!DzQ-Duv!L;T{6^r1{K^$p5 zNL8PZ*~fAq`CXs34_k=zAJFY@Qe$d3O8}_D5F_13Ssa9_NheR3=#Yw}@*y9q#k5L+ z`Oun!_-yUL$3(Y$gb8W(Ba0xige(nPj|KXRxG z0*@MC!22X=XbQoMMKu`&)H;@ocxp;mZfH*@>cCJy@2#eEdIuvhtmq}{C(0*k18pR! zxqfaNn{;#!^dUD=r(v$dFk=-hVUnVT=8%~wm9 z&?;d~m$#VW=sw>fQ31${K}32ak4am-Np&W%Qle@Wrb;LhpD~T(&wXaiJT`fRnSz#u ziPA6#U<^azDO9;`GBm2Mqi>l zt7mFhNcVDApAI35Et{aMkr1YFrkIC-noq8C{`ERagC=FEUuQm|B-wR5ER*G?nxWy% zmcyMp%&IcgO*$eA2rdR~PUf0R=H>QzgD57?j(MELAkPjak0(PcFQ7Y%L_6js(SgqP zjz6A6>g_*{ME|Yi@nnh>gfBJq{vRSy(_Ak-cAg*3gocksM=~70dtxWmWGrWuYfa8I<{k|04F0kyieV8Vxf&<7br!@hH%Sb6j?*l?;&d^{= zH*UmcQ&NkTh*DYl)QD%1SlP?UxD;w6gvvK=EZbP5hhe+QMF65N%GfC@(m|`uoN^BpXnz-3xOhOG2=g9&*(?op>ydy(jW>S)}&&?C(Fo!#zAt+y=Z8UVp@7BV4Y}S2MFGTU?Y7 zEd{cOVj*Sw5Cl-xVF*QTAi{JKPN&9k6%$E-jX`*3lLixuONz){pFk}fzLsXiH=qHyO&$QZ+f4!deMTk6RH2(Ln>5AesuCUf@a%8c57jK z$Zk$-4=Ghq_be4QhL&yZ2azIDN#`m|UBWKmeA<2}(_ANOSK!_L$l>;0(?6rewUTPe zJr0?R}o*Vl^y8^qc1`@U?U(vOji5 z^V|TkZXn-5N&~v8PF#`(Mbk8%9#OIu1CAU-G%-qoTavO5dL4L(SNFkHXq#st1oyyC z%;Q6sju!RSETz^|{V>xe1frQkAz4kD=1B!f*)hi>GA=wT1njEz-lLG~Y|Tqx)x<}D zvrh=#Wq3zPhGY4lIp-n&LX|VcF>mpR@mN>GA$1kvNjOUD$WhAbzw}yjC*?>}9$z(J zcxzD}4q!hJ#c~YuEZwdvzo7Jps8^G^sT`LkU{n>fY)C7KSIdd%$q~6q!mt@c=u!14 ztV`GYRrT`({f(>Yt7M08MVx@H;i}%cYF6F73UgQ&R2!t1$N+@wbNgOw$jPhZ&`Y#T zu)&OnLEYI8(?WVKNam?-!1k=_?p|k9vv6K#)MG&(ttEw-Mr-Tfc&bM~i72!#l^X0o z-{7I?i5Lf=S4s1rZ(uL!MMTW*F3(Dl2g8Mg=v57Katk0vuWGQm*kEV;3EZs?fVWhW#xKy&uSD?^Z06BZusZO78t zLs$Ze<+X~P0$VwDBS~1-) zVNp4FDk7Dke4eUh*Fg&egkUBD?NkTW!XAaAya-7jl=fkze0VMv0fhf`V`sg6!q{1F zpD=dTn-j)Pg#rj`aH~{fY|@QGS&V#}DV)Ue%HhRxCUiaCCDx|}pvd+Fpa*cZ(wkx_ zmt3h?MmhB?j|zxysuK2gq+pP!p93E>6FFyNJa{e<`S6}#kR=aIIUsF*Q)|Lu5NRs1 z3s>3k*|iY9>#-6F_~uj>%AH80D(J|4QSzb1PDYkvT|GBK+m?LHp+l2#>+5D`*MNBS zbwoT>SzQmYJt-taBRf_MsG)@FfDGbbK56tAq5#epAOK!Yq`pBx#LGIwFdJ7aCslm& zU^@V!E=san_M~aL5#v#?4z>r&78j4Af5w4nLxf z>iJlK%m$;HLS$~0nMe*nS2ck6CWiK2_#NfIPx0fX%8Su+5G#YB9_7MfC0n%OwEA4*^pjL_i-&NFW(Q98pTdPZgK- zlJvH0Krk4T+*uCAgJ#@U8jt3iCUx-_(Nq)XmqVHYjxIC!E8k%t)C({)NFpBS^sE+_ zTAVLyQT>tn)ZBK>Mu2akcm6;Rbqvi>tQm{%dnqP_nqh;J*(;r#3?9X(4Jd^NU>iU< zbubLdZ;86r5lC`L``-3G*uN-A0*}YT0djElumr0Q&6^EI^i(PsqB009%ISy)4{j*N zFQr0nCk5omn*}cStP$%ZPj>^hPHK0d$oM z(B4IV;}|LIq2{1ZlW8P1xNEG@ zeQpFvklur&ibl$W+m3fwzBD0Gw{UK{n@Tq`>ft`3oLSy}+cX5}=~^}lJ-MO~h9P)P z4eJ}RWjxK%jCHn92|Z?%ojo~R9d@GF+uOB=!txkz0jr6CL^3=8?eLnwcm?jbLX3bS zq|?ctO%bnJlgQ@Q|@`vUonI3lO4a5ChaG(aL2ybjn18|-Q7PdcK(NhL|- zk=7<{e~bfVj*v8k_pGy!f1ueMf)tTroEX4f0xD^#ONlb%=*Ljxur5&tA`%Ul^C_|^ zaMl2+Vo(mcJbtmB1p#}N2S`hkI+{|%_q6w50}?`eLugi>Db@#JX=@|1^PCu7gS5Um zkSAp-+$pSKP}IhZAO^FMg7(-RQI9kg-|5^-*@i`4`>$J$J}cLI-&JyUwPK};h6g!>*)It=(t zh5D?ZB1zwt6%1i&DT!9;>_eW-dTIKDAxS1KEWcBQg0Xp+6rRD)()%YAfs zK~jj6tD8p@^Zqs9YjUXdVJ1a>f#ek2A={>}YY!wK+m7ff5N~E-6?qD9WJx$N+e%5q z4KuK2HLxkLBM-eyjSwl!c&i+M{6<2toXbj5xgpymsUC7)*nKWKRivg?>H)KL@+)<6 zyh<$$$8RW4bRVZZD8<&yXu1F#G@cv7lQKfr>W??n{nmb`}VJgHXHW1U$ z-pl}kiGNf1kl8^reS@FLMgh=Jv90pZf~-6=B~M7x@4|D-u%#O|_~1@QQWU%+(Bb6S zD5Neae=8|PG6u$OM!duNf=@d@sbMhKdj}3dtV#Vtg2j)?MFLd?mhS<;hN4I$A&<0A z^IR%6!1c*10uaeSig8e8rZAFqxFq*P;Ll>kqp{VN_b%~eE)y^_9o5+gWKcD>Dm+5k z^H7n-4x~J3L9A(59tI{IHV=~7Ss1asP=L@4;#hVM%D!+O45tZ!5z!$kujUBpPeD|W zaJ>(^Hp%XxoG#x@P85`mkoG<6J?q3qQ$3XYMo9vsAob&)sp}!l#N6)(oD-@E+0yyp z-I2>W(C1Lid~UG~WZ)?jxu&Q|3S-OlZ`k_>?+@?#L;#W3R&|YqBM43w#5$ew z#RzqlyN^n%4&e%#zGuC-jD`xcMri)^B;bqrlxV1N%El&(0pyiN1`rO?u!aK4k`W7& zLGlm{bAm0x{u}_bT2a?C3w_?!q}IsLlXTUqVW_=LX;o63o#G) zf@dYGdc4{LSwYA#(@KqY&YDw6v*3{4{hne`X*z_-LZT7UG?Dc2KR&P0}T!u85DHoc?2x5HqW zUP|!fXq4)#r$lVR@i_A@@Ii;0=M!il%2HLmmF&k;7e*`wDP^)qcQu(&@VEeWIB4sv z$&Mo(Z%ZajYQRAvx7o%TWW-a7Eo2Z{OQL7tJlzXjlURn7B&e@Z{qmHG%SoP?mZ5$P z#rK)>FyP6LL{@S;%^or*R}OX}m0hw}GZ~l~_I=WPCs$KqEC3g9egrlLY^sFH24{~7 z9Ti2MCu-f)DeN!PbFP`nK)jpNg_>9~v-ftYq#D)%Fp<%wb`Y)|$gn46f<%t=FqjZ} z%ET2os0vd`gtvQCUe!)4XkfOLXMDk0uL+|$lErGwE2&2GV9Fk%EPl+s08+QhDe_OT zpqdw5vI{o(M8gEG14{O$?wUf5^v1Up#Bi`7$y`>4MG;sjs^Y0qM<8j;u<>+3@($5v zQnNf8#Aa(q*aR|(PLA0V6jHR)0wW&9??fQWK7i=+LrxOYl)7yfTB$}8a@&04Z_zQO0n%70HhGYjsu;L3P}%ipd~~iS;i%YJ-LVd6fj{>i{`o*%+(s` zwr%yRIin;0hO&N0ve`ss6Fw#@TO*b@$BI!lSux5cD@NHuTr5>iiFulA3njcqJ)1ChCP>y z8utF6H)?cowK6FMj(bQxgl|Fk(&E$QmAE_o(8D=K1HH}_U^D`wnza^B?Z z#qL(pVmTPk%r-lj9g|XX-P~2==tDElx#psm<~lovH`kdA-dvZ&-$Yx9dG>#jFQMDa zM>mF$X7;3r z8!(gZ&kEfV|M4SI>9CPB8+G%BZf&7pM#6g%x;2e|6+tDPR8ICBww*mW<2PIESF$e4 zal*8!g63*7OpRq5iLk9_tH6Buu0pq{k9@!HBy$UU~maL(}t_;8*E^64NA+T)MWb}B|0|Xu=hJ$W$$;m${g!qm4~E< z5f=aopkrg`S?+Xm=8y^(^@xaWw@GNm!9B-DNZ@j^J&iAkGtV}$li#t$M2tFngn`5h zP5ZW_8Kqp#JBLX~h(}fQjoO0Fi4U`;be2+-gI1i%hE%o#l~Lqm%tHPql~Y=ELb_cb zx*;iNy$ziZx(e{3lLr;ZBX}fKhr2x0qFy@DliPxbB90+psi5O2be+!W=MsO?lOWys z_*Evym=vKR7=65qLG}XjEZh*LRi{=m5N%_GArLm@R|BsOB@!l8gUXd-iDoioT=BL? zRDr47k;GUCjMgQ2)Fkapovbjc8!{s|LwSP3z*>32&+wz#ilWzycjR4|hW$ zk$%SxR)yhRfwzWI0obauOb&Lphg`6=XMW(!dFXv;q&ZMCJ;j zMk%ylnj?tNC3n(NNTnEGPo$?1-k;9iuDywH6PT4wnlM9PgiStHLUAMp19w=eoSvX) zl+%q-Maxc5scMqu0Q3xMX@^Be9EQOfT)QFnFEde3+44xCC1nv~RP9;=&yNZYaC^jj zkQacdMjo{dEUYXZ| zZI8eWNqgxa`LZ4dpun2M^QwGLtq94K+$sw3kP}xnO>RHsShIq~41&4C!y)KzN)(Z* zV=h-wfP$T9dk0w;(qDYeeA>73kJ}?_zFw%kmUx>qI-gs1NabqkRUOFon5Qeqc;l2q ziV^eB^lTSRhk85rlCBB%g`5NDN4mS)dv!YE0@4D3n?qQUOIHS5h?F8hh+_Y%s>JT3 zgkp%&Ahez+j6@;KR|=aTC51_4;*6qRf25xRN0MJij|UujN7sHfxD>(xhQc_7k{C9N z`bpS^twGXAr&MrA{I^HGXNS1@_is`*9|2TWw*d-B+|SDGmhO{-M1~8_qTo8*+OTCYb5fQZzF6{`l|c9q;32rs7z1*{OO~OnkmeL*#8D9(fRPR2Da&#Qvs1JTsBd%#5S+G&$Lo*`Dpd;vzT{NPD-Rh0+8gmgdz=9R%7>)o77b?h zsOdOXiei7n>k_Sp2$jUtvngAox9(`&fd*!6g%-Bv&!6{o@!((qvSpOt`~5D6ys5|g-1b7Y-V)^5|K0R=p@N(id=P2Cjj zvJT08F*SP&3f8=&s?a|x6^VP0P?9ZwYEu2CPsi&P$U23a1Prb+#LRvq+Z0yI%6JD3 zS)XRt688?o2kPv6#PH9HKVsgtV4HmhJo4+asbp=OXHhpPZ>%jTr>xD&B5O+wH;cMV zSqYp94b3L4*CTcj$jRON1E`zq8&R#$wk(p47hDJN$5PkqhehD|c!+IP8dZw5Y!0|t z)WsgeyDvZ?P*~-hSPmw$@!3SSHDw`Ea;Wat|8Lml_<}HaeZoOo{FysV!X(l4szl^! z-i>}Kt>P$b0aKI11@nCiyj7&VAxc3B0v)7NGIAjq&Ae)eS}R&XJ1xVN2p)mP89Cgy zN!JVC=kV?M+;{uszY+y*0 z(c~K2l3udgW;sRZbxsc?{gVtlv)kyaW#cOTvuY}pd$YU)Zt|uJ*W0t4j(k6;0BTRm zq$HAeneE4UXlBly%&kLjWzrZ;vd}q!FUT4={IDe)5%~8e`@vzWo5_Cfp!P@0N&fpBvshAm}K zjuZIL%%nP+2@)xEtlQ0-q5>x)>#sB-|Il1PCN$8(&jht=wkUI5&!Lz z1sQ7no#dui{i^FRybFZ~3KaN^GX^;`m^jeZUr6wzltD(K&O5Pz$6g zYPvYUthzNh0)M|Z4U1B+&>r*^csR+wk44Ko@F{POUH;8s%ds|pCKiQi5ayP7STr3c zrD0i_RHkQHq05^oe6vzwlhR=&6jllsgYpM)Ii-+G8c_}ws|hBPs}wBs*Wz&?pLds~ z^>iu&OF~d3Q@W6YC8Hn2uZ$|j(ghOE2%lK)V{rz@Yl+*TrOY(jGfO(OkQI7Px^`9g`*f=nhSV}y^BN|Z^&hORC(-E6860A z;&<;VCS&XEe8oKKq}~lGyeH1$eBe=Tnk0iS%5A8Vy5P+g>5#E@zwvuOPOJrLvm*6a z>U|$5MnqcSxqN?j4Vh^+< z5=2NzG3$gS*nAZeCY^Q7X%bMxp=Qf~6~%OvYPYA?yIAO0Xx*b@Gn>v{l4z6$!#mVq z=>c}FG`7*UM?Hr1I~qaN@DiKH7!&O6J^H=@via=A@~yxKdC!=zSm4myP+;CFsk?_; zNI(FG6{2%wWLUMy;YevD{fEi6p#2aK6shkrmt>>yL@zN0<(t*`4t z6jaz}c$bI;v^qiMWW(z{aOe=y@6pRWlmkcUKe(j*NC+w#NbJbvLim9}_c<*fj5-Eu4oW*Hrmr-OOn_Kx+M$+sak0%8Xin0s95GD`nB^xB10R^a9%fmAVZFFYr>FN(y-9w%N@v^ND zGIwR6qJYe2g%JYV(j+iA0IQ&AG?1hVdY6ferZCRZ&>D6XURDgw;i#t03##_eiS-HO zSVIX~I;L81w~<>_Yzj&vw+5*|nCy9!vJPcpHIeTPo~^~p@GJMXW0P*=4eUcrQd^`N zF@Vv1!mDoP_{nI7;%MS~BLK(~7~mxhw39N8Yu>*YizG0mnKKsfPeetQ6lA)Lk7LoC zPm>h&E*F{jNsdTGCtF+kVLnZsV#$y%=KD$x5fW=R7{SYo;70BeEkA@Pt=M3cUxr=e zXb51!ro$jIzRvSVIcgiGy((&B%_ms#Mlq zgcah91?9N!plpP`2qRauPlW6#!M!f6?>RS(-~;(uO;^srW5lD!GkO{~E$2POpCTEnx410rJ0N9jnU@xpnB%!iIz?_flGvEqhor{t5 zw9Uo5Gdtx(nv*Q}jcP(T(ZV>NaK?r}kM|<67!xgTJwWxbcN^i`Zr<&bHtR4QcO^KM zmC)AOgc%E(j5(A!XMoHzX7C$me=L$~Ll9MY0x}1F}cE#&%z>@qTp?m;r-mL^3T#blL($?c3@&FLo0@Ok}VS|3)`NsC% zE;Oo$qS8O{@TioPym1E{qf7dbWSW4CY+*_yJPMeIjEpCcYESzf472@kdy-;606;y( zo>By%T=heA{1}WzVznInz z<$VJ?yr&h-QIvixaS3q2lY0A&?Oojf5zI#u!2xJ~2Wg@MP|E(=i%>KOnCuGnUV`(V z$Hk+@QfKlH=H1NM?D%-*vGIk0<+1y=4rlXO+y2~{@yz(y?9<}mvzbOUZcdA#qJS^@ z;Ho^=Q01B>$Hp@PnsGhec<5~U8RuH#;qisWKgySIgz!h5_~ncfSGiZn2BHtG&8;!CokgJwf>*R?ltHr?Rzhci0h&cRt^_MA6yo@w{XHc zvWKrHoFlu3SL5Na@umL4*u9Gl7jCpupBVR^7XCM)4=x_k{m#MhM?QMp(C$FSP?LYz zP2)=+I_rCQeA)4{zSzA5!|AePDD?7a$B;L$Y;ZhE9rm0NgI{%@76D*-8IEawwG#M6 zwK6)K`a_!om>y_!1I4^j8 z;kub;0oF(&Ba7f}4vkTh|oc+_8k$K4gj-5ZX(Hx9=ic3&2A zUmksKF#3bDL-m0S&9U|3p>QB`s5r1F<{rim#(xbTL8%${Z{zL_s7BL-aooKr=2#k! zzxgT0lF*no<{Wd?kEM*c$GpRz9`oG#kD6u}cY6P)D{IF2+5_Gp!#@-9&s5iM_0OD6 zTe1V6oce&KZ8fwjuN)TcT+Nutn+eRU!`~wOTaAC~XV%OV&S=^Pj7w+yxL=EZ`S@2b z6N}GyZ}a8}EgtvJOt}IxK0nHxFwoS?+HIQCKXY7&n}j$b#8Dwe#gNNCbEg>cYT7-3 z$su8T$6^dR@-Y04l(<&?m1w@ybUWLkIjb*S+cTe&>}( zHK#DjzqvO+pd1&Dm=HkJZ9@2G?iT;(5Hk+p-KaSY<8Cn}ZgVX0&z!_hUvuE=xI-Lw zIN}b$cbapn5qo9fG`ex8V+j3?IRt(?E4+Szj-GV{W`?)8(>!dQNbWBDzgSbmFd`7L?NZy8vw-*U(D+?k;}xZTC~6&cme;HQE_Zob@0Y_ta|y#57!J+pN^yI{-XT6TG_d&`yeQ|BY!@y`Is0pZGeG40%U{WGt)vi?(ZZ8gw3koO^n zNWak`4m(7@LmYC5*Bs)JANXhb971z_z?iuB7lh=AAG}I`VvZ$ohlW1=wRRib7vHA2 zP8g1*+|Mr&m6$eYdg7JG;^!9nXAT14n(H3pztYZK?4S9O=Lc>EbLPidfWV!3K8;Gn z9GVL_dO@WBlB(5@IYi#f2gG&%{EMH^?LpiHX0Fp*&lzvHvd%r`pLyLO^xrr{!OXea z{WIW{m@D4nG-j^6QcDpS)du)JG_ow3vMQFc%J-mS$mjRwif|KQ3xBmPPRX41bXa%bpY{>&Fdu9mWuhL3(q3>^nYJa!*o8TEeN>!0}xZ`#Mu zv4WY~wUiGSct8(_nDsYLXf-^IJnZN z)7)E)u+bL8HFf~2t!svZyQwN17O6r<$`-jqQRV~KBnBB{d>kX4S%u^Buug!=)Q0MD zl3`t==00I;-$YO9jm^e2!Dc#fwz(CXiecY4GSGH}S~d4QMl%%&Cl?8#I1ZiNQPs}%b3&=+Z?Vi|qq(3hLO5+4Hfz5F2tkM$g~LM^BwyDrW;d$=S%?TlsrCfA8S$R<6JG?ds17bD1#1 z){=OauKwVUw@}%CnN(@g=lJ--ht6L5+Szrlk7u1oe|S8TEj69L(;y$C4;JRFi=H}; zOFE<;79JgEpMP*^zzGYBp33v={hsKlzx6+6^plzPRVVB+*h9vvuvA?Bm*}S#X2#QC zOvbdWsFJ=<9Us=DN%Jqm@iUh{G@fy0>CCu}GHCp3<7t6avU&POSu{>9-$VA_!K?t3 zu``#CY&6ctPJNqN`m@-ne~X^_x_@cx)bHr;LIO>hOm1(H&<4kk0jR<8jtSQb4&(LX zBL@fg;509r(frThQ4RB+|xk^9)JKLW_rC|Sk6n1SHu1^E^ z&eQtCBpF7g& z_mU@N)!?bMs6F9K*_v>sJR3bVlUF?AEfHGnNTvT(Tl;y`z7e~37aF`Sc3-P(VQ_pU zs+QeSP8ZzR7>{aDE|wpfE|%wkh*STLU*KNB)sHWI>GZ;nX8501Zk9`DyIEG4ZWi$W zqj0r&hqkc0%_YO_CMwSkqx{CcHfMhLuggj@6|D}_}uW@bgi~MS?o8&?+5-&SPUM1%U z+$>(x&2n8OA4P2#M$7J|pmuNlPG}!>*9Hv=g}I=I;8>Ng!AHMuHeA(MrbK7EL;c}R zUezXg26T3#4gYHJr-l;GHqoOs@9A*#ma+XCH!_EcPHZ}nR)~o@O%&36{ovhC|9nML z#@C-d^!2BESAHquZqMDmPYF-Pr$qXM>-32;6RLjG*aik zxk-G(@4QKzdq^x8+LQ|mIq@M#Hp}jEr!syROU(iH6K8n+l%1etyF~50yh2A9wy*=rVFDS_V zSoUwS?|$xw3sM(sT=I*hPiB2<>7Oj~EYp{TmyKn9B;&3H&u4DQ_l%y{u= z=GTs9e&xei@eeQh+v7{#Y)ZSeHtmza#z$*IPc;U2J%gaaxw^)t)@N$!9>-$cN9%*n zU^(M=n_FXb6V1UexZ|7KL*dqMGzVK+n`6zv$MNWiPz=i&zgZuudbB1u(G=SGP1*|J z87QjHU^BmGXa`5seI5ry-`Dcp+E}=$`aX#ISYzm!a7*xs2OhltOH);ikA|N5dh~1I z?J>Mrwe9KFuy>KS%_-Tisb zN_Up~l>2+0_3qW4E0zy0zi&ZJ<}IF|ySJxgyRUcsXX8XT*8Hu|qqYAOnhZVO`t-J^ zYaU(y<+?{(9uGZT|1`Q4Yn?EH&CQ{w1h%-jN9d`c??9>2Q?~(c-x0-Ld?qrcuRkqL z4EeKPc1(9qjRm|Xy93^lZN~Fc-P2=J*Edv-7@qRGKe+I&lT&wjeWykF$y5F}O76br zt`C-a%Z1Bb8QS&ihweD~9seyNFX!$L-u}Tn_i9c1U3}4#y{i{ihNiE7_J%vIAL~AU zaH_jKk-`3Jv7r=l=H!6?4M6N3^#v{+9hkgv?5^{7KO4S9jGa9Hmr*UoML#86T=X6; z>X|w@JrH%hJk@tv-0y$@b_S=PB#e<~`7Q6Dcp~bp5GmeI`mXh-0eti+CVUf)kxPd> zfo!+mY+^zW=sikHg_GCI`K_@Ok0V;TT%z zclJ3lE02q7J|w;o6W-~E?*5=>Y?ouxw}3%y3384UJ!xxk8BFK&ei#~ z^VdAm;{W3LW~%p30?$6#960ZNK^VWf>)iV>gRFfE{rewf#<>?9FKCkwKjI=t&Q*?n ze5&tx@uDM;F|Mul=A})3;s;LeWyH2G3*$w7`c$R=t*Jh^#_|93z*L`a`rOpe^s%Tr zYf5vy6(5*BJbg4K{&f1<;+Mr;9}bm|-7@ycv9=zu`aw|9e_v_o$X}Uwz9Q;g25g?z zo_7+ur>~DL{@$=Lbv-eP@HPa_uYL8z@#*Vhj`v>`@H|ft8?T)fmri+6z<6!=#8_L@ zGaS{A}={Vp*r7*@aQ@$k080H<%6uqS;5Hsedu~`HIQ0is7O1k;bWW)3*YaO5q83 zhBgJ352jrSw(#CB(mjDXT#emKUms5om_I(-X|iM!mW#91=vyu!b5 z!kD^+ICBw@{juqrE2Ejk{x{$MWJ<2<+VjrJLA@$a5KW&zSNuO39h&^e6Aygm{=Dp| z508EL{7sMKe?;WDpSbZe1Gy>FA0BjO4!VAYs$4HeUB5E2p&w~4PJW|e@|?of@NMO& zX2dy|@)+nfvei5K@!N0qZW7+r+EicE^;q6w5WLd=yW#lQ7*M})C@qjS;ks>N0e}N? zO3TjQTz3AWW#`Y8Y3|>|&wpdYiQ*HRhOaw+^>tI{mQG$hb~SW>pJfJK^bV~K{M`6u zG<5-y;1hwAiMv3k(fj-TT#mSh z)&*WJsf6=o`s2B8oG2c5Wrk5G19gXSC8YPLev6gW21o-VXxyz-58Pp}z>ce@OGZ z5&z4;E&y9Sba`MO+C_t{{{M(B{!w&69M`S~#O*0-w2`!tt4H=4k3|H=;jljD8hPJv z>PTC~q%+_Sjf4=0I`1m0oOC_u&U1}S8y7vYAosUTMrL_5vv6p&e}C!FUj|%HxYneM zTym}dE$Z*h(S;(K(fj^u1K&O^MizL7QvJUk`LglKuyNb)mSc`g|I%^@tF%$q?J0h3 zWTbw~Rr=B6(H}hNs4RczgsZl+a*OrxULjJqY#H4Z@Jx+N-wZOxyr)OL08Twu306h( zsnOK<#O1*3$nDVun?`)2KL5gW&!Btl$md5sJLr6A>d!Rq>+#{x*skf@nGE3hk5AnW z0puIq{BFTFj|Lh_Wy_R znW@_+cj0~aVsN87<{O0qQ@Mrr|1+@gJ=7e06ceaF1>9vgqu$LTjhF`vA8<_wqj94Y zSJ{Qdr#)k5r^ce0e-E&xuIDDA+4mMd=Lw|0oIZVX@yiRQ&tWW0WIzUNj0(;7TKtir zb^cd~gTFMAeo((rwC0aYEW_}bI)|YZny4s;q7FHh`rL7GCwg__zP#)qXKu!jqwe!} z-hOA^pN!$@-x)udywhKpd&8}s-2Hd7VnAoCxFx=1N6wO%V>_BE9T&ORjEt9$teLu_ z)W57D@Ij;Lh-lr-ZNyRs&);eMdq>(=P^!}Sx6@krX-D~pXYx+tBOvbN+0z2TyQHLI z@_~xU`zt2D=)F>;S4`el(F5KTr451np$^R5soL}%Wkc5nRt_BtENeNxyL9YJW#_+K zcK$16=l`bc{NMiT+4EnWybrTn>&P{bWFTDnhjQPK0Qj$mPHCyH#sl?3_k>@JT1@cymJdPJfz7tJ#mdY++)D)Li zEHRuT55Re_oaOU_VlY($i-ytq)cw;}N3;Kw;JA9S`IvVLJau8e`*Zg{^MK*{i~IlW z0RRT!;m;WT+fN?<+?U6`91~vx*^RB}?T0|MjNbG2P2WHDm1su)=zSRh&#)ucIeFjK zv9l~VHcs9Dekc>JNiFTy@v}x+sdroiel-!#bu^I>`Ho}vGrI%YM0_y&<6!6|BdOp5 zgr%>;pYttapT(b%5HOl{<#p#YAu9T#m=1EZgv{M^aIf#u`E@A`owu!9-aYrHg6mFGI~z7u~{Sz11n=7%cqrOK(J z(|1j{ftu-)-mPN6)Zyt82Mh=`OlV}*V2C#|6Exy zco16W=>7kzygQGQEUOO#9hFtpof)}BMnvvgWM(Xx5xGX>7P;?xW*|Tea6m{SS@uXC zK!7m~bal6^Q<5ywM~xwqwpw;|)2ixPKs0nWmOVKF*(%v$oQ5-=Dp{P#0$bBrlfNGPUh023srcp>dVVr={K(x8ma48*E{EzbKK*0qKRSE*=#ek~;;ZLB z`t-GmV1=`+`akC#h_8V_w|R8TSuS&2QSxTE*!Rg_2yGIUi;E8|N_l1A-6GuOB=RK#PM;;A*f2KCrzfS5ubQ=25(W7@ReeK+{!KmN&A78(F z(WDia{K9^1TQc6cOO5gN#1)dI35mv@6Inx-Kks&MV^~Fsm>gJvvBvh z!rfmwd+v7cH!3pE-TU~}^OLU?A3@fg#JA6$d#y3?jnKU>-Z`4O^YN)*Pbl2|c;W6* zke@+;TfIMEc7zRZOuU!VSiprSZeb?@c7&mX;*e)#Zz zIeYOW@}{%5ekAl`>5I3!g7AZF3Yse4fA4Mgf?Npp(6^SG-BWM4eE;8Gdg{?9Ka^_d zz3`O}r>c)1y?g2G(aL*|6^ggpf|mEMA3pTn(3=X0|E=7%J*`{~H3ZF!=gvNK@7bVj z`}A9bjGaw<`|NK8hth?^T;kjJo<4gz*f$T#`{P%C@u{cFXB$_~W&h(V7fNsb(#0UZ zpME-X@31oQ?W^Z1E3>_?gfd-ME1rC`x8;@dsS97Zl#D$2Y^o;Ml27(Mbnm(2XYYQp zva+K7oA)a#i)YVe{-pFu=&fJ<Z?J@mD8(GS^P#t z@#(jvtM0wEDtO#`Td5c{9P6eIe>2!0-ySql3qeg*zkhV|r0$Qe1@+0L`jNwbpZOcF zgc84fxL*2tsPFtMq0-dkN!_=DjrxT`P}CHH+)Mn{VgJ=oBysQd{ku00D5v7q&NwQ%>^+0{Gm znY!~6Q%&jFplSSCX>?NaFOP1dzj^28rO+2nBA*OO#Aq^DVX)V}D-<*#UOxM=dtW^K z_d)X_fA%-8h0b0sw?M<8!-wyci{Q%jP%QC32L;-TEUWV@MQN7tYF%<=W+>{6=Y@XhZyx}F|7x^aB{=w|TA zOUE}K3%&HE$}c8{UM(Fze|)QW_}6L@pL^Q}LN7fMy7@@x#v`HY*>43k)A93t_db%k z7`&gT`*7&_Oy>Qe>+cWUcz@_-^1@+#=J$&aHu`$yMkxN?(2e(oZl2w!ymzDAmvp^& zI~?p*r=kBbXkNW^HK+ovo(syvPhUItrOJ`tKYHm4m6`BgKlh^*KYD)SZRtNOJ`r>k zRXpDMrW=pHzxP`|IelaO@reun<%!_$@u0qVeC$0f!I{_a`5?DWqn|%|{_)2rgR{Hm zgI3jP^q-!@UMQcbHGKLsdZQxxpYESDADu>jHTbM>(s=bW`p*t`Gh2s0d^vRd&f|9- zzx&S3!@4^+4#Rh@A6B2llb535a#mleJ$mPxGCj%2(Yt@)v&Zi~dRLHu?>c(tQ=i#5 ze&_o`?|Oge-R}>*RFnAa;?;AZiX5|$G;r3X7)3! zzwrFVc7N>Wg6%8+a^~p8AbF2&ttKk+`CNIgx)gonB>v->`k$*v{ny7rFP=2~dO2l( zxA;?upk|E!_-X8!ciesP@X?PP9%p{+-J$0XZOJ$nB5my36v&s5&I^_JWBQ|De+Jp9((>yL$Q z-2R!P>yJNv_xT`mZXUmMeCty5p~phEib3)Bl~>OF)~(#XzVrOoL+R#M&XrHgzkV)V zd*{a2E7A|&x%sv8!92q^{no8Skmi}?FMQ(YRyHV)KYbGYYr!G%#cvNkd=h=~u~0?) z_wIi>D9=BAbZa};-pGsVKBA32cZb7{zXrK-~v7R0-zxW@Xcs5h_#89T{ zT&Ou5v{tL0$Ym}jg2vS+%by0Vh)-t1?+!hi2!7(3^sgU1`}0?hpUuRx;gi@eeK-{K zo+T1z&nEuildGj~f9!pI|JTRfmkga&eDpAK^mp$3)N7S|?MeKjK|x#j&hi*o z;!Z{5f4qMyTXA{lTIl%Jy_YL5kKQTonoa*}>5Gr|R-QKgi<9V|UjF0bE2oYB{3QOV z;mB#@7ash7ux(co-+ZvOR}x=4X}BH~Y{4FQ<>wyGRX$Ofys*=BxngJM_}Qw8P|Mvb z!wqLIUmgxR^WUDiczHDVfA8hfrhB&^Ke~CdqFg9lKUXf4u7{4VzwJ$L>Hpp2`7czz z?n@)(O84VuFIP7I)MM8|<@U_Q2fq=NxF3JRKY#oqP2WoY>eVN5QM3 z&jo3aKEHY=Xy^an)JgO=%1cE5^l&V{k-TyAeCB*m@)e($zA^jo`#v^Ybw1R(^tXpg z@BZM=RJ`-U*(7Vo_reD(0+VP$z2i2iB$<-*y^uY~S? zD(K5Q{7*r;mDBI#a!DAv^1;xj(!W>y#KhVM|3?1{8$pTLoQt2H3-*Sg{mg$jZT^>s zC#TK-s-pQn+z%GNbMxr>@y+s4cq=$OUwTlSM#I6|Y0ITxQ;%*<2D@^@^`l!=7eZ~h-~fEfN%QD~&weGppFRKJ#ZO*p zJ_AvwdU;d@He=Ydnx63Q5I7}QpKl#KHsf$6P9o{}|`L)Am^1;i89>Z%j*n| zp*|3@Est!w&0H|1&jKd!tybuAQ}R8;Le_*aqmM%BHb z*%zD(Uc5Yg{Ltl4)x}Wz@%h`QL6`GSKJ`S9!RH&wU2DNtOF@_Oz4xAdD0lHAx%%8! z?tSR!y?5RhoIC{Gns+|@<@X(Z=%eoqIyFz*O2KxVR=)H8x!B2t-#Kl4;{GT9>>mc5 zadT(yy?>?R?2-FdE}Z;M^=YX5>NNDh2QT0M;VU(lTAw)iT212rJPswk93)*Zx$n=X z2edx%XfVI;{H3qox_>2l+V+9+Ncn|7yAlm5uwVfG-y}944VAmHzh2S$%16KQokf1N zyvW0or)_Hw2Eg0P-wY-wJb(GYD08vLElPK%Qwou`~Qna)x&>2{vA{VfBrc6)JpQ9(`T12J@dl-XUc=v zZ%^^Fu1i6BU-Ob-f%+npnQp{jT2f7h4~FrYe20JUJqmSGr$#=HYbbx1Om?x12unr68As;pbqVNqqbCnX|+< zPoF&>jDLSL@q4Gw_9R{j@+bg6gL@tXlf=q%&~|(NeAG3V3-SF2Z%n*({qmTQLhh%qF(!G`Ay5) zd&?`q1d7*{w#)O_E^P1Zt#1Z*HvMl$a{oU(gQDuM%-#Bnok00t_5Yfnr9}Q(oK@9U zyni*?ss~dK|LVKW>#Famt2w^=e5N^)^X`w%ex9U4rwwduixWbMM{k8n>aAPk=Ue$@m--XBDjmMwB{sBDxEFOOjkAD!4e+Z9%7>|DhkN-94gH430F*fuEfmh}6 z_zQUa4>&$I4XPeMgmCFVX{Ihucb9nsoc>D`^{EK+}OL+Xt zc>F7P{Hu8UYk2(Yc>E7;>)@tA)utPJIr6Fpx7~2lApDo?gP8{5@3EWte7Ct6esGJP z@Ag~YJIjZ^o0|=M?}YuAk%TY)Ez2LC|5`{|V#% zPZ;-q!npqv+}o0VgmM2TjQc-f-2VyV{!bY9f5N!`6UP0YFz)|^asMZb`#)ja{|V#% zPZ;-q!npqv#{Hi#?*D{w|0j(5Kj8%3{S^x1{!bY9f5N!`6UP0YFz)|^asMZb`#)ja z{|V#%PZ;-q!npqv#{Hi#?*D{w|0j(5KVjVe3FH1x825j|xc?Kz{hu)I|AcY>Cye_) zVch=-)ZqS44etNc;Qmhy?*G)_{!b0=|J30APYv$>)ZqS44etNc;Qmhy?*G)_ z{!b0=|J30APYv$>)ZqS44etNc;Qmhy?*G)_{!b0=|J30APYv$>)ZqS44etNc;Qmhy z?*G)_{!b0=|J30APYv$>)ZqS44etNc;Qmhy?*G)_{!b0=|J30APYv$>)ZqS44etNc z;Qmhy?*G)_{!b0=|J30APYv$>)ZqS44etNc;Qmhy?*G)_{!b0=|J30APYv$>)ZqS4 z4etNc;Qmhy?*G)_{!b0=|J30APYv$>)ZqS44etNc;Qmhy?*G)_{!cCL|J36CPc82M z)Z+e6E$;u+;{H!9?*G){{!cCL|J36CPc82M)Z+e6E$;u+;{H!9?*G){{!cCL|J36C zPc82M)Z+e6E$;u+;{H!9?*G){{!cCL|J36CPc82M)Z+e6E$;u+;{H!9?*G){{!cCL z|J36CPc82M)Z+e6E$;u+;{H!9?*G){{!cCL|J36CPc82M)Z+e6E$;u+;{H!9?*G){ z{!cCL|J36CPc82M)Z+e6E$;u+;{H!9?*G){{!cCL|J36CPc82M)Z+e6E$;u+;{H!9 z?*G){{!cCL|J36CPc82M)Z+e6E$;u+;{H!9?*G){{!bn5|J33BPaW?6)ZzY59q#|s z;r>q@?*G)`{!bn5|J33BPaW?6)ZzY59q#|s;r>q@?*G)`{!bn5|J33BPaW?6)ZzY5 z9q#|s;r>q@?*G)`{!bn5|J33BPaW?6)ZzY59q#|s;r>q@?*G)`{!bn5|J33BPaW?6 z)ZzY59q#|s;r>q@?*G)`{!bn5|J33BPaW?6)ZzY59q#|s;r>q@?*G)`{!bn5|J33B zPaW?6)ZzY59q#|s;r>q@?*G)`{!bn5|J33BPaW?6)ZzY59q#|s;r>q@?*G)`{!bn5 z|J33BPaW?6)ZzY59q#|s;r>q@?*G)`{!cyb|J39DPd)Dc)Z_k7J?{V1%L~#Eng8M%a-2aK-{!aw=e%L~#Eng8M%a-2aK-{!aw=eZs?*Bw_|0jz3KT+KOiQ@iG6!(9kxc?Ky{huiA|3q>BCyM(&QQZHD;{Hz*_kW_e z{}aXipD6DCL~;Koiu*rN-2aK<{!bM5f1Zs?*Bw_|0jz3KT+KOiQ@iG6!(9kxc?Ky{huiA|3q>BCyM(&QQZHD;{Hz* z_kW_e{}aXipD6DCL~;Koiu*rN-2aK<{!bM5f1Zs?*Bw_|0jz3KT+KOiQ@iG4EKLxxc?Kw{ht`_|HN?rCx-h!G2H)& z;r>qy_kUuz{}aRgpBV1{#Bl#7hWkG;-2aK;{!a||e`2`*6T|(V81DbXaQ`QU`#&+< z|B2!LPYm~eVz~bk!~LHa?*GJa|0jm~KQY|@iQ)cF4EKLxxc?Kw{ht`_|HN?rCx-h! zG2H)&;r>qy_kUuz{}aRgpBV1{#Bl#7hWkG;-2aK;{!a||e`2`*6T|(V81DbXaQ`QU z`#&+<|B2!LPYm~eVz~bk!~LHa?*GJa|0jm~KQY|@iQ)cF4EKLxxc?Kw{ht`_|HN?r zCx-h!G2H)&;r>q?_kZHJ{}adkpE&OS#Bu*8j{84x-2aK={!bkDf8x0R6UY6ZIPU+% zasMZd`#*8q|B2)NPaOAu;<*14$Nir;?*GJb|0j<7KXKguiR1oH9QS|Xxc?K!{hv7Q z|HN_sCyx6+aoqojs;r>q(?*BC5{!bI`|1{zLPZRF{G~xbF6Yl>s;r>q(?*BC5{!bI`|1{zLPZRF{ zG~xbF6Yl>s;r>q(?*BC5{!bI`|1{zLPZRF{G~xbF6Yl>s;r>q(?*BC5{!bI`|1{zL zPZRF{G~xbF6Yl>s;r>q(?*BC5{!bI`|1{zLPZRF{G~xbF6Yl>s;r>q(?*BC5{!bI` z|1{zLPZRF{G~xbF6Yl>s;r>q(?*BC5{!bI`|1{zLPZRF{G~xbF6Yl>s;r>q(?*BC5 z{!bI`|1{zLPZRF{G~xbF6Yl>s;r>q(?*BC5{!cUR|1{(NPc!cSG~@nHGw%O1KwBr6xEAIca;{H!7?*Fvn{!c6J|Fq)%Pb=>K zwBr6xEAIca;{H!7?*Fvn{!c6J|Fq)%Pb=>KwBr6xEAIca;{H!7?*Fvn{!c6J|Fq)% zPb=>KwBr6xEAIca;{H!7?*Fvn{!c6J|Fq)%Pb=>KwBr6xEAIca;{H!7?*Fvn{!c6J z|Fq)%Pb=>KwBr6xEAIca;{H!7?*Fvn{!c6J|Fq)%Pb=>KwBr6xEAIca;{H!7?*Fvn z{!c6J|Fq)%Pb=>KwBr6xEAIca;{H!7?*Fvn{!c6J|Fq)%Pb=>KwBr6xEAIca;{H!7 z?*Fvn{!bh3|Fq%$PaE$4wBi0w8}9$K;r>q>?*Fvm{!bh3|Fq%$PaE$4wBi0w8}9$K z;r>q>?*Fvm{!bh3|Fq%$PaE$4wBi0w8}9$K;r>q>?*Fvm{!bh3|Fq%$PaE$4wBi0w z8}9$K;r>q>?*Fvm{!bh3|Fq%$PaE$4wBi0w8}9$K;r>q>?*Fvm{!bh3|Fq%$PaE$4 zwBi0w8}9$K;r>q>?*Fvm{!bh3|Fq%$PaE$4wBi0w8}9$K;r>q>?*Fvm{!bh3|Fq%$ zPaE$4wBi0w8}9$K;r>q>?*Fvm{!bh3|Fq%$PaE$4wBi0w8}9$K;r>q>?*Fvm{!csZ z|Fq-&Pdo1awB!CyJMRCqq-?*DY* z{!bU~|8(L0PZ#e0bm9I_7w-Rb;r>q-?*DY*{!bU~|8(L0PZ#e0bm9I_7w-Rb;r>q- z?*DY*{!bU~|8(L0PZ#e0bm9I_7w-Rb;r>q-?*DY*{!bU~|8(L0PZ#e0bm9I_7w-Rb z;r>q-?*DY*{!bU~|8(L0PZ#e0bm9I_7w-Rb;r>q-?*DY*{!bU~|8(L0PZ#e0bm9I_ z7w-Rb;r>q-?*DY*{!bU~|8(L0PZ#e0bm9I_7w-Rb;r>q-?*DY*{!bU~|8(L0PZ#e0 zbm9I_7w-Rb;r>q-?*DY*{!cgV|8(R2PdD!WbmRU{H}3y*D?*Alk z|0jX_KMCCbN#OoZ0{4Fsxc`&D{htKx|0Hn#CxQDv3Ecll;Qmhn_kR+&|C7M|p9Jpz zByj&Hf%`uR-2X}7{!aq;e-gO=lfeC-1n&PNaQ`QP`#%ZX|4HEfPXhOU61e}9!2O>D z?*Alk|0jX_KMCCbN#OoZ0{4Fsxc`&D{htKx|0Hn#CxQDv3Ecll;Qmhn_kR+&|C7M| zp9JpzByj&Hf%`uR-2X}7{!aq;e-gO=lfeC-1n&PNaQ`QP`#%ZX|4HEfPY>?@^x*za z5AOf;;Qmh!?*H`Q{!b6?|McMgPY>?@^x*za5AOf;;Qmh!?*H`Q{!b6?|McMgPY>?@ z^x*za5AOf;;Qmh!?*H`Q{!b6?|McMgPY>?@^x*za5AOf;;Qmh!?*H`Q{!b6?|McMg zPY>?@^x*za5AOf;;Qmh!?*H`Q{!b6?|McMgPY>?@^x*za5AOf;;Qmh!?*H`Q{!b6? z|McMgPY>?@^x*za5AOf;;Qmh!?*H`Q{!b6?|McMgPY>?@^x*za5AOf;;Qmh!?*H`Q z{!b6?|McMgPY>?@^x*za5AOf;;Qmh!?*H`Q{!b6?|McMgPcQEO^y2J;{H!B z?*H`S{!cIN|McSiPcQEO^y2J;{H!B?*H`S{!cIN|McSiPcQEO^y2J z;{H!B?*H`S{!cIN|McSiPcQEO^y2J;{H!B?*H`S{!cIN|McSiPcQEO^y2J;{H!B?*H`S{!cIN|McSiPcQEO^y2J;{H!B?*H`S{!cIN z|McSiPcQEO^y2J;{H!B?*H`S{!cIN|McSiPcQEO^y2J;{H!B?*H^I z(ZipiUflob#r>aN-2dst{hwak|LMj3pI+Sm>Baq@KHUH5!~LH=-2dsr{hvPE|LMd1 zpFZ6G>BIe>KHUH5!~LH=-2dsr{hvPE|LMd1pFZ6G>BIe>KHUH5!~LH=-2dsr{hvPE z|LMd1pFZ6G>BIe>KHUH5!~LH=-2dsr{hvPE|LMd1pFZ6G=}Xx2|N3zMrw{jk`f&fJ z5BGoiaQ~+d_ka3u|ECZ4fBJC$rw{jk`f&fJ5BGoiaQ~+d_ka3u|ECZ4fBJC$rw{jk z`f&fJ5BGoiaQ~+d_ka3u|ECZ4fBJC$rw{jk`f&fJ5BGoiaQ~+d_ka3u|ECZ4fBJC$ zrw{jk`f&fJ5BGoiaQ~+d_ka3u|ECZ4f0DTWlf?a>B<}wtasMZY`#(wC|4HKhPZIZk zlDPkq#QmQn?*All|0jw2KS|vGN#g!b68C?Sxc`&H{huW6|0Hq$CyDz%N!B<}wtasMZY`#(wC|4HKh zPZIZklDPkq#QmQn?*All|0jw2KS|vGN#g!b68C?Sxc`&H{huW6|0Hq$CyDz%N!B<}wtasMZY`#(wC z|4HKhPZIZkQn>$|Dqw_kU8j|C7S~pA_!@q;UTyh5J7#-2X}8{!a?`e^R*rlfwO<6z>0|aQ`QT z`#&k%|4HHgPYU;cQn>$|Dqw_kU8j|C7S~pA_!@q;UTyh5J7#-2X}8{!a?`e^R*rlfwO<6z>0| zaQ`QT`#&k%|4HHgPYU;cQn>$9D^2KRq5xc`&E{hti(|739g zCxiPx8QlNL;Qmhr_kS|D|C7P}pA7E*WN`l{gZn=j-2cho{!a$?e=@lLlfnI;4DSDA zaQ`QR`#%}n|H9D^2KRq5xc`&E{hti( z|739gCxiPx8QlNL;Qmhr_kS|D|C7P}pA7E*WN`l{gZn=j-2cho{!a$?e=@lLlfnI; z4DSDAaQ`QR`#=4-|I?5AKmEA>(~tW<{kZ?rkNZFUxc}3S`#=4-|I?5AKmEA>(~tW< z{kZ?rkNZFUxc}3S`#=4-|I?5AKmEA>(~tW<{kZ?rkNZFUxc}3S`#=4-|I?5AKmEA> z(~tW<{kZ?rkNZFUxc}3S`#=4-|I?5AKmEA>(~tW<{kZ?rkNZFUxc}3S`#=4-|I?5A zKmEA>(~tW<{kZ?rkNZFUxc}3S`#=4-|I?5AKmEA>(~tW<{kZ?rkNZFUxc}3S`#=4- z|I?5AKmEA>(~tW<{kZ?rkNZFUxc}3S`#=4-|I?5AKmEA>(~tW<{kZ?rkNZFUxc}3S z`#%G?|1*I5KLfb`Gl2U)1GxV)fcrlKxc@VN`#%G?|1*I5KLfb`Gl2U)1GxV)fcrlK zxc@VN`#%G?|1*I5KLfb`Gl2U)1GxV)fcrlKxc@VN`#%G?|1*I5KLfb`Gl2U)1GxV) zfcrlKxc@VN`#%G?|1*I5KLfb`Gl2U)1GxV)fcrlKxc@VN`#%G?|1*I5KLfb`Gl2U) z1GxV)fcrlKxc@VN`#%G?|1*I5KLfb`Gl2U)1GxV)fcrlKxc@VN`#%G?|1*I5KLfb` zGl2U)1GxV)fcrlKxc@VN`#%G?|1*I5KLfb`Gl2U)1GxV)fcrlKxc@VN`#)LS|HZw?*C+Q|0j$4KUv)W$>RP`7WaR$xc`&I{huuE|73ChCyV<(S=|50 z;{Hz-_kXgu|C7c2pDgbGWO4r|i~B!W-2chq{!bS7f3mp$lg0g?EbjkgasMZa`#)LS z|HZw?*C+Q|0j$4KUv)W$>RP`7WaR$xc`&I{huuE|73ChCyV<( zS=|50;{Hz-_kXgu|C7c2pDgbGWO4r|i~B!W-2chq{!bS7f3mp$lg0g?EbjkgasMZa z`#)LS|HZw?*C+Q|0j$4KRMk0$>IJ_4)=d@xc`&G{hu7}|KxE0 zCx`n#Io$ur;r>q!_kVJ@|C7W0pB(Q0IJ_4)=d@xc`&G{hu7} z|KxE0Cx`n#Io$ur;r>q!_kVJ@|C7W0pB(Q0IJ_4)=d@xc`&G z{hu7}|KxE0Cx`n#gSh`Qi2FZ-xc@VV`#*!Y|1*gDKZCgcGl=^?gSh`Qi2FZ-xc@VV z`#*!Y|1*gDKZCgcGl=^?gSh`Qi2FZ-xc@VV`#*!Y|1*gDKZCgcGl=^?gSh`Qi2FZ- zxc@VV`#*!Y|1*gDKZCgcGl=^?gSh`Qi2FZ-xc@VV`#*!Y|1*gDKZCgcGl=^?gSh`Q zi2FZ-xc@VV`#*!Y|1*gDKZCgcGl=^?gSh`Qi2FZ-xc@VV`#*!Y|1*gDKZCgcGl=^? zgSh`Qi2FZ-xc@VV`#*!Y|1*gDKZCgcGl=^?gSh`Qi2FZ-xc@VV`#*!Y|1*gDKZCgc zGl=^?L%9Dlg!?~3xc@VR`#(dt|1*U9KSQ|xGlcs;L%9Dlg!?~3xc@VR`#(dt|1*U9 zKSQ|xGlcs;L%9Dlg!?~3xc@VR`#(dt|1*U9KSQ|xGlcs;L%9Dlg!?~3xc@VR`#(dt z|1*U9KSQ|xGlcs;L%9Dlg!?~3xc@VR`#(dt|1*U9KSQ|xGlcs;L%9Dlg!?~3xc@VR z`#(dt|1*U9KSQ|xGlcs;L%9Dlg!?~3xc@VR`#(dt|1*U9KSQ|xGlcs;L%9Dlg!?~3 zxc@VR`#(dt|1*U9KSQ|xGlcs;L%9Dlg!?~3xc@VR`#(dt|1*U9KSQ|xGlcs;!?^!5 zjQc;sxc@VZ`#;0D|1*sHKf}2HGmQH`!?^!5jQc;sxc@VZ`#;0D|1*sHKf}2HGmQH` z!?^!5jQc;sxc@VZ`#;0D|1*sHKf}2HGmQH`!?^!5jQc;sxc@VZ`#;0D|1*sHKf}2H zGmQH`!?^!5jQc;sxc@VZ`#;0D|1*sHKf}2HGmQH`!?^!5jQc;sxc@VZ`#;0D|1*sH zKf}2HGmQH`!?^!5jQc;sxc@VZ`#;0D|1*sHKf}2HGmQH`!?^!5jQc;sxc@VZ`#;0D z|1*sHKf}2HGmQH`!?^!5jQc;sxc@VZ`#;0D|1*sHKf}2HGmQH`Be?%Fg8M%sxc@VP z`#&SN|1*O7KO?yRGlKg+Be?%Fg8M%sxc@VP`#&SN|1*O7KO?yRGlKg+Be?%Fg8M%s zxc@VP`#&SN|1*O7KO?yRGlKg+Be?%Fg8M%sxc@VP`#&SN|1*O7KO?yRGlKg+Be?%F zg8M%sxc@VP`#&SN|1*O7KO?yRGlKg+Be?%Fg8M%sxc@VP`#&SN|1*O7KO?yRGlKg+ zBe?%Fg8M%sxc@VP`#&SN|1*O7KO?yRGlKg+Be?%Fg8M%sxc@VP`#&SN|1*O7KO?yR zGlKg+Be?%Fg8M%sxc@VP`#&SN|1*O7KO?yRGlKg+qqzSwiu*sKxc@VX`#+<&|1*mF zKcl$+Gm85^qqzSwiu*sKxc@VX`#+<&|1*mFKcl$+Gm85^qqzSwiu*sKxc@VX`#+<& z|1*mFKcl$+Gm85^qqzSwiu*sKxc@VX`#+<&|1*mFKcl$+Gm85^qqzSwiu*sKxc@VX z`#+<&|1*mFKcl$+Gm85^qqzSwiu*sKxc@VX`#+<&|1*mFKcl$+Gm85^qqzSwiu*sK zxc@VX`#+<&|1*mFKcl$+Gm85^qqzSwiu*sKxc@VX`#+<&|1*mFKcl$+Gm85^qqzSw ziu*sKxc@VX`#+<&|1*mFKcl$+Gm85^W4Qk_hWkHbxc@VT`#)p2|1*aBKV!K6Glu&= zW4Qk_hWkHbxc@VT`#)p2|1*aBKV!K6Glu&=W4Qk_hWkHbxc@VT`#)p2|1*aBKV!K6 zGlu&=W4Qk_hWkHbxc@VT`#)p2|1*aBKV!K6Glu&=W4Qk_hWkHbxc@VT`#)p2|1*aB zKV!K6Glu&=W4Qk_hWkHbxc@VT`#)p2|1*aBKV!K6Glu&=W4Qk_hWkHbxc@VT`#)p2 z|1*aBKV!K6Glu&=W4Qk_hWkHbxc@VT`#)p2|1*aBKV!K6Glu&=W4Qk_hWkHbxc@VT z`#)p2|1*aBKV!K6Glu&=dEEcWaV{ z9`}Fpxc`&K{hvJU|KxH1Cy)C-dEEcWaV{9`}Fpxc`&K{hvJU|KxH1Cy)C-dEEcWB?*9~U|EGZa zKLyFBB;Qmhm_kRkw|5L#Ip91dx6mb8i zfcrlM-2W-y{!an-e+sz&Q^5V70`C75aQ~-(`#%NT|0&@9PXYIT3b_AM!2O>B?*9~U z|EGZaKLyFBB;Qmhm_kRkw|5L#Ip91dx z6mb8ifcrlM-2W-y{!an-e+sz&Q^5V70`C75aQ~-(`#GllyGlly< zQ@H;#h5J8Kxc@VS`#)2-|1*XAKU28>Glly zGllyGllyGllyGllyGllyGlly z;{Hz&_kW7G|5L>MpCa!66mkEji2FZ9-2W-!{!bD2e~P&OQ^ftBBJTebasQ`?`#(k8 z|0&}BPZ9Tjin#w%#QmQl?*9~V|EGxiKSkXCDdPT55%+(Jxc^hc{huQ4{}gfmr-=JM zMcn@>;{Hz&_kW7G|5L>MpCa!66mkEji2FZ9-2W-!{!bD2e~P&OQ^ftBBJTebasQ`? z`#(k8|0&}BPZ9Tjin#w%#QmQl?*9~V|EGxiKQp-hGlTm-Gr0dVgZn=-xc@VQ`#&?d z|1*R8KQp-hGlTm-Gr0dVgZn=-xc@VQ`#&?d|1*R8KQp-hGlTm-Gr0dVgZn=-xc@VQ z`#&?d|1*R8KQp-hGlTm-Gr0dVgZn=-xc@VQ`#&?d|1*R8KQp-hGlTm-Gr0dVgZn=- zxc@VQ`#&?d|1*R8KQp-hGlTm-Gr0dVgZn=-xc@VQ`#&?d|1*R8KQp-hGlTm-Gr0dV zgZn=-xc@VQ`#&?d|1*R8KQp-hGlTm-Gr0dVgZn=-xc@VQ`#&?d|1*R8KQp-hGlTm- zGr0dVgZn=-xc@VQ`#&?d|1*R8KeM?1GmHB_v$+2=i~B#bxc@VY`#-a||1*pGKeM?1 zGmHB_v$+2=i~B#bxc@VY`#-a||1*pGKeM?1GmHB_v$+2=i~B#bxc@VY`#-a||1*pG zKeM?1GmHB_v$+2=i~B#bxc@VY`#-a||1*pGKeM?1GmHB_v$+2=i~B#bxc@VY`#-a| z|1*pGKeM?1GmHB_v$+2=i~B#bxc@VY`#-a||1*pGKeM?1GmHB_v$+2=i~B#bxc@VY z`#-a||1*pGKeM?1GmHB_v$+2=i~B#bxc@VY`#-a||1*pGKeM?1GmHB_v$+2=i~B#b zxc@VY`#-a||1*pGKXbVMGl%;>bGZLAhxbGZLA zhxbGZLAhx zbGZLAhxbGZLAhxbGZLAhxbGZLAhxbGZLAhxbGZLAhxaE-2Yj{{hw9b|5?TT zpHaE-2Yj{{hw9b|5?TTpHaE-2Yj{{hw9b z|5?TTpHaE-2Yj{{hw9b|5?TTpHaE-2Yj{ z{hw9b|5?NRpEcb7S;PIGHQfJM!~LH%-2Yj_{hu}5|5?NRpEcb7S;PIGHQfJM!~LH% z-2Yj_{hu}5|5?NRpEcb7S;PIGHQfJM!~LH%-2Yj_{hu}5|5?NRpEcb7S;PIGHQfJM z!~LH%-2Yj_{hu}5|5?NRpEcb7S;PIGHQfJM!~LH%-2Yj_{hu}5|5?NRpEcb7S;PIG zHQfJM!~LH%-2Yj_{hu}5|5?NRpEcb7S;PIGHQfJM!~LH%-2Yj_{hu}5|5?NRpEcb7 zS;PIGHQfJM!~LH%-2Yj_{hu}5|5?NRpEcb7S;PIGHQfJM!~LH%-2Yj_{hu}5|5?ZV zpLN{-S;zgKb=?11$Nism-2Yj}{hxK*|5?ZVpLN{-S;zgKb=?11$Nism-2Yj}{hxK* z|5?ZVpLN{-S;zgKb=?11$Nism-2Yj}{hxK*|5?ZVpLN{-S;zgKb=?11$Nism-2Yj} z{hxK*|5?ZVpLN{-S;zgKb=?11$Nism-2Yj}{hxK*|5?ZVpLN{-S;zgKb=?11$Nism z-2Yj}{hxK*|5?ZVpLN{-S;zgKb=?11$Nism-2Yj}{hxK*|5?ZVpLN{-S;zgKb=?11 z$Nism-2Yj}{hxK*|5?ZVpLN{-S;zgKb=?11$Nism-2Yj}{hxK*|JlI(pAFpq*}(mu z4c!0P!2O>M-2d6Y{htlo|JlI(pAFpq*}(mu4c!0P!2O>M-2d6Y{htlo|JlI(pAFpq z*}(mu4c!0P!2O>M-2d6Y{htlo|JlI(pAFpq*}(mu4c!0P!2O>M-2d6Y{htlo|JlI( zpAFpq*}(mu4c!0P!2O>M-2d6ggy_cx?*DAy{?7*P|7_s?&j#-QY~cRS2JZiC;Qr4B z?*DAy{?7*P|7_s?&j#-QY~cRS2JZiC;Qr4B?*DAy{?7*P|7_s?&j#-QY~cRS2JZiC z;Qr4B?*DAy{?7*P|7_s?&j#-QY~cRS2JZiC;Qr4B?*DA!{?8`v|7_y^&nE8wY~udU zChq@i;{MMj?*DA!{?8`v|7_y^&nE8wY~udUChq@i;{MMj?*DA!{?8`v|7_y^&nE8w zY~udUChq@i;{MMj?*DA!{?8`v|7_y^&nE8wY~udUChq@i;{MMj?*DA!{?8`v|7_y^ z&nE8wY~udUChq@i;{MMj?*DA!{?8`v|7_y^&nE8wY~udUChq@i;{MMj?*DA!{?8`v z|7_y^&nE8wY~udUChq@i;{MMj?*DA!{?8`v|7_y^&nE8wY~udUChq@i;{MMj?*DA! z{?8`v|7_y^&nE8wY~udUChq@i;{MMj?*DAz{?8Wf|7_v@&lc|gY~lXT7ViIS;r`DS z?*DAz{?8Wf|7_v@&lc|gY~lXT7ViIS;r`DS?*DAz{?8Wf|7_v@&lc|gY~lXT7ViIS z;r`DS?*DAz{?8Wf|7_v@&lc|gY~lXT7ViIS;r`DS?*DAz{?8Wf|7_v@&lc|gY~lXT z7ViIS;r`DS?*DAz{?8Wf|7_v@&lc|gY~lXT7ViIS;r`DS?*DAz{?8Wf|7_v@&lc|g zY~lXT7ViIS;r`DS?*DAz{?8Wf|7_v@&lc|gY~lXT7ViIS;r`DS?*DAz{?8Wf|7_v@ z&lc|gY~lXT7ViIS;r`DS?*DA#{?9h<|7_#_&o=J=Y~%jVHtzpy-4(|W#;Qr4J?*HuI{?88X|LoxY&kpYY z?BM>-4(|W#;Qr4J?*HuI{?88X|LoxY&kpYY?BM>-4(|W#;Qr4J?*HuI{?88X|LoxY z&kpYY?BM>-4(|W#;Qr4J?*HuI{?88X|LoxY&kpYY?BM>-4(|W#;Qr4J?*HuI{?88X z|LoxY&kpYY?BM>-4(|W#;Qr4J?*HuI{?88X|LoxY&kpYY?BM>-4(|W#;Qr4J?*HuI z{?88X|LoxY&kpYY?BM>-4(|W#;Qr4J?*HuI{?88X|LoxY&kpYY?BM>-4(|W#;Qr4J z?*HuK{?9J%|Lo%a&o1u&?Bf2qv_kT*b|5L*KpAzo>lyLv2g!?}w-2W-z{!a<_e@eLjQ^Nh967K($ zaQ~--`#&Yz|0&`APYL&bO1S@1!u_8T?*Ei<|EGleKPBA%DdGN43HN_Wxc^ha{ht!< z|CDh5r-b`ICEWih;r>qv_kT*b|5L*KpAzo>lyLv2g!?}w-2W-z{!a<_e@eLjQ^Nh9 z67K($aQ~--`#&Yz|0&`APYL&bO1S@1!u_8T?*Ei<|EGleKPBA%DdGN43HN_Wxc^ha O{ht!<|5W1h|Nb8cMGD9O diff --git a/swtp/6800work.dsk b/swtp/6800work.dsk deleted file mode 100644 index 34a1da5eaab46067eff4ba6b00b0a236018e457c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1474560 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%0ANejgO{F()TkUKBDADAH$4Cb}&G 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

4u;Qn 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 diff --git a/swtp/swtp.txt b/swtp/swtp.txt deleted file mode 100644 index 4d16f9fb..00000000 --- a/swtp/swtp.txt +++ /dev/null @@ -1,100 +0,0 @@ -SWTP 6800 Emulator -===================== - -1. Background. - - The Southwest Technical Products (SWTP) SWTP 6800 was announced 1n the 1976 SWTP Catalog, which boasted you could buy and build this powerful computer kit for only $395. The kit consisted at that time of only the parts to build a case, power supply, mother board, CPU card, serial card with RS-232 or 20 ma loop interface, and memory card with 2048 *bytes* of static memory. - -2. Hardware - - We are simulating a fairly "loaded" SWTP 6800 from about 1978, with the following configuration: - - device simulates - name(s) - - CPU SWTP MP-A with Motorola 6080 CPU board, 62KB of RAM, 2K of EPROM with start boot ROM. - SIO SWTP MP-S Dual Serial Interface Board. Port 1 is assumed to be connected to a serial "glass TTY" that is your terminal running the Simulator. - PTR Second serial port of SIO is assumed to be connected to the paper tap reader/punch. - PTP Second serial port of SIO is assumed to be connected to the paper tap reader/punch. - DSK SWTP DC-4 Floppy Disk controller with up to four drives. - -2.1 The CPU Card (MP-A) - - We allow you to select memory sizes, but be aware that some sample software requires the full 32K (i.e. FLEX). We emulate the SWTP SWTBUG boot rom. - - SET CPU ITRAP Causes the simulator to halt if an invalid 8080 Opcode is detected. - SET CPU NOITRAP Does not stop on an invalid Opcode. This is how the real 6800 operates. - SET CPU MTRAP Causes the simulator to halt if an invalid address is accessed. - SET CPU NOMTRAP Does not stop on invalid address access. This is how a real 6800 operates. - SET CPU 4K - SET CPU 8K - SET CPU 12K - SET CPU 16K - ...... - SET CPU 32K All these set various CPU memory configurations. - The 2K EPROM at the high end of memory is always present and will always boot. - SET CPU MA000 Enable 8 K bytes of memory at $A000-$BFFF. Otherwise, only 128 bytes re available at $A000. - SET CPU NOMA000 Enable only 128 bytes of memory at $A000. - -The SWTBUG EPROM maps to both addresses $E000-E3FF and $FC00-FFFF. - -The real 6800, on receiving a HLT (Halt) instruction, freezes the processor and only an interrupt or CPU hardware reset will restore it. The simulator is a lot nicer, it will halt but send you back to the simulator command line. - -CPU Registers include the following: - - name size comments - - PC 16 Program Counter - A 8 Accumulator A - B 8 Accumulator B - IX 16 Index Register - C 1 Carry flag - Z 1 Zero Flag - H 1 Half-Carry flag - I 1 Interrupt flag - N 1 Negative flag - V 1 Overflao Flag - - -2.2 The Serial I/O Card (MP-S) - - 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 SWTP was $8004-8005 for the first port, and $8006-8007 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. - -2.3 The Floppy Disk controller (DC4) - - The SWTP DC4 is a simple programmed I/O interface to the SWTP MF-68 5-inch dual floppy drive, which was basically a pair of Shugart SA-400s 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 $8018-801B, and we follow the standard. Details on controlling this hardware are in the swtp_dsk.c source file. - - -3. Sample Software - - Running an SWTP 6800 in 1978 you would be running the FLEX Version 2.0 Operating System from Technical Systems Consultants, Inc. - -3.1 CP/M Version 2.2 - - This version is a port of the standard FLEX Version 2.0 to the SWTP 6800. - - To boot FLEX: - - sim> set cpu hex - sim> set cpu itrap - sim> set cpu mtrap - sim> att dsk 6800boot.dsk - sim> att dsk1 6800work.dsk - sim> set cpu MA000 - sim> set dsk1 rw - sim> go - - $D ; Capital D causes SWTBUG to boot Flex - FLEX 2.0 - - DATE (MM,DD,YY)? 03,09,99 ; Must enter a date from last century! - - +++ ;Flex prompt! - - - - - - diff --git a/swtp/swtp6800 b/swtp/swtp6800 deleted file mode 100644 index 0c8c2d1d..00000000 --- a/swtp/swtp6800 +++ /dev/null @@ -1,9 +0,0 @@ -reset -set cpu hex -set cpu itrap -set cpu mtrap -att dsk 6800boot.dsk -att dsk1 6800work.dsk -set cpu MA000 -set dsk1 rw -g diff --git a/swtp/swtp_cpu.c b/swtp/swtp_cpu.c deleted file mode 100644 index e93797f9..00000000 --- a/swtp/swtp_cpu.c +++ /dev/null @@ -1,2293 +0,0 @@ -/* swtp_6800_cpu.c: SWTP 6800 Motorola 6800 CPU simulator - - Copyright (c) 2005, 2007, William Beech - - 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 - WILLIAM A. BEECH 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 William A. Beech shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 - - cpu 6800 CPU - - The register state for the 6800 CPU is: - - A<0:7> Accumulator A - B<0:7> Accumulator B - IX<0:15> Index Register - H half-carry flag - I interrupt flag - N negative flag - Z zero flag - V overflow flag - C carry flag - PC<0:15> program counter - SP<0:15> Stack Pointer - - The 6800 is an 8-bit CPU, which uses 16-bit registers to address - up to 64KB of memory. - - The 72 basic instructions come in 1, 2, and 3-byte flavors. - - This routine is the instruction decode routine for the 6800. - 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: - - WAI instruction - I/O error in I/O simulator - Invalid OP code (if ITRAP is set on CPU) - Invalid mamory address (if MTRAP is set on CPU) - - 2. Interrupts. - There are 4 types of interrupt, and in effect they do a - hardware CALL instruction to one of 4 possible high memory addresses. - - 3. Non-existent memory. On the SWTP 6800, reads to non-existent memory - return 0FFH, and writes are ignored. In the simulator, the - largest possible memory is instantiated and initialized to zero. - Thus, only writes need be checked against actual memory size. - - 4. Adding I/O devices. These modules must be modified: - - swtp_6800_cpu.c add I/O service routines to dev_table - swtp_sys.c add pointer to data structures in sim_devices -*/ - -#include - -#include "swtp_defs.h" - -//#include -//#include - -#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ -#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) -#define UNIT_V_MSTOP (UNIT_V_UF+1) /* Stop on Invalid memory? */ -#define UNIT_MSTOP (1 << UNIT_V_MSTOP) -#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_V_MA000 (UNIT_V_UF+2) /* 128B or 8kB at 0xA000 */ -#define UNIT_MA000 (1 << UNIT_V_MA000) - -uint8 M[MAXMEMSIZE]; /* Memory */ -int32 A = 0; /* Accumulator A */ -int32 B = 0; /* Accumulator B */ -int32 IX = 0; /* Index register */ -int32 SP = 0; /* Stack pointer */ -int32 H = 0; /* Half-carry flag */ -int32 I = 1; /* Interrupt flag */ -int32 N = 0; /* Negative flag */ -int32 Z = 0; /* Zero flag */ -int32 V = 0; /* Overflow flag */ -int32 C = 0; /* Carry flag */ -int32 saved_PC = 0; /* Program counter */ -int32 INTE = 0; /* Interrupt Enable */ -int32 int_req = 0; /* Interrupt request */ - -int32 mem_fault = 0; /* memory fault flag */ - -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ;/* breakpoint info */ - -/* 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); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -void dump_regs(); -void go_rel(int32 cond); -int32 get_rel_addr(); -int32 get_dir_val(); -int32 get_dir_addr(); -int32 get_indir_val(); -int32 get_indir_addr(); -int32 get_ext_val(); -int32 get_ext_addr(); -int32 get_psw(); -void set_psw(int32 psw); -void condevalH(int32 res); -void condevalN(int32 res); -void condevalZ(int32 res); -void condevalC(int32 res); -void condevalVa(int32 op1, int32 op2); -void condevalVs(int32 op1, int32 op2); -void mem_put_byte(int32 addr, int32 val); -void mem_put_word(int32 addr, int32 val); -int32 mem_get_byte(int32 addr); -int32 mem_get_word(int32 addr); -int32 nulldev(int32 io, int32 data); - -/* external routines */ - -extern int32 sio0s(int32 io, int32 data); -extern int32 sio0d(int32 io, int32 data); -extern int32 sio1s(int32 io, int32 data); -extern int32 sio1d(int32 io, int32 data); -extern int32 fdcdrv(int32 io, int32 data); -extern int32 fdccmd(int32 io, int32 data); -extern int32 fdctrk(int32 io, int32 data); -extern int32 fdcsec(int32 io, int32 data); -extern int32 fdcdata(int32 io, int32 data); -extern int32 fprint_sym (FILE *of, int32 addr, uint32 *val, - UNIT *uptr, int32 sw); - - -/* This is the I/O configuration table. There are 32 possible -device addresses, if a device is plugged into a port it's routine -address is here, 'nulldev' means no device is available -*/ - -struct idev { - int32 (*routine)(int32, int32); -}; - -struct idev dev_table[32] = { - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 0 8000-8003*/ - {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 1 8004-8007*/ -/* sio1x routines just return the last value read on the matching - sio0x routine. SWTBUG tests for the MP-C with most port reads! */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 2 8008-800B*/ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 3 800C-800F*/ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 4 8010-8013*/ - {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 5 8014-8017*/ - {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /*Port 6 8018-801B*/ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /*Port 7 801C-801F*/ -}; - -/* SWTP 6800 SWTBUG BOOT EPROM, fits at 0E000-0E3FFH and replicated - at 0FC000-0FFFF for the interrupt vectors */ - -#define BOOTLEN 1024 - -int32 bootrom[BOOTLEN] = { -0xFE,0xA0,0x00,0x6E,0x00,0x8D,0x40,0x6E, -0x00,0x10,0x16,0x04,0xBD,0xE3,0x34,0x8D, -0x67,0x81,0x53,0x26,0xFA,0x8D,0x61,0x81, -0x39,0x27,0x29,0x81,0x31,0x26,0xF0,0x7F, -0xA0,0x0F,0x8D,0x31,0x80,0x02,0xB7,0xA0, -0x47,0x8D,0x1C,0x8D,0x28,0x7A,0xA0,0x47, -0x27,0x09,0xA7,0x00,0xA1,0x00,0x26,0x08, -0x08,0x20,0xF0,0x7C,0xA0,0x0F,0x27,0xCF, -0x86,0x3F,0x8D,0x31,0x7E,0xE2,0xD4,0x8D, -0x0C,0xB7,0xA0,0x0D,0x8D,0x07,0xB7,0xA0, -0x0E,0xFE,0xA0,0x0D,0x39,0x8D,0x53,0x48, -0x48,0x48,0x48,0x16,0x8D,0x4C,0x1B,0x16, -0xFB,0xA0,0x0F,0xF7,0xA0,0x0F,0x39,0x44, -0x44,0x44,0x44,0x84,0x0F,0x8B,0x30,0x81, -0x39,0x23,0x02,0x8B,0x07,0x7E,0xE1,0xD1, -0x7E,0xE1,0xAC,0x8D,0xF8,0x08,0xA6,0x00, -0x81,0x04,0x26,0xF7,0x39,0x7E,0xE1,0x4A, -0x8D,0xBD,0xCE,0xE1,0x9D,0x8D,0xEF,0xCE, -0xA0,0x0D,0x8D,0x34,0xFE,0xA0,0x0D,0x8D, -0x31,0x8D,0x31,0x8D,0xDB,0x81,0x20,0x27, -0xFA,0x81,0x0D,0x27,0xE0,0x81,0x5E,0x20, -0x2C,0x01,0x8D,0xCC,0x80,0x30,0x2B,0x4C, -0x81,0x09,0x2F,0x0A,0x81,0x11,0x2B,0x44, -0x81,0x16,0x2E,0x40,0x80,0x07,0x39,0xA6, -0x00,0x8D,0xA4,0xA6,0x00,0x08,0x20,0xA3, -0x8D,0xF5,0x8D,0xF3,0x86,0x20,0x20,0xA5, -0x8E,0xA0,0x42,0x20,0x2C,0x26,0x07,0x09, -0x09,0xFF,0xA0,0x0D,0x20,0xAC,0xFF,0xA0, -0x0D,0x20,0x02,0x20,0x6D,0x81,0x30,0x25, -0xA1,0x81,0x46,0x22,0x9D,0x8D,0xBD,0xBD, -0xE0,0x57,0x09,0xA7,0x00,0xA1,0x00,0x27, -0x91,0x7E,0xE0,0x40,0xBE,0xA0,0x08,0x20, -0x49,0xBF,0xA0,0x08,0x86,0xFF,0xBD,0xE3, -0x08,0xCE,0x80,0x04,0xBD,0xE2,0x84,0xA6, -0x00,0xA1,0x02,0x20,0x02,0x20,0x19,0x26, -0x39,0x86,0x03,0xA7,0x00,0x86,0x11,0xA7, -0x00,0x20,0x2F,0x01,0xBF,0xA0,0x08,0x30, -0x6D,0x06,0x26,0x02,0x6A,0x05,0x6A,0x06, -0xCE,0xE1,0x9D,0xBD,0xE0,0x7E,0xFE,0xA0, -0x08,0x08,0x8D,0x8E,0x8D,0x8C,0x8D,0x8A, -0x8D,0x86,0x8D,0x84,0xCE,0xA0,0x08,0xBD, -0xE0,0xC8,0xFE,0xA0,0x12,0x8C,0xE1,0x23, -0x27,0x19,0x8E,0xA0,0x42,0xCE,0x80,0x04, -0xFF,0xA0,0x0A,0x7F,0xA0,0x0C,0x8D,0x73, -0x27,0x03,0xBD,0xE2,0x7D,0xBD,0xE3,0x53, -0xBD,0xE3,0x47,0xCE,0xE1,0x9C,0xBD,0xE0, -0x7E,0x8D,0x39,0xCE,0xE3,0xD1,0xA1,0x00, -0x26,0x07,0xBD,0xE0,0xCC,0xEE,0x01,0x6E, -0x00,0x08,0x08,0x08,0x8C,0xE3,0xF8,0x26, -0xED,0x20,0xBF,0xFE,0xA0,0x12,0x6E,0x00, -0x53,0x39,0x04,0x0D,0x0A,0x15,0x00,0x00, -0x00,0x53,0x31,0x04,0x13,0x0D,0x0A,0x15, -0x00,0x00,0x00,0x24,0x04,0x20,0x4C,0xFE, -0xA0,0x06,0x6E,0x00,0x20,0x40,0xBD,0xE0, -0x47,0xFF,0xA0,0x04,0xBD,0xE0,0x47,0xBD, -0xE0,0x55,0x16,0xA6,0x00,0xFF,0xA0,0x0D, -0x11,0x27,0x02,0x20,0x21,0xCE,0xE1,0x9D, -0xBD,0xE0,0x7E,0xCE,0xA0,0x0D,0x20,0x10, -0x3B,0x20,0x3A,0xFF,0xA0,0x10,0xFE,0xA0, -0x0A,0x37,0xE6,0x01,0xE1,0x03,0x33,0x39, -0xBD,0xE0,0xC8,0xFE,0xA0,0x0D,0xBC,0xA0, -0x04,0x27,0x9E,0x08,0x20,0xCD,0x8D,0x06, -0x84,0x7F,0x39,0x31,0x31,0x31,0x37,0x8D, -0xDA,0x26,0x28,0x86,0x15,0xA7,0x00,0xA6, -0x00,0x47,0x24,0xFB,0xA6,0x01,0xF6,0xA0, -0x0C,0x27,0x07,0x20,0x11,0x37,0x8D,0xC3, -0x26,0x2E,0xC6,0x11,0xE7,0x00,0xE6,0x00, -0x57,0x57,0x24,0xFA,0xA7,0x01,0x33,0xFE, -0xA0,0x10,0x39,0xA6,0x00,0x2B,0xFC,0x8D, -0x3A,0xC6,0x04,0xE7,0x02,0x58,0x8D,0x2A, -0x0D,0x69,0x00,0x46,0x5A,0x26,0xF7,0x8D, -0x21,0xF6,0xA0,0x0C,0x27,0x13,0x20,0xDE, -0x8D,0x23,0xC6,0x0A,0x6A,0x00,0x8D,0x16, -0x8D,0x10,0xA7,0x00,0x0D,0x46,0x5A,0x26, -0xF7,0xE6,0x02,0x58,0x2A,0xC8,0x8D,0x02, -0x20,0xC4,0x6D,0x02,0x2A,0xFC,0x6C,0x02, -0x6A,0x02,0x39,0x6F,0x02,0x8D,0xF7,0x20, -0xF1,0x8D,0x83,0x16,0x7F,0xA0,0x0B,0xFE, -0xA0,0x0A,0x8D,0x10,0x8D,0x07,0xCE,0xE3, -0xEF,0x17,0x7E,0xE1,0x76,0x86,0x34,0xA7, -0x03,0xA7,0x02,0x39,0x6C,0x00,0x86,0x07, -0xA7,0x01,0x6C,0x00,0xA7,0x02,0x39,0x7F, -0x80,0x14,0x8D,0x2E,0xC6,0x0B,0x8D,0x25, -0xE6,0x04,0xC5,0x01,0x26,0xFA,0x6F,0x06, -0x8D,0x1D,0xC6,0x9C,0x8D,0x17,0xCE,0x24, -0x00,0xC5,0x02,0x27,0x06,0xB6,0x80,0x1B, -0xA7,0x00,0x08,0xF6,0x80,0x18,0xC5,0x01, -0x26,0xEF,0x7E,0x24,0x00,0xE7,0x04,0x8D, -0x00,0x39,0xCE,0xFF,0xFF,0x09,0x8C,0x80, -0x14,0x26,0xFA,0x39,0xCE,0xE0,0x09,0xBD, -0xE0,0x7E,0x8D,0xF1,0xBD,0xE3,0x47,0x20, -0x58,0xCE,0xE1,0x23,0xBC,0xA0,0x12,0x27, -0x1A,0x08,0x8D,0x32,0xBD,0xE0,0x47,0xFF, -0xA0,0x14,0xA6,0x00,0xB7,0xA0,0x16,0x86, -0x3F,0xA7,0x00,0xCE,0xE1,0x23,0x8D,0x1E, -0x7E,0xE1,0x6B,0xFE,0xA0,0x14,0xB6,0xA0, -0x16,0xA7,0x00,0xCE,0xE1,0x24,0x20,0xDA, -0xB7,0xA0,0x43,0xFE,0xA0,0x12,0x8C,0xE1, -0x23,0x27,0x06,0xCE,0xE1,0x24,0xFF,0xA0, -0x12,0x39,0x8D,0x5A,0x20,0x0F,0xCE,0xA0, -0x49,0xFF,0xA0,0x04,0x09,0x8D,0x52,0xCE, -0xE1,0x90,0xBD,0xE0,0x7E,0x8D,0x24,0x8D, -0x91,0x7E,0xE1,0x52,0x73,0xA0,0x0C,0x86, -0x11,0xC6,0x20,0x8D,0x1A,0xBD,0xE1,0xD9, -0x27,0x04,0x86,0x3C,0xA7,0x03,0x39,0x86, -0x13,0xC6,0x10,0x20,0x0A,0x86,0x12,0xC6, -0x04,0x20,0x04,0x86,0x14,0xC6,0x08,0xBD, -0xE0,0x75,0xBD,0xE1,0xD6,0x27,0x16,0x86, -0x02,0xCA,0x01,0x8D,0x0C,0x8D,0x08,0x86, -0x02,0xC6,0x01,0xE7,0x00,0x8D,0x02,0x86, -0x06,0xA7,0x01,0xE7,0x00,0x39,0xFE,0xA0, -0x02,0xFF,0xA0,0x44,0x8D,0xCF,0xB6,0xA0, -0x05,0xB0,0xA0,0x45,0xF6,0xA0,0x04,0xF2, -0xA0,0x44,0x26,0x04,0x81,0x10,0x25,0x02, -0x86,0x0F,0x8B,0x04,0xB7,0xA0,0x47,0x80, -0x03,0xB7,0xA0,0x46,0xCE,0xE1,0x93,0xBD, -0xE0,0x7E,0x5F,0xCE,0xA0,0x47,0x8D,0x24, -0xCE,0xA0,0x44,0x8D,0x1F,0x8D,0x1D,0xFE, -0xA0,0x44,0x8D,0x18,0x7A,0xA0,0x46,0x26, -0xF9,0xFF,0xA0,0x44,0x53,0x37,0x30,0x8D, -0x0B,0x33,0xFE,0xA0,0x44,0x09,0xBC,0xA0, -0x04,0x26,0xB3,0x39,0xEB,0x00,0x7E,0xE0, -0xBF,0x47,0xE1,0xD0,0x5A,0xC0,0x00,0x4D, -0xE0,0x88,0x46,0xE1,0xAE,0x52,0xE1,0x30, -0x4A,0xE0,0x05,0x43,0xE2,0xCC,0x44,0xE2, -0x8F,0x42,0xE2,0xD9,0x4F,0xE2,0x69,0x50, -0xE3,0x1A,0x4C,0xE0,0x0C,0x45,0xE3,0x1E, -0xE0,0x00,0xE1,0x8B,0xE1,0xA7,0xE0,0xD0 -}; - -/* 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, - 32768) }; - -REG cpu_reg[] = { - { HRDATA (PC, saved_PC, 16) }, - { HRDATA (A, A, 8) }, - { HRDATA (B, B, 8) }, - { HRDATA (IX, IX, 16) }, - { HRDATA (SP, SP, 16) }, - { FLDATA (H, H, 16) }, - { FLDATA (I, I, 16) }, - { FLDATA (N, N, 16) }, - { FLDATA (Z, Z, 16) }, - { FLDATA (V, V, 16) }, - { FLDATA (C, C, 16) }, - { FLDATA (INTE, INTE, 16) }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } }; - -MTAB cpu_mod[] = { - { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, - { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, - { UNIT_MSTOP, UNIT_MSTOP, "MTRAP", "MTRAP", NULL }, - { UNIT_MSTOP, 0, "NOMTRAP", "NOMTRAP", NULL }, - { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, - { UNIT_MA000, UNIT_MA000, "MA000", "MA000", NULL }, - { UNIT_MA000, 0, "NOMA000", "NOMA000", NULL }, - { 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 }; - -int32 PC; /* global for the helper routines */ - -int32 sim_instr (void) -{ - extern int32 sim_interval; - int32 IR, OP, DAR, reason, hi, lo, op1; -// uint32 val1[3]; - - PC = saved_PC & ADDRMASK; /* load local PC */ - reason = 0; - - /* Main instruction fetch/decode loop */ - - while (reason == 0) { /* loop until halted */ - if (sim_interval <= 0) /* check clock queue */ - if (reason = sim_process_event ()) - break; - if (mem_fault) { /* memory fault? */ - mem_fault = 0; /* reset fault flag */ - reason = STOP_MEMORY; - break; - } - if (int_req > 0) { /* interrupt? */ - /* 6800 interrupts not implemented yet. None were used, - on a standard SWTP 6800. All I/O is programmed. */ - } /* end interrupt */ - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - /* transient routine area - trace */ - /* - if (PC >= 0xa100 && PC < 0xa400) { - dump_regs(); - printf("\n\r%04X: ", PC); - val1[0] = M[PC]; - val1[1] = M[PC+1]; - val1[2] = M[PC+2]; - fprint_sym(stdout, PC, val1, NULL, SWMASK ('M')); - } -*/ - IR = OP = mem_get_byte(PC); /* fetch instruction */ - PC = (PC + 1) & ADDRMASK; /* increment PC */ - sim_interval--; - - /* The Big Instruction Decode Switch */ - - switch (IR) { - - case 0x01: /* NOP */ - break; - case 0x06: /* TAP */ - set_psw(A); - break; - case 0x07: /* TPA */ - A = get_psw(); - break; - case 0x08: /* INX */ - IX = (IX + 1) & ADDRMASK; - condevalZ(IX); - break; - case 0x09: /* DEX */ - IX = (IX - 1) & ADDRMASK; - condevalZ(IX); - break; - case 0x0A: /* CLV */ - V = 0; - break; - case 0x0B: /* SEV */ - V = 0x10000; - break; - case 0x0C: /* CLC */ - C = 0; - break; - case 0x0D: /* SEC */ - C = 0x10000; - break; - case 0x0E: /* CLI */ - I = 0; - break; - case 0x0F: /* SEI */ - I = 0x10000; - break; - case 0x10: /* SBA */ - op1 = A; - A = A - B; - condevalN(A); - condevalZ(A); - condevalC(A); - condevalVs(B, op1); - A &= 0xFF; - break; - case 0x11: /* CBA */ - lo = A - B; - condevalN(lo); - condevalZ(lo); - condevalC(lo); - condevalVs(B, A); - break; - case 0x16: /* TAB */ - B = A; - condevalN(B); - condevalZ(B); - V = 0; - break; - case 0x17: /* TBA */ - A = B; - condevalN(B); - condevalZ(B); - V = 0; - break; - case 0x19: /* DAA */ - DAR = A & 0x0F; - op1 = C; - if (DAR > 9 || C) { - DAR += 6; - A &= 0xF0; - A |= DAR & 0x0F; - C = 0; - if (DAR & 0x10) - C = 0x10000; - } - DAR = (A >> 4) & 0x0F; - if (DAR > 9 || C) { - DAR += 6; - if (C) - DAR++; - A &= 0x0F; - A |= (DAR << 4); - } - C = op1; - if ((DAR << 4) & 0x100) - C = 0x10000; - condevalN(A); - condevalZ(A); - A &= 0xFF; - break; - case 0x1B: /* ABA */ - A += B; - condevalH(A); - condevalN(A); - condevalZ(A); - condevalC(A); - condevalVa(A, B); - A &= 0xFF; - break; - case 0x20: /* BRA rel */ - go_rel(1); - break; - case 0x22: /* BHI rel */ - go_rel(!(C | Z)); - break; - case 0x23: /* BLS rel */ - go_rel(C | Z); - break; - case 0x24: /* BCC rel */ - go_rel(!C); - break; - case 0x25: /* BCS rel */ - go_rel(C); - break; - case 0x26: /* BNE rel */ - go_rel(!Z); - break; - case 0x27: /* BEQ rel */ - go_rel(Z); - break; - case 0x28: /* BVC rel */ - go_rel(!V); - break; - case 0x29: /* BVS rel */ - go_rel(V); - break; - case 0x2A: /* BPL rel */ - go_rel(!N); - break; - case 0x2B: /* BMI rel */ - go_rel(N); - break; - case 0x2C: /* BGE rel */ - go_rel(!(N ^ V)); - break; - case 0x2D: /* BLT rel */ - go_rel(N ^ V); - break; - case 0x2E: /* BGT rel */ - go_rel(!(Z | (N ^ V))); - break; - case 0x2F: /* BLE rel */ - go_rel(Z | (N ^ V)); - break; - case 0x30: /* TSX */ - IX = (SP + 1) & ADDRMASK; - break; - case 0x31: /* INS */ - SP = (SP + 1) & ADDRMASK; - break; - case 0x32: /* PUL A */ - SP = (SP + 1) & ADDRMASK; - A = mem_get_byte(SP); - break; - case 0x33: /* PUL B */ - SP = (SP + 1) & ADDRMASK; - B = mem_get_byte(SP); - break; - case 0x34: /* DES */ - SP = (SP - 1) & ADDRMASK; - break; - case 0x35: /* TXS */ - SP = (IX - 1) & ADDRMASK; - break; - case 0x36: /* PSH A */ - mem_put_byte(SP, A); - SP = (SP - 1) & ADDRMASK; - break; - case 0x37: /* PSH B */ - mem_put_byte(SP, B); - SP = (SP - 1) & ADDRMASK; - break; - case 0x39: /* RTS */ - SP = (SP + 1) & ADDRMASK; - PC = mem_get_word(SP) & ADDRMASK; - SP = (SP + 1) & ADDRMASK; - break; - case 0x3B: /* RTI */ - SP = (SP + 1) & ADDRMASK; - set_psw(mem_get_byte(SP)); - SP = (SP + 1) & ADDRMASK; - B = mem_get_byte(SP); - SP = (SP + 1) & ADDRMASK; - A = mem_get_byte(SP); - SP = (SP + 1) & ADDRMASK; - IX = mem_get_word(SP); - SP = (SP + 2) & ADDRMASK; - PC = mem_get_word(SP) & ADDRMASK; - SP = (SP + 1) & ADDRMASK; - break; - case 0x3E: /* WAI */ - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 2) & ADDRMASK; - mem_put_word(SP, IX); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, A); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, B); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, get_psw()); - SP = (SP - 1) & ADDRMASK; - if (I) { - reason = STOP_HALT; - continue; - } else { - I = 0x10000; - PC = mem_get_word(0xFFFE) & ADDRMASK; - } - break; - case 0x3F: /* SWI */ - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 2) & ADDRMASK; - mem_put_word(SP, IX); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, A); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, B); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, get_psw()); - SP = (SP - 1) & ADDRMASK; - I = 0x10000; - PC = mem_get_word(0xFFFB) & ADDRMASK; - break; - case 0x40: /* NEG A */ - A = (0 - A) & 0xFF; - V = 0; - if (A & 0x80) - V = 0x10000; - C = 0; - if (A) - C = 0x10000; - condevalN(A); - condevalZ(A); - break; - case 0x43: /* COM A */ - A = ~A & 0xFF; - V = 0; - C = 0x10000; - condevalN(A); - condevalZ(A); - break; - case 0x44: /* LSR A */ - C = 0; - if (A & 0x01) - C = 0x10000; - A = (A >> 1) & 0xFF; - N = 0; - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x46: /* ROR A */ - hi = C; - C = 0; - if (A & 0x01) - C = 0x10000; - A = (A >> 1) & 0xFF; - if (hi) - A |= 0x80; - condevalN(A); - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x47: /* ASR A */ - C = 0; - if (A & 0x01) - C = 0x10000; - lo = A & 0x8000; - A = (A >> 1) & 0xFF; - A |= lo; - condevalN(A); - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x48: /* ASL A */ - C = 0; - if (A & 0x80) - C = 0x10000; - A = (A << 1) & 0xFF; - condevalN(A); - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x49: /* ROL A */ - hi = C; - C = 0; - if (A & 0x80) - C = 0x10000; - A = (A << 1) & 0xFF; - if (hi) - A |= 0x01; - condevalN(A); - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x4A: /* DEC A */ - V = 0; - if (A == 0x80) - V = 0x10000; - A = (A - 1) & 0xFF; - condevalN(A); - condevalZ(A); - break; - case 0x4C: /* INC A */ - V = 0; - if (A == 0x7F) - V = 0x10000; - A = (A + 1) & 0xFF; - condevalN(A); - condevalZ(A); - break; - case 0x4D: /* TST A */ - lo = (A - 0) & 0xFF; - V = 0; - C = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x4F: /* CLR A */ - A = 0; - N = V = C = 0; - Z = 0x10000; - break; - case 0x50: /* NEG B */ - B = (0 - V) & 0xFF; - V = 0; - if (B & 0x8000) - V = 0x10000; - C = 0; - if (B) - C = 0x10000; - condevalN(B); - condevalZ(B); - break; - case 0x53: /* COM B */ - B = ~B & 0xFF; - V = 0; - C = 0x10000; - condevalN(B); - condevalZ(B); - break; - case 0x54: /* LSR B */ - C = 0; - if (B & 0x01) - C = 0x10000; - B = (B >> 1) & 0xFF; - N = 0; - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x56: /* ROR B */ - hi = C; - C = 0; - if (B & 0x01) - C = 0x10000; - B = (B >> 1) & 0xFF; - if (hi) - B |= 0x80; - condevalN(B); - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x57: /* ASR B */ - C = 0; - if (B & 0x01) - C = 0x10000; - lo = B & 0x8000; - B = (B >> 1) & 0xFF; - B |= lo; - condevalN(B); - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x58: /* ASL B */ - C = 0; - if (B & 0x80) - C = 0x10000; - B = (B << 1) & 0xFF; - condevalN(B); - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x59: /* ROL B */ - hi = C; - C = 0; - if (B & 0x80) - C = 0x10000; - B = (B << 1) & 0xFF; - if (hi) - B |= 0x01; - condevalN(B); - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x5A: /* DEC B */ - V = 0; - if (B == 0x80) - V = 0x10000; - B = (B - 1) & 0xFF; - condevalN(B); - condevalZ(B); - break; - case 0x5C: /* INC B */ - V = 0; - if (B == 0x7F) - V = 0x10000; - B = (B + 1) & 0xFF; - condevalN(B); - condevalZ(B); - break; - case 0x5D: /* TST B */ - lo = (B - 0) & 0xFF; - V = 0; - C = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x5F: /* CLR B */ - B = 0; - N = V = C = 0; - Z = 0x10000; - break; - case 0x60: /* NEG ind */ - DAR = get_indir_addr(); - lo = (0 - mem_get_byte(DAR)) & 0xFF; - mem_put_byte(DAR, lo); - V = 0; - if (lo & 0x80) - V = 0x10000; - C = 0; - if (lo) - C = 0x10000; - condevalN(lo); - condevalZ(lo); - break; - case 0x63: /* COM ind */ - DAR = get_indir_addr(); - lo = ~mem_get_byte(DAR) & 0xFF; - mem_put_byte(DAR, lo); - V = 0; - C = 0x10000; - condevalN(lo); - condevalZ(lo); - break; - case 0x64: /* LSR ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - lo >>= 1; - mem_put_byte(DAR, lo); - N = 0; - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x66: /* ROR ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - hi = C; - C = 0; - if (lo & 0x01) - C = 0x10000; - lo >>= 1; - if (hi) - lo |= 0x80; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x67: /* ASR ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - lo = (lo & 0x80) | (lo >> 1); - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x68: /* ASL ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x80) - C = 0x10000; - lo <<= 1; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x69: /* ROL ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - hi = C; - C = 0; - if (lo & 0x80) - C = 0x10000; - lo <<= 1; - if (hi) - lo |= 0x01; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x6A: /* DEC ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - V = 0; - if (lo == 0x80) - V = 0x10000; - lo = (lo - 1) & 0xFF; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - break; - case 0x6C: /* INC ind */ - DAR= get_indir_addr(); - lo = mem_get_byte(DAR); - V = 0; - if (lo == 0x7F) - V = 0x10000; - lo = (lo + 1) & 0xFF; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - break; - case 0x6D: /* TST ind */ - lo = (get_indir_val() - 0) & 0xFF; - V = 0; - C = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x6E: /* JMP ind */ - PC = get_indir_addr(); - break; - case 0x6F: /* CLR ind */ - mem_put_byte(get_indir_addr(), 0); - N = V = C = 0; - Z = 0x10000; - break; - case 0x70: /* NEG ext */ - DAR = get_ext_addr(PC); - lo = (0 - mem_get_byte(DAR)) & 0xFF; - mem_put_byte(DAR, lo); - V = 0; - if (lo & 0x80) - V = 0x10000; - C = 0; - if (lo) - C = 0x10000; - condevalN(lo); - condevalZ(lo); - break; - case 0x73: /* COM ext */ - DAR = get_ext_addr(); - lo = ~mem_get_byte(DAR) & 0xFF; - mem_put_byte(DAR, lo); - V = 0; - C = 0x10000; - condevalN(lo); - condevalZ(lo); - break; - case 0x74: /* LSR ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - lo >>= 1; - mem_put_byte(DAR, lo); - N = 0; - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x76: /* ROR ext */ - DAR = get_ext_addr(); - hi = C; - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - lo >>= 1; - if (hi) - lo |= 0x80; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x77: /* ASR ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - hi = lo & 0x80; - lo >>= 1; - lo |= hi; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x78: /* ASL ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x80) - C = 0x10000; - lo <<= 1; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x79: /* ROL ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - hi = C; - C = 0; - if (lo & 0x80) - C = 0x10000; - lo <<= 1; - if (hi) - lo |= 0x01; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x7A: /* DEC ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - V = 0; - if (lo == 0x80) - V = 0x10000; - lo = (lo - 1) & 0xFF; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - break; - case 0x7C: /* INC ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - V = 0; - if (lo == 0x7F) - V = 0x10000; - lo = (lo + 1) & 0xFF; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - break; - case 0x7D: /* TST ext */ - lo = mem_get_byte(get_ext_addr()) - 0; - V = 0; - C = 0; - condevalN(lo); - condevalZ(lo & 0xFF); - break; - case 0x7E: /* JMP ext */ - PC = get_ext_addr() & ADDRMASK; - break; - case 0x7F: /* CLR ext */ - mem_put_byte(get_ext_addr(), 0); - N = V = C = 0; - Z = 0x10000; - break; - case 0x80: /* SUB A imm */ - op1 = get_dir_addr(); - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x81: /* CMP A imm */ - op1 = get_dir_addr(); - lo = A - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(lo, op1); - break; - case 0x82: /* SBC A imm */ - op1 = get_dir_addr(); - if (C) - A = A - op1 - 1; - else - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x84: /* AND A imm */ - A = (A & get_dir_addr()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x85: /* BIT A imm */ - lo = (A & get_dir_addr()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x86: /* LDA A imm */ - A = get_dir_addr(); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x88: /* EOR A imm */ - A = (A ^ get_dir_addr()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x89: /* ADC A imm */ - op1 = get_dir_addr(); - if (C) - A = A + op1 + 1; - else - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x8A: /* ORA A imm */ - A = (A | get_dir_addr()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x8B: /* ADD A imm */ - op1 = get_dir_addr(); - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x8C: /* CPX imm */ - op1 = IX - get_ext_addr(); - condevalZ(op1); - condevalN(op1 >> 8); - V = op1 & 0x10000; - break; - case 0x8D: /* BSR rel */ - lo = get_rel_addr(); - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 1) & ADDRMASK; - PC = PC + lo; - PC &= ADDRMASK; - break; - case 0x8E: /* LDS imm */ - SP = get_ext_addr(); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0x90: /* SUB A dir */ - op1 = get_dir_val(); - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x91: /* CMP A dir */ - op1 = get_dir_val(); - lo = A - op1; - condevalN(lo); - condevalZ(lo & 0xff); - condevalC(lo); - condevalVs(A, op1); - break; - case 0x92: /* SBC A dir */ - op1 = get_dir_val(); - if (C) - A = A - op1 - 1; - else - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x94: /* AND A dir */ - A = (A & get_dir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x95: /* BIT A dir */ - lo = (A & get_dir_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x96: /* LDA A dir */ - A = get_dir_val(); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x97: /* STA A dir */ - mem_put_byte(get_dir_addr(), A); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x98: /* EOR A dir */ - A = (A ^ get_dir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x99: /* ADC A dir */ - op1 = get_dir_val(); - if (C) - A = A + op1 + 1; - else - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x9A: /* ORA A dir */ - A = (A | get_dir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x9B: /* ADD A dir */ - op1 = get_dir_val(); - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x9C: /* CPX dir */ - op1 = IX - mem_get_word(get_dir_addr()); - condevalZ(op1); - condevalN(op1 >> 8); - V = op1 & 0x10000; - break; - case 0x9E: /* LDS dir */ - SP = mem_get_word(get_dir_addr()); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0x9F: /* STS dir */ - mem_put_word(get_dir_addr(), SP); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xA0: /* SUB A ind */ - op1 = get_indir_val(); - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xA1: /* CMP A ind */ - op1 = get_indir_val(); - lo = A - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(A, op1); - break; - case 0xA2: /* SBC A ind */ - op1 = get_indir_val(); - if (C) - A = A - op1 - 1; - else - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xA4: /* AND A ind */ - A = (A & get_indir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xA5: /* BIT A ind */ - lo = (A & get_indir_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xA6: /* LDA A ind */ - A = get_indir_val(); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xA7: /* STA A ind */ - mem_put_byte(get_indir_addr(), A); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xA8: /* EOR A ind */ - A = (A ^ get_indir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xA9: /* ADC A ind */ - op1 = get_indir_val(); - if (C) - A = A + op1 + 1; - else - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xAA: /* ORA A ind */ - A = (A | get_indir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xAB: /* ADD A ind */ - op1 = get_indir_val(); - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xAC: /* CPX ind */ - op1 = (IX - get_indir_addr()) & ADDRMASK; - condevalZ(op1); - condevalN(op1 >> 8); - V = op1 & 0x10000; - break; - case 0xAD: /* JSR ind */ - DAR = get_indir_addr(); - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 1) & ADDRMASK; - PC = DAR; - break; - case 0xAE: /* LDS ind */ - SP = mem_get_word(get_indir_addr()); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xAF: /* STS ind */ - mem_put_word(get_indir_addr(), SP); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xB0: /* SUB A ext */ - op1 = get_ext_val(); - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xB1: /* CMP A ext */ - op1 = get_ext_val(); - lo = A - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(A, op1); - break; - case 0xB2: /* SBC A ext */ - op1 = get_ext_val(); - if (C) - A = A - op1 - 1; - else - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xB4: /* AND A ext */ - A = (A & get_ext_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xB5: /* BIT A ext */ - lo = (A & get_ext_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xB6: /* LDA A ext */ - A = get_ext_val(); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xB7: /* STA A ext */ - mem_put_byte(get_ext_addr(), A); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xB8: /* EOR A ext */ - A = (A ^ get_ext_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xB9: /* ADC A ext */ - op1 = get_ext_val(); - if (C) - A = A + op1 + 1; - else - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xBA: /* ORA A ext */ - A = (A | get_ext_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xBB: /* ADD A ext */ - op1 = get_ext_val(); - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xBC: /* CPX ext */ - op1 = (IX - mem_get_word(get_ext_addr())) & ADDRMASK; - condevalZ(op1); - condevalN(op1 >> 8); - V = op1 & 0x10000; - break; - case 0xBD: /* JSR ext */ - DAR = get_ext_addr(); - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 1) & ADDRMASK; - PC = DAR; - break; - case 0xBE: /* LDS ext */ - SP = mem_get_word(get_ext_addr()); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xBF: /* STS ext */ - mem_put_word(get_ext_addr(), SP); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xC0: /* SUB B imm */ - op1 = get_dir_addr(); - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xC1: /* CMP B imm */ - op1 = get_dir_addr(); - lo = B - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(B, op1); - break; - case 0xC2: /* SBC B imm */ - op1 = get_dir_addr(); - if (C) - B = B - op1 - 1; - else - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xC4: /* AND B imm */ - B = (B & get_dir_addr()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xC5: /* BIT B imm */ - lo = (B & get_dir_addr()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xC6: /* LDA B imm */ - B = get_dir_addr(); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xC8: /* EOR B imm */ - B = (B ^ get_dir_addr()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xC9: /* ADC B imm */ - op1 = get_dir_addr(); - if (C) - B = B + op1 + 1; - else - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xCA: /* ORA B imm */ - B = (B | get_dir_addr()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xCB: /* ADD B imm */ - op1 = get_dir_addr(); - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xCE: /* LDX imm */ - IX = get_ext_addr(); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xD0: /* SUB B dir */ - op1 = get_dir_val(); - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xD1: /* CMP B dir */ - op1 = get_dir_val(); - lo = B - op1; - condevalN(lo); - condevalZ(lo); - condevalC(lo); - condevalVs(B, op1); - break; - case 0xD2: /* SBC B dir */ - op1 = get_dir_val(); - if (C) - B = B - op1 - 1; - else - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xD4: /* AND B dir */ - B = (B & get_dir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xD5: /* BIT B dir */ - lo = (B & get_dir_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xD6: /* LDA B dir */ - B = get_dir_val(); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xD7: /* STA B dir */ - mem_put_byte(get_dir_addr(), B); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xD8: /* EOR B dir */ - B = (B ^ get_dir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xD9: /* ADC B dir */ - op1 = get_dir_val(); - if (C) - B = B + op1 + 1; - else - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xDA: /* ORA B dir */ - B = (B | get_dir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xDB: /* ADD B dir */ - op1 = get_dir_val(); - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xDE: /* LDX dir */ - IX = mem_get_word(get_dir_addr()); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xDF: /* STX dir */ - mem_put_word(get_dir_addr(), IX); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xE0: /* SUB B ind */ - op1 = get_indir_val(); - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xE1: /* CMP B ind */ - op1 = get_indir_val(); - lo = B - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(B, op1); - break; - case 0xE2: /* SBC B ind */ - op1 = get_indir_val(); - if (C) - B = B - op1 - 1; - else - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xE4: /* AND B ind */ - B = (B & get_indir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xE5: /* BIT B ind */ - lo = (B & get_indir_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xE6: /* LDA B ind */ - B = get_indir_val(); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xE7: /* STA B ind */ - mem_put_byte(get_indir_addr(), B); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xE8: /* EOR B ind */ - B = (B ^ get_indir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xE9: /* ADC B ind */ - op1 = get_indir_val(); - if (C) - B = B + op1 + 1; - else - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xEA: /* ORA B ind */ - B = (B | get_indir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xEB: /* ADD B ind */ - op1 = get_indir_val(); - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xEE: /* LDX ind */ - IX = mem_get_word(get_indir_addr()); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xEF: /* STX ind */ - mem_put_word(get_indir_addr(), IX); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xF0: /* SUB B ext */ - op1 = get_ext_val(); - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xF1: /* CMP B ext */ - op1 = get_ext_val(); - lo = B - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(B, op1); - break; - case 0xF2: /* SBC B ext */ - op1 = get_ext_val(); - if (C) - B = B - op1 - 1; - else - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xF4: /* AND B ext */ - B = (B & get_ext_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xF5: /* BIT B ext */ - lo = (B & get_ext_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xF6: /* LDA B ext */ - B = get_ext_val(); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xF7: /* STA B ext */ - mem_put_byte(get_ext_addr(), B); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xF8: /* EOR B ext */ - B = (B ^ get_ext_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xF9: /* ADC B ext */ - op1 = get_ext_val(); - if (C) - B = B + op1 + 1; - else - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xFA: /* ORA B ext */ - B = (B | get_ext_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xFB: /* ADD B ext */ - op1 = get_ext_val(); - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xFE: /* LDX ext */ - IX = mem_get_word(get_ext_addr()); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xFF: /* STX ext */ - mem_put_word(get_ext_addr(), IX); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - - default: { /* Unassigned */ - if (cpu_unit.flags & UNIT_OPSTOP) { - reason = STOP_OPCODE; - PC--; - } - break; - } - } - } - /* Simulation halted - lets dump all the registers! */ - dump_regs(); - saved_PC = PC; - return reason; -} - -/* dump the working registers */ - -void dump_regs() -{ - printf("\r\nPC=%04X SP=%04X IX=%04X ", PC, SP, IX); - printf("A=%02X B=%02X PSW=%02X", A, B, get_psw()); -} - -/* this routine does the jump to relative offset if the condition is - met. Otherwise, execution continues at the current PC. */ - -void go_rel(int32 cond) -{ - int32 temp; - - temp = get_rel_addr(); - if (cond) - PC += temp; - PC &= ADDRMASK; -} - -/* returns the relative offset sign-extended */ - -int32 get_rel_addr() -{ - int32 temp; - - temp = mem_get_byte(PC++); - if (temp & 0x80) - temp |= 0xFF00; - return temp & ADDRMASK; -} - -/* returns the value at the direct address pointed to by PC */ - -int32 get_dir_val() -{ - return mem_get_byte(get_dir_addr()); -} - -/* returns the direct address pointed to by PC */ - -int32 get_dir_addr() -{ - int32 temp; - - temp = mem_get_byte(PC); - PC = (PC + 1) & ADDRMASK; - return temp & 0xFF; -} - -/* returns the value at the indirect address pointed to by PC */ - -int32 get_indir_val() -{ - return mem_get_byte(get_indir_addr()); -} - -/* returns the indirect address pointed to by PC or immediate byte */ - -int32 get_indir_addr() -{ - int32 temp; - - temp = (mem_get_byte(PC++) + IX) & ADDRMASK; - PC &= ADDRMASK; - return temp; -} - -/* returns the value at the extended address pointed to by PC */ - -int32 get_ext_val() -{ - return mem_get_byte(get_ext_addr()); -} - -/* returns the extended address pointed to by PC or immediate word */ - -int32 get_ext_addr() -{ - int32 temp; - - temp = (mem_get_byte(PC) << 8) | mem_get_byte(PC+1); - PC = (PC +2) & ADDRMASK; - return temp; -} - -/* return a PSW from the current flags */ - -int32 get_psw() -{ - int32 psw; - - psw = 0xC0; - if (H) - psw |= 0x20; - if (I) - psw |= 0x10; - if (N) - psw |= 0x08; - if (Z) - psw |= 0x04; - if (V) - psw |= 0x02; - if (C) - psw |= 0x01; - return psw; -} - -/* set the current flags from a PSW */ - -void set_psw(int32 psw) -{ - H = 0; - if (psw & 0x20) - H = 0x10000; - I = 0; - if (psw & 0x10) - I = 0x10000; - N = 0; - if (psw & 0x08) - N = 0x10000; - Z = 0; - if (psw & 0x04) - Z = 0x10000; - V = 0; - if (psw & 0x02) - V = 0x10000; - C = 0; - if (psw & 0x01) - C = 0x10000; -} - -/* test and set H */ - -void condevalH(int32 res) -{ - H = (res & 0x10) << 12; -} - -/* test and set N */ - -void condevalN(int32 res) -{ - N = 0; - if (res & 0x80) - N = 0x10000; -} - -/* test and set Z */ - -void condevalZ(int32 res) -{ - Z = 0; - if (res == 0) - Z = 0x10000; -} - -/* test and set V for addition */ - -void condevalVa(int32 op1, int32 op2) -{ - if (C) { - V = 0; - if (((op1 & 0x80) && (op2 & 0x80)) || - (((op1 & 0x80) == 0) && ((op2 & 0x80) == 0))) - V = 0x10000; - } -} - -/* test and set V for subtraction */ - -void condevalVs(int32 op1, int32 op2) -{ - if (C) { - V = 0; - if (((op1 & 0x80) && ((op2 & 0x80) == 0)) || - (((op1 & 0x80) == 0) && (op2 & 0x80))) - V = 0x10000; - } -} - -/* test and set C */ - -void condevalC(int32 res) -{ - C = (res & 0x100) << 8; -} - -/* memory write operations */ - -/* put word */ - -void mem_put_word(int32 addr, int32 val) -{ - mem_put_byte(addr,val >> 8); - mem_put_byte(addr + 1, val); -} - -/* put byte */ - -void mem_put_byte(int32 addr, int32 val) -{ - if (addr >= 0x0000 && addr < (int32) MEMSIZE) /* memory cards */ - M[addr] = val & 0xFF; - else if (addr >= 0x8000 && addr < 0x8020) /* memory mapped I/O */ - dev_table[addr - 0x8000].routine(1, val); - else if (addr >= 0xA000 && addr < 0xA080) /* CPU memory */ - M[addr] = val & 0xFF; - else if ((addr >= 0xA080 && addr < 0xC000) && /* extended CPU memory */ - cpu_unit.flags & UNIT_MA000) - M[addr] = val & 0xFF; - else { - if (cpu_unit.flags & UNIT_MSTOP) - mem_fault = 1; - printf("Invalid write to %04X\n\r", addr); - } -} - -/* memory read operations */ - -/* get word */ - -int32 mem_get_word(int32 addr) -{ - int32 temp; - - temp = (mem_get_byte(addr) << 8) | mem_get_byte(addr+1); - return temp; -} - -/* get byte */ - -int32 mem_get_byte(int32 addr) -{ - int32 val; - - if (addr >= 0x0000 && addr < (int32) MEMSIZE) /* memory cards */ - val = M[addr]; - else if (addr >= 0x8000 && addr < 0x8020) /* memory mapped I/O */ - val = dev_table[addr - 0x8000].routine(0, 0); - else if (addr >= 0xA000 && addr < 0xA080) /* CPU memory */ - val = M[addr]; - else if ((addr >= 0xA080 && addr < 0xC000) && /* extended CPU memory */ - cpu_unit.flags & UNIT_MA000) - val = M[addr]; - else if (addr >= 0xE000 && addr < 0x10000) /* ROM memory */ - val = M[addr]; - else { - if (cpu_unit.flags & UNIT_MSTOP) - mem_fault = 1; - val = 0xFF; /* default for no memory at address */ - printf("Invalid read of %04X\n\r", addr); - } - return val & 0xFF; -} - -/* calls from the simulator */ - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ - int i; - - I = 0x10000; - saved_PC = (M[0xFFFE] << 8) | M[0xFFFF]; - int_req = 0; - sim_brk_types = sim_brk_dflt = SWMASK ('E'); - /* copy in rom image at E000 */ - for (i = 0; i < BOOTLEN; i++) { - M[i + 0xE000] = bootrom[i] & 0xFF; - } - /* copy in rom image at FC00 for vectors! */ - for (i = 0; i < BOOTLEN; i++) { - M[i + 0xFC00] = bootrom[i] & 0xFF; - } - return SCPE_OK; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ - if (addr >= MAXMEMSIZE) - return SCPE_NXM; - if (vptr != NULL) - *vptr = mem_get_byte(addr); - return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ - if (addr >= MAXMEMSIZE) - return SCPE_NXM; - mem_put_byte(addr, val); -// printf("Deposit to %04X of %02X\n\r", addr, val); - return SCPE_OK; -} - -/* adjust the memory size for the emulator 4k to 32k in 4k steps */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - int32 mc = 0; - uint32 i; - - if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 0x0FFF) != 0)) - return SCPE_ARG; - for (i = val; i < MEMSIZE; i++) - mc = mc | M[i]; - if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) - return SCPE_OK; - MEMSIZE = val; - return SCPE_OK; -} - -/* dummy i/o device */ - -int32 nulldev(int32 io, int32 data) -{ - if (io == 0) - return (0xFF); - return 0; -} - diff --git a/swtp/swtp_dsk.c b/swtp/swtp_dsk.c deleted file mode 100644 index 9c8c7d38..00000000 --- a/swtp/swtp_dsk.c +++ /dev/null @@ -1,506 +0,0 @@ -/* swtp_dc4_dsk.c: SWTP DC-4 DISK Simulator - - Copyright (c) 2005, William A. Beech - - 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 William A. Beech shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 - - - The DC-4 is a 5-inch floppy controller which can control up - to 4 daisy-chained 5-inch floppy drives. The controller is based on - the Western Digital 1797 Floppy Disk Controller (FDC) chip. This - file only emulates the minimum DC-4 functionality to interface with - the virtual disk file. - - The floppy controller is interfaced to the CPU by use of 5 memory - addreses. These are device numbers 5 and 6 (0x8014-0x801B). - - Address Mode Function - ------- ---- -------- - - 0x8014 Read Returns FDC interrupt status - 0x8014 Write Selects the drive/head/motor control - 0x8018 Read Returns status of FDC - 0x8018 Write FDC command register - 0x8019 Read Returns FDC track register - 0x8019 Write Set FDC track register - 0x801A Read Returns FDC sector register - 0x801A Write Set FDC sector register - 0x801B Read Read data - 0x801B Write Write data - - Drive Select Read (0x8014): - - +---+---+---+---+---+---+---+---+ - | I | D | X | X | X | X | X | X | - +---+---+---+---+---+---+---+---+ - - I = Set indicates an interrupt request from the FDC pending. - D = DRQ pending - same as bit 1 of FDC status register. - - Drive Select Write (0x8014): - - +---+---+---+---+---+---+---+---+ - | M | S | X | X | X | X | Device| - +---+---+---+---+---+---+---+---+ - - M = If this bit is 1, the one-shot is triggered/retriggered to - start/keep the motors on. - S = Side select. If set, side one is selected otherwise side zero - is selected. - X = not used - Device = value 0 thru 3, selects drive 0-3 to be controlled. - - Drive Status Read (0x8018): - - +---+---+---+---+---+---+---+---+ - | R | P | H | S | C | L | D | B | - +---+---+---+---+---+---+---+---+ - - B - When 1, the controller is busy. - D - When 1, index mark detected (type I) or data request - read data - ready/write data empty (type II or III). - H - When 1, track 0 (type I) or lost data (type II or III). - C - When 1, crc error detected. - S - When 1, seek (type I) or RNF (type II or III) error. - H - When 1, head is currently loaded (type I) or record type/ - write fault (type II or III). - P - When 1, indicates that diskette is write-protected. - R - When 1, drive is not ready. - - Drive Control Write (0x8018) for type I commands: - - +---+---+---+---+---+---+---+---+ - | 0 | S2| S1| S0| H | V | R1| R0| - +---+---+---+---+---+---+---+---+ - - R0/R1 - Selects the step rate. - V - When 1, verify on destination track. - H - When 1, loads head to drive surface. - S0/S1/S2 = 000 - home. - 001 - seek track in data register. - 010 - step without updating track register. - 011 - step and update track register. - 100 - step in without updating track register. - 101 - step in and update track register. - 110 - step out without updating track register. - 111 - step out and update track register. - - Drive Control Write (0x8018) for type II commands: - - +---+---+---+---+---+---+---+---+ - | 1 | 0 | T | M | S | E | B | A | - +---+---+---+---+---+---+---+---+ - - A - Zero for read, 1 on write deleted data mark else data mark. - B - When 1, shifts sector length field definitions one place. - E - When, delay operation 15 ms, 0 no delay. - S - When 1, select side 1, 0 select side 0. - M - When 1, multiple records, 0 for single record. - T - When 1, write command, 0 for read. - - Drive Control Write (0x8018) for type III commands: - - +---+---+---+---+---+---+---+---+ - | 1 | 1 | T0| T1| 0 | E | 0 | 0 | - +---+---+---+---+---+---+---+---+ - - E - When, delay operation 15 ms, 0 no delay. - T0/T1 - 00 - read address command. - 10 - read track command. - 11 - write track command. - - Tracks are numbered from 0 up to one minus the last track in the 1797! - - Track Register Read (0x8019): - - +---+---+---+---+---+---+---+---+ - | Track Number | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the track position. - - Track Register Write (0x8019): - - +---+---+---+---+---+---+---+---+ - | Track Number | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the track register. - - Sectors are numbers from 1 up to the last sector in the 1797! - - Sector Register Read (0x801A): - - +---+---+---+---+---+---+---+---+ - | Sector Number | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the sector position. - - Sector Register Write (0x801A): - - +---+---+---+---+---+---+---+---+ - | Sector Number | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the sector register. - - Data Register Read (0x801B): - - +---+---+---+---+---+---+---+---+ - | Data | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the data register. - - Data Register Write (0x801B): - - +---+---+---+---+---+---+---+---+ - | Data | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the data register. - - A FLEX disk is defined as follows: - - Track Sector Use - 0 1 Boot sector - 0 2 Boot sector (cont) - 0 3 Unused - 0 4 System Identity Record (explained below) - 0 5 Unused - 0 6-last Directory - 10 entries/sector (explained below) - 1 1 First available data sector - last-1 last Last available data sector - - System Identity Record - - Byte Use - 0x10 Volume ID (8 bytes) - 0x18 ??? - 0x19 ??? - 0x1A ??? - 0x1B Volume number (2 bytes) - 0x1D First free sector (2 bytes) - 0x1F Last track minus one (byte) - 0x20 Last sector (byte) - 0x21 Total sectors on disk (2 bytes) - 0x23 Month (byte - 0x24 Day (byte) - 0x25 Year (byte) - 0x26 Last track minus one (byte) - 0x27 Last sector (byte) - -*/ - -#include - -#include "swtp_defs.h" - -#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ -#define UNIT_ENABLE (1 << UNIT_V_ENABLE) - -/* emulate a SS FLEX disk with 72 sectors and 80 tracks */ - -#define NUM_DISK 4 /* standard 1797 maximum */ -#define SECT_SIZE 256 /* standard FLEX sector */ -#define NUM_SECT 72 /* sectors/track */ -#define TRAK_SIZE (SECT_SIZE * NUM_SECT) -#define HEADS 1 /* handle as SS with twice the sectors */ -#define NUM_CYL 80 /* maximum tracks */ -#define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE) - -/* 1797 status bits */ - -#define BUSY 0x01 -#define DRQ 0x02 -#define WRPROT 0x40 -#define NOTRDY 0x80 - -/* debug prints */ - -#define DEBUG 0 - - -/* prototypes */ - -t_stat dsk_svc (UNIT *uptr); -t_stat dsk_reset (DEVICE *dptr); -int32 fdcdrv(int32 io, int32 data); -int32 fdccmd(int32 io, int32 data); -int32 fdctrk(int32 io, int32 data); -int32 fdcsec(int32 io, int32 data); -int32 fdcdata(int32 io, int32 data); - -/* Global data on status */ - -int32 cur_dsk = NUM_DISK; /* Currently selected drive */ -int32 cur_trk[NUM_DISK] = {0, 0, 0, 0}; -int32 cur_sec[NUM_DISK] = {0, 0, 0, 0}; -int32 cur_byt[NUM_DISK] = {0, 0, 0, 0}; -int32 cur_flg[NUM_DISK] = {NOTRDY, NOTRDY, NOTRDY, NOTRDY}; - -/* Variables */ - -uint8 dskbuf[SECT_SIZE]; /* Data Buffer */ -UNIT *dptr = NULL; /* fileref to write dirty buffer to */ -int32 fdcbyte; -int32 intrq = 0; /* interrupt request flag */ - -/* DC-4 Simh Device Data Structures */ - -UNIT dsk_unit[] = { - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) } }; - -REG dsk_reg[] = { - { HRDATA (DISK, cur_dsk, 4) }, - { NULL } }; - -MTAB dsk_mod[] = { - { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, - { UNIT_ENABLE, 0, "RO", "RO", NULL }, - { 0 } }; - -DEVICE dsk_dev = { - "DSK", dsk_unit, dsk_reg, dsk_mod, - NUM_DISK, 16, 16, 1, 16, 8, - NULL, NULL, &dsk_reset, - NULL, NULL, NULL }; - -/* service routines to handle simlulator functions */ - -/* service routine - actually gets char & places in buffer */ - -t_stat dsk_svc (UNIT *uptr) -{ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat dsk_reset (DEVICE *dptr) -{ -cur_dsk = 0; -return SCPE_OK; -} - -/* I/O instruction handlers, called from the CPU module when an - memory read or write to the proper addresses is issued. - - Each function is passed an 'io' flag, where 0 means a read from - the port, and 1 means a write to the port. On input, the actual - input is passed as the return value, on output, 'data' is written - to the device. -*/ - -/* DC-4 drive select register routine - this register is not part of the 1797 -*/ - -int32 fdcdrv(int32 io, int32 data) -{ -/* **** probably need to grab the parameters from the SIR and set the limits */ - if (io) { /* write to DC-4 drive register */ - cur_dsk = data & 0x03; /* only 2 drive select bits */ -#if DEBUG > 0 - printf("Drive set to %d\n\r", cur_dsk); -#endif - if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0) - cur_flg[cur_dsk] |= WRPROT; /* set WPROT */ - return 0; - } else { /* read from DC-4 drive register */ -#if DEBUG > 0 - printf("Drive read as %02X\n\r", intrq); -#endif - return intrq; - } -} - -/* WD 1797 FDC command register routine */ - -int32 fdccmd(int32 io, int32 data) -{ - static int32 val = 0, val1 = NOTRDY, i; - static long pos; - UNIT *uptr; - - if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */ - cur_flg[cur_dsk] |= NOTRDY; /* set not ready flag */ - printf("Drive %d is not attached\n\r", cur_dsk); - return 0; - } else { - cur_flg[cur_dsk] &= ~NOTRDY; /* clear not ready flag */ - } - uptr = dsk_dev.units + cur_dsk; /* get virtual drive address */ - if (io) { /* write command to fdc */ - switch(data) { - case 0x8C: /* read command */ - case 0x9C: -#if DEBUG > 0 - printf("Read of disk %d, track %d, sector %d\n\r", - cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]); -#endif - pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */ - pos += SECT_SIZE * (cur_sec[cur_dsk] - 1); -#if DEBUG > 0 - printf("Read pos = %ld ($%04X)\n\r", pos, pos); -#endif - sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */ - sim_fread(dskbuf, 256, 1, uptr -> fileref); /* read in buffer */ - cur_flg[cur_dsk] |= BUSY | DRQ; /* set DRQ & BUSY */ - i = cur_byt[cur_dsk] = 0; /* clear counter */ - break; - case 0xAC: /* write command */ -#if DEBUG > 0 - printf("Write of disk %d, track %d, sector %d\n\r", - cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]); -#endif - if (cur_flg[cur_dsk] & WRPROT) { - printf("Drive %d is write-protected\n\r", cur_dsk); - } else { - pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */ - pos += SECT_SIZE * (cur_sec[cur_dsk] - 1); -#if DEBUG > 1 - printf("Write pos = %ld ($%04X)\n\r", pos, pos); -#endif - sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */ - dptr = uptr; /* save pointer for actual write */ - cur_flg[cur_dsk] |= BUSY | DRQ;/* set DRQ & BUSY */ - i = cur_byt[cur_dsk] = 0; /* clear counter */ - } - break; - case 0x18: /* seek command */ - case 0x1B: - cur_trk[cur_dsk] = fdcbyte; /* set track */ - cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ -#if DEBUG > 0 - printf("Seek of disk %d, track %d\n\r", cur_dsk, fdcbyte); -#endif - break; - case 0x0B: /* restore command */ - cur_trk[cur_dsk] = 0; /* home the drive */ - cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ -#if DEBUG > 0 - printf("Drive %d homed\n\r", cur_dsk); -#endif - break; - default: - printf("Unknown FDC command %02XH\n\r", data); - } - } else { /* read status from fdc */ - val = cur_flg[cur_dsk]; /* set return value */ - if (val1 == 0 && val == 0x03) /* delay BUSY going high */ - val = 0x02; /* set DRQ first */ - if (val != val1) { /* now allow BUSY after on read */ - val1 = val; -#if DEBUG > 0 - printf("Drive %d status=%02X\n\r", cur_dsk, cur_flg[cur_dsk]); -#endif - } - } - return val; -} - -/* WD 1797 FDC track register routine */ - -int32 fdctrk(int32 io, int32 data) -{ - if (io) { - cur_trk[cur_dsk] = data & 0xFF; -#if DEBUG > 1 - printf("Drive %d track set to %d\n\r", cur_dsk, data); -#endif - } else - ; -#if DEBUG > 1 - printf("Drive %d track read as %d\n\r", cur_dsk, cur_trk[cur_dsk]); -#endif - return cur_trk[cur_dsk]; -} - -/* WD 1797 FDC sector register routine */ - -int32 fdcsec(int32 io, int32 data) -{ - if (io) { - cur_sec[cur_dsk] = data & 0xFF; - if (cur_sec[cur_dsk] == 0) /* fix for swtp boot! */ - cur_sec[cur_dsk] = 1; -#if DEBUG > 1 - printf("Drive %d sector set to %d\n\r", cur_dsk, data); -#endif - } else - ; -#if DEBUG > 1 - printf("Drive %d sector read as %d\n\r", cur_dsk, cur_sec[cur_dsk]); -#endif - return cur_sec[cur_dsk]; -} - -/* WD 1797 FDC data register routine */ - -int32 fdcdata(int32 io, int32 data) -{ - int32 i; - - if (io) { /* write byte to fdc */ - fdcbyte = data; /* save for seek */ - if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes to buffer */ -#if DEBUG > 3 - printf("Writing byte %d of %02X\n\r", cur_byt[cur_dsk], data); -#endif - cur_byt[cur_dsk]++; /* step counter */ - dskbuf[i] = data; /* byte into buffer */ - if (cur_byt[cur_dsk] == SECT_SIZE) { - cur_flg[cur_dsk] &= ~(BUSY | DRQ); - if (dptr) { /* if initiated by FDC write command */ - sim_fwrite(dskbuf, 256, 1, dptr -> fileref); /* write it */ - dptr = NULL; - } -#if DEBUG > 0 - printf("Sector write complete\n\r"); -#endif - } - } - return 0; - } else { /* read byte from fdc */ - if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes from buffer */ -#if DEBUG > 1 - printf("Reading byte %d\n\r", cur_byt[cur_dsk]); -#endif - cur_byt[cur_dsk]++; /* step counter */ - if (cur_byt[cur_dsk] == SECT_SIZE) { /* done? */ - cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ -#if DEBUG > 0 - printf("Sector read complete\n\r"); -#endif - } - return (dskbuf[i] & 0xFF); - } else - return 0; - } -} - diff --git a/swtp/swtp_sio.c b/swtp/swtp_sio.c deleted file mode 100644 index 1f6f8a77..00000000 --- a/swtp/swtp_sio.c +++ /dev/null @@ -1,312 +0,0 @@ -/* swtp_sio: SWTP serial I/O card - -Copyright (c) 2005, William Beech - - 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 - Willaim Beech 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 William A. Beech shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 - - These functions support a simulated SWTP MP-S interface card. - The card had two physical I/O ports which could be connected - to any serial I/O device that would connect to a current loop - or RS232 interface. Available baud rates were jumper selectable - for each port from 110 to 9600. The ports appear at all 4 addresses. - This fact is used by SWTBUG to determine the presence of the MP-S vice - MP-C serial card. - - All I/O is via either programmed I/O or interrupt controlled I/O. - It has a status port and a data port. A write to the status port - can select some options for the device (0x03 will reset the port). - A read of the status port gets the port status: - - +---+---+---+---+---+---+---+---+ - | I | P | O | F |CTS|DCD|TXE|RXF| - +---+---+---+---+---+---+---+---+ - - RXF - A 1 in this bit position means a character has been received - on the data port and is ready to be read. - TXE - A 1 in this bit means the port is ready to receive a character - on the data port and transmit it out over the serial line. - - A read to the data port gets the buffered character, a write - to the data port writes the character to the device. -*/ - -#include -#include - -#include "swtp_defs.h" - -#define UNIT_V_ANSI (UNIT_V_UF + 0) // ANSI mode -#define UNIT_ANSI (1 << UNIT_V_ANSI) - -t_stat sio_svc (UNIT *uptr); -t_stat sio_reset (DEVICE *dptr); -t_stat ptr_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptp_svc (UNIT *uptr); -t_stat ptp_reset (DEVICE *dptr); - -int32 ptr_stopioe = 0, ptp_stopioe = 0; // stop on error - -// MP-S Standard I/O Data Structures - -UNIT sio_unit = { UDATA (&sio_svc, 0, 0), - KBD_POLL_WAIT }; - -REG sio_reg[] = { - { ORDATA (DATA, sio_unit.buf, 8) }, - { ORDATA (STAT, sio_unit.u3, 8) }, - { NULL } }; - -MTAB sio_mod[] = { - { UNIT_ANSI, 0, "TTY", "TTY", NULL }, - { 0 } }; - -DEVICE sio_dev = { - "MP-S", &sio_unit, sio_reg, sio_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &sio_reset, - NULL, NULL, NULL }; - -UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), - KBD_POLL_WAIT }; -DEVICE ptr_dev = { - "PTR", &ptr_unit, NULL, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - NULL, NULL, NULL }; - -UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), - KBD_POLL_WAIT }; -DEVICE ptp_dev = { - "PTP", &ptp_unit, NULL, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, NULL, NULL }; - -/* Service routines to handle simulator functions */ - -/* service routine - actually gets char & places in buffer */ - -int32 ptp_rdr(int32 io, int32 data); - -int32 ptp_flag = 0, ptr_flag = 0; - -/* console input service routine */ - -t_stat sio_svc (UNIT *uptr) -{ - int32 temp; - - sim_activate (&sio_unit, sio_unit.wait); // continue poll - if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) - return temp; // no char or error? - sio_unit.buf = temp & 0xFF; // Save char - sio_unit.u3 |= 0x01; // Set RXF flag - - /* Do any special character handling here */ - - sio_unit.pos++; // step character count - return SCPE_OK; -} - -/* paper tape reader input service routine */ - -t_stat ptr_svc (UNIT *uptr) -{ - return SCPE_OK; -} - -/* paper tape punch output service routine */ - -t_stat ptp_svc (UNIT *uptr) -{ - return SCPE_OK; -} - -/* Reset console */ - -t_stat sio_reset (DEVICE *dptr) -{ - sio_unit.buf = 0; // Data buffer - sio_unit.u3 = 0x02; // Status buffer - sim_activate (&sio_unit, sio_unit.wait); // activate unit - return SCPE_OK; -} - -/* Reset paper tape reader */ - -t_stat ptr_reset (DEVICE *dptr) -{ - ptr_unit.buf = 0; - ptr_unit.u3 = 0x02; - sim_cancel (&ptr_unit); // deactivate unit - return SCPE_OK; -} - -/* Reset paper tape punch */ - -t_stat ptp_reset (DEVICE *dptr) -{ - ptp_unit.buf = 0; - ptp_unit.u3 = 0x02; - sim_cancel (&ptp_unit); // deactivate unit - return SCPE_OK; -} - -/* I/O instruction handlers, called from the CPU module when a - read or write occur to addresses 0x8000-0x801F. - - Each function is passed an 'io' flag, where 0 means a read from - the port, and 1 means a write to the port. On input, the actual - input is passed as the return value, on output, 'data' is written - to the device. - - This code emulates a SWTP MP-S Serial Card with a Model 33 Teletype - attached. The Model 33 uses DC1-DC4 codes to enable or disable the - paper tape reader and punch. Those devices are defined in this module, - and the code built to emulate those functions if the PTP and/or PTR - are attached in the simulator. -*/ - -/* Port 1 (0x8004-0x8007) controls the Model 33 Teletype */ - -int32 ptr_flg1 = 0; -int32 odata, status; - - -int32 sio0s(int32 io, int32 data) -{ - UNIT *uptr; - - if (io == 0) { // control register read - if (ptr_flag) { // reader enabled? - if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? - ptr_unit.u3 &= 0xFE; // no, clear RXF flag - else { - uptr = ptr_dev.units;// not EOF? - if (feof(uptr -> fileref)) - ptr_unit.u3 &= 0xFE; - else - ptr_unit.u3 |= 0x01; - } - return (status = ptr_unit.u3); // no - done - } else { - return (status = sio_unit.u3); // return console status - } - } else { // control register write - if (data == 0x03) { // reset port! - sio_unit.u3 = 0x02; // reset console - sio_unit.buf = 0; - sio_unit.pos = 0; - ptr_unit.u3 = 0x02; // reset reader - ptr_unit.buf = 0; - ptr_unit.pos = 0; - ptp_unit.u3 = 0x02; // reset punch - ptp_unit.buf = 0; - ptp_unit.pos = 0; - } - return (status = 0); // invalid io - } -} - -int32 sio0d(int32 io, int32 data) -{ - UNIT *uptr; - - if (io == 0) { // data register read - if (ptr_flag) { // RDR enabled? - if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? - return 0; // no, done -// printf("ptr_unit.u3=%02X\n", ptr_unit.u3); - if ((ptr_unit.u3 & 0x01) == 0) { // yes, more data? -// printf("Returning old %02X\n", odata); // no, return previous byte - return (odata & 0xFF); - } - uptr = ptr_dev.units; // get data byte - if ((odata = getc(uptr -> fileref)) == EOF) { // end of file? -// printf("Got EOF\n"); - ptr_unit.u3 &= 0xFE; // clear RXF flag - return (odata = 0); // no data - } -// printf("Returning new %02X\n", odata); - ptr_unit.pos++; // step character count - ptr_unit.u3 &= 0xFE; // clear RXF flag - return (odata & 0xFF); // return character - } else { - sio_unit.u3 &= 0xFE; // clear RXF flag - return (odata = sio_unit.buf); // return next char - } - } else { // data register write - if (isprint(data) || data == '\r' || data == '\n') { // printable? - sim_putchar(data); // print character on console - if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached? - uptr = ptp_dev.units; // punch character to file - putc(data, uptr -> fileref); - ptp_unit.pos++; // step character counter - } - } else { // DC1-DC4 control Reader/Punch - switch (data) { - case 0x11: // RDR on - ptr_flag = 1; - ptr_flg1 = 0; - ptr_unit.u3 |= 0x01; -// printf("Reader on\r\n"); - break; - case 0x12: // PTP on - ptp_flag = 1; - ptp_unit.u3 |= 0x02; -// printf("Punch on\r\n"); - break; - case 0x13: // RDR off - ptr_flag = 0; -// printf("Reader off-%d bytes read\r\n", ptr_unit.pos); - break; - case 0x14: // PTP off - ptp_flag = 0; -// printf("Punch off-%d bytes written\r\n", ptp_unit.pos); - break; - default: // ignore all other characters - break; - } - } - } - return (odata = 0); -} - -/* because each port appears at 2 addresses and this fact is used - to determine if it is a MP-C or MP-S repeatedly in the SWTBUG - monitor, this code assures that reads of the high ports return - the same data as was read the last time on the low ports. -*/ - -int32 sio1s(int32 io, int32 data) -{ - return status; -} - -int32 sio1d(int32 io, int32 data) -{ - return odata; -} - diff --git a/swtp/swtp_sys.c b/swtp/swtp_sys.c deleted file mode 100644 index 391065cd..00000000 --- a/swtp/swtp_sys.c +++ /dev/null @@ -1,425 +0,0 @@ -/* swtp_sys.c: SWTP 6800 system interface - - Copyright (c) 2005, William Beech - - 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 - WILLIAM A BEECH 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 William A. Beech shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 - -*/ - -#include -#include -#include "swtp_defs.h" - -/* externals */ - -extern DEVICE cpu_dev; -extern DEVICE dsk_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern DEVICE sio_dev; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE lpt_dev; -extern unsigned char M[]; -extern int32 saved_PC; -extern int32 sim_switches; -//extern int32 (*sim_vm_fprint_addr)(FILE*, DEVICE*,t_addr); - -/* prototypes */ - -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag); -int32 fprint_sym (FILE *of, int32 addr, uint32 *val, - UNIT *uptr, int32 sw); -t_addr fprint_addr(FILE *stream, DEVICE *dptr, t_addr addr); -int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); -void sim_special_init (void); - -/* links into scp */ - -void (*sim_vm_init)(void) = &sim_special_init; - -/* 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[] = "SWTP 6800"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 16; - -DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptp_dev, &ptr_dev, &dsk_dev, NULL }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Unknown I/O Instruction", - "HALT instruction", - "Breakpoint", - "Invalid Opcode", - "Invalid Memory" }; - -static const char *opcode[] = { -"???", "NOP", "???", "???", //0x00 -"???", "???", "TAP", "TPA", -"INX", "DEX", "CLV", "SEV", -"CLC", "SEC", "CLI", "SEI", -"SBA", "CBA", "???", "???", //0x10 -"???", "???", "TAB", "TBA", -"???", "DAA", "???", "ABA", -"???", "???", "???", "???", -"BRA", "???", "BHI", "BLS", //0x20 -"BCC", "BCS", "BNE", "BEQ", -"BVC", "BVS", "BPL", "BMI", -"BGE", "BLT", "BGT", "BLE", -"TSX", "INS", "PULA", "PULB", //0x30 -"DES", "TXS", "PSHA", "PSHB", -"???", "RTS", "???", "RTI", -"???", "???", "WAI", "SWI", -"NEGA", "???", "???", "COMA", //0x40 -"LSRA", "???", "RORA", "ASRA", -"ASLA", "ROLA", "DECA", "???", -"INCA", "TSTA", "???", "CLRA", -"NEGB", "???", "???", "COMB", //0x50 -"LSRB", "???", "RORB", "ASRB", -"ASLB", "ROLB", "DECB", "???", -"INCB", "TSTB", "???", "CLRB", -"NEG", "???", "???", "COM", //0x60 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"NEG", "???", "???", "COM", //0x70 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"SUBA", "CMPA", "SBCA", "???", //0x80 -"ANDA", "BITA", "LDAA", "???", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "BSR", "LDS", "???", -"SUBA", "CMPA", "SBCA", "???", //0x90 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "???", "LDS", "STS", -"SUBA", "CMPA", "SBCA", "???", //0xA0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX X", "JSR X", "LDS X", "STS X", -"SUBA", "CMPA", "SBCA", "???", //0xB0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "JSR", "LDS", "STS", -"SUBB", "CMPB", "SBCB", "???", //0xC0 -"ANDB", "BITB", "LDAB", "???", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "???", -"SUBB", "CMPB", "SBCB", "???", //0xD0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xE0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xF0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", - }; - -int32 oplen[256] = { -0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 -1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, -2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, -2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, -3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 -2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 }; - -/* This is the dumper/loader. This command uses the -h to signify a - hex dump/load vice a binary one. If no address is given to load, it - takes the address from the hex record or the current PC for binary. -*/ - -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ - int32 i, cnt = 0, addr = 0, start = 0x10000, end = 0, bytecnt, - cksum1, cksum, bytes[250]; - char buffer[256]; - - sscanf(cptr," %x-%x", &start, &end); - if (flag) { // dump - if (start == 0x10000) // no address parameter - return SCPE_2FARG; - if (sim_switches & 0x80) { // hex dump - addr = start; - while (addr <= end) { // more records to write - if ((addr + 16) <= end) // how many bytes this record - bytecnt = 16 + 3; - else - bytecnt = end - addr + 4; - cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum - fprintf(fileref, "S1%02X%02X%02X", bytecnt, addr>>8, addr&0xFF); //header - for (i=0; i> 8) - (addr & 0xFF); //init cksum - for (i=0; i < bytecnt-3; i++) - cksum -= bytes[i]; - cksum &= 0xFF; - if (cksum != cksum1) - printf("Checksum error\n"); - else { - for (i=0; i < bytecnt-3; i++) { - M[addr++] = bytes[i]; - cnt++; - } - } - } else if (buffer[1] == '9') // end of file - printf("End of file\n"); - } - } - } else { // binary load - if (start == 0x10000) // no starting address - addr = saved_PC; - else - addr = start; - start = addr; - while ((i = getc (fileref)) != EOF) { - M[addr] = i; - addr++; - cnt++; - } - } - printf ("%d Bytes loaded starting at %04X\n", cnt, start); - } - return (SCPE_OK); -} - -/* 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) -{ - int32 i, inst, inst1; - - if (sw & SWMASK ('D')) { // dump memory - for (i=0; i<16; i++) - fprintf(of, "%02X ", val[i]); - fprintf(of, " "); - for (i=0; i<16; i++) - if (isprint(val[i])) - fprintf(of, "%c", val[i]); - else - fprintf(of, "."); - return -15; - } else if (sw & SWMASK ('M')) { // dump instruction mnemonic - inst = val[0]; - if (!oplen[inst]) { // invalid opcode - fprintf(of, "%02X", inst); - return 0; - } - inst1 = inst & 0xF0; - fprintf (of, "%s", opcode[inst]); // mnemonic - if (strlen(opcode[inst]) == 3) - fprintf(of, " "); - if (inst1 == 0x20 || inst == 0x8D) { // rel operand - inst1 = val[1]; - if (val[1] & 0x80) - inst1 |= 0xFF00; - fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); - } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand - if ((inst & 0x0F) < 0x0C) - fprintf(of, " #$%02X", val[1]); - else - fprintf(of, " #$%02X%02X", val[1], val[2]); - } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand - fprintf(of, " %d,X", val[1]); - else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand - fprintf(of, " $%02X%02X", val[1], val[2]); - return (-(oplen[inst] - 1)); - } else - return SCPE_ARG; -} - -/* address output routine */ - -t_addr fprint_addr(FILE *of, DEVICE *dptr, t_addr addr) -{ - fprintf(of, "%04X", addr); - return 0; -} - -/* 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) -{ - int32 cflag, i = 0, j, r; - char gbuf[CBUFSIZE]; - - cflag = (uptr == NULL) || (uptr == &cpu_unit); - while (isspace (*cptr)) cptr++; /* absorb spaces */ - if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) - return SCPE_ARG; /* must have 1 char */ - val[0] = (uint32) cptr[0]; - return SCPE_OK; - } - if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ - if (cptr[0] == 0) - return SCPE_ARG; /* must have 1 char */ - val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; - return SCPE_OK; - } - -/* An instruction: get opcode (all characters until null, comma, - or numeric (including spaces). -*/ - - while (1) { - if (*cptr == ',' || *cptr == '\0' || - isdigit(*cptr)) - break; - gbuf[i] = toupper(*cptr); - cptr++; - i++; - } - -/* Allow for RST which has numeric as part of opcode */ - - if (toupper(gbuf[0]) == 'R' && - toupper(gbuf[1]) == 'S' && - toupper(gbuf[2]) == 'T') { - gbuf[i] = toupper(*cptr); - cptr++; - i++; - } - -/* Allow for 'MOV' which is only opcode that has comma in it. */ - - if (toupper(gbuf[0]) == 'M' && - toupper(gbuf[1]) == 'O' && - toupper(gbuf[2]) == 'V') { - gbuf[i] = toupper(*cptr); - cptr++; - i++; - gbuf[i] = toupper(*cptr); - cptr++; - i++; - } - -/* kill trailing spaces if any */ - gbuf[i] = '\0'; - for (j = i - 1; gbuf[j] == ' '; j--) { - gbuf[j] = '\0'; - } - -/* find opcode in table */ - for (j = 0; j < 256; j++) { - if (strcmp(gbuf, opcode[j]) == 0) - break; - } - if (j > 255) /* not found */ - return SCPE_ARG; - - val[0] = j; /* store opcode */ - if (oplen[j] < 2) /* if 1-byter we are done */ - return SCPE_OK; - if (*cptr == ',') cptr++; - cptr = get_glyph(cptr, gbuf, 0); /* get address */ - sscanf(gbuf, "%o", &r); - if (oplen[j] == 2) { - val[1] = r & 0xFF; - return (-1); - } - val[1] = r & 0xFF; - val[2] = (r >> 8) & 0xFF; - return (-2); -} - -/* initialize optional interfaces */ - -void sim_special_init (void) -{ -// *sim_vm_fprint_addr = &fprint_addr; -} - diff --git a/swtp6800/common/bootrom.c b/swtp6800/common/bootrom.c new file mode 100644 index 00000000..c3ecc6e8 --- /dev/null +++ b/swtp6800/common/bootrom.c @@ -0,0 +1,231 @@ +/* bootrom.c: Boot ROM simulator for Motorola processors + + Copyright (c) 2010-2011, William A. Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a single simulated 2704 to 2764 EPROM device on + an 8-bit computer system.. This device allows the the device buffer to + be loaded from a binary file containing the emulated EPROM code. + + These functions support a simulated 2704, 2708, 2716, 2732 or 2764 EPROM + device on a CPU board. The byte get and put routines use an offset into + the boot EPROM image to locate the proper byte. This allows another device + to set the base address for the boot EPROM. The device type is stored as + a binary number in the first three unit flag bits. + + This device uses a dynamically allocated buffer to hold the EPROM image. + A call to BOOTROM_config will free the current buffer. A call to + BOOTROM_reset will allocate a new buffer of BOOTROM_unit.capac bytes. A + call to BOOTROM_attach will load the buffer with the EPROM image. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ +#define UNIT_MSIZE (0x7 << UNIT_V_MSIZE) +#define UNIT_NONE (0 << UNIT_V_MSIZE) /* No EPROM */ +#define UNIT_2704 (1 << UNIT_V_MSIZE) /* 2704 mode */ +#define UNIT_2708 (2 << UNIT_V_MSIZE) /* 2708 mode */ +#define UNIT_2716 (3 << UNIT_V_MSIZE) /* 2716 mode */ +#define UNIT_2732 (4 << UNIT_V_MSIZE) /* 2732 mode */ +#define UNIT_2764 (5 << UNIT_V_MSIZE) /* 2764 mode */ + +/* function prototypes */ + +t_stat BOOTROM_svc (UNIT *uptr); +t_stat BOOTROM_config (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat BOOTROM_attach (UNIT *uptr, char *cptr); +t_stat BOOTROM_reset (DEVICE *dptr); +int32 BOOTROM_get_mbyte(int32 offset); + +/* SIMH Standard I/O Data Structures */ + +UNIT BOOTROM_unit = { UDATA (NULL, + UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), + KBD_POLL_WAIT }; + +MTAB BOOTROM_mod[] = { + { UNIT_MSIZE, UNIT_NONE, "None", "NONE", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2704, "2704", "2704", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2708, "2708", "2708", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2716, "2716", "2716", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2732, "2732", "2732", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2764, "2764", "2764", &BOOTROM_config }, + { 0 } +}; + +DEBTAB BOOTROM_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE BOOTROM_dev = { + "BOOTROM", /* name */ + &BOOTROM_unit, /* units */ + NULL, /* registers */ + BOOTROM_mod, /* modifiers */ + 1, /* numunits */ + 16, /* aradix */ + 32, /* awidth */ + 1, /* aincr */ + 16, /* dradix */ + 8, /* dwidth */ + NULL, /* examine */ + NULL, /* deposit */ + &BOOTROM_reset, /* reset */ + NULL, /* boot */ + &BOOTROM_attach, /* attach */ + NULL, /* detach */ + NULL, /* ctxt */ + DEV_DEBUG, /* flags */ + 0, /* dctrl */ + BOOTROM_debug, /* debflags */ + NULL, /* msize */ + NULL /* lname */ +}; + +/* global variables */ + +/* BOOTROM_attach - attach file to EPROM unit */ + +t_stat BOOTROM_attach (UNIT *uptr, char *cptr) +{ + t_stat r; + + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_attach: cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_attach: Error\n"); + return r; + } + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_attach: Done\n"); + return (BOOTROM_reset (NULL)); +} + +/* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */ + +t_stat BOOTROM_config (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + if (BOOTROM_dev.dctrl & DEBUG_flow) /* entry message */ + printf("BOOTROM_config: val=%d\n", val); + if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ + if (BOOTROM_dev.dctrl & DEBUG_flow) /* No */ + printf("BOOTROM_config: Parameter error\n"); + return SCPE_ARG; + } + if (val == UNIT_NONE) + BOOTROM_unit.capac = 0; /* set EPROM size */ + else + BOOTROM_unit.capac = 0x200 << ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ + if (BOOTROM_unit.filebuf) { /* free buffer */ + free (BOOTROM_unit.filebuf); + BOOTROM_unit.filebuf = NULL; + } + if (BOOTROM_dev.dctrl & DEBUG_flow) /* status message */ + printf("BOOTROM_config: BOOTROM_unit.capac=%d\n", + BOOTROM_unit.capac); + if (BOOTROM_dev.dctrl & DEBUG_flow) /* exit message */ + printf("BOOTROM_config: Done\n"); + return SCPE_OK; +} + +/* EPROM reset */ + +t_stat BOOTROM_reset (DEVICE *dptr) +{ + t_addr j; + int c; + FILE *fp; + + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_reset: \n"); + if ((BOOTROM_unit.flags & UNIT_MSIZE) == 0) { /* if none selected */ +// printf(" EPROM: Defaulted to None\n"); +// printf(" \"set eprom NONE | 2704 | 2708 | 2716 | 2732 | 2764\"\n"); +// printf(" \"att eprom \"\n"); + BOOTROM_unit.capac = 0; /* set EPROM size to 0 */ + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_reset: Done1\n"); + return SCPE_OK; + } /* if attached */ +// printf(" EPROM: Initializing [%04X-%04XH]\n", +// 0xE000, 0xE000 + BOOTROM_unit.capac - 1); + if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ + BOOTROM_unit.filebuf = malloc(BOOTROM_unit.capac); /* allocate EPROM buffer */ + if (BOOTROM_unit.filebuf == NULL) { + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_reset: Malloc error\n"); + return SCPE_MEM; + } + } + fp = fopen(BOOTROM_unit.filename, "rb"); /* open EPROM file */ + if (fp == NULL) { + printf("\tUnable to open ROM file %s\n",BOOTROM_unit.filename); + printf("\tNo ROM image loaded!!!\n"); + return SCPE_OK; + } + j = 0; /* load EPROM file */ + c = fgetc(fp); + while (c != EOF) { + *((uint8 *)(BOOTROM_unit.filebuf) + j++) = c & 0xFF; + c = fgetc(fp); + if (j > BOOTROM_unit.capac) { + printf("\tImage is too large - Load truncated!!!\n"); + break; + } + } + fclose(fp); +// printf("\t%d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_reset: Done2\n"); + return SCPE_OK; +} + +/* get a byte from memory - byte offset of image */ + +int32 BOOTROM_get_mbyte(int32 offset) +{ + int32 val; + + if (BOOTROM_unit.filebuf == NULL) { + if (BOOTROM_dev.dctrl & DEBUG_read) + printf("BOOTROM_get_mbyte: EPROM not configured\n"); + return 0xFF; + } + if (BOOTROM_dev.dctrl & DEBUG_read) + printf("BOOTROM_get_mbyte: offset=%04X\n", offset); + val = *((uint8 *)(BOOTROM_unit.filebuf) + offset) & 0xFF; + if (BOOTROM_dev.dctrl & DEBUG_read) + printf("BOOTROM_get_mbyte: Normal val=%02X\n", val); + return val; +} + +/* end of bootrom.c */ diff --git a/swtp6800/common/dc-4.c b/swtp6800/common/dc-4.c new file mode 100644 index 00000000..80cfd54d --- /dev/null +++ b/swtp6800/common/dc-4.c @@ -0,0 +1,570 @@ +/* dc4.c: SWTP DC-4 FDC Simulator + + Copyright (c) 2005-2011, William A. Beech + + 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 + WILLIAM A BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + The DC-4 is a 5-inch floppy controller which can control up + to 4 daisy-chained 5-inch floppy drives. The controller is based on + the Western Digital 1797 Floppy Disk Controller (FDC) chip. This + file only emulates the minimum DC-4 functionality to interface with + the virtual disk file. + + The floppy controller is interfaced to the CPU by use of 5 memory + addreses. These are SS-30 slot numbers 5 and 6 (0x8014-0x801B). + + Address Mode Function + ------- ---- -------- + + 0x8014 Read Returns FDC interrupt status + 0x8014 Write Selects the drive/head/motor control + 0x8018 Read Returns status of FDC + 0x8018 Write FDC command register + 0x8019 Read Returns FDC track register + 0x8019 Write Set FDC track register + 0x801A Read Returns FDC sector register + 0x801A Write Set FDC sector register + 0x801B Read Read data + 0x801B Write Write data + + Drive Select Read (0x8014): + + +---+---+---+---+---+---+---+---+ + | I | D | X | X | X | X | X | X | + +---+---+---+---+---+---+---+---+ + + I = Set indicates an interrupt request from the FDC pending. + D = DRQ pending - same as bit 1 of FDC status register. + + Drive Select Write (0x8014): + + +---+---+---+---+---+---+---+---+ + | M | S | X | X | X | X | Device| + +---+---+---+---+---+---+---+---+ + + M = If this bit is 1, the one-shot is triggered/retriggered to + start/keep the motors on. + S = Side select. If set, side one is selected otherwise side zero + is selected. + X = not used + Device = value 0 thru 3, selects drive 0-3 to be controlled. + + Drive Status Read (0x8018): + + +---+---+---+---+---+---+---+---+ + | R | P | H | S | C | L | D | B | + +---+---+---+---+---+---+---+---+ + + B - When 1, the controller is busy. + D - When 1, index mark detected (type I) or data request - read data + ready/write data empty (type II or III). + H - When 1, track 0 (type I) or lost data (type II or III). + C - When 1, crc error detected. + S - When 1, seek (type I) or RNF (type II or III) error. + H - When 1, head is currently loaded (type I) or record type/ + write fault (type II or III). + P - When 1, indicates that diskette is write-protected. + R - When 1, drive is not ready. + + Drive Control Write (0x8018) for type I commands: + + +---+---+---+---+---+---+---+---+ + | 0 | S2| S1| S0| H | V | R1| R0| + +---+---+---+---+---+---+---+---+ + + R0/R1 - Selects the step rate. + V - When 1, verify on destination track. + H - When 1, loads head to drive surface. + S0/S1/S2 = 000 - home. + 001 - seek track in data register. + 010 - step without updating track register. + 011 - step and update track register. + 100 - step in without updating track register. + 101 - step in and update track register. + 110 - step out without updating track register. + 111 - step out and update track register. + + Drive Control Write (0x8018) for type II commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 0 | T | M | S | E | B | A | + +---+---+---+---+---+---+---+---+ + + A - Zero for read, 1 on write deleted data mark else data mark. + B - When 1, shifts sector length field definitions one place. + E - When, delay operation 15 ms, 0 no delay. + S - When 1, select side 1, 0 select side 0. + M - When 1, multiple records, 0 for single record. + T - When 1, write command, 0 for read. + + Drive Control Write (0x8018) for type III commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 1 | T0| T1| 0 | E | 0 | 0 | + +---+---+---+---+---+---+---+---+ + + E - When, delay operation 15 ms, 0 no delay. + T0/T1 - 00 - read address command. + 10 - read track command. + 11 - write track command. + + Tracks are numbered from 0 up to one minus the last track in the 1797! + + Track Register Read (0x8019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the track position. + + Track Register Write (0x8019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the track register. + + Sectors are numbers from 1 up to the last sector in the 1797! + + Sector Register Read (0x801A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the sector position. + + Sector Register Write (0x801A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the sector register. + + Data Register Read (0x801B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the data register. + + Data Register Write (0x801B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the data register. + + A FLEX disk is defined as follows: + + Track Sector Use + 0 1 Boot sector + 0 2 Boot sector (cont) + 0 3 Unused + 0 4 System Identity Record (explained below) + 0 5 Unused + 0 6-last Directory - 10 entries/sector (explained below) + 1 1 First available data sector + last-1 last Last available data sector + + System Identity Record + + Byte Use + 0x00 Two bytes of zeroes (Clears forward link) + 0x10 Volume name in ASCII(11 bytes) + 0x1B Volume number in binary (2 bytes) + 0x1D Address of first free data sector (Track-Sector) (2 bytes) + 0x1F Address of last free data sector (Track-Sector) (2 bytes) + 0x21 Total number of data sectors in binary (2 bytes) + 0x23 Current date (Month-Day-Year) in binary + 0x26 Highest track number on disk in binary (byte) + 0x27 Highest sector number on a track in binary (byte) + + The following unit registers are used by this controller emulation: + + dsk_unit[cur_drv].u3 unit current flags + dsk_unit[cur_drv].u4 unit current track + dsk_unit[cur_drv].u5 unit current sector + dsk_unit[cur_drv].pos unit current sector byte index into buffer + dsk_unit[cur_drv].filebuf unit current sector buffer + dsk_unit[cur_drv].fileref unit current attached file reference +*/ + +#include +#include "swtp_defs.h" + +#define DEBUG 0 + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) + +/* emulate a SS FLEX disk with 72 sectors and 80 tracks */ + +#define NUM_DISK 4 /* standard 1797 maximum */ +#define SECT_SIZE 256 /* standard FLEX sector */ +#define NUM_SECT 72 /* sectors/track */ +#define TRAK_SIZE (SECT_SIZE * NUM_SECT) /* trk size (bytes) */ +#define HEADS 1 /* handle as SS with twice the sectors */ +#define NUM_CYL 80 /* maximum tracks */ +#define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE) /* dsk size (bytes) */ + +#define SECSIZ 256 /* standard FLEX sector */ + +/* SIR offsets */ +#define MAXCYL 0x26 /* last cylinder # */ +#define MAXSEC 0x27 /* last sector # */ + +/* 1797 status bits */ + +#define BUSY 0x01 +#define DRQ 0x02 +#define WRPROT 0x40 +#define NOTRDY 0x80 + +/* function prototypes */ + +t_stat dsk_reset (DEVICE *dptr); + +/* SS-50 I/O address space functions */ + +int32 fdcdrv(int32 io, int32 data); +int32 fdccmd(int32 io, int32 data); +int32 fdctrk(int32 io, int32 data); +int32 fdcsec(int32 io, int32 data); +int32 fdcdata(int32 io, int32 data); + +/* Local Variables */ + +int32 fdcbyte; +int32 intrq = 0; /* interrupt request flag */ +int32 cur_dsk; /* Currently selected drive */ +int32 wrt_flag = 0; /* FDC write flag */ + +int32 spt; /* sectors/track */ +int32 trksiz; /* trk size (bytes) */ +int32 heds; /* number of heads */ +int32 cpd; /* cylinders/disk */ +int32 dsksiz; /* dsk size (bytes) */ + +/* Floppy Disk Controller data structures + + dsk_dev Mother Board device descriptor + dsk_unit Mother Board unit descriptor + dsk_reg Mother Board register list + dsk_mod Mother Board modifiers list +*/ + +UNIT dsk_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } +}; + +REG dsk_reg[] = { + { HRDATA (DISK, cur_dsk, 4) }, + { NULL } +}; + +MTAB dsk_mod[] = { + { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, + { UNIT_ENABLE, 0, "RO", "RO", NULL }, + { 0 } +}; + +DEBTAB dsk_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE dsk_dev = { + "DC-4", //name + dsk_unit, //units + dsk_reg, //registers + dsk_mod, //modifiers + 4, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &dsk_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + dsk_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat dsk_reset (DEVICE *dptr) +{ + int i; + + cur_dsk = 5; /* force initial SIR read */ + for (i=0; i +#include "swtp_defs.h" + +#define I2716_NUM 4 /* number of 2716 EPROMS */ + +extern int32 get_base(void); + +/* function prototypes */ + +t_stat i2716_attach (UNIT *uptr, char *cptr); +t_stat i2716_reset (DEVICE *dptr); +int32 i2716_get_mbyte(int32 offset); + +/* SIMH EPROM Standard I/O Data Structures */ + +UNIT i2716_unit[] = { + { UDATA (NULL,UNIT_ATTABLE+UNIT_ROABLE+UNIT_RO, 0), 0 }, + { UDATA (NULL,UNIT_ATTABLE+UNIT_ROABLE+UNIT_RO, 0), 0 }, + { UDATA (NULL,UNIT_ATTABLE+UNIT_ROABLE+UNIT_RO, 0), 0 }, + { UDATA (NULL,UNIT_ATTABLE+UNIT_ROABLE+UNIT_RO, 0), 0 } +}; + +MTAB i2716_mod[] = { + { 0 } +}; + +DEBTAB i2716_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE i2716_dev = { + "I2716", /* name */ + i2716_unit, /* units */ + NULL, /* registers */ + i2716_mod, /* modifiers */ + I2716_NUM, /* numunits */ + 16, /* aradix */ + 32, /* awidth */ + 1, /* aincr */ + 16, /* dradix */ + 8, /* dwidth */ + NULL, /* examine */ + NULL, /* deposit */ + &i2716_reset, /* reset */ + NULL, /* boot */ + &i2716_attach, /* attach */ + NULL, /* detach */ + NULL, /* ctxt */ + DEV_DEBUG, /* flags */ + 0, /* dctrl */ + i2716_debug, /* debflags */ + NULL, /* msize */ + NULL /* lname */ +}; + +/* global variables */ + +/* i2716_attach - attach file to EPROM unit + force EPROM reset at completion */ + +t_stat i2716_attach (UNIT *uptr, char *cptr) +{ + int32 j, c; + t_stat r; + FILE *fp; + + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_attach: cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_attach: Error\n"); + return r; + } + if (i2716_dev.dctrl & DEBUG_read) + printf("\tOpen file\n"); + fp = fopen(uptr->filename, "rb"); /* open EPROM file */ + if (fp == NULL) { + printf("i2716%d: Unable to open ROM file %s\n", (int)(uptr - i2716_dev.units), uptr->filename); + printf("\tNo ROM image loaded!!!\n"); + return SCPE_OK; + } + if (i2716_dev.dctrl & DEBUG_read) + printf("\tRead file\n"); + j = 0; /* load EPROM file */ + c = fgetc(fp); + while (c != EOF) { + *((uint8 *)(uptr->filebuf) + j++) = c & 0xFF; + c = fgetc(fp); + if (j > 2048) { + printf("\tImage is too large - Load truncated!!!\n"); + break; + } + } + if (i2716_dev.dctrl & DEBUG_read) + printf("\tClose file\n"); + fclose(fp); +// printf("i2716%d: %d bytes of ROM image %s loaded\n",uptr - i2716_dev.units, j, uptr->filename); + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_attach: Done\n"); + return SCPE_OK; +} + +/* EPROM reset */ + +t_stat i2716_reset (DEVICE *dptr) +{ + int32 i, base; + UNIT *uptr; + + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_reset: \n"); + for (i = 0; i < I2716_NUM; i++) { /* init all units */ + uptr = i2716_dev.units + i; + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716 %d unit.flags=%08X\n", i, uptr->flags); + uptr->capac = 2048; + uptr->u3 = 2048 * i; + base = get_base(); + if (uptr->filebuf == NULL) { /* no buffer allocated */ + uptr->filebuf = malloc(2048); /* allocate EPROM buffer */ + if (uptr->filebuf == NULL) { + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_reset: Malloc error\n"); + return SCPE_MEM; + } + } + if (base == 0) { +// printf("i2716%d: Not enabled on MP-A2\n", i); + continue; + } +// printf("i2716%d: Initializing [%04X-%04XH]\n", +// i, base+uptr->u3, base+uptr->u3 + uptr->capac); +// if ((uptr->flags & UNIT_ATT) == 0) { +// printf("i2716%d: No file attached\n", i); +// } + } + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + EPROM memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 i2716_get_mbyte(int32 offset) +{ + int32 i, val, org, len; + UNIT *uptr; + + for (i = 0; i < I2716_NUM; i++) { /* find addressed unit */ + uptr = i2716_dev.units + i; + org = uptr->u3; + len = uptr->capac - 1; + if ((offset >= org) && (offset < (org + len))) { + if (uptr->filebuf == NULL) { + if (i2716_dev.dctrl & DEBUG_read) + printf("i2716_get_mbyte: EPROM not configured\n"); + return 0xFF; + } else { + val = *((uint8 *)(uptr->filebuf) + (offset - org)); + if (i2716_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } + } + } + if (i2716_dev.dctrl & DEBUG_read) + printf("i2716_get_mbyte: Out of range\n"); + return 0xFF; +} + +/* end of i2716.c */ diff --git a/swtp6800/common/m6800.c b/swtp6800/common/m6800.c new file mode 100644 index 00000000..c7f8bf02 --- /dev/null +++ b/swtp6800/common/m6800.c @@ -0,0 +1,2018 @@ +/* m6800.c: SWTP 6800 CPU simulator + + Copyright (c) 2005-2011, William Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + cpu Motorola M6800 CPU + + The register state for the M6800 CPU is: + + A<0:7> Accumulator A + B<0:7> Accumulator B + IX<0:15> Index Register + CCR<0:7> Condition Code Register + HF half-carry flag + IF interrupt flag + NF negative flag + ZF zero flag + VF overflow flag + CF carry flag + PC<0:15> program counter + SP<0:15> Stack Pointer + + The M6800 is an 8-bit CPU, which uses 16-bit registers to address + up to 64KB of memory. + + The 72 basic instructions come in 1, 2, and 3-byte flavors. + + This routine is the instruction decode routine for the M6800. + It is called from the CPU board simulator 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: + + WAI instruction + I/O error in I/O simulator + Invalid OP code (if ITRAP is set on CPU) + Invalid mamory address (if MTRAP is set on CPU) + + 2. Interrupts. + There are 4 types of interrupt, and in effect they do a + hardware CALL instruction to one of 4 possible high memory addresses. + + 3. Non-existent memory. + On the SWTP 6800, reads to non-existent memory + return 0FFH, and writes are ignored. +*/ + +#include + +#include "swtp_defs.h" + +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_MSTOP (UNIT_V_UF+1) /* Stop on Invalid memory? */ +#define UNIT_MSTOP (1 << UNIT_V_MSTOP) + +/* Flag values to set proper positions in CCR */ +#define HF 0x20 +#define IF 0x10 +#define NF 0x08 +#define ZF 0x04 +#define VF 0x02 +#define CF 0x01 + +/* Macros to handle the flags in the CCR */ +#define CCR_ALWAYS_ON (0xC0) /* for 6800 */ +#define CCR_MSK (HF|IF|NF|ZF|VF|CF) +#define TOGGLE_FLAG(FLAG) (CCR ^= FLAG) +#define SET_FLAG(FLAG) (CCR |= FLAG) +#define CLR_FLAG(FLAG) (CCR &= ~FLAG) +#define GET_FLAG(FLAG) (CCR & FLAG) +#define COND_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) +#define COND_SET_FLAG_N(VAR) \ + if (VAR & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) +#define COND_SET_FLAG_Z(VAR) \ + if (VAR == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) +#define COND_SET_FLAG_H(VAR) \ + if (VAR & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) +#define COND_SET_FLAG_C(VAR) \ + if (VAR & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) +#define COND_SET_FLAG_V(COND) \ + if (COND) SET_FLAG(VF); else CLR_FLAG(VF) + +/* local global variables */ + +int32 A = 0; /* Accumulator A */ +int32 B = 0; /* Accumulator B */ +int32 IX = 0; /* Index register */ +int32 SP = 0; /* Stack pointer */ +int32 CCR = CCR_ALWAYS_ON | IF; /* Condition Code Register */ +int32 saved_PC = 0; /* Program counter */ +int32 PC; /* global for the helper routines */ +int32 INTE = 0; /* Interrupt Enable */ +int32 int_req = 0; /* Interrupt request */ + +int32 mem_fault = 0; /* memory fault flag */ + +extern int32 sim_int_char; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +/* function prototypes */ + +t_stat m6800_reset (DEVICE *dptr); +void dump_regs(void); +void dump_regs1(void); +int32 fetch_byte(int32 flag); +int32 fetch_word(void); +uint8 pop_byte(void); +uint16 pop_word(void); +void push_byte(uint8 val); +void push_word(uint16 val); +void go_rel(int32 cond); +int32 get_rel_addr(void); +int32 get_dir_val(void); +int32 get_dir_addr(void); +int32 get_indir_val(void); +int32 get_indir_addr(void); +int32 get_ext_val(void); +int32 get_ext_addr(void); +int32 get_flag(int32 flag); +void condevalVa(int32 op1, int32 op2); +void condevalVs(int32 op1, int32 op2); + +/* external routines */ + +extern void CPU_BD_put_mbyte(int32 addr, int32 val); +extern void CPU_BD_put_mword(int32 addr, int32 val); +extern int32 CPU_BD_get_mbyte(int32 addr); +extern int32 CPU_BD_get_mword(int32 addr); +extern int32 sim_switches; + +/* CPU data structures + + m6800_dev CPU device descriptor + m6800_unit CPU unit descriptor + m6800_reg CPU register list + m6800_mod CPU modifiers list */ + +UNIT m6800_unit = { UDATA (NULL, 0, 0) }; + +REG m6800_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (A, A, 8) }, + { HRDATA (B, B, 8) }, + { HRDATA (IX, IX, 16) }, + { HRDATA (SP, SP, 16) }, + { HRDATA (CCR, CCR, 8) }, + { FLDATA (INTE, INTE, 16) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB m6800_mod[] = { + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { UNIT_MSTOP, UNIT_MSTOP, "MTRAP", "MTRAP", NULL }, + { UNIT_MSTOP, 0, "NOMTRAP", "NOMTRAP", NULL }, + { 0 } }; + +DEBTAB m6800_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE m6800_dev = { + "CPU", //name + &m6800_unit, //units + m6800_reg, //registers + m6800_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &m6800_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + m6800_debug, //debflags + NULL, //msize + NULL //lname +}; + +static const char *opcode[] = { +"???", "NOP", "???", "???", //0x00 +"???", "???", "TAP", "TPA", +"INX", "DEX", "CLV", "SEV", +"CLC", "SEC", "CLI", "SEI", +"SBA", "CBA", "???", "???", //0x10 +"???", "???", "TAB", "TBA", +"???", "DAA", "???", "ABA", +"???", "???", "???", "???", +"BRA", "???", "BHI", "BLS", //0x20 +"BCC", "BCS", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"TSX", "INS", "PULA", "PULB", //0x30 +"DES", "TXS", "PSHA", "PSHB", +"???", "RTS", "???", "RTI", +"???", "???", "WAI", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"ASLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"ASLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "???", //0x80 +"ANDA", "BITA", "LDAA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "BSR", "LDS", "???", +"SUBA", "CMPA", "SBCA", "???", //0x90 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "???", "LDS", "STS", +"SUBA", "CMPA", "SBCA", "???", //0xA0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX X", "JSR X", "LDS X", "STS X", +"SUBA", "CMPA", "SBCA", "???", //0xB0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "JSR", "LDS", "STS", +"SUBB", "CMPB", "SBCB", "???", //0xC0 +"ANDB", "BITB", "LDAB", "???", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "???", +"SUBB", "CMPB", "SBCB", "???", //0xD0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xE0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xF0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +}; + +int32 oplen[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +int32 sim_instr (void) +{ + extern int32 sim_interval; + int32 IR, OP, DAR, reason, hi, lo, op1; + + PC = saved_PC & ADDRMASK; /* load local PC */ + reason = 0; + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ +// dump_regs1(); + if (sim_interval <= 0) /* check clock queue */ + if (reason = sim_process_event ()) + break; + if (mem_fault) { /* memory fault? */ + mem_fault = 0; /* reset fault flag */ + reason = STOP_MEMORY; + break; + } + if (int_req > 0) { /* interrupt? */ + /* 6800 interrupts not implemented yet. None were used, + on a standard SWTP 6800. All I/O is programmed. */ + } /* end interrupt */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + IR = OP = fetch_byte(0); /* fetch instruction */ + sim_interval--; + + /* The Big Instruction Decode Switch */ + + switch (IR) { + + case 0x01: /* NOP */ + break; + case 0x06: /* TAP */ + CCR = A; + break; + case 0x07: /* TPA */ + A = CCR; + break; + case 0x08: /* INX */ + IX = (IX + 1) & ADDRMASK; + COND_SET_FLAG_Z(IX); + break; + case 0x09: /* DEX */ + IX = (IX - 1) & ADDRMASK; + COND_SET_FLAG_Z(IX); + break; + case 0x0A: /* CLV */ + CLR_FLAG(VF); + break; + case 0x0B: /* SEV */ + SET_FLAG(VF); + break; + case 0x0C: /* CLC */ + CLR_FLAG(CF); + break; + case 0x0D: /* SEC */ + SET_FLAG(CF); + break; + case 0x0E: /* CLI */ + CLR_FLAG(IF); + break; + case 0x0F: /* SEI */ + SET_FLAG(IF); + break; + case 0x10: /* SBA */ + op1 = A; + A = A - B; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_C(A); + condevalVs(B, op1); + A &= 0xFF; + break; + case 0x11: /* CBA */ + lo = A - B; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, A); + break; + case 0x16: /* TAB */ + B = A; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0x17: /* TBA */ + A = B; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0x19: /* DAA */ + DAR = A & 0x0F; + op1 = get_flag(CF); + if (DAR > 9 || get_flag(CF)) { + DAR += 6; + A &= 0xF0; + A |= (DAR & 0x0F); + COND_SET_FLAG(DAR & 0x10,CF); + } + DAR = (A >> 4) & 0x0F; + if (DAR > 9 || get_flag(CF)) { + DAR += 6; + if (get_flag(CF)) + DAR++; + A &= 0x0F; + A |= (DAR << 4); + } + COND_SET_FLAG(op1,CF); + if ((DAR << 4) & 0x100) + SET_FLAG(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + A &= 0xFF; + break; + case 0x1B: /* ABA */ + A += B; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_C(A); + condevalVa(A, B); + A &= 0xFF; + break; + case 0x20: /* BRA rel */ + go_rel(1); + break; + case 0x22: /* BHI rel */ + go_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* BLS rel */ + go_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* BCC rel */ + go_rel(!get_flag(CF)); + break; + case 0x25: /* BCS rel */ + go_rel(get_flag(CF)); + break; + case 0x26: /* BNE rel */ + go_rel(!get_flag(ZF)); + break; + case 0x27: /* BEQ rel */ + go_rel(get_flag(ZF)); + break; + case 0x28: /* BVC rel */ + go_rel(!get_flag(VF)); + break; + case 0x29: /* BVS rel */ + go_rel(get_flag(VF)); + break; + case 0x2A: /* BPL rel */ + go_rel(!get_flag(NF)); + break; + case 0x2B: /* BMI rel */ + go_rel(get_flag(NF)); + break; + case 0x2C: /* BGE rel */ + go_rel(!(get_flag(NF) ^ get_flag(VF))); + break; + case 0x2D: /* BLT rel */ + go_rel(get_flag(NF) ^ get_flag(VF)); + break; + case 0x2E: /* BGT rel */ + go_rel(!(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)))); + break; + case 0x2F: /* BLE rel */ + go_rel(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF))); + break; + case 0x30: /* TSX */ + IX = (SP + 1) & ADDRMASK; + break; + case 0x31: /* INS */ + SP = (SP + 1) & ADDRMASK; + break; + case 0x32: /* PUL A */ + A = pop_byte(); + break; + case 0x33: /* PUL B */ + B = pop_byte(); + break; + case 0x34: /* DES */ + SP = (SP - 1) & ADDRMASK; + break; + case 0x35: /* TXS */ + SP = (IX - 1) & ADDRMASK; + break; + case 0x36: /* PSH A */ + push_byte(A); + break; + case 0x37: /* PSH B */ + push_byte(B); + break; + case 0x39: /* RTS */ + PC = pop_word(); + break; + case 0x3B: /* RTI */ + CCR = pop_byte(); + B = pop_byte(); + A = pop_byte(); + IX = pop_word(); + PC = pop_word(); + break; + case 0x3E: /* WAI */ + push_word(PC); + push_word(IX); + push_byte(A); + push_byte(B); + push_byte(CCR); + if (get_flag(IF)) { + reason = STOP_HALT; + continue; + } else { + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFE) & ADDRMASK; + } + break; + case 0x3F: /* SWI */ + push_word(PC); + push_word(IX); + push_byte(A); + push_byte(B); + push_byte(CCR); + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFB) & ADDRMASK; + break; + case 0x40: /* NEG A */ + A = (0 - A) & 0xFF; + COND_SET_FLAG_V(A & 0x80); + COND_SET_FLAG(A,CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x43: /* COM A */ + A = ~A & 0xFF; + CLR_FLAG(VF); + SET_FLAG(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x44: /* LSR A */ + COND_SET_FLAG(A & 0x01,CF); + A = (A >> 1) & 0xFF; + CLR_FLAG(NF); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x46: /* ROR A */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x01,CF); + A = (A >> 1) & 0xFF; + if (hi) + A |= 0x80; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x47: /* ASR A */ + COND_SET_FLAG(A & 0x01,CF); + lo = A & 0x80; + A = (A >> 1) & 0xFF; + A |= lo; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x48: /* ASL A */ + COND_SET_FLAG(A & 0x80,CF); + A = (A << 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x49: /* ROL A */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x80,CF); + A = (A << 1) & 0xFF; + if (hi) + A |= 0x01; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x4A: /* DEC A */ + COND_SET_FLAG_V(A == 0x80); + A = (A - 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4C: /* INC A */ + COND_SET_FLAG_V(A == 0x7F); + A = (A + 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4D: /* TST A */ + lo = (A - 0) & 0xFF; + CLR_FLAG(VF); + CLR_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x4F: /* CLR A */ + A = 0; + CLR_FLAG(NF); + CLR_FLAG(VF); + CLR_FLAG(CF); + SET_FLAG(ZF); + break; + case 0x50: /* NEG B */ + B = (0 - B) & 0xFF; + COND_SET_FLAG_V(B & 0x80); + COND_SET_FLAG(B,CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x53: /* COM B */ + B = ~B; + B &= 0xFF; + CLR_FLAG(VF); + SET_FLAG(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x54: /* LSR B */ + COND_SET_FLAG(B & 0x01,CF); + B = (B >> 1) & 0xFF; + CLR_FLAG(NF); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x56: /* ROR B */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x01,CF); + B = (B >> 1) & 0xFF; + if (hi) + B |= 0x80; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x57: /* ASR B */ + COND_SET_FLAG(B & 0x01,CF); + lo = B & 0x80; + B = (B >> 1) & 0xFF; + B |= lo; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x58: /* ASL B */ + COND_SET_FLAG(B & 0x80,CF); + B = (B << 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x59: /* ROL B */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x80,CF); + B = (B << 1) & 0xFF; + if (hi) + B |= 0x01; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x5A: /* DEC B */ + COND_SET_FLAG_V(B == 0x80); + B = (B - 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5C: /* INC B */ + COND_SET_FLAG_V(B == 0x7F); + B = (B + 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5D: /* TST B */ + lo = (B - 0) & 0xFF; + CLR_FLAG(VF); + CLR_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x5F: /* CLR B */ + B = 0; + CLR_FLAG(NF); + CLR_FLAG(VF); + CLR_FLAG(CF); + SET_FLAG(ZF); + break; + case 0x60: /* NEG ind */ + DAR = get_indir_addr(); + lo = (0 - CPU_BD_get_mbyte(DAR)) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_V(lo & 0x80); + COND_SET_FLAG(lo,CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x63: /* COM ind */ + DAR = get_indir_addr(); + lo = ~CPU_BD_get_mbyte(DAR); + lo &= 0xFF; + CPU_BD_put_mbyte(DAR, lo); + CLR_FLAG(VF); + SET_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x64: /* LSR ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + lo >>= 1; + CPU_BD_put_mbyte(DAR, lo); + CLR_FLAG(NF); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x66: /* ROR ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + hi = get_flag(CF); + COND_SET_FLAG(lo & 0x01,CF); + lo >>= 1; + if (hi) + lo |= 0x80; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x67: /* ASR ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + lo = (lo & 0x80) | (lo >> 1); + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x68: /* ASL ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x80,CF); + lo <<= 1; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x69: /* ROL ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + hi = get_flag(CF); + COND_SET_FLAG(lo & 0x80,CF); + lo <<= 1; + if (hi) + lo |= 0x01; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x6A: /* DEC ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG_V(lo == 0x80); + lo = (lo - 1) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x6C: /* INC ind */ + DAR= get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG_V(lo == 0x7F); + lo = (lo + 1) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x6D: /* TST ind */ + lo = (get_indir_val() - 0) & 0xFF; + CLR_FLAG(VF); + CLR_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x6E: /* JMP ind */ + PC = get_indir_addr(); + break; + case 0x6F: /* CLR ind */ + CPU_BD_put_mbyte(get_indir_addr(), 0); + CLR_FLAG(NF); + CLR_FLAG(VF); + CLR_FLAG(CF); + SET_FLAG(ZF); + break; + case 0x70: /* NEG ext */ + DAR = get_ext_addr(); + lo = (0 - CPU_BD_get_mbyte(DAR)) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_V(lo & 0x80); + CLR_FLAG(CF); + if (lo) + SET_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x73: /* COM ext */ + DAR = get_ext_addr(); + lo = ~CPU_BD_get_mbyte(DAR); + lo &= 0xFF; + CPU_BD_put_mbyte(DAR, lo); + CLR_FLAG(VF); + SET_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x74: /* LSR ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + lo >>= 1; + CPU_BD_put_mbyte(DAR, lo); + CLR_FLAG(NF); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x76: /* ROR ext */ + DAR = get_ext_addr(); + hi = get_flag(CF); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + lo >>= 1; + if (hi) + lo |= 0x80; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x77: /* ASR ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + hi = lo & 0x80; + lo >>= 1; + lo |= hi; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x78: /* ASL ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x80,CF); + lo <<= 1; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x79: /* ROL ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + hi = get_flag(CF); + COND_SET_FLAG(lo & 0x80,CF); + lo <<= 1; + if (hi) + lo |= 0x01; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x7A: /* DEC ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG_V(lo == 0x80); + lo = (lo - 1) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x7C: /* INC ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG_V(lo == 0x7F); + lo = (lo + 1) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x7D: /* TST ext */ + lo = CPU_BD_get_mbyte(get_ext_addr()) - 0; + CLR_FLAG(VF); + CLR_FLAG(CF); + COND_SET_FLAG_N(lo); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0x7E: /* JMP ext */ + PC = get_ext_addr() & ADDRMASK; + break; + case 0x7F: /* CLR ext */ + CPU_BD_put_mbyte(get_ext_addr(), 0); + CLR_FLAG(NF); + CLR_FLAG(VF); + CLR_FLAG(CF); + SET_FLAG(ZF); + break; + case 0x80: /* SUB A imm */ + op1 = get_dir_addr(); + A = A - op1; + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x81: /* CMP A imm */ + op1 = get_dir_addr(); + lo = A - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(lo, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0x82: /* SBC A imm */ + op1 = get_dir_addr(); + A = A - op1 - get_flag(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x84: /* AND A imm */ + A = (A & get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x85: /* BIT A imm */ + lo = (A & get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x86: /* LDA A imm */ + A = get_dir_addr(); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x88: /* EOR A imm */ + A = (A ^ get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x89: /* ADC A imm */ + op1 = get_dir_addr(); + A = A + op1 + get_flag(CF); + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x8A: /* ORA A imm */ + A = (A | get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x8B: /* ADD A imm */ + op1 = get_dir_addr(); + A = A + op1; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x8C: /* CPX imm */ + op1 = IX - get_ext_addr(); + COND_SET_FLAG_Z(op1); + COND_SET_FLAG_N(op1 >> 8); + COND_SET_FLAG_V(op1 & 0x10000); + break; + case 0x8D: /* BSR rel */ + lo = get_rel_addr(); + push_word(PC); + PC = PC + lo; + PC &= ADDRMASK; + break; + case 0x8E: /* LDS imm */ + SP = get_ext_addr(); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0x90: /* SUB A dir */ + op1 = get_dir_val(); + A = A - op1; + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x91: /* CMP A dir */ + op1 = get_dir_val(); + lo = A - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(A, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0x92: /* SBC A dir */ + op1 = get_dir_val(); + A = A - op1 - get_flag(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x94: /* AND A dir */ + A = (A & get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x95: /* BIT A dir */ + lo = (A & get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x96: /* LDA A dir */ + A = get_dir_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x97: /* STA A dir */ + CPU_BD_put_mbyte(get_dir_addr(), A); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x98: /* EOR A dir */ + A = (A ^ get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x99: /* ADC A dir */ + op1 = get_dir_val(); + A = A + op1 + get_flag(CF); + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x9A: /* ORA A dir */ + A = (A | get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x9B: /* ADD A dir */ + op1 = get_dir_val(); + A = A + op1; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x9C: /* CPX dir */ + op1 = IX - CPU_BD_get_mword(get_dir_addr()); + COND_SET_FLAG_Z(op1); + COND_SET_FLAG_N(op1 >> 8); + COND_SET_FLAG_V(op1 & 0x10000); + break; + case 0x9E: /* LDS dir */ + SP = CPU_BD_get_mword(get_dir_addr()); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0x9F: /* STS dir */ + CPU_BD_put_mword(get_dir_addr(), SP); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xA0: /* SUB A ind */ + op1 = get_indir_val(); + A = A - op1; + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xA1: /* CMP A ind */ + op1 = get_indir_val(); + lo = A - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(A, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xA2: /* SBC A ind */ + op1 = get_indir_val(); + A = A - op1 - get_flag(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xA4: /* AND A ind */ + A = (A & get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA5: /* BIT A ind */ + lo = (A & get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xA6: /* LDA A ind */ + A = get_indir_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA7: /* STA A ind */ + CPU_BD_put_mbyte(get_indir_addr(), A); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA8: /* EOR A ind */ + A = (A ^ get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA9: /* ADC A ind */ + op1 = get_indir_val(); + A = A + op1 + get_flag(CF); + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xAA: /* ORA A ind */ + A = (A | get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xAB: /* ADD A ind */ + op1 = get_indir_val(); + A = A + op1; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xAC: /* CPX ind */ + op1 = (IX - get_indir_addr()) & ADDRMASK; + COND_SET_FLAG_Z(op1); + COND_SET_FLAG_N(op1 >> 8); + COND_SET_FLAG_V(op1 & 0x10000); + break; + case 0xAD: /* JSR ind */ + DAR = get_indir_addr(); + push_word(PC); + PC = DAR; + break; + case 0xAE: /* LDS ind */ + SP = CPU_BD_get_mword(get_indir_addr()); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xAF: /* STS ind */ + CPU_BD_put_mword(get_indir_addr(), SP); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xB0: /* SUB A ext */ + op1 = get_ext_val(); + A = A - op1; + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xB1: /* CMP A ext */ + op1 = get_ext_val(); + lo = A - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(A, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xB2: /* SBC A ext */ + op1 = get_ext_val(); + A = A - op1 - get_flag(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xB4: /* AND A ext */ + A = (A & get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB5: /* BIT A ext */ + lo = (A & get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xB6: /* LDA A ext */ + A = get_ext_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB7: /* STA A ext */ + CPU_BD_put_mbyte(get_ext_addr(), A); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB8: /* EOR A ext */ + A = (A ^ get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB9: /* ADC A ext */ + op1 = get_ext_val(); + A = A + op1 + get_flag(CF); + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xBA: /* ORA A ext */ + A = (A | get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xBB: /* ADD A ext */ + op1 = get_ext_val(); + A = A + op1; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xBC: /* CPX ext */ + op1 = (IX - CPU_BD_get_mword(get_ext_addr()));// & ADDRMASK; + COND_SET_FLAG_Z(op1); + COND_SET_FLAG_N(op1 >> 8); + COND_SET_FLAG_V(op1 & 0x10000); + break; + case 0xBD: /* JSR ext */ + DAR = get_ext_addr(); + push_word(PC); + PC = DAR; + break; + case 0xBE: /* LDS ext */ + SP = CPU_BD_get_mword(get_ext_addr()); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xBF: /* STS ext */ + CPU_BD_put_mword(get_ext_addr(), SP); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xC0: /* SUB B imm */ + op1 = get_dir_addr(); + B = B - op1; + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xC1: /* CMP B imm */ + op1 = get_dir_addr(); + lo = B - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xC2: /* SBC B imm */ + op1 = get_dir_addr(); + B = B - op1 - get_flag(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xC4: /* AND B imm */ + B = (B & get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC5: /* BIT B imm */ + lo = (B & get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xC6: /* LDA B imm */ + B = get_dir_addr(); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC8: /* EOR B imm */ + B = (B ^ get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC9: /* ADC B imm */ + op1 = get_dir_addr(); + B = B + op1 + get_flag(CF); + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xCA: /* ORA B imm */ + B = (B | get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xCB: /* ADD B imm */ + op1 = get_dir_addr(); + B = B + op1; + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xCE: /* LDX imm */ + IX = get_ext_addr(); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xD0: /* SUB B dir */ + op1 = get_dir_val(); + B = B - op1; + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xD1: /* CMP B dir */ + op1 = get_dir_val(); + lo = B - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, op1); + break; + case 0xD2: /* SBC B dir */ + op1 = get_dir_val(); + B = B - op1 - get_flag(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xD4: /* AND B dir */ + B = (B & get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD5: /* BIT B dir */ + lo = (B & get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xD6: /* LDA B dir */ + B = get_dir_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD7: /* STA B dir */ + CPU_BD_put_mbyte(get_dir_addr(), B); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD8: /* EOR B dir */ + B = (B ^ get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD9: /* ADC B dir */ + op1 = get_dir_val(); + B = B + op1 + get_flag(CF); + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xDA: /* ORA B dir */ + B = (B | get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xDB: /* ADD B dir */ + op1 = get_dir_val(); + B = B + op1; + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xDE: /* LDX dir */ + IX = CPU_BD_get_mword(get_dir_addr()); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xDF: /* STX dir */ + CPU_BD_put_mword(get_dir_addr(), IX); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xE0: /* SUB B ind */ + op1 = get_indir_val(); + B = B - op1; + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xE1: /* CMP B ind */ + op1 = get_indir_val(); + lo = B - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xE2: /* SBC B ind */ + op1 = get_indir_val(); + B = B - op1 - get_flag(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xE4: /* AND B ind */ + B = (B & get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE5: /* BIT B ind */ + lo = (B & get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xE6: /* LDA B ind */ + B = get_indir_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE7: /* STA B ind */ + CPU_BD_put_mbyte(get_indir_addr(), B); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE8: /* EOR B ind */ + B = (B ^ get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE9: /* ADC B ind */ + op1 = get_indir_val(); + B = B + op1 + get_flag(CF); + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xEA: /* ORA B ind */ + B = (B | get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xEB: /* ADD B ind */ + op1 = get_indir_val(); + B = B + op1; + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xEE: /* LDX ind */ + IX = CPU_BD_get_mword(get_indir_addr()); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xEF: /* STX ind */ + CPU_BD_put_mword(get_indir_addr(), IX); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xF0: /* SUB B ext */ + op1 = get_ext_val(); + B = B - op1; + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xF1: /* CMP B ext */ + op1 = get_ext_val(); + lo = B - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xF2: /* SBC B ext */ + op1 = get_ext_val(); + B = B - op1 - get_flag(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xF4: /* AND B ext */ + B = (B & get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF5: /* BIT B ext */ + lo = (B & get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xF6: /* LDA B ext */ + B = get_ext_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF7: /* STA B ext */ + CPU_BD_put_mbyte(get_ext_addr(), B); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF8: /* EOR B ext */ + B = (B ^ get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF9: /* ADC B ext */ + op1 = get_ext_val(); + B = B + op1 + get_flag(CF); + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xFA: /* ORA B ext */ + B = (B | get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xFB: /* ADD B ext */ + op1 = get_ext_val(); + B = B + op1; + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xFE: /* LDX ext */ + IX = CPU_BD_get_mword(get_ext_addr()); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xFF: /* STX ext */ + CPU_BD_put_mword(get_ext_addr(), IX); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + + default: { /* Unassigned */ + if (m6800_unit.flags & UNIT_OPSTOP) { + reason = STOP_OPCODE; + PC--; + } + break; + } + } + } + /* Simulation halted - lets dump all the registers! */ + dump_regs(); + saved_PC = PC; + return reason; +} + +/* dump the working registers */ + +void dump_regs(void) +{ + printf("\r\nPC=%04X SP=%04X IX=%04X ", PC, SP, IX); + printf("A=%02X B=%02X CCR=%02X", A, B, CCR); +} + +void dump_regs1(void) +{ + printf("PC=%04X SP=%04X IX=%04X ", PC, SP, IX); + printf("A=%02X B=%02X CCR=%02X\n", A, B, CCR); +} + +/* fetch an instruction or byte */ +int32 fetch_byte(int32 flag) +{ + uint8 val; + + val = CPU_BD_get_mbyte(PC) & 0xFF; /* fetch byte */ + if (m6800_dev.dctrl & DEBUG_asm) { /* display source code */ + switch (flag) { + case 0: /* opcode fetch */ + printf("\n%04X %s", PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + printf("0%02XH", val); + break; + } + } + PC = (PC + 1) & ADDRMASK; /* increment PC */ + return val; +} + +/* fetch a word */ +int32 fetch_word(void) +{ + uint16 val; + + val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ + val |= CPU_BD_get_mbyte(PC + 1) & 0xFF; /* fetch low byte */ + if (m6800_dev.dctrl & DEBUG_asm) + printf("0%04XH", val); + PC = (PC + 2) & ADDRMASK; /* increment PC */ + return val; +} + +/* push a byte to the stack */ +void push_byte(uint8 val) +{ + CPU_BD_put_mbyte(SP, val & 0xFF); + SP = (SP - 1) & ADDRMASK; +} + +/* push a word to the stack */ +void push_word(uint16 val) +{ + push_byte(val & 0xFF); + push_byte(val >> 8); +} + +/* pop a byte from the stack */ +uint8 pop_byte(void) +{ + register uint8 res; + + SP = (SP + 1) & ADDRMASK; + res = CPU_BD_get_mbyte(SP); + return res; +} + +/* pop a word from the stack */ +uint16 pop_word(void) +{ + register uint16 res; + + res = pop_byte() << 8; + res |= pop_byte(); + return res; +} + +/* this routine does the jump to relative offset if the condition is + met. Otherwise, execution continues at the current PC. */ + +void go_rel(int32 cond) +{ + int32 temp; + + temp = get_rel_addr(); + if (cond) + PC += temp; + PC &= ADDRMASK; +} + +/* returns the relative offset sign-extended */ + +int32 get_rel_addr(void) +{ + int32 temp; + + temp = fetch_byte(1); + if (temp & 0x80) + temp |= 0xFF00; + return temp & ADDRMASK; +} + +/* returns the value at the direct address pointed to by PC */ + +int32 get_dir_val(void) +{ + return CPU_BD_get_mbyte(get_dir_addr()); +} + +/* returns the direct address pointed to by PC */ + +int32 get_dir_addr(void) +{ + int32 temp; + + temp = fetch_byte(1); + return temp & 0xFF; +} + +/* returns the value at the indirect address pointed to by PC */ + +int32 get_indir_val(void) +{ + return CPU_BD_get_mbyte(get_indir_addr()); +} + +/* returns the indirect address pointed to by PC or immediate byte */ + +int32 get_indir_addr(void) +{ + int32 temp; + + temp = (fetch_byte(1) + IX) & ADDRMASK; + return temp; +} + +/* returns the value at the extended address pointed to by PC */ + +int32 get_ext_val(void) +{ + return CPU_BD_get_mbyte(get_ext_addr()); +} + +/* returns the extended address pointed to by PC or immediate word */ + +int32 get_ext_addr(void) +{ + int32 temp; + + temp = fetch_word(); + return temp; +} + +/* return 1 for flag set or 0 for flag clear */ + +int32 get_flag(int32 flg) +{ + if (CCR & flg) + return 1; + else + return 0; +} + +/* test and set V for addition */ + +void condevalVa(int32 op1, int32 op2) +{ + if (get_flag(CF)) + COND_SET_FLAG_V(((op1 & 0x80) && (op2 & 0x80)) || ( + ((op1 & 0x80) == 0) && ((op2 & 0x80) == 0))); +} + +/* test and set V for subtraction */ + +void condevalVs(int32 op1, int32 op2) +{ + if (get_flag(CF)) + COND_SET_FLAG_V(((op1 & 0x80) && ((op2 & 0x80) == 0)) || + (((op1 & 0x80) == 0) && (op2 & 0x80))); +} + +/* calls from the simulator */ + +/* Reset routine */ + +t_stat m6800_reset (DEVICE *dptr) +{ + CCR = CCR_ALWAYS_ON | IF; + int_req = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + saved_PC = CPU_BD_get_mword(0xFFFE); +// if (saved_PC == 0xFFFF) +// printf("No EPROM image found - M6800 reset incomplete!\n"); +// else +// printf("EPROM vector=%04X\n", saved_PC); + return SCPE_OK; +} + + +/* This is the dumper/loader. This command uses the -h to signify a + hex dump/load vice a binary one. If no address is given to load, it + takes the address from the hex record or the current PC for binary. +*/ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + CPU_BD_put_mbyte(addr, i); + addr++; + cnt++; + } // end while + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code + for M6800 +*/ + +int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) +{ + int32 i, inst, inst1; + + if (sw & SWMASK ('D')) { // dump memory + for (i=0; i<16; i++) + fprintf(of, "%02X ", val[i]); + fprintf(of, " "); + for (i=0; i<16; i++) + if (isprint(val[i])) + fprintf(of, "%c", val[i]); + else + fprintf(of, "."); + return -15; + } else if (sw & SWMASK ('M')) { // dump instruction mnemonic + inst = val[0]; + if (!oplen[inst]) { // invalid opcode + fprintf(of, "%02X", inst); + return 0; + } + inst1 = inst & 0xF0; + fprintf (of, "%s", opcode[inst]); // mnemonic + if (strlen(opcode[inst]) == 3) + fprintf(of, " "); + if (inst1 == 0x20 || inst == 0x8D) { // rel operand + inst1 = val[1]; + if (val[1] & 0x80) + inst1 |= 0xFF00; + fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); + } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand + if ((inst & 0x0F) < 0x0C) + fprintf(of, " #$%02X", val[1]); + else + fprintf(of, " #$%02X%02X", val[1], val[2]); + } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand + fprintf(of, " %d,X", val[1]); + else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand + fprintf(of, " $%02X%02X", val[1], val[2]); + return (-(oplen[inst] - 1)); + } else + 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) +{ + return (-2); +} + +/* end of m6800.c */ diff --git a/swtp6800/common/m6810.c b/swtp6800/common/m6810.c new file mode 100644 index 00000000..3bb5660a --- /dev/null +++ b/swtp6800/common/m6810.c @@ -0,0 +1,146 @@ +/* m6810.c: Motorola m6810 RAM emulator + + Copyright (c) 2011, William A. Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated m6810 RAM device on a CPU board. The + byte get and put routines use an offset into the RAM image to locate the + proper byte. This allows another device to set the base address for the + M6810. +*/ + +#include +#include "swtp_defs.h" + +/* function prototypes */ + +t_stat m6810_reset (DEVICE *dptr); +int32 m6810_get_mbyte(int32 offset); +void m6810_put_mbyte(int32 offset, int32 val); + +/* SIMH RAM Standard I/O Data Structures */ + +UNIT m6810_unit = { UDATA (NULL, UNIT_BINK, 128), + 0 }; + +MTAB m6810_mod[] = { + { 0 } +}; + +DEBTAB m6810_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE m6810_dev = { + "M6810", //name + &m6810_unit, //units + NULL, //registers + m6810_mod, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &m6810_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + m6810_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* global variables */ + +/* m6810_reset */ + +t_stat m6810_reset (DEVICE *dptr) +{ + if (m6810_dev.dctrl & DEBUG_flow) + printf("m6810_reset: \n"); + if (m6810_unit.filebuf == NULL) { + m6810_unit.filebuf = malloc(128); + if (m6810_unit.filebuf == NULL) { + printf("m6810_reset: Malloc error\n"); + return SCPE_MEM; + } + m6810_unit.capac = 128; + } + if (m6810_dev.dctrl & DEBUG_flow) + printf("m6810_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + RAM memory read or write is issued. +*/ + +/* get a byte from memory - from offset from start of RAM*/ + +int32 m6810_get_mbyte(int32 offset) +{ + int32 val; + + if (m6810_dev.dctrl & DEBUG_read) + printf("m6810_get_mbyte: offset=%04X\n", offset); + if (((t_addr)offset) < m6810_unit.capac) { + val = *((uint8 *)(m6810_unit.filebuf) + offset) & 0xFF; + if (m6810_dev.dctrl & DEBUG_read) + printf("val=%04X\n", val); + return val; + } else { + if (m6810_dev.dctrl & DEBUG_read) + printf("m6810_get_mbyte: out of range\n"); + return 0xFF; + } +} + +/* put a byte to memory */ + +void m6810_put_mbyte(int32 offset, int32 val) +{ + if (m6810_dev.dctrl & DEBUG_write) + printf("m6810_put_mbyte: offset=%04X, val=%02X\n", offset, val); + if ((t_addr)offset < m6810_unit.capac) { + *((uint8 *)(m6810_unit.filebuf) + offset) = val & 0xFF; + return; + } else { + if (m6810_dev.dctrl & DEBUG_write) + printf("m6810_put_mbyte: out of range\n"); + return; + } +} + +/* end of m6810.c */ diff --git a/swtp6800/common/mp-8m.c b/swtp6800/common/mp-8m.c new file mode 100644 index 00000000..9126b05a --- /dev/null +++ b/swtp6800/common/mp-8m.c @@ -0,0 +1,209 @@ +/* mp-8m.c: SWTP 8K Byte Memory Card emulator + + Copyright (c) 2011, William A. Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support 6 simulated MP-8M memory cards on an SS-50 system. + + Each unit uses a dynamically allocated 8192 byte buffer to hold the data. + Each unit contains the base address in mp_8m_unit.u3. The unit capacity is + held in mp_8m_unit.capac. Each unit can be enabled or disabled to reconfigure + the RAM for the system. +*/ + +#include +#include "swtp_defs.h" + +#define MP_8M_NUM 6 /* number of MP-*m boards */ + +/* prototypes */ + +t_stat mp_8m_reset (DEVICE *dptr); +int32 mp_8m_get_mbyte(int32 addr); +int32 mp_8m_get_mword(int32 addr); +void mp_8m_put_mbyte(int32 addr, int32 val); +void mp_8m_put_mword(int32 addr, int32 val); + +/* isbc064 Standard I/O Data Structures */ + +UNIT mp_8m_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 } +}; + +MTAB mp_8m_mod[] = { + { 0 } +}; + +DEBTAB mp_8m_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE mp_8m_dev = { + "MP-8M", //name + mp_8m_unit, //units + NULL, //registers + mp_8m_mod, //modifiers + MP_8M_NUM, //numunits + 16, //aradix + 8, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposite + &mp_8m_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + mp_8m_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat mp_8m_reset (DEVICE *dptr) +{ + int32 i, j, val; + UNIT *uptr; + + if (mp_8m_dev.dctrl & DEBUG_flow) + printf("mp_8m_reset: \n"); + for (i = 0; i < MP_8M_NUM; i++) { /* init all units */ + uptr = mp_8m_dev.units + i; + if (mp_8m_dev.dctrl & DEBUG_flow) + printf("MP-8M %d unit.flags=%08X\n", i, uptr->flags); + uptr->capac = 0x2000; + if (i < 4) + uptr->u3 = 0x2000 * i; + else + uptr->u3 = 0x2000 * (i + 1); + if (uptr->filebuf == NULL) { + uptr->filebuf = malloc(0x2000); + if (uptr->filebuf == NULL) { + printf("mp_8m_reset: Malloc error\n"); + return SCPE_MEM; + } + for (j=0; j<8192; j++) { /* fill pattern for testing */ + val = (0xA0 | i); + *((uint8 *)(uptr->filebuf) + j) = val & 0xFF; + } + } + if (mp_8m_dev.dctrl & DEBUG_flow) + printf("MP-8M %d initialized at [%04X-%04XH]\n", i, uptr->u3, + uptr->u3 + uptr->capac - 1); + } + if (mp_8m_dev.dctrl & DEBUG_flow) + printf("mp_8m_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the mp-b2 module when an + external memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 mp_8m_get_mbyte(int32 addr) +{ + int32 val, org, len; + int32 i; + UNIT *uptr; + + if (mp_8m_dev.dctrl & DEBUG_read) + printf("mp_8m_get_mbyte: addr=%04X", addr); + for (i = 0; i < MP_8M_NUM; i++) { /* find addressed unit */ + uptr = mp_8m_dev.units + i; + org = uptr->u3; + len = uptr->capac - 1; + if ((addr >= org) && (addr <= org + len)) { + val = *((uint8 *)(uptr->filebuf) + (addr - org)); + if (mp_8m_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } + } + if (mp_8m_dev.dctrl & DEBUG_read) + printf("mp_8m_get_mbyte: Out of range\n"); + return 0xFF; /* multibus has active high pullups */ +} + +/* get a word from memory */ + +int32 mp_8m_get_mword(int32 addr) +{ + int32 val; + + val = (mp_8m_get_mbyte(addr) << 8); + val |= mp_8m_get_mbyte(addr+1); + return val; +} + +/* put a byte into memory */ + +void mp_8m_put_mbyte(int32 addr, int32 val) +{ + int32 org, len; + int32 i; + UNIT *uptr; + + if (mp_8m_dev.dctrl & DEBUG_write) + printf("mp_8m_put_mbyte: addr=%04X, val=%02X", addr, val); + for (i = 0; i < MP_8M_NUM; i++) { /* find addressed unit */ + uptr = mp_8m_dev.units + i; + org = uptr->u3; + len = uptr->capac - 1; + if ((addr >= org) && (addr < org + len)) { + *((uint8 *)(uptr->filebuf) + (addr - org)) = val & 0xFF; + if (mp_8m_dev.dctrl & DEBUG_write) + printf("\n"); + return; + } + } + if (mp_8m_dev.dctrl & DEBUG_write) + printf("mp_8m_put_mbyte: Out of range\n"); +} + +/* put a word into memory */ + +void mp_8m_put_mword(int32 addr, int32 val) +{ + mp_8m_put_mbyte(addr, val >> 8); + mp_8m_put_mbyte(addr+1, val); +} + +/* end of mp-8m.c */ diff --git a/swtp6800/common/mp-a.c b/swtp6800/common/mp-a.c new file mode 100644 index 00000000..6dd77509 --- /dev/null +++ b/swtp6800/common/mp-a.c @@ -0,0 +1,211 @@ +/* mp-a.c: SWTP MP-A M6800 CPU simulator + + Copyright (c) 2011, William Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + The MP-A CPU Board contains the following devices [mp-a.c]: + M6800 processor [m6800.c]. + M6810 128 byte RAM at 0xA000 [m6810.c]. + M6830, SWTBUG, or custom boot ROM at 0xE000 [bootrom.c]. + Interface to the SS-50 bus and the MP-B2 Mother Board for I/O + and memory boards [mp-b2.c]. + Note: The file names of the emulator source programs for each device are + contained in "[]". +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_SWT (UNIT_V_UF) /* on SWTBUG, off MIKBUG */ +#define UNIT_SWT (1 << UNIT_V_SWT) +#define UNIT_V_RAM (UNIT_V_UF+1) /* off disables 6810 RAM */ +#define UNIT_RAM (1 << UNIT_V_RAM) + +/* local global variables */ + +/* function prototypes */ + +int32 CPU_BD_get_mbyte(int32 addr); +int32 CPU_BD_get_mword(int32 addr); +void CPU_BD_put_mbyte(int32 addr, int32 val); +void CPU_BD_put_mword(int32 addr, int32 val); + +/* external routines */ + +/* MP-B2 bus routines */ +extern int32 MB_get_mbyte(int32 addr); +extern int32 MB_get_mword(int32 addr); +extern void MB_put_mbyte(int32 addr, int32 val); +extern void MB_put_mword(int32 addr, int32 val); + +/* M6810 bus routines */ +extern int32 m6810_get_mbyte(int32 addr); +extern void m6810_put_mbyte(int32 addr, int32 val); + +/* BOOTROM bus routines */ +extern UNIT BOOTROM_unit; +extern int32 BOOTROM_get_mbyte(int32 offset); + +/* MP-A data structures + + CPU_BD_dev MP-A2 device descriptor + CPU_BD_unit MP-A2 unit descriptor + CPU_BD_reg MP-A2 register list + CPU_BD_mod MP-A2 modifiers list */ + +UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; + +REG CPU_BD_reg[] = { + { NULL } +}; + +MTAB CPU_BD_mod[] = { + { UNIT_SWT, UNIT_SWT, "SWT", "SWT", NULL }, + { UNIT_SWT, 0, "NOSWT", "NOSWT", NULL }, + { UNIT_RAM, UNIT_RAM, "RAM", "RAM", NULL }, + { UNIT_RAM, 0, "NORAM", "NORAM", NULL }, + { 0 } +}; + +DEBTAB CPU_BD_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE CPU_BD_dev = { + "MP-A", //name + &CPU_BD_unit, //units + CPU_BD_reg, //registers + CPU_BD_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + CPU_BD_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* get a byte from memory */ + +int32 CPU_BD_get_mbyte(int32 addr) +{ + int32 val; + + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0xA000: + if (CPU_BD_unit.flags & UNIT_RAM) { + val = m6810_get_mbyte(addr - 0xA000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: m6810 val=%02X\n", val); + return val; + } else { + val = MB_get_mbyte(addr) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: m6810 val=%02X\n", val); + return val; + } + case 0xE000: + val = BOOTROM_get_mbyte(addr - 0xE000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: EPROM=%02X\n", val); + return val; + case 0xF000: + val = BOOTROM_get_mbyte(addr - (0x10000 - BOOTROM_unit.capac)) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: EPROM=%02X\n", val); + return val; + default: + val = MB_get_mbyte(addr) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: mp_b2 val=%02X\n", val); + return val; + } +} + +/* get a word from memory */ + +int32 CPU_BD_get_mword(int32 addr) +{ + int32 val; + + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mword: addr=%04X\n", addr); + val = (CPU_BD_get_mbyte(addr) << 8); + val |= CPU_BD_get_mbyte(addr+1); + val &= 0xFFFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void CPU_BD_put_mbyte(int32 addr, int32 val) +{ + if (CPU_BD_dev.dctrl & DEBUG_write) + printf("CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); + switch(addr & 0xF000) { + case 0xA000: + if (CPU_BD_unit.flags & UNIT_RAM) { + m6810_put_mbyte(addr - 0xA000, val); + return; + } else { + MB_put_mbyte(addr, val); + return; + } + default: + MB_put_mbyte(addr, val); + return; + } +} + +/* put a word to memory */ + +void CPU_BD_put_mword(int32 addr, int32 val) +{ + if (CPU_BD_dev.dctrl & DEBUG_write) + printf("CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); + CPU_BD_put_mbyte(addr, val >> 8); + CPU_BD_put_mbyte(addr+1, val); +} + +/* end of mp-a.c */ diff --git a/swtp6800/common/mp-a2.c b/swtp6800/common/mp-a2.c new file mode 100644 index 00000000..21805dcb --- /dev/null +++ b/swtp6800/common/mp-a2.c @@ -0,0 +1,263 @@ +/* mp-a2.c: SWTP MP-A2 M6800 CPU simulator + + Copyright (c) 2011, William Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + The MP-A2 CPU Board contains the following devices [mp-a2.c]: + M6800 processor [m6800.c]. + M6810 128 byte RAM at 0xA000 [m6810.c]. + M6830, SWTBUG, or custom boot ROM at 0xE000 [bootrom.c]. + 4 ea 2716 EPROMs at either 0xC000, 0xC800, 0xD000 and 0xD800 (LO_PROM)or + 0xE000, 0xE800, 0xF000 and 0xF800 (HI_PROM) [eprom.c]. + Interface to the SS-50 bus and the MP-B2 Mother Board for I/O + and memory boards [mp-b2.c]. + Note: The file names of the emulator source programs for each device are + contained in "[]". +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_USER_D (UNIT_V_UF) /* user defined switch */ +#define UNIT_USER_D (1 << UNIT_V_USER_D) +#define UNIT_V_4K_8K (UNIT_V_UF+1) /* off if HI_PROM and only 2K EPROM */ +#define UNIT_4K_8K (1 << UNIT_V_4K_8K) +#define UNIT_V_SWT (UNIT_V_UF+2) /* on SWTBUG, off MIKBUG */ +#define UNIT_SWT (1 << UNIT_V_SWT) +#define UNIT_V_8K (UNIT_V_UF+3) /* off if HI_PROM and only 2K or 4k EPROM */ +#define UNIT_8K (1 << UNIT_V_8K) +#define UNIT_V_RAM (UNIT_V_UF+4) /* off disables 6810 RAM */ +#define UNIT_RAM (1 << UNIT_V_RAM) +#define UNIT_V_LO_PROM (UNIT_V_UF+5) /* on EPROMS @ C000-CFFFH, off no EPROMS */ +#define UNIT_LO_PROM (1 << UNIT_V_LO_PROM) +#define UNIT_V_HI_PROM (UNIT_V_UF+6) /* on EPROMS @ F000-FFFFH, off fo LO_PROM, MON, or no EPROMS */ +#define UNIT_HI_PROM (1 << UNIT_V_HI_PROM) +#define UNIT_V_MON (UNIT_V_UF+7) /* on for monitor vectors in high memory */ +#define UNIT_MON (1 << UNIT_V_MON) + +/* local global variables */ + +/* function prototypes */ + +int32 get_base(void); +int32 CPU_BD_get_mbyte(int32 addr); +int32 CPU_BD_get_mword(int32 addr); +void CPU_BD_put_mbyte(int32 addr, int32 val); +void CPU_BD_put_mword(int32 addr, int32 val); + +/* external routines */ + +/* MP-B2 bus routines */ +extern int32 MB_get_mbyte(int32 addr); +extern int32 MB_get_mword(int32 addr); +extern void MB_put_mbyte(int32 addr, int32 val); +extern void MB_put_mword(int32 addr, int32 val); + +/* M6810 bus routines */ +extern int32 m6810_get_mbyte(int32 addr); +extern void m6810_put_mbyte(int32 addr, int32 val); + +/* BOOTROM bus routines */ +extern UNIT BOOTROM_unit; +extern int32 BOOTROM_get_mbyte(int32 offset); + +/* I2716 bus routines */ +extern int32 i2716_get_mbyte(int32 offset); + +/* MP-A2 data structures + + CPU_BD_dev MP-A2 device descriptor + CPU_BD_unit MP-A2 unit descriptor + CPU_BD_reg MP-A2 register list + CPU_BD_mod MP-A2 modifiers list */ + +UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; + +REG CPU_BD_reg[] = { + { NULL } +}; + +MTAB CPU_BD_mod[] = { + { UNIT_USER_D, UNIT_USER_D, "USER_D", "USER_D", NULL }, + { UNIT_USER_D, 0, "NOUSER_D", "NOUSER_D", NULL }, + { UNIT_4K_8K, UNIT_4K_8K, "4K_8K", "4K_8K", NULL }, + { UNIT_4K_8K, 0, "NO4K_8K", "NO4K_8K", NULL }, + { UNIT_SWT, UNIT_SWT, "SWT", "SWT", NULL }, + { UNIT_SWT, 0, "NOSWT", "NOSWT", NULL }, + { UNIT_8K, UNIT_8K, "8K", "8K", NULL }, + { UNIT_8K, 0, "NO8K", "NO8K", NULL }, + { UNIT_RAM, UNIT_RAM, "RAM", "RAM", NULL }, + { UNIT_RAM, 0, "NORAM", "NORAM", NULL }, + { UNIT_LO_PROM, UNIT_LO_PROM, "LO_PROM", "LO_PROM", NULL }, + { UNIT_LO_PROM, 0, "NOLO_PROM", "NOLO_PROM", NULL }, + { UNIT_HI_PROM, UNIT_HI_PROM, "HI_PROM", "HI_PROM", NULL }, + { UNIT_HI_PROM, 0, "NOHI_PROM", "NOHI_PROM", NULL }, + { UNIT_MON, UNIT_MON, "MON", "MON", NULL }, + { UNIT_MON, 0, "NOMON", "NOMON", NULL }, + { 0 } +}; + +DEBTAB CPU_BD_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE CPU_BD_dev = { + "MP-A2", //name + &CPU_BD_unit, //units + CPU_BD_reg, //registers + CPU_BD_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + CPU_BD_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* get base address of 2716's */ + +int32 get_base(void) +{ + if (CPU_BD_unit.flags & UNIT_LO_PROM) + return 0xC000; + else if (CPU_BD_unit.flags & UNIT_HI_PROM) + return 0xF000; + return 0; +} + +/* get a byte from memory */ + +int32 CPU_BD_get_mbyte(int32 addr) +{ + int32 val; + + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0xA000: + if (CPU_BD_unit.flags & UNIT_RAM) { + val = m6810_get_mbyte(addr - 0xA000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: m6810 val=%02X\n", val); + return val; + } else { + val = MB_get_mbyte(addr) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: m6810 val=%02X\n", val); + return val; + } + case 0xC000: + if (CPU_BD_unit.flags & UNIT_LO_PROM) { + val = i2716_get_mbyte(addr - 0xC000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: 2716=%02X\n", val); + return val; + } else + return 0xFF; + break; + case 0xE000: + val = BOOTROM_get_mbyte(addr - 0xE000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: EPROM=%02X\n", val); + return val; + case 0xF000: + if (CPU_BD_unit.flags & UNIT_MON) { + val = BOOTROM_get_mbyte(addr - (0x10000 - BOOTROM_unit.capac)) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: EPROM=%02X\n", val); + return val; + } + default: + val = MB_get_mbyte(addr) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: mp_b2 val=%02X\n", val); + return val; + } +} + +/* get a word from memory */ + +int32 CPU_BD_get_mword(int32 addr) +{ + int32 val; + + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mword: addr=%04X\n", addr); + val = (CPU_BD_get_mbyte(addr) << 8); + val |= CPU_BD_get_mbyte(addr+1); + val &= 0xFFFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void CPU_BD_put_mbyte(int32 addr, int32 val) +{ + if (CPU_BD_dev.dctrl & DEBUG_write) + printf("CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); + switch(addr & 0xF000) { + case 0xA000: + if (CPU_BD_unit.flags & UNIT_RAM) { + m6810_put_mbyte(addr - 0xA000, val); + return; + } else { + MB_put_mbyte(addr, val); + return; + } + default: + MB_put_mbyte(addr, val); + return; + } +} + +/* put a word to memory */ + +void CPU_BD_put_mword(int32 addr, int32 val) +{ + if (CPU_BD_dev.dctrl & DEBUG_write) + printf("CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); + CPU_BD_put_mbyte(addr, val >> 8); + CPU_BD_put_mbyte(addr+1, val); +} + +/* end of mp-a2.c */ diff --git a/swtp6800/common/mp-b2.c b/swtp6800/common/mp-b2.c new file mode 100644 index 00000000..7b93d7d5 --- /dev/null +++ b/swtp6800/common/mp-b2.c @@ -0,0 +1,322 @@ +/* mp-b2.c: SWTP SS-50/SS-30 MP-B2 Mother Board + + Copyright (c) 2011, William A. Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_RAM_0000 (UNIT_V_UF) /* MP-8M board 0 enable */ +#define UNIT_RAM_0000 (1 << UNIT_V_RAM_0000) +#define UNIT_V_RAM_2000 (UNIT_V_UF+1) /* MP-8M board 1 enable */ +#define UNIT_RAM_2000 (1 << UNIT_V_RAM_2000) +#define UNIT_V_RAM_4000 (UNIT_V_UF+2) /* MP-8M board 2 enable */ +#define UNIT_RAM_4000 (1 << UNIT_V_RAM_4000) +#define UNIT_V_RAM_6000 (UNIT_V_UF+3) /* MP-8M board 3 enable */ +#define UNIT_RAM_6000 (1 << UNIT_V_RAM_6000) +#define UNIT_V_RAM_A000 (UNIT_V_UF+4) /* MP-8M board 4 enable */ +#define UNIT_RAM_A000 (1 << UNIT_V_RAM_A000) +#define UNIT_V_RAM_C000 (UNIT_V_UF+5) /* MP-8M board 5 enable */ +#define UNIT_RAM_C000 (1 << UNIT_V_RAM_C000) + +/* function prototypes */ + +/* empty I/O device routine */ +int32 nulldev(int32 io, int32 data); + +/* SS-50 bus routines */ +int32 MB_get_mbyte(int32 addr); +int32 MB_get_mword(int32 addr); +void MB_put_mbyte(int32 addr, int32 val); +void MB_put_mword(int32 addr, int32 val); + +/* MP-8M bus routines */ +extern int32 mp_8m_get_mbyte(int32 addr); +extern void mp_8m_put_mbyte(int32 addr, int32 val); + +/* SS-50 I/O address space functions */ + +/* MP-S serial I/O routines */ +extern int32 sio0s(int32 io, int32 data); +extern int32 sio0d(int32 io, int32 data); +extern int32 sio1s(int32 io, int32 data); +extern int32 sio1d(int32 io, int32 data); + +/* DC-4 FDC I/O routines */ +extern int32 fdcdrv(int32 io, int32 data); +extern int32 fdccmd(int32 io, int32 data); +extern int32 fdctrk(int32 io, int32 data); +extern int32 fdcsec(int32 io, int32 data); +extern int32 fdcdata(int32 io, int32 data); + +/* This is the I/O configuration table. There are 32 possible +device addresses, if a device is plugged into a port it's routine +address is here, 'nulldev' means no device is available +*/ + +struct idev { + int32 (*routine)(); +}; + +struct idev dev_table[32] = { + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 0 8000-8003 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 1 8004-8007 */ +/* sio1x routines just return the last value read on the matching + sio0x routine. SWTBUG tests for the MP-C with most port reads! */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 2 8008-800B*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 3 800C-800F*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 4 8010-8013*/ + {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 5 8014-8017*/ + {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /*Port 6 8018-801B*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /*Port 7 801C-801F*/ +}; + +/* dummy i/o device */ + +int32 nulldev(int32 io, int32 data) +{ + if (io == 0) + return (0xFF); + return 0; +} + +/* Mother Board data structures + + MB_dev Mother Board device descriptor + MB_unit Mother Board unit descriptor + MB_reg Mother Board register list + MB_mod Mother Board modifiers list +*/ + +UNIT MB_unit = { + UDATA (NULL, 0, 0) +}; + +REG MB_reg[] = { + { NULL } +}; + +MTAB MB_mod[] = { + { UNIT_RAM_0000, UNIT_RAM_0000, "BD0 On", "BD0", NULL }, + { UNIT_RAM_0000, 0, "BD0 Off", "NOBD0", NULL }, + { UNIT_RAM_2000, UNIT_RAM_2000, "BD1 On", "BD1", NULL }, + { UNIT_RAM_2000, 0, "BD1 Off", "NOBD1", NULL }, + { UNIT_RAM_4000, UNIT_RAM_4000, "BD2 On", "BD2", NULL }, + { UNIT_RAM_4000, 0, "BD2 Off", "NOBD2", NULL }, + { UNIT_RAM_6000, UNIT_RAM_6000, "BD3 On", "BD3", NULL }, + { UNIT_RAM_6000, 0, "BD3 Off", "NOBD3", NULL }, + { UNIT_RAM_A000, UNIT_RAM_A000, "BD4 On", "BD4", NULL }, + { UNIT_RAM_A000, 0, "BD4 Off", "NOBD4", NULL }, + { UNIT_RAM_C000, UNIT_RAM_C000, "BD5 On", "BD5", NULL }, + { UNIT_RAM_C000, 0, "BD5 Off", "NOBD5", NULL }, + { 0 } +}; + +DEBTAB MB_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE MB_dev = { + "MP-B2", //name + &MB_unit, //units + MB_reg, //registers + MB_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + MB_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* get a byte from memory */ + +int32 MB_get_mbyte(int32 addr) +{ + int32 val; + + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0x0000: + case 0x1000: + if (MB_unit.flags & UNIT_RAM_0000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0x2000: + case 0x3000: + if (MB_unit.flags & UNIT_RAM_2000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0x4000: + case 0x5000: + if (MB_unit.flags & UNIT_RAM_4000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0x6000: + case 0x7000: + if (MB_unit.flags & UNIT_RAM_6000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0x8000: + val = (dev_table[addr - 0x8000].routine(0, 0)) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: I/O addr=%04X val=%02X\n", addr, val); + return val; + case 0xA000: + case 0xB000: + if (MB_unit.flags & UNIT_RAM_A000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0xC000: + case 0xD000: + if (MB_unit.flags & UNIT_RAM_C000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + default: + return 0xFF; + } +} + +/* get a word from memory */ + +int32 MB_get_mword(int32 addr) +{ + int32 val; + + + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mword: addr=%04X\n", addr); + val = (MB_get_mbyte(addr) << 8); + val |= MB_get_mbyte(addr+1); + val &= 0xFFFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void MB_put_mbyte(int32 addr, int32 val) +{ + if (MB_dev.dctrl & DEBUG_write) + printf("MB_put_mbyte: addr=%04X, val=%02X\n", addr, val); + switch(addr & 0xF000) { + case 0x0000: + case 0x1000: + if (MB_unit.flags & UNIT_RAM_0000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0x2000: + case 0x3000: + if (MB_unit.flags & UNIT_RAM_2000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0x4000: + case 0x5000: + if (MB_unit.flags & UNIT_RAM_4000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0x6000: + case 0x7000: + if (MB_unit.flags & UNIT_RAM_6000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0x8000: + dev_table[addr - 0x8000].routine(1, val); + return; + case 0xA000: + case 0xB000: + if (MB_unit.flags & UNIT_RAM_A000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0xC000: + case 0xD000: + if (MB_unit.flags & UNIT_RAM_C000) { + mp_8m_put_mbyte(addr, val); + return; + } + default: + return; + } +} + +/* put a word to memory */ + +void MB_put_mword(int32 addr, int32 val) +{ + if (MB_dev.dctrl & DEBUG_write) + printf("MB_ptt_mword: addr=%04X, val=%04X\n", addr, val); + MB_put_mbyte(addr, val >> 8); + MB_put_mbyte(addr+1, val); +} + +/* end of mp-b2.c */ diff --git a/swtp6800/common/mp-s.c b/swtp6800/common/mp-s.c new file mode 100644 index 00000000..6c9c12a3 --- /dev/null +++ b/swtp6800/common/mp-s.c @@ -0,0 +1,330 @@ +/* mp-s.c: SWTP MP-S serial I/O card emulator + + Copyright (c) 2005-2011, William Beech + + 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 + Willaim Beech 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated SWTP MP-S interface card. + The card contains one M6850 ACIA. The ACIA implements one complete + serial port. It provides 7 or 8-bit ASCII RS-232 interface to Terminals + or 20 mA current loop interface to a model 33 or 37 Teletype. It is not + compatible with baudot Teletypes. Baud rates from 110 to 1200 are + switch selectable from S! on the MP-S. The ACIA ports appear at all + 4 addresses. This fact is used by SWTBUG to determine the presence of the + MP-S vice MP-C serial card. The ACIA interrupt request line can be connected + to the IRQ or NMI interrupt lines by a jumper on the MP-S. + + All I/O is via either programmed I/O or interrupt controlled I/O. + It has a status port and a data port. A write to the status port + can select some options for the device (0x03 will reset the port). + A read of the status port gets the port status: + + +---+---+---+---+---+---+---+---+ + | I | P | O | F |CTS|DCD|TXE|RXF| + +---+---+---+---+---+---+---+---+ + + RXF - A 1 in this bit position means a character has been received + on the data port and is ready to be read. + TXE - A 1 in this bit means the port is ready to receive a character + on the data port and transmit it out over the serial line. + + A read to the data port gets the buffered character, a write + to the data port writes the character to the device. +*/ + +#include +#include +#include "swtp_defs.h" + +#define UNIT_V_TTY (UNIT_V_UF) // TTY or ANSI mode +#define UNIT_TTY (1 << UNIT_V_TTY) + +/* local global variables */ + +int32 ptr_stopioe = 0; // stop on error +int32 ptp_stopioe = 0; // stop on error +int32 odata; +int32 status; + +int32 ptp_flag = 0; +int32 ptr_flag = 0; + +/* function prototypes */ + +t_stat sio_svc (UNIT *uptr); +t_stat ptr_svc (UNIT *uptr); +t_stat ptp_svc (UNIT *uptr); +t_stat sio_reset (DEVICE *dptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptp_reset (DEVICE *dptr); +int32 sio0s(int32 io, int32 data); +int32 sio0d(int32 io, int32 data); +int32 sio1s(int32 io, int32 data); +int32 sio1d(int32 io, int32 data); + +/* sio data structures + + sio_dev SIO device descriptor + sio_unit SIO unit descriptor + sio_reg SIO register list + sio_mod SIO modifiers list */ + +UNIT sio_unit = { UDATA (&sio_svc, 0, 0), KBD_POLL_WAIT +}; + +REG sio_reg[] = { + { ORDATA (DATA, sio_unit.buf, 8) }, + { ORDATA (STAT, sio_unit.u3, 8) }, + { NULL } +}; + +MTAB sio_mod[] = { + { UNIT_TTY, UNIT_TTY, "TTY", "TTY", NULL }, + { UNIT_TTY, 0, "ANSI", "ANSI", NULL }, + { 0 } +}; + +DEVICE sio_dev = { + "MP-S", &sio_unit, sio_reg, sio_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &sio_reset, + NULL, NULL, NULL +}; + +/* paper tape reader data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_reg PTR register list + ptr_mod PTR modifiers list */ + +UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT +}; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, NULL, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptr_reset, + NULL, NULL, NULL +}; + +/* paper tape punch data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_reg PTP register list + ptp_mod PTP modifiers list */ + +UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT +}; +DEVICE ptp_dev = { + "PTP", &ptp_unit, NULL, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptp_reset, + NULL, NULL, NULL +}; + +/* console input service routine */ + +int32 sio_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&sio_unit, sio_unit.wait); // continue poll + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; // no char or error? + sio_unit.buf = temp & 0xFF; // Save char + sio_unit.u3 |= 0x01; // Set RXF flag + /* Do any special character handling here */ + sio_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape reader input service routine */ + +int32 ptr_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&ptr_unit, ptr_unit.wait); // continue poll + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; // no char or error? + ptr_unit.buf = temp & 0xFF; // Save char + ptr_unit.u3 |= 0x01; // Set RXF flag + /* Do any special character handling here */ + ptr_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape punch output service routine */ + +int32 ptp_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +/* Reset console */ + +int32 sio_reset (DEVICE *dptr) +{ + sio_unit.buf = 0; // Data buffer + sio_unit.u3 = 0x02; // Status buffer + sim_activate (&sio_unit, sio_unit.wait); // activate unit + return SCPE_OK; +} + +/* Reset paper tape reader */ + +int32 ptr_reset (DEVICE *dptr) +{ + ptr_unit.buf = 0; + ptr_unit.u3 = 0x02; + sim_activate (&ptr_unit, ptr_unit.wait); // activate unit +// sim_cancel (&ptr_unit); // deactivate unit + return SCPE_OK; +} + +/* Reset paper tape punch */ + +int32 ptp_reset (DEVICE *dptr) +{ + ptp_unit.buf = 0; + ptp_unit.u3 = 0x02; + sim_activate (&ptp_unit, ptp_unit.wait); // activate unit +// sim_cancel (&ptp_unit); // deactivate unit + return SCPE_OK; +} + +/* I/O instruction handlers, called from the MP-B2 module when a + read or write occur to addresses 0x8004-0x8007. */ + +int32 sio0s(int32 io, int32 data) +{ + if (io == 0) { // control register read + if (ptr_flag) { // reader enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) { // attached? + ptr_unit.u3 &= 0xFE; // no, clear RXF flag + ptr_flag = 0; // clear reader flag + printf("Reader not attached to file\n"); + } else { // attached + if (feof(ptr_unit.fileref)) { // EOF + ptr_unit.u3 &= 0xFE; // clear RXF flag + ptr_flag = 0; // clear reader flag + } else // not EOF + ptr_unit.u3 |= 0x01; // set ready + } + return (status = ptr_unit.u3); // return ptr status + } else { + return (status = sio_unit.u3); // return console status + } + } else { // control register write + if (data == 0x03) { // reset port! + sio_unit.u3 = 0x02; // reset console + sio_unit.buf = 0; + sio_unit.pos = 0; + ptr_unit.u3 = 0x02; // reset reader + ptr_unit.buf = 0; + ptr_unit.pos = 0; + ptp_unit.u3 = 0x02; // reset punch + ptp_unit.buf = 0; + ptp_unit.pos = 0; + } + return (status = 0); // invalid io + } +} + +int32 sio0d(int32 io, int32 data) +{ + if (io == 0) { // data register read + if (ptr_flag) { // RDR enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? + return 0; // no, done +// printf("ptr_unit.u3=%02X\n", ptr_unit.u3); + if ((ptr_unit.u3 & 0x01) == 0) { // yes, more data? +// printf("Returning old %02X\n", odata); // no, return previous byte + return (odata & 0xFF); + } + if ((odata = getc(ptr_unit.fileref)) == EOF) { // end of file? +// printf("Got EOF\n"); + ptr_unit.u3 &= 0xFE; // clear RXF flag + return (odata = 0); // no data + } +// printf("Returning new %02X\n", odata); + ptr_unit.pos++; // step character count + ptr_unit.u3 &= 0xFE; // clear RXF flag + return (odata & 0xFF); // return character + } else { + sio_unit.u3 &= 0xFE; // clear RXF flag + return (odata = sio_unit.buf); // return next char + } + } else { // data register write + if (isprint(data) || data == '\r' || data == '\n') { // printable? + sim_putchar(data); // print character on console + if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached? + putc(data, ptp_unit.fileref); + ptp_unit.pos++; // step character counter + } + } else { // DC1-DC4 control Reader/Punch + switch (data) { + case 0x11: // PTR on + ptr_flag = 1; + ptr_unit.u3 |= 0x01; +// printf("Reader on\n"); + break; + case 0x12: // PTP on + ptp_flag = 1; + ptp_unit.u3 |= 0x02; +// printf("Punch on\n"); + break; + case 0x13: // PTR off + ptr_flag = 0; +// printf("Reader off-%d bytes read\n", ptr_unit.pos); + break; + case 0x14: // PTP off + ptp_flag = 0; +// printf("Punch off-%d bytes written\n", ptp_unit.pos); + break; + default: // ignore all other characters + break; + } + } + } + return (odata = 0); +} + +/* because each port appears at 2 addresses and this fact is used + to determine if it is a MP-C or MP-S repeatedly in the SWTBUG + monitor, this code assures that reads of the high ports return + the same data as was read the last time on the low ports. +*/ + +int32 sio1s(int32 io, int32 data) +{ + return status; +} + +int32 sio1d(int32 io, int32 data) +{ + return odata; +} + +/* end of mp-s.c */ \ No newline at end of file diff --git a/swtp6800/swtp6800/mp-a2_sys.c b/swtp6800/swtp6800/mp-a2_sys.c new file mode 100644 index 00000000..8a043061 --- /dev/null +++ b/swtp6800/swtp6800/mp-a2_sys.c @@ -0,0 +1,87 @@ +/* mp-a_sys.c: SWTP 6800 system interface + + Copyright (c) 2005, William Beech + + 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 + WILLIAM A BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE CPU_BD_dev; +extern DEVICE m6800_dev; +extern REG m6800_reg[]; +extern DEVICE BOOTROM_dev; +extern DEVICE m6810_dev; +extern DEVICE i2716_dev; + +extern DEVICE MB_dev; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE mp_8m_dev; +extern DEVICE dsk_dev; + +/* 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[] = "SWTP 6800, V2, MP-A2 CPU Board"; + +REG *sim_PC = &m6800_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &CPU_BD_dev, + &m6800_dev, + &BOOTROM_dev, + &m6810_dev, + &i2716_dev, + &MB_dev, + &sio_dev, + &ptr_dev, + &ptp_dev, + &mp_8m_dev, + &dsk_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode", + "Invalid Memory" +}; + +/* end of mp-a_sys.c */ diff --git a/swtp6800/swtp6800/mp-a_sys.c b/swtp6800/swtp6800/mp-a_sys.c new file mode 100644 index 00000000..4460b781 --- /dev/null +++ b/swtp6800/swtp6800/mp-a_sys.c @@ -0,0 +1,85 @@ +/* mp-a_sys.c: SWTP 6800 system interface + + Copyright (c) 2005, William Beech + + 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 + WILLIAM A BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE CPU_BD_dev; +extern DEVICE m6800_dev; +extern REG m6800_reg[]; +extern DEVICE BOOTROM_dev; +extern DEVICE m6810_dev; + +extern DEVICE MB_dev; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE mp_8m_dev; +extern DEVICE dsk_dev; + +/* 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[] = "SWTP 6800, V2, MP-A CPU Board"; + +REG *sim_PC = &m6800_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &CPU_BD_dev, + &m6800_dev, + &BOOTROM_dev, + &m6810_dev, + &MB_dev, + &sio_dev, + &ptr_dev, + &ptp_dev, + &mp_8m_dev, + &dsk_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode", + "Invalid Memory" +}; + +/* end of mp-a_sys.c */ diff --git a/swtp6800/swtp6800/swtbug.bin b/swtp6800/swtp6800/swtbug.bin new file mode 100644 index 0000000000000000000000000000000000000000..8cef56ad69bb15ad2ce9f2c3e0e24b140853491c GIT binary patch literal 1024 zcmXX_U1%It6uxtJvOBxkb$65Pv`uZjHJh25lyuhy!c?K5-R{~FQL;!v9u%LXF-aea zJ`|nZ!7zx)sTN;bIYHfdDIy5jmyQv%Ln-OB1rb_7W_BTY5KXI?)NPsdZtA^oe>mrS z_dDOYCqOb!U~HbGWYKPpz&l1+X~EluroLe0l?N3}LcU7tSb}Ha&;=~1QHv}SMUvQq z4=}0THjhJIZ~P4LIwl}e$7cdeXi$EI4;jYy$&WF)jY+M*$3k*3XK4L&F{1l-b^j_n zl4`^dm2FM;&w%avS76iSC?gyK@_hbkFtueQRL^*m9Ts4%nj0E7qDNvzdZ=K?!(-Km zRwM9LjY#ZE_y_(r8TLuM9`yM5B zdKD$JZ8s&iD%y>O8d;`1Vy~i^A&Z!4i?AaCcgf9#6*|*36Xq;!PY+O%;36!+Ct$*Y zi<0f#2(V|#?^pM71{|x6u?oiFyc)6_AKJ~b-7LBOWgZHe+q}yajM(1VpTazmBx$Mn zNcn@Ua)5bK*2F|?7a^pa7ki(cvLYJ~Fg#D#nC+F?DDu_z-jHjArcjkvhueaf@&Z9MJuD1I(p*AWlI~BO$GDkx81&ixJykScwnCcO>!euB>~TaUni+@xhxcs%7gaXt zO#$K{nbZ+B2v9R@@m&j$wy^-WSFr0_Jhg@5UszB?BQ-$H +#include "sim_defs.h" // simulator defs /* Memory */ -#define MAXMEMSIZE 65536 // max memory size -#define MEMSIZE (cpu_unit.capac)// actual memory size -#define ADDRMASK (MAXMEMSIZE - 1)// address mask +#define MAXMEMSIZE 65536 // max memory size +#define MEMSIZE (m6800_unit.capac) // actual memory size +#define ADDRMASK (MAXMEMSIZE - 1) // address mask #define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_all 0xFFFF + /* Simulator stop codes */ -#define STOP_RSRV 1 // must be 1 -#define STOP_HALT 2 // HALT-really WAI -#define STOP_IBKPT 3 // breakpoint -#define STOP_OPCODE 4 // invalid opcode -#define STOP_MEMORY 5 // invalid memory address +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address From 4af7be06cc0c2627d8e9b4e8db718ad4ba7210f2 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 23 Apr 2012 12:25:29 -0700 Subject: [PATCH 068/112] Inherit sim_rev.h from v3.9-0-rc3 --- sim_rev.h | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 5 deletions(-) diff --git a/sim_rev.h b/sim_rev.h index f3fefd3e..93b173ca 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -36,7 +36,7 @@ patch date module(s) and fix(es) - 0 xx-yyy-1 scp.c: + 0 01-May-2012 scp.c: - added *nix READLINE support (Mark Pizzolato) - fixed handling of DO with no arguments (Dave Bryan) - fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) @@ -49,9 +49,14 @@ patch date module(s) and fix(es) sim_ether.c - major revision (Dave Hittner and Mark Pizzolato) + - fixed array overrun which caused SEGFAULT on hosts with many + devices which libpcap can access. + - fixed duplicate MAC address detection to work reliably on switch + connected LANs sim_tmxr.c: - - made option negotiation more reliable (Mark Pizzolato) + - made telnet option negotiation more reliable, VAX simulator now + works with PuTTY as console (Mark Pizzolato) h316_cpu.c: - fixed bugs in MPY, DIV introduced in 3.8-1 (from Theo Engel) @@ -96,7 +101,7 @@ patch date module(s) and fix(es) hp2100_cpu7.c (Dave Bryan): - Corrected "opsize" parameter type in vis_abs - hp2100_defs.h (Dave Bryan): + hp2100_defs.h (Dave Bryan): - Added hp_setsc, hp_showsc functions to support SC modifier - DMA channels renamed from 0,1 to 1,2 to match documentation - Revised I/O signal enum values for concurrent signals @@ -112,7 +117,7 @@ patch date module(s) and fix(es) hp2100_dp.c (Dave Bryan): - Added CNTLR_TYPE cast to dp_settype - hp2100_ds.c (Dave Bryan): + hp2100_ds.c (Dave Bryan): - Rewritten to use the MAC/ICD disc controller library - ioIOO now notifies controller service of parameter output - Corrected SRQ generation and FIFO under/overrun detection @@ -137,13 +142,14 @@ patch date module(s) and fix(es) - Revised for new multi-card paradigm hp2100_lps.c (Dave Bryan): - - Revised detection of CLC at last DMA cycle + - Revised detection of CLC at last DMA cycle - Corrected 12566B (DIAG mode) jumper settings hp2100_ms.c (Dave Bryan): - Added CNTLR_TYPE cast to ms_settype hp2100_mt.c (Dave Bryan): + - Removed redundant MTAB_VUN from "format" MTAB entry - Fixed command scanning error in mtcio ioIOO handler hp2100_stddev.c (Dave Bryan): @@ -165,6 +171,13 @@ patch date module(s) and fix(es) id_pas.c: - fixed TT_GET_MODE test to use TTUF_MODE_x (Michael Bloom) + - revised to use clock coscheduling + + id_tt.c, id_ttc.p: + - revised to use clock coscheduling + + id_uvc.c: + - added clock coscheduling routine 1401_cpu.c: - reverted multiple tape indicator implementation @@ -184,6 +197,9 @@ patch date module(s) and fix(es) pdp1_stddev.c: - fixed unitialized variable in tty output service (Michael Bloom) + pdp10_fe.c: + - revised to use clock coscheduling + pdp11_defs.h: - fixed priority of PIRQ vs IO; added INT_INTERNALn @@ -217,9 +233,82 @@ patch date module(s) and fix(es) pdp11_ts.c: - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) + pdp11_tu.c: + - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) + + pdp11_vh.c: (Mark Pizzolato) + - fixed SET VH LINES=n to correctly adjust the number + of lines available to be 8, 16, 24, or 32. + - fixed performance issue avoiding redundant polling + + pdp11_xq.c: (Mark Pizzolato) + - Fixed missing information from save/restore which + caused operations to not complete correctly after + a restore until the OS reset the controller. + - Added address conflict check during attach. + - Fixed loopback processing to correctly handle forward packets. + - Fixed interrupt dispatch issue which caused delivered packets + (in and out) to sometimes not interrupt the CPU after processing. + - Fixed the SCP visibile SA registers to always display the + ROM mac address, even after it is changed by SET XQ MAC=. + - Added changes so that the Console DELQA diagnostic (>>>TEST 82) + will succeed. + - Added DELQA-T (aka DELQA Plus) device emulation support. + - Added dropped frame statistics to record when the receiver discards + received packets due to the receiver being disabled, or due to the + XQ device's packet receive queue being full. + - Fixed bug in receive processing when we're not polling. This could + cause receive processing to never be activated again if we don't + read all available packets via eth_read each time we get the + opportunity. + - Added the ability to Coalesce received packet interrupts. This + is enabled by SET XQ POLL=DELAY=nnn where nnn is a number of + microseconds to delay the triggering of an interrupt when a packet + is received. + - Added SET XQ POLL=DISABLE (aka SET XQ POLL=0) to operate without + polling for packet read completion. + - Changed the sanity and id timer mechanisms to use a separate timer + unit so that transmit and recieve activities can be dealt with + by the normal xq_svc routine. + Dynamically determine the timer polling rate based on the + calibrated tmr_poll and clk_tps values of the simulator. + - Enabled the SET XQ POLL to be meaningful if the simulator currently + doesn't support idling. + - Changed xq_debug_setup to use sim_debug instead of printf so that + all debug output goes to the same place. + - Restored the call to xq_svc after all successful calls to eth_write + to allow receive processing to happen before the next event + service time. This must have been inadvertently commented out + while other things were being tested. + + pdp11_xu.c: (Mark Pizzolato) + - Added SHOW XU FILTERS modifier (Dave Hittner) + - Corrected SELFTEST command, enabling use by VMS 3.7, VMS 4.7, and Ultrix 1.1 (Dave Hittner) + - Added address conflict check during attach. + - Added loopback processing support + - Fixed the fact that no broadcast packets were received by the DEUNA + - Fixed transmitted packets to have the correct source MAC address. + - Fixed incorrect address filter setting calling eth_filter(). + + pdp18b_stddev.c: + - added clock coscheduling + - revised TTI to use clock coscheduling and to fix perpetual CAF bug + + pdp18b_ttx.c: + - revised to use clock coscheduling + + pdp8_clk.c: + - added clock coscheduling + pdp8_fpp.c: (Rick Murphy) - many bug fixes; now functional + pdp8_tt.c: + - revised to use clock coscheduling and to fix perpetual CAF bug + + pdp8_ttx.c: + - revised to use clock cosheduling + pdp8_sys.c: - added link to FPP @@ -247,6 +336,9 @@ patch date module(s) and fix(es) - fixed integer overflow bug in EMODH - fixed POLYH normalizing before add mask bug + vax_stddev.c: + - revised to use clock coscheduling + vax_syscm.c: - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) @@ -258,6 +350,7 @@ patch date module(s) and fix(es) vax780_stddev.c - added REBOOT support (Mark Pizzolato) + - revised to use clock coscheduling vaxmod_def.h - moved all Qbus devices to BR4; deleted RP definitions From ad9cd1b51c79afb94b5815ddbbdc19f8fb01ee84 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 24 Apr 2012 12:16:38 -0700 Subject: [PATCH 069/112] Numerous Control Flow Fixes: Fixed do file line numbers in messages to properly track after nested do command files. Generalized do file command echoing to always include the do file line number Fixed SET ON which was broken when SET ON INHERIT and SET ON NOINHERIT was added. Fixed ON INHERIT behaviors for global ini files. Added SET QUIET and SET NOQUIET commands Added -Q flag to DO command file processing which sets quiet mode while that command file executes Changed generic include file name to simh.ini from simh.rc to be consistent with other include files Changed generic include file to come from the user HOME or HOMEPATH directory and if not found, the current default directory Fixed format string used to provide quotes around arguments containing spaces while producing %* expansion. Fixed return from do_cmd to return the status from the last command executed --- scp.c | 212 +++++++++++++++++++++++++++++++++-------------------- sim_defs.h | 1 + 2 files changed, 133 insertions(+), 80 deletions(-) diff --git a/scp.c b/scp.c index 5c80a8f6..cb919b73 100644 --- a/scp.c +++ b/scp.c @@ -408,8 +408,10 @@ t_stat shift_args (char *do_arg[], size_t arg_count); t_stat set_on (int32 flag, char *cptr); t_stat set_verify (int32 flag, char *cptr); t_stat set_message (int32 flag, char *cptr); +t_stat set_quiet (int32 flag, char *cptr); t_stat set_asynch (int32 flag, char *cptr); t_stat do_cmd_label (int32 flag, char *cptr, char *label); +void int_handler (int signal); /* Global data */ @@ -446,7 +448,7 @@ FILEREF *sim_log_ref = NULL; /* log file file referen FILE *sim_deb = NULL; /* debug file */ FILEREF *sim_deb_ref = NULL; /* debug file file reference */ static FILE *sim_gotofile; /* the currently open do file */ -static int32 sim_goto_line; /* the current line number in the currently open do file */ +static int32 sim_goto_line[MAX_DO_NEST_LVL+1]; /* the current line number in the currently open do file */ static int32 sim_do_echo = 0; /* the echo status of the currently open do file */ static int32 sim_show_message = 1; /* the message display status of the currently open do file */ static int32 sim_on_inherit = 0; /* the inherit status of on state and conditions when executing do files */ @@ -455,6 +457,7 @@ int32 sim_do_depth = 0; static int32 sim_on_check[MAX_DO_NEST_LVL+1]; static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1]; static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE]; +static char *sim_do_label[MAX_DO_NEST_LVL+1]; static t_stat sim_last_cmd_stat; /* Command Status */ @@ -653,9 +656,13 @@ static CTAB cmd_table[] = { "set on inherit enables inheritance of ON state and actions into do command files\n" "set on noinherit disables inheritance of ON state and actions into do command files\n" "set verify re-enables display of command file processed commands\n" + "set verbose re-enables display of command file processed commands\n" "set noverify disables display of command file processed commands\n" + "set noverbose disables display of command file processed commands\n" "set message re-enables display of command file error messages\n" "set nomessage disables display of command file error messages\n" + "set quiet disables suppression of some output and messages\n" + "set noquiet re-enables suppression of some output and messages\n" "set OCT|DEC|HEX set device display radix\n" "set ENABLED enable device\n" "set DISABLED disable device\n" @@ -688,7 +695,7 @@ static CTAB cmd_table[] = { "sh{ow} {arg,...} show unit parameters\n" "sh{ow} on show on condition actions\n" }, { "DO", &do_cmd, 1, - "do {-V} {-O} {-E} {arg,arg...}\b" + "do {-V} {-O} {-E} {-Q} {arg,arg...}\b" " process command file\n" }, { "GOTO", &goto_cmd, 1, "goto

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

4u;Qn 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 diff --git a/swtp/swtp.txt b/swtp/swtp.txt deleted file mode 100644 index 4d16f9fb..00000000 --- a/swtp/swtp.txt +++ /dev/null @@ -1,100 +0,0 @@ -SWTP 6800 Emulator -===================== - -1. Background. - - The Southwest Technical Products (SWTP) SWTP 6800 was announced 1n the 1976 SWTP Catalog, which boasted you could buy and build this powerful computer kit for only $395. The kit consisted at that time of only the parts to build a case, power supply, mother board, CPU card, serial card with RS-232 or 20 ma loop interface, and memory card with 2048 *bytes* of static memory. - -2. Hardware - - We are simulating a fairly "loaded" SWTP 6800 from about 1978, with the following configuration: - - device simulates - name(s) - - CPU SWTP MP-A with Motorola 6080 CPU board, 62KB of RAM, 2K of EPROM with start boot ROM. - SIO SWTP MP-S Dual Serial Interface Board. Port 1 is assumed to be connected to a serial "glass TTY" that is your terminal running the Simulator. - PTR Second serial port of SIO is assumed to be connected to the paper tap reader/punch. - PTP Second serial port of SIO is assumed to be connected to the paper tap reader/punch. - DSK SWTP DC-4 Floppy Disk controller with up to four drives. - -2.1 The CPU Card (MP-A) - - We allow you to select memory sizes, but be aware that some sample software requires the full 32K (i.e. FLEX). We emulate the SWTP SWTBUG boot rom. - - SET CPU ITRAP Causes the simulator to halt if an invalid 8080 Opcode is detected. - SET CPU NOITRAP Does not stop on an invalid Opcode. This is how the real 6800 operates. - SET CPU MTRAP Causes the simulator to halt if an invalid address is accessed. - SET CPU NOMTRAP Does not stop on invalid address access. This is how a real 6800 operates. - SET CPU 4K - SET CPU 8K - SET CPU 12K - SET CPU 16K - ...... - SET CPU 32K All these set various CPU memory configurations. - The 2K EPROM at the high end of memory is always present and will always boot. - SET CPU MA000 Enable 8 K bytes of memory at $A000-$BFFF. Otherwise, only 128 bytes re available at $A000. - SET CPU NOMA000 Enable only 128 bytes of memory at $A000. - -The SWTBUG EPROM maps to both addresses $E000-E3FF and $FC00-FFFF. - -The real 6800, on receiving a HLT (Halt) instruction, freezes the processor and only an interrupt or CPU hardware reset will restore it. The simulator is a lot nicer, it will halt but send you back to the simulator command line. - -CPU Registers include the following: - - name size comments - - PC 16 Program Counter - A 8 Accumulator A - B 8 Accumulator B - IX 16 Index Register - C 1 Carry flag - Z 1 Zero Flag - H 1 Half-Carry flag - I 1 Interrupt flag - N 1 Negative flag - V 1 Overflao Flag - - -2.2 The Serial I/O Card (MP-S) - - 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 SWTP was $8004-8005 for the first port, and $8006-8007 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. - -2.3 The Floppy Disk controller (DC4) - - The SWTP DC4 is a simple programmed I/O interface to the SWTP MF-68 5-inch dual floppy drive, which was basically a pair of Shugart SA-400s 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 $8018-801B, and we follow the standard. Details on controlling this hardware are in the swtp_dsk.c source file. - - -3. Sample Software - - Running an SWTP 6800 in 1978 you would be running the FLEX Version 2.0 Operating System from Technical Systems Consultants, Inc. - -3.1 CP/M Version 2.2 - - This version is a port of the standard FLEX Version 2.0 to the SWTP 6800. - - To boot FLEX: - - sim> set cpu hex - sim> set cpu itrap - sim> set cpu mtrap - sim> att dsk 6800boot.dsk - sim> att dsk1 6800work.dsk - sim> set cpu MA000 - sim> set dsk1 rw - sim> go - - $D ; Capital D causes SWTBUG to boot Flex - FLEX 2.0 - - DATE (MM,DD,YY)? 03,09,99 ; Must enter a date from last century! - - +++ ;Flex prompt! - - - - - - diff --git a/swtp/swtp6800 b/swtp/swtp6800 deleted file mode 100644 index 0c8c2d1d..00000000 --- a/swtp/swtp6800 +++ /dev/null @@ -1,9 +0,0 @@ -reset -set cpu hex -set cpu itrap -set cpu mtrap -att dsk 6800boot.dsk -att dsk1 6800work.dsk -set cpu MA000 -set dsk1 rw -g diff --git a/swtp/swtp_cpu.c b/swtp/swtp_cpu.c deleted file mode 100644 index e93797f9..00000000 --- a/swtp/swtp_cpu.c +++ /dev/null @@ -1,2293 +0,0 @@ -/* swtp_6800_cpu.c: SWTP 6800 Motorola 6800 CPU simulator - - Copyright (c) 2005, 2007, William Beech - - 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 - WILLIAM A. BEECH 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 William A. Beech shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 - - cpu 6800 CPU - - The register state for the 6800 CPU is: - - A<0:7> Accumulator A - B<0:7> Accumulator B - IX<0:15> Index Register - H half-carry flag - I interrupt flag - N negative flag - Z zero flag - V overflow flag - C carry flag - PC<0:15> program counter - SP<0:15> Stack Pointer - - The 6800 is an 8-bit CPU, which uses 16-bit registers to address - up to 64KB of memory. - - The 72 basic instructions come in 1, 2, and 3-byte flavors. - - This routine is the instruction decode routine for the 6800. - 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: - - WAI instruction - I/O error in I/O simulator - Invalid OP code (if ITRAP is set on CPU) - Invalid mamory address (if MTRAP is set on CPU) - - 2. Interrupts. - There are 4 types of interrupt, and in effect they do a - hardware CALL instruction to one of 4 possible high memory addresses. - - 3. Non-existent memory. On the SWTP 6800, reads to non-existent memory - return 0FFH, and writes are ignored. In the simulator, the - largest possible memory is instantiated and initialized to zero. - Thus, only writes need be checked against actual memory size. - - 4. Adding I/O devices. These modules must be modified: - - swtp_6800_cpu.c add I/O service routines to dev_table - swtp_sys.c add pointer to data structures in sim_devices -*/ - -#include - -#include "swtp_defs.h" - -//#include -//#include - -#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ -#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) -#define UNIT_V_MSTOP (UNIT_V_UF+1) /* Stop on Invalid memory? */ -#define UNIT_MSTOP (1 << UNIT_V_MSTOP) -#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_V_MA000 (UNIT_V_UF+2) /* 128B or 8kB at 0xA000 */ -#define UNIT_MA000 (1 << UNIT_V_MA000) - -uint8 M[MAXMEMSIZE]; /* Memory */ -int32 A = 0; /* Accumulator A */ -int32 B = 0; /* Accumulator B */ -int32 IX = 0; /* Index register */ -int32 SP = 0; /* Stack pointer */ -int32 H = 0; /* Half-carry flag */ -int32 I = 1; /* Interrupt flag */ -int32 N = 0; /* Negative flag */ -int32 Z = 0; /* Zero flag */ -int32 V = 0; /* Overflow flag */ -int32 C = 0; /* Carry flag */ -int32 saved_PC = 0; /* Program counter */ -int32 INTE = 0; /* Interrupt Enable */ -int32 int_req = 0; /* Interrupt request */ - -int32 mem_fault = 0; /* memory fault flag */ - -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ;/* breakpoint info */ - -/* 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); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -void dump_regs(); -void go_rel(int32 cond); -int32 get_rel_addr(); -int32 get_dir_val(); -int32 get_dir_addr(); -int32 get_indir_val(); -int32 get_indir_addr(); -int32 get_ext_val(); -int32 get_ext_addr(); -int32 get_psw(); -void set_psw(int32 psw); -void condevalH(int32 res); -void condevalN(int32 res); -void condevalZ(int32 res); -void condevalC(int32 res); -void condevalVa(int32 op1, int32 op2); -void condevalVs(int32 op1, int32 op2); -void mem_put_byte(int32 addr, int32 val); -void mem_put_word(int32 addr, int32 val); -int32 mem_get_byte(int32 addr); -int32 mem_get_word(int32 addr); -int32 nulldev(int32 io, int32 data); - -/* external routines */ - -extern int32 sio0s(int32 io, int32 data); -extern int32 sio0d(int32 io, int32 data); -extern int32 sio1s(int32 io, int32 data); -extern int32 sio1d(int32 io, int32 data); -extern int32 fdcdrv(int32 io, int32 data); -extern int32 fdccmd(int32 io, int32 data); -extern int32 fdctrk(int32 io, int32 data); -extern int32 fdcsec(int32 io, int32 data); -extern int32 fdcdata(int32 io, int32 data); -extern int32 fprint_sym (FILE *of, int32 addr, uint32 *val, - UNIT *uptr, int32 sw); - - -/* This is the I/O configuration table. There are 32 possible -device addresses, if a device is plugged into a port it's routine -address is here, 'nulldev' means no device is available -*/ - -struct idev { - int32 (*routine)(int32, int32); -}; - -struct idev dev_table[32] = { - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 0 8000-8003*/ - {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 1 8004-8007*/ -/* sio1x routines just return the last value read on the matching - sio0x routine. SWTBUG tests for the MP-C with most port reads! */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 2 8008-800B*/ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 3 800C-800F*/ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 4 8010-8013*/ - {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 5 8014-8017*/ - {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /*Port 6 8018-801B*/ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /*Port 7 801C-801F*/ -}; - -/* SWTP 6800 SWTBUG BOOT EPROM, fits at 0E000-0E3FFH and replicated - at 0FC000-0FFFF for the interrupt vectors */ - -#define BOOTLEN 1024 - -int32 bootrom[BOOTLEN] = { -0xFE,0xA0,0x00,0x6E,0x00,0x8D,0x40,0x6E, -0x00,0x10,0x16,0x04,0xBD,0xE3,0x34,0x8D, -0x67,0x81,0x53,0x26,0xFA,0x8D,0x61,0x81, -0x39,0x27,0x29,0x81,0x31,0x26,0xF0,0x7F, -0xA0,0x0F,0x8D,0x31,0x80,0x02,0xB7,0xA0, -0x47,0x8D,0x1C,0x8D,0x28,0x7A,0xA0,0x47, -0x27,0x09,0xA7,0x00,0xA1,0x00,0x26,0x08, -0x08,0x20,0xF0,0x7C,0xA0,0x0F,0x27,0xCF, -0x86,0x3F,0x8D,0x31,0x7E,0xE2,0xD4,0x8D, -0x0C,0xB7,0xA0,0x0D,0x8D,0x07,0xB7,0xA0, -0x0E,0xFE,0xA0,0x0D,0x39,0x8D,0x53,0x48, -0x48,0x48,0x48,0x16,0x8D,0x4C,0x1B,0x16, -0xFB,0xA0,0x0F,0xF7,0xA0,0x0F,0x39,0x44, -0x44,0x44,0x44,0x84,0x0F,0x8B,0x30,0x81, -0x39,0x23,0x02,0x8B,0x07,0x7E,0xE1,0xD1, -0x7E,0xE1,0xAC,0x8D,0xF8,0x08,0xA6,0x00, -0x81,0x04,0x26,0xF7,0x39,0x7E,0xE1,0x4A, -0x8D,0xBD,0xCE,0xE1,0x9D,0x8D,0xEF,0xCE, -0xA0,0x0D,0x8D,0x34,0xFE,0xA0,0x0D,0x8D, -0x31,0x8D,0x31,0x8D,0xDB,0x81,0x20,0x27, -0xFA,0x81,0x0D,0x27,0xE0,0x81,0x5E,0x20, -0x2C,0x01,0x8D,0xCC,0x80,0x30,0x2B,0x4C, -0x81,0x09,0x2F,0x0A,0x81,0x11,0x2B,0x44, -0x81,0x16,0x2E,0x40,0x80,0x07,0x39,0xA6, -0x00,0x8D,0xA4,0xA6,0x00,0x08,0x20,0xA3, -0x8D,0xF5,0x8D,0xF3,0x86,0x20,0x20,0xA5, -0x8E,0xA0,0x42,0x20,0x2C,0x26,0x07,0x09, -0x09,0xFF,0xA0,0x0D,0x20,0xAC,0xFF,0xA0, -0x0D,0x20,0x02,0x20,0x6D,0x81,0x30,0x25, -0xA1,0x81,0x46,0x22,0x9D,0x8D,0xBD,0xBD, -0xE0,0x57,0x09,0xA7,0x00,0xA1,0x00,0x27, -0x91,0x7E,0xE0,0x40,0xBE,0xA0,0x08,0x20, -0x49,0xBF,0xA0,0x08,0x86,0xFF,0xBD,0xE3, -0x08,0xCE,0x80,0x04,0xBD,0xE2,0x84,0xA6, -0x00,0xA1,0x02,0x20,0x02,0x20,0x19,0x26, -0x39,0x86,0x03,0xA7,0x00,0x86,0x11,0xA7, -0x00,0x20,0x2F,0x01,0xBF,0xA0,0x08,0x30, -0x6D,0x06,0x26,0x02,0x6A,0x05,0x6A,0x06, -0xCE,0xE1,0x9D,0xBD,0xE0,0x7E,0xFE,0xA0, -0x08,0x08,0x8D,0x8E,0x8D,0x8C,0x8D,0x8A, -0x8D,0x86,0x8D,0x84,0xCE,0xA0,0x08,0xBD, -0xE0,0xC8,0xFE,0xA0,0x12,0x8C,0xE1,0x23, -0x27,0x19,0x8E,0xA0,0x42,0xCE,0x80,0x04, -0xFF,0xA0,0x0A,0x7F,0xA0,0x0C,0x8D,0x73, -0x27,0x03,0xBD,0xE2,0x7D,0xBD,0xE3,0x53, -0xBD,0xE3,0x47,0xCE,0xE1,0x9C,0xBD,0xE0, -0x7E,0x8D,0x39,0xCE,0xE3,0xD1,0xA1,0x00, -0x26,0x07,0xBD,0xE0,0xCC,0xEE,0x01,0x6E, -0x00,0x08,0x08,0x08,0x8C,0xE3,0xF8,0x26, -0xED,0x20,0xBF,0xFE,0xA0,0x12,0x6E,0x00, -0x53,0x39,0x04,0x0D,0x0A,0x15,0x00,0x00, -0x00,0x53,0x31,0x04,0x13,0x0D,0x0A,0x15, -0x00,0x00,0x00,0x24,0x04,0x20,0x4C,0xFE, -0xA0,0x06,0x6E,0x00,0x20,0x40,0xBD,0xE0, -0x47,0xFF,0xA0,0x04,0xBD,0xE0,0x47,0xBD, -0xE0,0x55,0x16,0xA6,0x00,0xFF,0xA0,0x0D, -0x11,0x27,0x02,0x20,0x21,0xCE,0xE1,0x9D, -0xBD,0xE0,0x7E,0xCE,0xA0,0x0D,0x20,0x10, -0x3B,0x20,0x3A,0xFF,0xA0,0x10,0xFE,0xA0, -0x0A,0x37,0xE6,0x01,0xE1,0x03,0x33,0x39, -0xBD,0xE0,0xC8,0xFE,0xA0,0x0D,0xBC,0xA0, -0x04,0x27,0x9E,0x08,0x20,0xCD,0x8D,0x06, -0x84,0x7F,0x39,0x31,0x31,0x31,0x37,0x8D, -0xDA,0x26,0x28,0x86,0x15,0xA7,0x00,0xA6, -0x00,0x47,0x24,0xFB,0xA6,0x01,0xF6,0xA0, -0x0C,0x27,0x07,0x20,0x11,0x37,0x8D,0xC3, -0x26,0x2E,0xC6,0x11,0xE7,0x00,0xE6,0x00, -0x57,0x57,0x24,0xFA,0xA7,0x01,0x33,0xFE, -0xA0,0x10,0x39,0xA6,0x00,0x2B,0xFC,0x8D, -0x3A,0xC6,0x04,0xE7,0x02,0x58,0x8D,0x2A, -0x0D,0x69,0x00,0x46,0x5A,0x26,0xF7,0x8D, -0x21,0xF6,0xA0,0x0C,0x27,0x13,0x20,0xDE, -0x8D,0x23,0xC6,0x0A,0x6A,0x00,0x8D,0x16, -0x8D,0x10,0xA7,0x00,0x0D,0x46,0x5A,0x26, -0xF7,0xE6,0x02,0x58,0x2A,0xC8,0x8D,0x02, -0x20,0xC4,0x6D,0x02,0x2A,0xFC,0x6C,0x02, -0x6A,0x02,0x39,0x6F,0x02,0x8D,0xF7,0x20, -0xF1,0x8D,0x83,0x16,0x7F,0xA0,0x0B,0xFE, -0xA0,0x0A,0x8D,0x10,0x8D,0x07,0xCE,0xE3, -0xEF,0x17,0x7E,0xE1,0x76,0x86,0x34,0xA7, -0x03,0xA7,0x02,0x39,0x6C,0x00,0x86,0x07, -0xA7,0x01,0x6C,0x00,0xA7,0x02,0x39,0x7F, -0x80,0x14,0x8D,0x2E,0xC6,0x0B,0x8D,0x25, -0xE6,0x04,0xC5,0x01,0x26,0xFA,0x6F,0x06, -0x8D,0x1D,0xC6,0x9C,0x8D,0x17,0xCE,0x24, -0x00,0xC5,0x02,0x27,0x06,0xB6,0x80,0x1B, -0xA7,0x00,0x08,0xF6,0x80,0x18,0xC5,0x01, -0x26,0xEF,0x7E,0x24,0x00,0xE7,0x04,0x8D, -0x00,0x39,0xCE,0xFF,0xFF,0x09,0x8C,0x80, -0x14,0x26,0xFA,0x39,0xCE,0xE0,0x09,0xBD, -0xE0,0x7E,0x8D,0xF1,0xBD,0xE3,0x47,0x20, -0x58,0xCE,0xE1,0x23,0xBC,0xA0,0x12,0x27, -0x1A,0x08,0x8D,0x32,0xBD,0xE0,0x47,0xFF, -0xA0,0x14,0xA6,0x00,0xB7,0xA0,0x16,0x86, -0x3F,0xA7,0x00,0xCE,0xE1,0x23,0x8D,0x1E, -0x7E,0xE1,0x6B,0xFE,0xA0,0x14,0xB6,0xA0, -0x16,0xA7,0x00,0xCE,0xE1,0x24,0x20,0xDA, -0xB7,0xA0,0x43,0xFE,0xA0,0x12,0x8C,0xE1, -0x23,0x27,0x06,0xCE,0xE1,0x24,0xFF,0xA0, -0x12,0x39,0x8D,0x5A,0x20,0x0F,0xCE,0xA0, -0x49,0xFF,0xA0,0x04,0x09,0x8D,0x52,0xCE, -0xE1,0x90,0xBD,0xE0,0x7E,0x8D,0x24,0x8D, -0x91,0x7E,0xE1,0x52,0x73,0xA0,0x0C,0x86, -0x11,0xC6,0x20,0x8D,0x1A,0xBD,0xE1,0xD9, -0x27,0x04,0x86,0x3C,0xA7,0x03,0x39,0x86, -0x13,0xC6,0x10,0x20,0x0A,0x86,0x12,0xC6, -0x04,0x20,0x04,0x86,0x14,0xC6,0x08,0xBD, -0xE0,0x75,0xBD,0xE1,0xD6,0x27,0x16,0x86, -0x02,0xCA,0x01,0x8D,0x0C,0x8D,0x08,0x86, -0x02,0xC6,0x01,0xE7,0x00,0x8D,0x02,0x86, -0x06,0xA7,0x01,0xE7,0x00,0x39,0xFE,0xA0, -0x02,0xFF,0xA0,0x44,0x8D,0xCF,0xB6,0xA0, -0x05,0xB0,0xA0,0x45,0xF6,0xA0,0x04,0xF2, -0xA0,0x44,0x26,0x04,0x81,0x10,0x25,0x02, -0x86,0x0F,0x8B,0x04,0xB7,0xA0,0x47,0x80, -0x03,0xB7,0xA0,0x46,0xCE,0xE1,0x93,0xBD, -0xE0,0x7E,0x5F,0xCE,0xA0,0x47,0x8D,0x24, -0xCE,0xA0,0x44,0x8D,0x1F,0x8D,0x1D,0xFE, -0xA0,0x44,0x8D,0x18,0x7A,0xA0,0x46,0x26, -0xF9,0xFF,0xA0,0x44,0x53,0x37,0x30,0x8D, -0x0B,0x33,0xFE,0xA0,0x44,0x09,0xBC,0xA0, -0x04,0x26,0xB3,0x39,0xEB,0x00,0x7E,0xE0, -0xBF,0x47,0xE1,0xD0,0x5A,0xC0,0x00,0x4D, -0xE0,0x88,0x46,0xE1,0xAE,0x52,0xE1,0x30, -0x4A,0xE0,0x05,0x43,0xE2,0xCC,0x44,0xE2, -0x8F,0x42,0xE2,0xD9,0x4F,0xE2,0x69,0x50, -0xE3,0x1A,0x4C,0xE0,0x0C,0x45,0xE3,0x1E, -0xE0,0x00,0xE1,0x8B,0xE1,0xA7,0xE0,0xD0 -}; - -/* 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, - 32768) }; - -REG cpu_reg[] = { - { HRDATA (PC, saved_PC, 16) }, - { HRDATA (A, A, 8) }, - { HRDATA (B, B, 8) }, - { HRDATA (IX, IX, 16) }, - { HRDATA (SP, SP, 16) }, - { FLDATA (H, H, 16) }, - { FLDATA (I, I, 16) }, - { FLDATA (N, N, 16) }, - { FLDATA (Z, Z, 16) }, - { FLDATA (V, V, 16) }, - { FLDATA (C, C, 16) }, - { FLDATA (INTE, INTE, 16) }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } }; - -MTAB cpu_mod[] = { - { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, - { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, - { UNIT_MSTOP, UNIT_MSTOP, "MTRAP", "MTRAP", NULL }, - { UNIT_MSTOP, 0, "NOMTRAP", "NOMTRAP", NULL }, - { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, - { UNIT_MA000, UNIT_MA000, "MA000", "MA000", NULL }, - { UNIT_MA000, 0, "NOMA000", "NOMA000", NULL }, - { 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 }; - -int32 PC; /* global for the helper routines */ - -int32 sim_instr (void) -{ - extern int32 sim_interval; - int32 IR, OP, DAR, reason, hi, lo, op1; -// uint32 val1[3]; - - PC = saved_PC & ADDRMASK; /* load local PC */ - reason = 0; - - /* Main instruction fetch/decode loop */ - - while (reason == 0) { /* loop until halted */ - if (sim_interval <= 0) /* check clock queue */ - if (reason = sim_process_event ()) - break; - if (mem_fault) { /* memory fault? */ - mem_fault = 0; /* reset fault flag */ - reason = STOP_MEMORY; - break; - } - if (int_req > 0) { /* interrupt? */ - /* 6800 interrupts not implemented yet. None were used, - on a standard SWTP 6800. All I/O is programmed. */ - } /* end interrupt */ - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - /* transient routine area - trace */ - /* - if (PC >= 0xa100 && PC < 0xa400) { - dump_regs(); - printf("\n\r%04X: ", PC); - val1[0] = M[PC]; - val1[1] = M[PC+1]; - val1[2] = M[PC+2]; - fprint_sym(stdout, PC, val1, NULL, SWMASK ('M')); - } -*/ - IR = OP = mem_get_byte(PC); /* fetch instruction */ - PC = (PC + 1) & ADDRMASK; /* increment PC */ - sim_interval--; - - /* The Big Instruction Decode Switch */ - - switch (IR) { - - case 0x01: /* NOP */ - break; - case 0x06: /* TAP */ - set_psw(A); - break; - case 0x07: /* TPA */ - A = get_psw(); - break; - case 0x08: /* INX */ - IX = (IX + 1) & ADDRMASK; - condevalZ(IX); - break; - case 0x09: /* DEX */ - IX = (IX - 1) & ADDRMASK; - condevalZ(IX); - break; - case 0x0A: /* CLV */ - V = 0; - break; - case 0x0B: /* SEV */ - V = 0x10000; - break; - case 0x0C: /* CLC */ - C = 0; - break; - case 0x0D: /* SEC */ - C = 0x10000; - break; - case 0x0E: /* CLI */ - I = 0; - break; - case 0x0F: /* SEI */ - I = 0x10000; - break; - case 0x10: /* SBA */ - op1 = A; - A = A - B; - condevalN(A); - condevalZ(A); - condevalC(A); - condevalVs(B, op1); - A &= 0xFF; - break; - case 0x11: /* CBA */ - lo = A - B; - condevalN(lo); - condevalZ(lo); - condevalC(lo); - condevalVs(B, A); - break; - case 0x16: /* TAB */ - B = A; - condevalN(B); - condevalZ(B); - V = 0; - break; - case 0x17: /* TBA */ - A = B; - condevalN(B); - condevalZ(B); - V = 0; - break; - case 0x19: /* DAA */ - DAR = A & 0x0F; - op1 = C; - if (DAR > 9 || C) { - DAR += 6; - A &= 0xF0; - A |= DAR & 0x0F; - C = 0; - if (DAR & 0x10) - C = 0x10000; - } - DAR = (A >> 4) & 0x0F; - if (DAR > 9 || C) { - DAR += 6; - if (C) - DAR++; - A &= 0x0F; - A |= (DAR << 4); - } - C = op1; - if ((DAR << 4) & 0x100) - C = 0x10000; - condevalN(A); - condevalZ(A); - A &= 0xFF; - break; - case 0x1B: /* ABA */ - A += B; - condevalH(A); - condevalN(A); - condevalZ(A); - condevalC(A); - condevalVa(A, B); - A &= 0xFF; - break; - case 0x20: /* BRA rel */ - go_rel(1); - break; - case 0x22: /* BHI rel */ - go_rel(!(C | Z)); - break; - case 0x23: /* BLS rel */ - go_rel(C | Z); - break; - case 0x24: /* BCC rel */ - go_rel(!C); - break; - case 0x25: /* BCS rel */ - go_rel(C); - break; - case 0x26: /* BNE rel */ - go_rel(!Z); - break; - case 0x27: /* BEQ rel */ - go_rel(Z); - break; - case 0x28: /* BVC rel */ - go_rel(!V); - break; - case 0x29: /* BVS rel */ - go_rel(V); - break; - case 0x2A: /* BPL rel */ - go_rel(!N); - break; - case 0x2B: /* BMI rel */ - go_rel(N); - break; - case 0x2C: /* BGE rel */ - go_rel(!(N ^ V)); - break; - case 0x2D: /* BLT rel */ - go_rel(N ^ V); - break; - case 0x2E: /* BGT rel */ - go_rel(!(Z | (N ^ V))); - break; - case 0x2F: /* BLE rel */ - go_rel(Z | (N ^ V)); - break; - case 0x30: /* TSX */ - IX = (SP + 1) & ADDRMASK; - break; - case 0x31: /* INS */ - SP = (SP + 1) & ADDRMASK; - break; - case 0x32: /* PUL A */ - SP = (SP + 1) & ADDRMASK; - A = mem_get_byte(SP); - break; - case 0x33: /* PUL B */ - SP = (SP + 1) & ADDRMASK; - B = mem_get_byte(SP); - break; - case 0x34: /* DES */ - SP = (SP - 1) & ADDRMASK; - break; - case 0x35: /* TXS */ - SP = (IX - 1) & ADDRMASK; - break; - case 0x36: /* PSH A */ - mem_put_byte(SP, A); - SP = (SP - 1) & ADDRMASK; - break; - case 0x37: /* PSH B */ - mem_put_byte(SP, B); - SP = (SP - 1) & ADDRMASK; - break; - case 0x39: /* RTS */ - SP = (SP + 1) & ADDRMASK; - PC = mem_get_word(SP) & ADDRMASK; - SP = (SP + 1) & ADDRMASK; - break; - case 0x3B: /* RTI */ - SP = (SP + 1) & ADDRMASK; - set_psw(mem_get_byte(SP)); - SP = (SP + 1) & ADDRMASK; - B = mem_get_byte(SP); - SP = (SP + 1) & ADDRMASK; - A = mem_get_byte(SP); - SP = (SP + 1) & ADDRMASK; - IX = mem_get_word(SP); - SP = (SP + 2) & ADDRMASK; - PC = mem_get_word(SP) & ADDRMASK; - SP = (SP + 1) & ADDRMASK; - break; - case 0x3E: /* WAI */ - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 2) & ADDRMASK; - mem_put_word(SP, IX); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, A); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, B); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, get_psw()); - SP = (SP - 1) & ADDRMASK; - if (I) { - reason = STOP_HALT; - continue; - } else { - I = 0x10000; - PC = mem_get_word(0xFFFE) & ADDRMASK; - } - break; - case 0x3F: /* SWI */ - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 2) & ADDRMASK; - mem_put_word(SP, IX); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, A); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, B); - SP = (SP - 1) & ADDRMASK; - mem_put_byte(SP, get_psw()); - SP = (SP - 1) & ADDRMASK; - I = 0x10000; - PC = mem_get_word(0xFFFB) & ADDRMASK; - break; - case 0x40: /* NEG A */ - A = (0 - A) & 0xFF; - V = 0; - if (A & 0x80) - V = 0x10000; - C = 0; - if (A) - C = 0x10000; - condevalN(A); - condevalZ(A); - break; - case 0x43: /* COM A */ - A = ~A & 0xFF; - V = 0; - C = 0x10000; - condevalN(A); - condevalZ(A); - break; - case 0x44: /* LSR A */ - C = 0; - if (A & 0x01) - C = 0x10000; - A = (A >> 1) & 0xFF; - N = 0; - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x46: /* ROR A */ - hi = C; - C = 0; - if (A & 0x01) - C = 0x10000; - A = (A >> 1) & 0xFF; - if (hi) - A |= 0x80; - condevalN(A); - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x47: /* ASR A */ - C = 0; - if (A & 0x01) - C = 0x10000; - lo = A & 0x8000; - A = (A >> 1) & 0xFF; - A |= lo; - condevalN(A); - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x48: /* ASL A */ - C = 0; - if (A & 0x80) - C = 0x10000; - A = (A << 1) & 0xFF; - condevalN(A); - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x49: /* ROL A */ - hi = C; - C = 0; - if (A & 0x80) - C = 0x10000; - A = (A << 1) & 0xFF; - if (hi) - A |= 0x01; - condevalN(A); - condevalZ(A); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x4A: /* DEC A */ - V = 0; - if (A == 0x80) - V = 0x10000; - A = (A - 1) & 0xFF; - condevalN(A); - condevalZ(A); - break; - case 0x4C: /* INC A */ - V = 0; - if (A == 0x7F) - V = 0x10000; - A = (A + 1) & 0xFF; - condevalN(A); - condevalZ(A); - break; - case 0x4D: /* TST A */ - lo = (A - 0) & 0xFF; - V = 0; - C = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x4F: /* CLR A */ - A = 0; - N = V = C = 0; - Z = 0x10000; - break; - case 0x50: /* NEG B */ - B = (0 - V) & 0xFF; - V = 0; - if (B & 0x8000) - V = 0x10000; - C = 0; - if (B) - C = 0x10000; - condevalN(B); - condevalZ(B); - break; - case 0x53: /* COM B */ - B = ~B & 0xFF; - V = 0; - C = 0x10000; - condevalN(B); - condevalZ(B); - break; - case 0x54: /* LSR B */ - C = 0; - if (B & 0x01) - C = 0x10000; - B = (B >> 1) & 0xFF; - N = 0; - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x56: /* ROR B */ - hi = C; - C = 0; - if (B & 0x01) - C = 0x10000; - B = (B >> 1) & 0xFF; - if (hi) - B |= 0x80; - condevalN(B); - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x57: /* ASR B */ - C = 0; - if (B & 0x01) - C = 0x10000; - lo = B & 0x8000; - B = (B >> 1) & 0xFF; - B |= lo; - condevalN(B); - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x58: /* ASL B */ - C = 0; - if (B & 0x80) - C = 0x10000; - B = (B << 1) & 0xFF; - condevalN(B); - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x59: /* ROL B */ - hi = C; - C = 0; - if (B & 0x80) - C = 0x10000; - B = (B << 1) & 0xFF; - if (hi) - B |= 0x01; - condevalN(B); - condevalZ(B); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x5A: /* DEC B */ - V = 0; - if (B == 0x80) - V = 0x10000; - B = (B - 1) & 0xFF; - condevalN(B); - condevalZ(B); - break; - case 0x5C: /* INC B */ - V = 0; - if (B == 0x7F) - V = 0x10000; - B = (B + 1) & 0xFF; - condevalN(B); - condevalZ(B); - break; - case 0x5D: /* TST B */ - lo = (B - 0) & 0xFF; - V = 0; - C = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x5F: /* CLR B */ - B = 0; - N = V = C = 0; - Z = 0x10000; - break; - case 0x60: /* NEG ind */ - DAR = get_indir_addr(); - lo = (0 - mem_get_byte(DAR)) & 0xFF; - mem_put_byte(DAR, lo); - V = 0; - if (lo & 0x80) - V = 0x10000; - C = 0; - if (lo) - C = 0x10000; - condevalN(lo); - condevalZ(lo); - break; - case 0x63: /* COM ind */ - DAR = get_indir_addr(); - lo = ~mem_get_byte(DAR) & 0xFF; - mem_put_byte(DAR, lo); - V = 0; - C = 0x10000; - condevalN(lo); - condevalZ(lo); - break; - case 0x64: /* LSR ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - lo >>= 1; - mem_put_byte(DAR, lo); - N = 0; - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x66: /* ROR ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - hi = C; - C = 0; - if (lo & 0x01) - C = 0x10000; - lo >>= 1; - if (hi) - lo |= 0x80; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x67: /* ASR ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - lo = (lo & 0x80) | (lo >> 1); - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x68: /* ASL ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x80) - C = 0x10000; - lo <<= 1; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x69: /* ROL ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - hi = C; - C = 0; - if (lo & 0x80) - C = 0x10000; - lo <<= 1; - if (hi) - lo |= 0x01; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x6A: /* DEC ind */ - DAR = get_indir_addr(); - lo = mem_get_byte(DAR); - V = 0; - if (lo == 0x80) - V = 0x10000; - lo = (lo - 1) & 0xFF; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - break; - case 0x6C: /* INC ind */ - DAR= get_indir_addr(); - lo = mem_get_byte(DAR); - V = 0; - if (lo == 0x7F) - V = 0x10000; - lo = (lo + 1) & 0xFF; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - break; - case 0x6D: /* TST ind */ - lo = (get_indir_val() - 0) & 0xFF; - V = 0; - C = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x6E: /* JMP ind */ - PC = get_indir_addr(); - break; - case 0x6F: /* CLR ind */ - mem_put_byte(get_indir_addr(), 0); - N = V = C = 0; - Z = 0x10000; - break; - case 0x70: /* NEG ext */ - DAR = get_ext_addr(PC); - lo = (0 - mem_get_byte(DAR)) & 0xFF; - mem_put_byte(DAR, lo); - V = 0; - if (lo & 0x80) - V = 0x10000; - C = 0; - if (lo) - C = 0x10000; - condevalN(lo); - condevalZ(lo); - break; - case 0x73: /* COM ext */ - DAR = get_ext_addr(); - lo = ~mem_get_byte(DAR) & 0xFF; - mem_put_byte(DAR, lo); - V = 0; - C = 0x10000; - condevalN(lo); - condevalZ(lo); - break; - case 0x74: /* LSR ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - lo >>= 1; - mem_put_byte(DAR, lo); - N = 0; - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x76: /* ROR ext */ - DAR = get_ext_addr(); - hi = C; - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - lo >>= 1; - if (hi) - lo |= 0x80; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x77: /* ASR ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x01) - C = 0x10000; - hi = lo & 0x80; - lo >>= 1; - lo |= hi; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x78: /* ASL ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - C = 0; - if (lo & 0x80) - C = 0x10000; - lo <<= 1; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x79: /* ROL ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - hi = C; - C = 0; - if (lo & 0x80) - C = 0x10000; - lo <<= 1; - if (hi) - lo |= 0x01; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - V = 0; - if (N ^ C) - V = 0x10000; - break; - case 0x7A: /* DEC ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - V = 0; - if (lo == 0x80) - V = 0x10000; - lo = (lo - 1) & 0xFF; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - break; - case 0x7C: /* INC ext */ - DAR = get_ext_addr(); - lo = mem_get_byte(DAR); - V = 0; - if (lo == 0x7F) - V = 0x10000; - lo = (lo + 1) & 0xFF; - mem_put_byte(DAR, lo); - condevalN(lo); - condevalZ(lo); - break; - case 0x7D: /* TST ext */ - lo = mem_get_byte(get_ext_addr()) - 0; - V = 0; - C = 0; - condevalN(lo); - condevalZ(lo & 0xFF); - break; - case 0x7E: /* JMP ext */ - PC = get_ext_addr() & ADDRMASK; - break; - case 0x7F: /* CLR ext */ - mem_put_byte(get_ext_addr(), 0); - N = V = C = 0; - Z = 0x10000; - break; - case 0x80: /* SUB A imm */ - op1 = get_dir_addr(); - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x81: /* CMP A imm */ - op1 = get_dir_addr(); - lo = A - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(lo, op1); - break; - case 0x82: /* SBC A imm */ - op1 = get_dir_addr(); - if (C) - A = A - op1 - 1; - else - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x84: /* AND A imm */ - A = (A & get_dir_addr()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x85: /* BIT A imm */ - lo = (A & get_dir_addr()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x86: /* LDA A imm */ - A = get_dir_addr(); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x88: /* EOR A imm */ - A = (A ^ get_dir_addr()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x89: /* ADC A imm */ - op1 = get_dir_addr(); - if (C) - A = A + op1 + 1; - else - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x8A: /* ORA A imm */ - A = (A | get_dir_addr()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x8B: /* ADD A imm */ - op1 = get_dir_addr(); - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x8C: /* CPX imm */ - op1 = IX - get_ext_addr(); - condevalZ(op1); - condevalN(op1 >> 8); - V = op1 & 0x10000; - break; - case 0x8D: /* BSR rel */ - lo = get_rel_addr(); - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 1) & ADDRMASK; - PC = PC + lo; - PC &= ADDRMASK; - break; - case 0x8E: /* LDS imm */ - SP = get_ext_addr(); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0x90: /* SUB A dir */ - op1 = get_dir_val(); - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x91: /* CMP A dir */ - op1 = get_dir_val(); - lo = A - op1; - condevalN(lo); - condevalZ(lo & 0xff); - condevalC(lo); - condevalVs(A, op1); - break; - case 0x92: /* SBC A dir */ - op1 = get_dir_val(); - if (C) - A = A - op1 - 1; - else - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x94: /* AND A dir */ - A = (A & get_dir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x95: /* BIT A dir */ - lo = (A & get_dir_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0x96: /* LDA A dir */ - A = get_dir_val(); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x97: /* STA A dir */ - mem_put_byte(get_dir_addr(), A); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x98: /* EOR A dir */ - A = (A ^ get_dir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x99: /* ADC A dir */ - op1 = get_dir_val(); - if (C) - A = A + op1 + 1; - else - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x9A: /* ORA A dir */ - A = (A | get_dir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0x9B: /* ADD A dir */ - op1 = get_dir_val(); - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0x9C: /* CPX dir */ - op1 = IX - mem_get_word(get_dir_addr()); - condevalZ(op1); - condevalN(op1 >> 8); - V = op1 & 0x10000; - break; - case 0x9E: /* LDS dir */ - SP = mem_get_word(get_dir_addr()); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0x9F: /* STS dir */ - mem_put_word(get_dir_addr(), SP); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xA0: /* SUB A ind */ - op1 = get_indir_val(); - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xA1: /* CMP A ind */ - op1 = get_indir_val(); - lo = A - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(A, op1); - break; - case 0xA2: /* SBC A ind */ - op1 = get_indir_val(); - if (C) - A = A - op1 - 1; - else - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xA4: /* AND A ind */ - A = (A & get_indir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xA5: /* BIT A ind */ - lo = (A & get_indir_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xA6: /* LDA A ind */ - A = get_indir_val(); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xA7: /* STA A ind */ - mem_put_byte(get_indir_addr(), A); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xA8: /* EOR A ind */ - A = (A ^ get_indir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xA9: /* ADC A ind */ - op1 = get_indir_val(); - if (C) - A = A + op1 + 1; - else - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xAA: /* ORA A ind */ - A = (A | get_indir_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xAB: /* ADD A ind */ - op1 = get_indir_val(); - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xAC: /* CPX ind */ - op1 = (IX - get_indir_addr()) & ADDRMASK; - condevalZ(op1); - condevalN(op1 >> 8); - V = op1 & 0x10000; - break; - case 0xAD: /* JSR ind */ - DAR = get_indir_addr(); - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 1) & ADDRMASK; - PC = DAR; - break; - case 0xAE: /* LDS ind */ - SP = mem_get_word(get_indir_addr()); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xAF: /* STS ind */ - mem_put_word(get_indir_addr(), SP); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xB0: /* SUB A ext */ - op1 = get_ext_val(); - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xB1: /* CMP A ext */ - op1 = get_ext_val(); - lo = A - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(A, op1); - break; - case 0xB2: /* SBC A ext */ - op1 = get_ext_val(); - if (C) - A = A - op1 - 1; - else - A = A - op1; - condevalN(A); - condevalC(A); - condevalVs(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xB4: /* AND A ext */ - A = (A & get_ext_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xB5: /* BIT A ext */ - lo = (A & get_ext_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xB6: /* LDA A ext */ - A = get_ext_val(); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xB7: /* STA A ext */ - mem_put_byte(get_ext_addr(), A); - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xB8: /* EOR A ext */ - A = (A ^ get_ext_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xB9: /* ADC A ext */ - op1 = get_ext_val(); - if (C) - A = A + op1 + 1; - else - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xBA: /* ORA A ext */ - A = (A | get_ext_val()) & 0xFF; - V = 0; - condevalN(A); - condevalZ(A); - break; - case 0xBB: /* ADD A ext */ - op1 = get_ext_val(); - A = A + op1; - condevalH(A); - condevalN(A); - condevalC(A); - condevalVa(A, op1); - A &= 0xFF; - condevalZ(A); - break; - case 0xBC: /* CPX ext */ - op1 = (IX - mem_get_word(get_ext_addr())) & ADDRMASK; - condevalZ(op1); - condevalN(op1 >> 8); - V = op1 & 0x10000; - break; - case 0xBD: /* JSR ext */ - DAR = get_ext_addr(); - SP = (SP - 1) & ADDRMASK; - mem_put_word(SP, PC); - SP = (SP - 1) & ADDRMASK; - PC = DAR; - break; - case 0xBE: /* LDS ext */ - SP = mem_get_word(get_ext_addr()); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xBF: /* STS ext */ - mem_put_word(get_ext_addr(), SP); - condevalN(SP >> 8); - condevalZ(SP); - V = 0; - break; - case 0xC0: /* SUB B imm */ - op1 = get_dir_addr(); - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xC1: /* CMP B imm */ - op1 = get_dir_addr(); - lo = B - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(B, op1); - break; - case 0xC2: /* SBC B imm */ - op1 = get_dir_addr(); - if (C) - B = B - op1 - 1; - else - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xC4: /* AND B imm */ - B = (B & get_dir_addr()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xC5: /* BIT B imm */ - lo = (B & get_dir_addr()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xC6: /* LDA B imm */ - B = get_dir_addr(); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xC8: /* EOR B imm */ - B = (B ^ get_dir_addr()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xC9: /* ADC B imm */ - op1 = get_dir_addr(); - if (C) - B = B + op1 + 1; - else - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xCA: /* ORA B imm */ - B = (B | get_dir_addr()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xCB: /* ADD B imm */ - op1 = get_dir_addr(); - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xCE: /* LDX imm */ - IX = get_ext_addr(); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xD0: /* SUB B dir */ - op1 = get_dir_val(); - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xD1: /* CMP B dir */ - op1 = get_dir_val(); - lo = B - op1; - condevalN(lo); - condevalZ(lo); - condevalC(lo); - condevalVs(B, op1); - break; - case 0xD2: /* SBC B dir */ - op1 = get_dir_val(); - if (C) - B = B - op1 - 1; - else - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xD4: /* AND B dir */ - B = (B & get_dir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xD5: /* BIT B dir */ - lo = (B & get_dir_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xD6: /* LDA B dir */ - B = get_dir_val(); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xD7: /* STA B dir */ - mem_put_byte(get_dir_addr(), B); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xD8: /* EOR B dir */ - B = (B ^ get_dir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xD9: /* ADC B dir */ - op1 = get_dir_val(); - if (C) - B = B + op1 + 1; - else - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xDA: /* ORA B dir */ - B = (B | get_dir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xDB: /* ADD B dir */ - op1 = get_dir_val(); - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xDE: /* LDX dir */ - IX = mem_get_word(get_dir_addr()); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xDF: /* STX dir */ - mem_put_word(get_dir_addr(), IX); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xE0: /* SUB B ind */ - op1 = get_indir_val(); - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xE1: /* CMP B ind */ - op1 = get_indir_val(); - lo = B - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(B, op1); - break; - case 0xE2: /* SBC B ind */ - op1 = get_indir_val(); - if (C) - B = B - op1 - 1; - else - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xE4: /* AND B ind */ - B = (B & get_indir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xE5: /* BIT B ind */ - lo = (B & get_indir_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xE6: /* LDA B ind */ - B = get_indir_val(); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xE7: /* STA B ind */ - mem_put_byte(get_indir_addr(), B); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xE8: /* EOR B ind */ - B = (B ^ get_indir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xE9: /* ADC B ind */ - op1 = get_indir_val(); - if (C) - B = B + op1 + 1; - else - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xEA: /* ORA B ind */ - B = (B | get_indir_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xEB: /* ADD B ind */ - op1 = get_indir_val(); - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xEE: /* LDX ind */ - IX = mem_get_word(get_indir_addr()); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xEF: /* STX ind */ - mem_put_word(get_indir_addr(), IX); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xF0: /* SUB B ext */ - op1 = get_ext_val(); - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xF1: /* CMP B ext */ - op1 = get_ext_val(); - lo = B - op1; - condevalN(lo); - condevalZ(lo & 0xFF); - condevalC(lo); - condevalVs(B, op1); - break; - case 0xF2: /* SBC B ext */ - op1 = get_ext_val(); - if (C) - B = B - op1 - 1; - else - B = B - op1; - condevalN(B); - condevalC(B); - condevalVs(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xF4: /* AND B ext */ - B = (B & get_ext_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xF5: /* BIT B ext */ - lo = (B & get_ext_val()) & 0xFF; - V = 0; - condevalN(lo); - condevalZ(lo); - break; - case 0xF6: /* LDA B ext */ - B = get_ext_val(); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xF7: /* STA B ext */ - mem_put_byte(get_ext_addr(), B); - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xF8: /* EOR B ext */ - B = (B ^ get_ext_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xF9: /* ADC B ext */ - op1 = get_ext_val(); - if (C) - B = B + op1 + 1; - else - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xFA: /* ORA B ext */ - B = (B | get_ext_val()) & 0xFF; - V = 0; - condevalN(B); - condevalZ(B); - break; - case 0xFB: /* ADD B ext */ - op1 = get_ext_val(); - B = B + op1; - condevalH(B); - condevalN(B); - condevalC(B); - condevalVa(B, op1); - B &= 0xFF; - condevalZ(B); - break; - case 0xFE: /* LDX ext */ - IX = mem_get_word(get_ext_addr()); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - case 0xFF: /* STX ext */ - mem_put_word(get_ext_addr(), IX); - condevalN(IX >> 8); - condevalZ(IX); - V = 0; - break; - - default: { /* Unassigned */ - if (cpu_unit.flags & UNIT_OPSTOP) { - reason = STOP_OPCODE; - PC--; - } - break; - } - } - } - /* Simulation halted - lets dump all the registers! */ - dump_regs(); - saved_PC = PC; - return reason; -} - -/* dump the working registers */ - -void dump_regs() -{ - printf("\r\nPC=%04X SP=%04X IX=%04X ", PC, SP, IX); - printf("A=%02X B=%02X PSW=%02X", A, B, get_psw()); -} - -/* this routine does the jump to relative offset if the condition is - met. Otherwise, execution continues at the current PC. */ - -void go_rel(int32 cond) -{ - int32 temp; - - temp = get_rel_addr(); - if (cond) - PC += temp; - PC &= ADDRMASK; -} - -/* returns the relative offset sign-extended */ - -int32 get_rel_addr() -{ - int32 temp; - - temp = mem_get_byte(PC++); - if (temp & 0x80) - temp |= 0xFF00; - return temp & ADDRMASK; -} - -/* returns the value at the direct address pointed to by PC */ - -int32 get_dir_val() -{ - return mem_get_byte(get_dir_addr()); -} - -/* returns the direct address pointed to by PC */ - -int32 get_dir_addr() -{ - int32 temp; - - temp = mem_get_byte(PC); - PC = (PC + 1) & ADDRMASK; - return temp & 0xFF; -} - -/* returns the value at the indirect address pointed to by PC */ - -int32 get_indir_val() -{ - return mem_get_byte(get_indir_addr()); -} - -/* returns the indirect address pointed to by PC or immediate byte */ - -int32 get_indir_addr() -{ - int32 temp; - - temp = (mem_get_byte(PC++) + IX) & ADDRMASK; - PC &= ADDRMASK; - return temp; -} - -/* returns the value at the extended address pointed to by PC */ - -int32 get_ext_val() -{ - return mem_get_byte(get_ext_addr()); -} - -/* returns the extended address pointed to by PC or immediate word */ - -int32 get_ext_addr() -{ - int32 temp; - - temp = (mem_get_byte(PC) << 8) | mem_get_byte(PC+1); - PC = (PC +2) & ADDRMASK; - return temp; -} - -/* return a PSW from the current flags */ - -int32 get_psw() -{ - int32 psw; - - psw = 0xC0; - if (H) - psw |= 0x20; - if (I) - psw |= 0x10; - if (N) - psw |= 0x08; - if (Z) - psw |= 0x04; - if (V) - psw |= 0x02; - if (C) - psw |= 0x01; - return psw; -} - -/* set the current flags from a PSW */ - -void set_psw(int32 psw) -{ - H = 0; - if (psw & 0x20) - H = 0x10000; - I = 0; - if (psw & 0x10) - I = 0x10000; - N = 0; - if (psw & 0x08) - N = 0x10000; - Z = 0; - if (psw & 0x04) - Z = 0x10000; - V = 0; - if (psw & 0x02) - V = 0x10000; - C = 0; - if (psw & 0x01) - C = 0x10000; -} - -/* test and set H */ - -void condevalH(int32 res) -{ - H = (res & 0x10) << 12; -} - -/* test and set N */ - -void condevalN(int32 res) -{ - N = 0; - if (res & 0x80) - N = 0x10000; -} - -/* test and set Z */ - -void condevalZ(int32 res) -{ - Z = 0; - if (res == 0) - Z = 0x10000; -} - -/* test and set V for addition */ - -void condevalVa(int32 op1, int32 op2) -{ - if (C) { - V = 0; - if (((op1 & 0x80) && (op2 & 0x80)) || - (((op1 & 0x80) == 0) && ((op2 & 0x80) == 0))) - V = 0x10000; - } -} - -/* test and set V for subtraction */ - -void condevalVs(int32 op1, int32 op2) -{ - if (C) { - V = 0; - if (((op1 & 0x80) && ((op2 & 0x80) == 0)) || - (((op1 & 0x80) == 0) && (op2 & 0x80))) - V = 0x10000; - } -} - -/* test and set C */ - -void condevalC(int32 res) -{ - C = (res & 0x100) << 8; -} - -/* memory write operations */ - -/* put word */ - -void mem_put_word(int32 addr, int32 val) -{ - mem_put_byte(addr,val >> 8); - mem_put_byte(addr + 1, val); -} - -/* put byte */ - -void mem_put_byte(int32 addr, int32 val) -{ - if (addr >= 0x0000 && addr < (int32) MEMSIZE) /* memory cards */ - M[addr] = val & 0xFF; - else if (addr >= 0x8000 && addr < 0x8020) /* memory mapped I/O */ - dev_table[addr - 0x8000].routine(1, val); - else if (addr >= 0xA000 && addr < 0xA080) /* CPU memory */ - M[addr] = val & 0xFF; - else if ((addr >= 0xA080 && addr < 0xC000) && /* extended CPU memory */ - cpu_unit.flags & UNIT_MA000) - M[addr] = val & 0xFF; - else { - if (cpu_unit.flags & UNIT_MSTOP) - mem_fault = 1; - printf("Invalid write to %04X\n\r", addr); - } -} - -/* memory read operations */ - -/* get word */ - -int32 mem_get_word(int32 addr) -{ - int32 temp; - - temp = (mem_get_byte(addr) << 8) | mem_get_byte(addr+1); - return temp; -} - -/* get byte */ - -int32 mem_get_byte(int32 addr) -{ - int32 val; - - if (addr >= 0x0000 && addr < (int32) MEMSIZE) /* memory cards */ - val = M[addr]; - else if (addr >= 0x8000 && addr < 0x8020) /* memory mapped I/O */ - val = dev_table[addr - 0x8000].routine(0, 0); - else if (addr >= 0xA000 && addr < 0xA080) /* CPU memory */ - val = M[addr]; - else if ((addr >= 0xA080 && addr < 0xC000) && /* extended CPU memory */ - cpu_unit.flags & UNIT_MA000) - val = M[addr]; - else if (addr >= 0xE000 && addr < 0x10000) /* ROM memory */ - val = M[addr]; - else { - if (cpu_unit.flags & UNIT_MSTOP) - mem_fault = 1; - val = 0xFF; /* default for no memory at address */ - printf("Invalid read of %04X\n\r", addr); - } - return val & 0xFF; -} - -/* calls from the simulator */ - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ - int i; - - I = 0x10000; - saved_PC = (M[0xFFFE] << 8) | M[0xFFFF]; - int_req = 0; - sim_brk_types = sim_brk_dflt = SWMASK ('E'); - /* copy in rom image at E000 */ - for (i = 0; i < BOOTLEN; i++) { - M[i + 0xE000] = bootrom[i] & 0xFF; - } - /* copy in rom image at FC00 for vectors! */ - for (i = 0; i < BOOTLEN; i++) { - M[i + 0xFC00] = bootrom[i] & 0xFF; - } - return SCPE_OK; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ - if (addr >= MAXMEMSIZE) - return SCPE_NXM; - if (vptr != NULL) - *vptr = mem_get_byte(addr); - return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ - if (addr >= MAXMEMSIZE) - return SCPE_NXM; - mem_put_byte(addr, val); -// printf("Deposit to %04X of %02X\n\r", addr, val); - return SCPE_OK; -} - -/* adjust the memory size for the emulator 4k to 32k in 4k steps */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - int32 mc = 0; - uint32 i; - - if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 0x0FFF) != 0)) - return SCPE_ARG; - for (i = val; i < MEMSIZE; i++) - mc = mc | M[i]; - if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) - return SCPE_OK; - MEMSIZE = val; - return SCPE_OK; -} - -/* dummy i/o device */ - -int32 nulldev(int32 io, int32 data) -{ - if (io == 0) - return (0xFF); - return 0; -} - diff --git a/swtp/swtp_dsk.c b/swtp/swtp_dsk.c deleted file mode 100644 index 9c8c7d38..00000000 --- a/swtp/swtp_dsk.c +++ /dev/null @@ -1,506 +0,0 @@ -/* swtp_dc4_dsk.c: SWTP DC-4 DISK Simulator - - Copyright (c) 2005, William A. Beech - - 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 William A. Beech shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 - - - The DC-4 is a 5-inch floppy controller which can control up - to 4 daisy-chained 5-inch floppy drives. The controller is based on - the Western Digital 1797 Floppy Disk Controller (FDC) chip. This - file only emulates the minimum DC-4 functionality to interface with - the virtual disk file. - - The floppy controller is interfaced to the CPU by use of 5 memory - addreses. These are device numbers 5 and 6 (0x8014-0x801B). - - Address Mode Function - ------- ---- -------- - - 0x8014 Read Returns FDC interrupt status - 0x8014 Write Selects the drive/head/motor control - 0x8018 Read Returns status of FDC - 0x8018 Write FDC command register - 0x8019 Read Returns FDC track register - 0x8019 Write Set FDC track register - 0x801A Read Returns FDC sector register - 0x801A Write Set FDC sector register - 0x801B Read Read data - 0x801B Write Write data - - Drive Select Read (0x8014): - - +---+---+---+---+---+---+---+---+ - | I | D | X | X | X | X | X | X | - +---+---+---+---+---+---+---+---+ - - I = Set indicates an interrupt request from the FDC pending. - D = DRQ pending - same as bit 1 of FDC status register. - - Drive Select Write (0x8014): - - +---+---+---+---+---+---+---+---+ - | M | S | X | X | X | X | Device| - +---+---+---+---+---+---+---+---+ - - M = If this bit is 1, the one-shot is triggered/retriggered to - start/keep the motors on. - S = Side select. If set, side one is selected otherwise side zero - is selected. - X = not used - Device = value 0 thru 3, selects drive 0-3 to be controlled. - - Drive Status Read (0x8018): - - +---+---+---+---+---+---+---+---+ - | R | P | H | S | C | L | D | B | - +---+---+---+---+---+---+---+---+ - - B - When 1, the controller is busy. - D - When 1, index mark detected (type I) or data request - read data - ready/write data empty (type II or III). - H - When 1, track 0 (type I) or lost data (type II or III). - C - When 1, crc error detected. - S - When 1, seek (type I) or RNF (type II or III) error. - H - When 1, head is currently loaded (type I) or record type/ - write fault (type II or III). - P - When 1, indicates that diskette is write-protected. - R - When 1, drive is not ready. - - Drive Control Write (0x8018) for type I commands: - - +---+---+---+---+---+---+---+---+ - | 0 | S2| S1| S0| H | V | R1| R0| - +---+---+---+---+---+---+---+---+ - - R0/R1 - Selects the step rate. - V - When 1, verify on destination track. - H - When 1, loads head to drive surface. - S0/S1/S2 = 000 - home. - 001 - seek track in data register. - 010 - step without updating track register. - 011 - step and update track register. - 100 - step in without updating track register. - 101 - step in and update track register. - 110 - step out without updating track register. - 111 - step out and update track register. - - Drive Control Write (0x8018) for type II commands: - - +---+---+---+---+---+---+---+---+ - | 1 | 0 | T | M | S | E | B | A | - +---+---+---+---+---+---+---+---+ - - A - Zero for read, 1 on write deleted data mark else data mark. - B - When 1, shifts sector length field definitions one place. - E - When, delay operation 15 ms, 0 no delay. - S - When 1, select side 1, 0 select side 0. - M - When 1, multiple records, 0 for single record. - T - When 1, write command, 0 for read. - - Drive Control Write (0x8018) for type III commands: - - +---+---+---+---+---+---+---+---+ - | 1 | 1 | T0| T1| 0 | E | 0 | 0 | - +---+---+---+---+---+---+---+---+ - - E - When, delay operation 15 ms, 0 no delay. - T0/T1 - 00 - read address command. - 10 - read track command. - 11 - write track command. - - Tracks are numbered from 0 up to one minus the last track in the 1797! - - Track Register Read (0x8019): - - +---+---+---+---+---+---+---+---+ - | Track Number | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the track position. - - Track Register Write (0x8019): - - +---+---+---+---+---+---+---+---+ - | Track Number | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the track register. - - Sectors are numbers from 1 up to the last sector in the 1797! - - Sector Register Read (0x801A): - - +---+---+---+---+---+---+---+---+ - | Sector Number | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the sector position. - - Sector Register Write (0x801A): - - +---+---+---+---+---+---+---+---+ - | Sector Number | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the sector register. - - Data Register Read (0x801B): - - +---+---+---+---+---+---+---+---+ - | Data | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the data register. - - Data Register Write (0x801B): - - +---+---+---+---+---+---+---+---+ - | Data | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the data register. - - A FLEX disk is defined as follows: - - Track Sector Use - 0 1 Boot sector - 0 2 Boot sector (cont) - 0 3 Unused - 0 4 System Identity Record (explained below) - 0 5 Unused - 0 6-last Directory - 10 entries/sector (explained below) - 1 1 First available data sector - last-1 last Last available data sector - - System Identity Record - - Byte Use - 0x10 Volume ID (8 bytes) - 0x18 ??? - 0x19 ??? - 0x1A ??? - 0x1B Volume number (2 bytes) - 0x1D First free sector (2 bytes) - 0x1F Last track minus one (byte) - 0x20 Last sector (byte) - 0x21 Total sectors on disk (2 bytes) - 0x23 Month (byte - 0x24 Day (byte) - 0x25 Year (byte) - 0x26 Last track minus one (byte) - 0x27 Last sector (byte) - -*/ - -#include - -#include "swtp_defs.h" - -#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ -#define UNIT_ENABLE (1 << UNIT_V_ENABLE) - -/* emulate a SS FLEX disk with 72 sectors and 80 tracks */ - -#define NUM_DISK 4 /* standard 1797 maximum */ -#define SECT_SIZE 256 /* standard FLEX sector */ -#define NUM_SECT 72 /* sectors/track */ -#define TRAK_SIZE (SECT_SIZE * NUM_SECT) -#define HEADS 1 /* handle as SS with twice the sectors */ -#define NUM_CYL 80 /* maximum tracks */ -#define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE) - -/* 1797 status bits */ - -#define BUSY 0x01 -#define DRQ 0x02 -#define WRPROT 0x40 -#define NOTRDY 0x80 - -/* debug prints */ - -#define DEBUG 0 - - -/* prototypes */ - -t_stat dsk_svc (UNIT *uptr); -t_stat dsk_reset (DEVICE *dptr); -int32 fdcdrv(int32 io, int32 data); -int32 fdccmd(int32 io, int32 data); -int32 fdctrk(int32 io, int32 data); -int32 fdcsec(int32 io, int32 data); -int32 fdcdata(int32 io, int32 data); - -/* Global data on status */ - -int32 cur_dsk = NUM_DISK; /* Currently selected drive */ -int32 cur_trk[NUM_DISK] = {0, 0, 0, 0}; -int32 cur_sec[NUM_DISK] = {0, 0, 0, 0}; -int32 cur_byt[NUM_DISK] = {0, 0, 0, 0}; -int32 cur_flg[NUM_DISK] = {NOTRDY, NOTRDY, NOTRDY, NOTRDY}; - -/* Variables */ - -uint8 dskbuf[SECT_SIZE]; /* Data Buffer */ -UNIT *dptr = NULL; /* fileref to write dirty buffer to */ -int32 fdcbyte; -int32 intrq = 0; /* interrupt request flag */ - -/* DC-4 Simh Device Data Structures */ - -UNIT dsk_unit[] = { - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) } }; - -REG dsk_reg[] = { - { HRDATA (DISK, cur_dsk, 4) }, - { NULL } }; - -MTAB dsk_mod[] = { - { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, - { UNIT_ENABLE, 0, "RO", "RO", NULL }, - { 0 } }; - -DEVICE dsk_dev = { - "DSK", dsk_unit, dsk_reg, dsk_mod, - NUM_DISK, 16, 16, 1, 16, 8, - NULL, NULL, &dsk_reset, - NULL, NULL, NULL }; - -/* service routines to handle simlulator functions */ - -/* service routine - actually gets char & places in buffer */ - -t_stat dsk_svc (UNIT *uptr) -{ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat dsk_reset (DEVICE *dptr) -{ -cur_dsk = 0; -return SCPE_OK; -} - -/* I/O instruction handlers, called from the CPU module when an - memory read or write to the proper addresses is issued. - - Each function is passed an 'io' flag, where 0 means a read from - the port, and 1 means a write to the port. On input, the actual - input is passed as the return value, on output, 'data' is written - to the device. -*/ - -/* DC-4 drive select register routine - this register is not part of the 1797 -*/ - -int32 fdcdrv(int32 io, int32 data) -{ -/* **** probably need to grab the parameters from the SIR and set the limits */ - if (io) { /* write to DC-4 drive register */ - cur_dsk = data & 0x03; /* only 2 drive select bits */ -#if DEBUG > 0 - printf("Drive set to %d\n\r", cur_dsk); -#endif - if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0) - cur_flg[cur_dsk] |= WRPROT; /* set WPROT */ - return 0; - } else { /* read from DC-4 drive register */ -#if DEBUG > 0 - printf("Drive read as %02X\n\r", intrq); -#endif - return intrq; - } -} - -/* WD 1797 FDC command register routine */ - -int32 fdccmd(int32 io, int32 data) -{ - static int32 val = 0, val1 = NOTRDY, i; - static long pos; - UNIT *uptr; - - if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */ - cur_flg[cur_dsk] |= NOTRDY; /* set not ready flag */ - printf("Drive %d is not attached\n\r", cur_dsk); - return 0; - } else { - cur_flg[cur_dsk] &= ~NOTRDY; /* clear not ready flag */ - } - uptr = dsk_dev.units + cur_dsk; /* get virtual drive address */ - if (io) { /* write command to fdc */ - switch(data) { - case 0x8C: /* read command */ - case 0x9C: -#if DEBUG > 0 - printf("Read of disk %d, track %d, sector %d\n\r", - cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]); -#endif - pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */ - pos += SECT_SIZE * (cur_sec[cur_dsk] - 1); -#if DEBUG > 0 - printf("Read pos = %ld ($%04X)\n\r", pos, pos); -#endif - sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */ - sim_fread(dskbuf, 256, 1, uptr -> fileref); /* read in buffer */ - cur_flg[cur_dsk] |= BUSY | DRQ; /* set DRQ & BUSY */ - i = cur_byt[cur_dsk] = 0; /* clear counter */ - break; - case 0xAC: /* write command */ -#if DEBUG > 0 - printf("Write of disk %d, track %d, sector %d\n\r", - cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]); -#endif - if (cur_flg[cur_dsk] & WRPROT) { - printf("Drive %d is write-protected\n\r", cur_dsk); - } else { - pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */ - pos += SECT_SIZE * (cur_sec[cur_dsk] - 1); -#if DEBUG > 1 - printf("Write pos = %ld ($%04X)\n\r", pos, pos); -#endif - sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */ - dptr = uptr; /* save pointer for actual write */ - cur_flg[cur_dsk] |= BUSY | DRQ;/* set DRQ & BUSY */ - i = cur_byt[cur_dsk] = 0; /* clear counter */ - } - break; - case 0x18: /* seek command */ - case 0x1B: - cur_trk[cur_dsk] = fdcbyte; /* set track */ - cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ -#if DEBUG > 0 - printf("Seek of disk %d, track %d\n\r", cur_dsk, fdcbyte); -#endif - break; - case 0x0B: /* restore command */ - cur_trk[cur_dsk] = 0; /* home the drive */ - cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ -#if DEBUG > 0 - printf("Drive %d homed\n\r", cur_dsk); -#endif - break; - default: - printf("Unknown FDC command %02XH\n\r", data); - } - } else { /* read status from fdc */ - val = cur_flg[cur_dsk]; /* set return value */ - if (val1 == 0 && val == 0x03) /* delay BUSY going high */ - val = 0x02; /* set DRQ first */ - if (val != val1) { /* now allow BUSY after on read */ - val1 = val; -#if DEBUG > 0 - printf("Drive %d status=%02X\n\r", cur_dsk, cur_flg[cur_dsk]); -#endif - } - } - return val; -} - -/* WD 1797 FDC track register routine */ - -int32 fdctrk(int32 io, int32 data) -{ - if (io) { - cur_trk[cur_dsk] = data & 0xFF; -#if DEBUG > 1 - printf("Drive %d track set to %d\n\r", cur_dsk, data); -#endif - } else - ; -#if DEBUG > 1 - printf("Drive %d track read as %d\n\r", cur_dsk, cur_trk[cur_dsk]); -#endif - return cur_trk[cur_dsk]; -} - -/* WD 1797 FDC sector register routine */ - -int32 fdcsec(int32 io, int32 data) -{ - if (io) { - cur_sec[cur_dsk] = data & 0xFF; - if (cur_sec[cur_dsk] == 0) /* fix for swtp boot! */ - cur_sec[cur_dsk] = 1; -#if DEBUG > 1 - printf("Drive %d sector set to %d\n\r", cur_dsk, data); -#endif - } else - ; -#if DEBUG > 1 - printf("Drive %d sector read as %d\n\r", cur_dsk, cur_sec[cur_dsk]); -#endif - return cur_sec[cur_dsk]; -} - -/* WD 1797 FDC data register routine */ - -int32 fdcdata(int32 io, int32 data) -{ - int32 i; - - if (io) { /* write byte to fdc */ - fdcbyte = data; /* save for seek */ - if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes to buffer */ -#if DEBUG > 3 - printf("Writing byte %d of %02X\n\r", cur_byt[cur_dsk], data); -#endif - cur_byt[cur_dsk]++; /* step counter */ - dskbuf[i] = data; /* byte into buffer */ - if (cur_byt[cur_dsk] == SECT_SIZE) { - cur_flg[cur_dsk] &= ~(BUSY | DRQ); - if (dptr) { /* if initiated by FDC write command */ - sim_fwrite(dskbuf, 256, 1, dptr -> fileref); /* write it */ - dptr = NULL; - } -#if DEBUG > 0 - printf("Sector write complete\n\r"); -#endif - } - } - return 0; - } else { /* read byte from fdc */ - if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes from buffer */ -#if DEBUG > 1 - printf("Reading byte %d\n\r", cur_byt[cur_dsk]); -#endif - cur_byt[cur_dsk]++; /* step counter */ - if (cur_byt[cur_dsk] == SECT_SIZE) { /* done? */ - cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ -#if DEBUG > 0 - printf("Sector read complete\n\r"); -#endif - } - return (dskbuf[i] & 0xFF); - } else - return 0; - } -} - diff --git a/swtp/swtp_sio.c b/swtp/swtp_sio.c deleted file mode 100644 index 1f6f8a77..00000000 --- a/swtp/swtp_sio.c +++ /dev/null @@ -1,312 +0,0 @@ -/* swtp_sio: SWTP serial I/O card - -Copyright (c) 2005, William Beech - - 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 - Willaim Beech 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 William A. Beech shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 - - These functions support a simulated SWTP MP-S interface card. - The card had two physical I/O ports which could be connected - to any serial I/O device that would connect to a current loop - or RS232 interface. Available baud rates were jumper selectable - for each port from 110 to 9600. The ports appear at all 4 addresses. - This fact is used by SWTBUG to determine the presence of the MP-S vice - MP-C serial card. - - All I/O is via either programmed I/O or interrupt controlled I/O. - It has a status port and a data port. A write to the status port - can select some options for the device (0x03 will reset the port). - A read of the status port gets the port status: - - +---+---+---+---+---+---+---+---+ - | I | P | O | F |CTS|DCD|TXE|RXF| - +---+---+---+---+---+---+---+---+ - - RXF - A 1 in this bit position means a character has been received - on the data port and is ready to be read. - TXE - A 1 in this bit means the port is ready to receive a character - on the data port and transmit it out over the serial line. - - A read to the data port gets the buffered character, a write - to the data port writes the character to the device. -*/ - -#include -#include - -#include "swtp_defs.h" - -#define UNIT_V_ANSI (UNIT_V_UF + 0) // ANSI mode -#define UNIT_ANSI (1 << UNIT_V_ANSI) - -t_stat sio_svc (UNIT *uptr); -t_stat sio_reset (DEVICE *dptr); -t_stat ptr_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptp_svc (UNIT *uptr); -t_stat ptp_reset (DEVICE *dptr); - -int32 ptr_stopioe = 0, ptp_stopioe = 0; // stop on error - -// MP-S Standard I/O Data Structures - -UNIT sio_unit = { UDATA (&sio_svc, 0, 0), - KBD_POLL_WAIT }; - -REG sio_reg[] = { - { ORDATA (DATA, sio_unit.buf, 8) }, - { ORDATA (STAT, sio_unit.u3, 8) }, - { NULL } }; - -MTAB sio_mod[] = { - { UNIT_ANSI, 0, "TTY", "TTY", NULL }, - { 0 } }; - -DEVICE sio_dev = { - "MP-S", &sio_unit, sio_reg, sio_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &sio_reset, - NULL, NULL, NULL }; - -UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), - KBD_POLL_WAIT }; -DEVICE ptr_dev = { - "PTR", &ptr_unit, NULL, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - NULL, NULL, NULL }; - -UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), - KBD_POLL_WAIT }; -DEVICE ptp_dev = { - "PTP", &ptp_unit, NULL, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, NULL, NULL }; - -/* Service routines to handle simulator functions */ - -/* service routine - actually gets char & places in buffer */ - -int32 ptp_rdr(int32 io, int32 data); - -int32 ptp_flag = 0, ptr_flag = 0; - -/* console input service routine */ - -t_stat sio_svc (UNIT *uptr) -{ - int32 temp; - - sim_activate (&sio_unit, sio_unit.wait); // continue poll - if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) - return temp; // no char or error? - sio_unit.buf = temp & 0xFF; // Save char - sio_unit.u3 |= 0x01; // Set RXF flag - - /* Do any special character handling here */ - - sio_unit.pos++; // step character count - return SCPE_OK; -} - -/* paper tape reader input service routine */ - -t_stat ptr_svc (UNIT *uptr) -{ - return SCPE_OK; -} - -/* paper tape punch output service routine */ - -t_stat ptp_svc (UNIT *uptr) -{ - return SCPE_OK; -} - -/* Reset console */ - -t_stat sio_reset (DEVICE *dptr) -{ - sio_unit.buf = 0; // Data buffer - sio_unit.u3 = 0x02; // Status buffer - sim_activate (&sio_unit, sio_unit.wait); // activate unit - return SCPE_OK; -} - -/* Reset paper tape reader */ - -t_stat ptr_reset (DEVICE *dptr) -{ - ptr_unit.buf = 0; - ptr_unit.u3 = 0x02; - sim_cancel (&ptr_unit); // deactivate unit - return SCPE_OK; -} - -/* Reset paper tape punch */ - -t_stat ptp_reset (DEVICE *dptr) -{ - ptp_unit.buf = 0; - ptp_unit.u3 = 0x02; - sim_cancel (&ptp_unit); // deactivate unit - return SCPE_OK; -} - -/* I/O instruction handlers, called from the CPU module when a - read or write occur to addresses 0x8000-0x801F. - - Each function is passed an 'io' flag, where 0 means a read from - the port, and 1 means a write to the port. On input, the actual - input is passed as the return value, on output, 'data' is written - to the device. - - This code emulates a SWTP MP-S Serial Card with a Model 33 Teletype - attached. The Model 33 uses DC1-DC4 codes to enable or disable the - paper tape reader and punch. Those devices are defined in this module, - and the code built to emulate those functions if the PTP and/or PTR - are attached in the simulator. -*/ - -/* Port 1 (0x8004-0x8007) controls the Model 33 Teletype */ - -int32 ptr_flg1 = 0; -int32 odata, status; - - -int32 sio0s(int32 io, int32 data) -{ - UNIT *uptr; - - if (io == 0) { // control register read - if (ptr_flag) { // reader enabled? - if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? - ptr_unit.u3 &= 0xFE; // no, clear RXF flag - else { - uptr = ptr_dev.units;// not EOF? - if (feof(uptr -> fileref)) - ptr_unit.u3 &= 0xFE; - else - ptr_unit.u3 |= 0x01; - } - return (status = ptr_unit.u3); // no - done - } else { - return (status = sio_unit.u3); // return console status - } - } else { // control register write - if (data == 0x03) { // reset port! - sio_unit.u3 = 0x02; // reset console - sio_unit.buf = 0; - sio_unit.pos = 0; - ptr_unit.u3 = 0x02; // reset reader - ptr_unit.buf = 0; - ptr_unit.pos = 0; - ptp_unit.u3 = 0x02; // reset punch - ptp_unit.buf = 0; - ptp_unit.pos = 0; - } - return (status = 0); // invalid io - } -} - -int32 sio0d(int32 io, int32 data) -{ - UNIT *uptr; - - if (io == 0) { // data register read - if (ptr_flag) { // RDR enabled? - if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? - return 0; // no, done -// printf("ptr_unit.u3=%02X\n", ptr_unit.u3); - if ((ptr_unit.u3 & 0x01) == 0) { // yes, more data? -// printf("Returning old %02X\n", odata); // no, return previous byte - return (odata & 0xFF); - } - uptr = ptr_dev.units; // get data byte - if ((odata = getc(uptr -> fileref)) == EOF) { // end of file? -// printf("Got EOF\n"); - ptr_unit.u3 &= 0xFE; // clear RXF flag - return (odata = 0); // no data - } -// printf("Returning new %02X\n", odata); - ptr_unit.pos++; // step character count - ptr_unit.u3 &= 0xFE; // clear RXF flag - return (odata & 0xFF); // return character - } else { - sio_unit.u3 &= 0xFE; // clear RXF flag - return (odata = sio_unit.buf); // return next char - } - } else { // data register write - if (isprint(data) || data == '\r' || data == '\n') { // printable? - sim_putchar(data); // print character on console - if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached? - uptr = ptp_dev.units; // punch character to file - putc(data, uptr -> fileref); - ptp_unit.pos++; // step character counter - } - } else { // DC1-DC4 control Reader/Punch - switch (data) { - case 0x11: // RDR on - ptr_flag = 1; - ptr_flg1 = 0; - ptr_unit.u3 |= 0x01; -// printf("Reader on\r\n"); - break; - case 0x12: // PTP on - ptp_flag = 1; - ptp_unit.u3 |= 0x02; -// printf("Punch on\r\n"); - break; - case 0x13: // RDR off - ptr_flag = 0; -// printf("Reader off-%d bytes read\r\n", ptr_unit.pos); - break; - case 0x14: // PTP off - ptp_flag = 0; -// printf("Punch off-%d bytes written\r\n", ptp_unit.pos); - break; - default: // ignore all other characters - break; - } - } - } - return (odata = 0); -} - -/* because each port appears at 2 addresses and this fact is used - to determine if it is a MP-C or MP-S repeatedly in the SWTBUG - monitor, this code assures that reads of the high ports return - the same data as was read the last time on the low ports. -*/ - -int32 sio1s(int32 io, int32 data) -{ - return status; -} - -int32 sio1d(int32 io, int32 data) -{ - return odata; -} - diff --git a/swtp/swtp_sys.c b/swtp/swtp_sys.c deleted file mode 100644 index 391065cd..00000000 --- a/swtp/swtp_sys.c +++ /dev/null @@ -1,425 +0,0 @@ -/* swtp_sys.c: SWTP 6800 system interface - - Copyright (c) 2005, William Beech - - 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 - WILLIAM A BEECH 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 William A. Beech shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. - - Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 - -*/ - -#include -#include -#include "swtp_defs.h" - -/* externals */ - -extern DEVICE cpu_dev; -extern DEVICE dsk_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern DEVICE sio_dev; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE lpt_dev; -extern unsigned char M[]; -extern int32 saved_PC; -extern int32 sim_switches; -//extern int32 (*sim_vm_fprint_addr)(FILE*, DEVICE*,t_addr); - -/* prototypes */ - -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag); -int32 fprint_sym (FILE *of, int32 addr, uint32 *val, - UNIT *uptr, int32 sw); -t_addr fprint_addr(FILE *stream, DEVICE *dptr, t_addr addr); -int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); -void sim_special_init (void); - -/* links into scp */ - -void (*sim_vm_init)(void) = &sim_special_init; - -/* 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[] = "SWTP 6800"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 16; - -DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptp_dev, &ptr_dev, &dsk_dev, NULL }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Unknown I/O Instruction", - "HALT instruction", - "Breakpoint", - "Invalid Opcode", - "Invalid Memory" }; - -static const char *opcode[] = { -"???", "NOP", "???", "???", //0x00 -"???", "???", "TAP", "TPA", -"INX", "DEX", "CLV", "SEV", -"CLC", "SEC", "CLI", "SEI", -"SBA", "CBA", "???", "???", //0x10 -"???", "???", "TAB", "TBA", -"???", "DAA", "???", "ABA", -"???", "???", "???", "???", -"BRA", "???", "BHI", "BLS", //0x20 -"BCC", "BCS", "BNE", "BEQ", -"BVC", "BVS", "BPL", "BMI", -"BGE", "BLT", "BGT", "BLE", -"TSX", "INS", "PULA", "PULB", //0x30 -"DES", "TXS", "PSHA", "PSHB", -"???", "RTS", "???", "RTI", -"???", "???", "WAI", "SWI", -"NEGA", "???", "???", "COMA", //0x40 -"LSRA", "???", "RORA", "ASRA", -"ASLA", "ROLA", "DECA", "???", -"INCA", "TSTA", "???", "CLRA", -"NEGB", "???", "???", "COMB", //0x50 -"LSRB", "???", "RORB", "ASRB", -"ASLB", "ROLB", "DECB", "???", -"INCB", "TSTB", "???", "CLRB", -"NEG", "???", "???", "COM", //0x60 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"NEG", "???", "???", "COM", //0x70 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"SUBA", "CMPA", "SBCA", "???", //0x80 -"ANDA", "BITA", "LDAA", "???", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "BSR", "LDS", "???", -"SUBA", "CMPA", "SBCA", "???", //0x90 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "???", "LDS", "STS", -"SUBA", "CMPA", "SBCA", "???", //0xA0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX X", "JSR X", "LDS X", "STS X", -"SUBA", "CMPA", "SBCA", "???", //0xB0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "JSR", "LDS", "STS", -"SUBB", "CMPB", "SBCB", "???", //0xC0 -"ANDB", "BITB", "LDAB", "???", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "???", -"SUBB", "CMPB", "SBCB", "???", //0xD0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xE0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xF0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", - }; - -int32 oplen[256] = { -0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 -1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, -2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, -2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, -3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 -2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 }; - -/* This is the dumper/loader. This command uses the -h to signify a - hex dump/load vice a binary one. If no address is given to load, it - takes the address from the hex record or the current PC for binary. -*/ - -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ - int32 i, cnt = 0, addr = 0, start = 0x10000, end = 0, bytecnt, - cksum1, cksum, bytes[250]; - char buffer[256]; - - sscanf(cptr," %x-%x", &start, &end); - if (flag) { // dump - if (start == 0x10000) // no address parameter - return SCPE_2FARG; - if (sim_switches & 0x80) { // hex dump - addr = start; - while (addr <= end) { // more records to write - if ((addr + 16) <= end) // how many bytes this record - bytecnt = 16 + 3; - else - bytecnt = end - addr + 4; - cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum - fprintf(fileref, "S1%02X%02X%02X", bytecnt, addr>>8, addr&0xFF); //header - for (i=0; i> 8) - (addr & 0xFF); //init cksum - for (i=0; i < bytecnt-3; i++) - cksum -= bytes[i]; - cksum &= 0xFF; - if (cksum != cksum1) - printf("Checksum error\n"); - else { - for (i=0; i < bytecnt-3; i++) { - M[addr++] = bytes[i]; - cnt++; - } - } - } else if (buffer[1] == '9') // end of file - printf("End of file\n"); - } - } - } else { // binary load - if (start == 0x10000) // no starting address - addr = saved_PC; - else - addr = start; - start = addr; - while ((i = getc (fileref)) != EOF) { - M[addr] = i; - addr++; - cnt++; - } - } - printf ("%d Bytes loaded starting at %04X\n", cnt, start); - } - return (SCPE_OK); -} - -/* 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) -{ - int32 i, inst, inst1; - - if (sw & SWMASK ('D')) { // dump memory - for (i=0; i<16; i++) - fprintf(of, "%02X ", val[i]); - fprintf(of, " "); - for (i=0; i<16; i++) - if (isprint(val[i])) - fprintf(of, "%c", val[i]); - else - fprintf(of, "."); - return -15; - } else if (sw & SWMASK ('M')) { // dump instruction mnemonic - inst = val[0]; - if (!oplen[inst]) { // invalid opcode - fprintf(of, "%02X", inst); - return 0; - } - inst1 = inst & 0xF0; - fprintf (of, "%s", opcode[inst]); // mnemonic - if (strlen(opcode[inst]) == 3) - fprintf(of, " "); - if (inst1 == 0x20 || inst == 0x8D) { // rel operand - inst1 = val[1]; - if (val[1] & 0x80) - inst1 |= 0xFF00; - fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); - } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand - if ((inst & 0x0F) < 0x0C) - fprintf(of, " #$%02X", val[1]); - else - fprintf(of, " #$%02X%02X", val[1], val[2]); - } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand - fprintf(of, " %d,X", val[1]); - else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand - fprintf(of, " $%02X%02X", val[1], val[2]); - return (-(oplen[inst] - 1)); - } else - return SCPE_ARG; -} - -/* address output routine */ - -t_addr fprint_addr(FILE *of, DEVICE *dptr, t_addr addr) -{ - fprintf(of, "%04X", addr); - return 0; -} - -/* 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) -{ - int32 cflag, i = 0, j, r; - char gbuf[CBUFSIZE]; - - cflag = (uptr == NULL) || (uptr == &cpu_unit); - while (isspace (*cptr)) cptr++; /* absorb spaces */ - if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) - return SCPE_ARG; /* must have 1 char */ - val[0] = (uint32) cptr[0]; - return SCPE_OK; - } - if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ - if (cptr[0] == 0) - return SCPE_ARG; /* must have 1 char */ - val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; - return SCPE_OK; - } - -/* An instruction: get opcode (all characters until null, comma, - or numeric (including spaces). -*/ - - while (1) { - if (*cptr == ',' || *cptr == '\0' || - isdigit(*cptr)) - break; - gbuf[i] = toupper(*cptr); - cptr++; - i++; - } - -/* Allow for RST which has numeric as part of opcode */ - - if (toupper(gbuf[0]) == 'R' && - toupper(gbuf[1]) == 'S' && - toupper(gbuf[2]) == 'T') { - gbuf[i] = toupper(*cptr); - cptr++; - i++; - } - -/* Allow for 'MOV' which is only opcode that has comma in it. */ - - if (toupper(gbuf[0]) == 'M' && - toupper(gbuf[1]) == 'O' && - toupper(gbuf[2]) == 'V') { - gbuf[i] = toupper(*cptr); - cptr++; - i++; - gbuf[i] = toupper(*cptr); - cptr++; - i++; - } - -/* kill trailing spaces if any */ - gbuf[i] = '\0'; - for (j = i - 1; gbuf[j] == ' '; j--) { - gbuf[j] = '\0'; - } - -/* find opcode in table */ - for (j = 0; j < 256; j++) { - if (strcmp(gbuf, opcode[j]) == 0) - break; - } - if (j > 255) /* not found */ - return SCPE_ARG; - - val[0] = j; /* store opcode */ - if (oplen[j] < 2) /* if 1-byter we are done */ - return SCPE_OK; - if (*cptr == ',') cptr++; - cptr = get_glyph(cptr, gbuf, 0); /* get address */ - sscanf(gbuf, "%o", &r); - if (oplen[j] == 2) { - val[1] = r & 0xFF; - return (-1); - } - val[1] = r & 0xFF; - val[2] = (r >> 8) & 0xFF; - return (-2); -} - -/* initialize optional interfaces */ - -void sim_special_init (void) -{ -// *sim_vm_fprint_addr = &fprint_addr; -} - diff --git a/swtp6800/common/bootrom.c b/swtp6800/common/bootrom.c new file mode 100644 index 00000000..608ecae0 --- /dev/null +++ b/swtp6800/common/bootrom.c @@ -0,0 +1,231 @@ +/* bootrom.c: Boot ROM simulator for Motorola processors + + Copyright (c) 2010-2011, William A. Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a single simulated 2704 to 2764 EPROM device on + an 8-bit computer system.. This device allows the the device buffer to + be loaded from a binary file containing the emulated EPROM code. + + These functions support a simulated 2704, 2708, 2716, 2732 or 2764 EPROM + device on a CPU board. The byte get and put routines use an offset into + the boot EPROM image to locate the proper byte. This allows another device + to set the base address for the boot EPROM. The device type is stored as + a binary number in the first three unit flag bits. + + This device uses a dynamically allocated buffer to hold the EPROM image. + A call to BOOTROM_config will free the current buffer. A call to + BOOTROM_reset will allocate a new buffer of BOOTROM_unit.capac bytes. A + call to BOOTROM_attach will load the buffer with the EPROM image. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ +#define UNIT_MSIZE (0x7 << UNIT_V_MSIZE) +#define UNIT_NONE (0 << UNIT_V_MSIZE) /* No EPROM */ +#define UNIT_2704 (1 << UNIT_V_MSIZE) /* 2704 mode */ +#define UNIT_2708 (2 << UNIT_V_MSIZE) /* 2708 mode */ +#define UNIT_2716 (3 << UNIT_V_MSIZE) /* 2716 mode */ +#define UNIT_2732 (4 << UNIT_V_MSIZE) /* 2732 mode */ +#define UNIT_2764 (5 << UNIT_V_MSIZE) /* 2764 mode */ + +/* function prototypes */ + +t_stat BOOTROM_svc (UNIT *uptr); +t_stat BOOTROM_config (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat BOOTROM_attach (UNIT *uptr, char *cptr); +t_stat BOOTROM_reset (DEVICE *dptr); +int32 BOOTROM_get_mbyte(int32 offset); + +/* SIMH Standard I/O Data Structures */ + +UNIT BOOTROM_unit = { UDATA (NULL, + UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), + KBD_POLL_WAIT }; + +MTAB BOOTROM_mod[] = { + { UNIT_MSIZE, UNIT_NONE, "None", "NONE", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2704, "2704", "2704", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2708, "2708", "2708", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2716, "2716", "2716", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2732, "2732", "2732", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2764, "2764", "2764", &BOOTROM_config }, + { 0 } +}; + +DEBTAB BOOTROM_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE BOOTROM_dev = { + "BOOTROM", /* name */ + &BOOTROM_unit, /* units */ + NULL, /* registers */ + BOOTROM_mod, /* modifiers */ + 1, /* numunits */ + 16, /* aradix */ + 32, /* awidth */ + 1, /* aincr */ + 16, /* dradix */ + 8, /* dwidth */ + NULL, /* examine */ + NULL, /* deposit */ + &BOOTROM_reset, /* reset */ + NULL, /* boot */ + &BOOTROM_attach, /* attach */ + NULL, /* detach */ + NULL, /* ctxt */ + DEV_DEBUG, /* flags */ + 0, /* dctrl */ + BOOTROM_debug, /* debflags */ + NULL, /* msize */ + NULL /* lname */ +}; + +/* global variables */ + +/* BOOTROM_attach - attach file to EPROM unit */ + +t_stat BOOTROM_attach (UNIT *uptr, char *cptr) +{ + t_stat r; + + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_attach: cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_attach: Error\n"); + return r; + } + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_attach: Done\n"); + return (BOOTROM_reset (NULL)); +} + +/* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */ + +t_stat BOOTROM_config (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + if (BOOTROM_dev.dctrl & DEBUG_flow) /* entry message */ + printf("BOOTROM_config: val=%d\n", val); + if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ + if (BOOTROM_dev.dctrl & DEBUG_flow) /* No */ + printf("BOOTROM_config: Parameter error\n"); + return SCPE_ARG; + } + if (val == UNIT_NONE) + BOOTROM_unit.capac = 0; /* set EPROM size */ + else + BOOTROM_unit.capac = 0x200 << (val >> UNIT_V_MSIZE) - 1; /* set EPROM size */ + if (BOOTROM_unit.filebuf) { /* free buffer */ + free (BOOTROM_unit.filebuf); + BOOTROM_unit.filebuf = NULL; + } + if (BOOTROM_dev.dctrl & DEBUG_flow) /* status message */ + printf("BOOTROM_config: BOOTROM_unit.capac=%d\n", + BOOTROM_unit.capac); + if (BOOTROM_dev.dctrl & DEBUG_flow) /* exit message */ + printf("BOOTROM_config: Done\n"); + return SCPE_OK; +} + +/* EPROM reset */ + +t_stat BOOTROM_reset (DEVICE *dptr) +{ + int j, c; + FILE *fp; + t_stat r; + + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_reset: \n"); + if ((BOOTROM_unit.flags & UNIT_MSIZE) == 0) { /* if none selected */ +// printf(" EPROM: Defaulted to None\n"); +// printf(" \"set eprom NONE | 2704 | 2708 | 2716 | 2732 | 2764\"\n"); +// printf(" \"att eprom \"\n"); + BOOTROM_unit.capac = 0; /* set EPROM size to 0 */ + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_reset: Done1\n"); + return SCPE_OK; + } /* if attached */ +// printf(" EPROM: Initializing [%04X-%04XH]\n", +// 0xE000, 0xE000 + BOOTROM_unit.capac - 1); + if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ + BOOTROM_unit.filebuf = malloc(BOOTROM_unit.capac); /* allocate EPROM buffer */ + if (BOOTROM_unit.filebuf == NULL) { + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_reset: Malloc error\n"); + return SCPE_MEM; + } + } + fp = fopen(BOOTROM_unit.filename, "rb"); /* open EPROM file */ + if (fp == NULL) { + printf("\tUnable to open ROM file %s\n",BOOTROM_unit.filename); + printf("\tNo ROM image loaded!!!\n"); + return SCPE_OK; + } + j = 0; /* load EPROM file */ + c = fgetc(fp); + while (c != EOF) { + *(uint8 *)(BOOTROM_unit.filebuf + j++) = c & 0xFF; + c = fgetc(fp); + if (j > BOOTROM_unit.capac) { + printf("\tImage is too large - Load truncated!!!\n"); + break; + } + } + fclose(fp); +// printf("\t%d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); + if (BOOTROM_dev.dctrl & DEBUG_flow) + printf("BOOTROM_reset: Done2\n"); + return SCPE_OK; +} + +/* get a byte from memory - byte offset of image */ + +int32 BOOTROM_get_mbyte(int32 offset) +{ + int32 val; + + if (BOOTROM_unit.filebuf == NULL) { + if (BOOTROM_dev.dctrl & DEBUG_read) + printf("BOOTROM_get_mbyte: EPROM not configured\n"); + return 0xFF; + } + if (BOOTROM_dev.dctrl & DEBUG_read) + printf("BOOTROM_get_mbyte: offset=%04X\n", offset); + val = *(uint8 *)(BOOTROM_unit.filebuf + offset) & 0xFF; + if (BOOTROM_dev.dctrl & DEBUG_read) + printf("BOOTROM_get_mbyte: Normal val=%02X\n", val); + return val; +} + +/* end of bootrom.c */ diff --git a/swtp6800/common/dc-4.c b/swtp6800/common/dc-4.c new file mode 100644 index 00000000..d4379808 --- /dev/null +++ b/swtp6800/common/dc-4.c @@ -0,0 +1,571 @@ +/* dc4.c: SWTP DC-4 FDC Simulator + + Copyright (c) 2005-2011, William A. Beech + + 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 + WILLIAM A BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + The DC-4 is a 5-inch floppy controller which can control up + to 4 daisy-chained 5-inch floppy drives. The controller is based on + the Western Digital 1797 Floppy Disk Controller (FDC) chip. This + file only emulates the minimum DC-4 functionality to interface with + the virtual disk file. + + The floppy controller is interfaced to the CPU by use of 5 memory + addreses. These are SS-30 slot numbers 5 and 6 (0x8014-0x801B). + + Address Mode Function + ------- ---- -------- + + 0x8014 Read Returns FDC interrupt status + 0x8014 Write Selects the drive/head/motor control + 0x8018 Read Returns status of FDC + 0x8018 Write FDC command register + 0x8019 Read Returns FDC track register + 0x8019 Write Set FDC track register + 0x801A Read Returns FDC sector register + 0x801A Write Set FDC sector register + 0x801B Read Read data + 0x801B Write Write data + + Drive Select Read (0x8014): + + +---+---+---+---+---+---+---+---+ + | I | D | X | X | X | X | X | X | + +---+---+---+---+---+---+---+---+ + + I = Set indicates an interrupt request from the FDC pending. + D = DRQ pending - same as bit 1 of FDC status register. + + Drive Select Write (0x8014): + + +---+---+---+---+---+---+---+---+ + | M | S | X | X | X | X | Device| + +---+---+---+---+---+---+---+---+ + + M = If this bit is 1, the one-shot is triggered/retriggered to + start/keep the motors on. + S = Side select. If set, side one is selected otherwise side zero + is selected. + X = not used + Device = value 0 thru 3, selects drive 0-3 to be controlled. + + Drive Status Read (0x8018): + + +---+---+---+---+---+---+---+---+ + | R | P | H | S | C | L | D | B | + +---+---+---+---+---+---+---+---+ + + B - When 1, the controller is busy. + D - When 1, index mark detected (type I) or data request - read data + ready/write data empty (type II or III). + H - When 1, track 0 (type I) or lost data (type II or III). + C - When 1, crc error detected. + S - When 1, seek (type I) or RNF (type II or III) error. + H - When 1, head is currently loaded (type I) or record type/ + write fault (type II or III). + P - When 1, indicates that diskette is write-protected. + R - When 1, drive is not ready. + + Drive Control Write (0x8018) for type I commands: + + +---+---+---+---+---+---+---+---+ + | 0 | S2| S1| S0| H | V | R1| R0| + +---+---+---+---+---+---+---+---+ + + R0/R1 - Selects the step rate. + V - When 1, verify on destination track. + H - When 1, loads head to drive surface. + S0/S1/S2 = 000 - home. + 001 - seek track in data register. + 010 - step without updating track register. + 011 - step and update track register. + 100 - step in without updating track register. + 101 - step in and update track register. + 110 - step out without updating track register. + 111 - step out and update track register. + + Drive Control Write (0x8018) for type II commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 0 | T | M | S | E | B | A | + +---+---+---+---+---+---+---+---+ + + A - Zero for read, 1 on write deleted data mark else data mark. + B - When 1, shifts sector length field definitions one place. + E - When, delay operation 15 ms, 0 no delay. + S - When 1, select side 1, 0 select side 0. + M - When 1, multiple records, 0 for single record. + T - When 1, write command, 0 for read. + + Drive Control Write (0x8018) for type III commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 1 | T0| T1| 0 | E | 0 | 0 | + +---+---+---+---+---+---+---+---+ + + E - When, delay operation 15 ms, 0 no delay. + T0/T1 - 00 - read address command. + 10 - read track command. + 11 - write track command. + + Tracks are numbered from 0 up to one minus the last track in the 1797! + + Track Register Read (0x8019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the track position. + + Track Register Write (0x8019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the track register. + + Sectors are numbers from 1 up to the last sector in the 1797! + + Sector Register Read (0x801A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the sector position. + + Sector Register Write (0x801A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the sector register. + + Data Register Read (0x801B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the data register. + + Data Register Write (0x801B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the data register. + + A FLEX disk is defined as follows: + + Track Sector Use + 0 1 Boot sector + 0 2 Boot sector (cont) + 0 3 Unused + 0 4 System Identity Record (explained below) + 0 5 Unused + 0 6-last Directory - 10 entries/sector (explained below) + 1 1 First available data sector + last-1 last Last available data sector + + System Identity Record + + Byte Use + 0x00 Two bytes of zeroes (Clears forward link) + 0x10 Volume name in ASCII(11 bytes) + 0x1B Volume number in binary (2 bytes) + 0x1D Address of first free data sector (Track-Sector) (2 bytes) + 0x1F Address of last free data sector (Track-Sector) (2 bytes) + 0x21 Total number of data sectors in binary (2 bytes) + 0x23 Current date (Month-Day-Year) in binary + 0x26 Highest track number on disk in binary (byte) + 0x27 Highest sector number on a track in binary (byte) + + The following unit registers are used by this controller emulation: + + dsk_unit[cur_drv].u3 unit current flags + dsk_unit[cur_drv].u4 unit current track + dsk_unit[cur_drv].u5 unit current sector + dsk_unit[cur_drv].pos unit current sector byte index into buffer + dsk_unit[cur_drv].filebuf unit current sector buffer + dsk_unit[cur_drv].fileref unit current attached file reference +*/ + +#include +#include "swtp_defs.h" + +#define DEBUG 0 + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) + +/* emulate a SS FLEX disk with 72 sectors and 80 tracks */ + +#define NUM_DISK 4 /* standard 1797 maximum */ +#define SECT_SIZE 256 /* standard FLEX sector */ +#define NUM_SECT 72 /* sectors/track */ +#define TRAK_SIZE (SECT_SIZE * NUM_SECT) /* trk size (bytes) */ +#define HEADS 1 /* handle as SS with twice the sectors */ +#define NUM_CYL 80 /* maximum tracks */ +#define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE) /* dsk size (bytes) */ + +#define SECSIZ 256 /* standard FLEX sector */ + +/* SIR offsets */ +#define MAXCYL 0x26 /* last cylinder # */ +#define MAXSEC 0x27 /* last sector # */ + +/* 1797 status bits */ + +#define BUSY 0x01 +#define DRQ 0x02 +#define WRPROT 0x40 +#define NOTRDY 0x80 + +/* function prototypes */ + +t_stat dsk_reset (DEVICE *dptr); + +/* SS-50 I/O address space functions */ + +int32 fdcdrv(int32 io, int32 data); +int32 fdccmd(int32 io, int32 data); +int32 fdctrk(int32 io, int32 data); +int32 fdcsec(int32 io, int32 data); +int32 fdcdata(int32 io, int32 data); + +/* Local Variables */ + +int32 fdcbyte; +int32 intrq = 0; /* interrupt request flag */ +int32 cur_dsk; /* Currently selected drive */ +int32 wrt_flag = 0; /* FDC write flag */ + +int32 spt; /* sectors/track */ +int32 trksiz; /* trk size (bytes) */ +int32 heds; /* number of heads */ +int32 cpd; /* cylinders/disk */ +int32 dsksiz; /* dsk size (bytes) */ + +/* Floppy Disk Controller data structures + + dsk_dev Mother Board device descriptor + dsk_unit Mother Board unit descriptor + dsk_reg Mother Board register list + dsk_mod Mother Board modifiers list +*/ + +UNIT dsk_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } +}; + +REG dsk_reg[] = { + { HRDATA (DISK, cur_dsk, 4) }, + { NULL } +}; + +MTAB dsk_mod[] = { + { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, + { UNIT_ENABLE, 0, "RO", "RO", NULL }, + { 0 } +}; + +DEBTAB dsk_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE dsk_dev = { + "DC-4", //name + dsk_unit, //units + dsk_reg, //registers + dsk_mod, //modifiers + 4, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &dsk_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + dsk_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat dsk_reset (DEVICE *dptr) +{ + int i; + + cur_dsk = 5; /* force initial SIR read */ + for (i=0; i +#include "swtp_defs.h" + +#define I2716_NUM 4 /* number of 2716 EPROMS */ + +extern int32 get_base(void); + +/* function prototypes */ + +t_stat i2716_attach (UNIT *uptr, char *cptr); +t_stat i2716_reset (DEVICE *dptr); +int32 i2716_get_mbyte(int32 offset); + +/* SIMH EPROM Standard I/O Data Structures */ + +UNIT i2716_unit[] = { + { UDATA (NULL,UNIT_ATTABLE+UNIT_ROABLE+UNIT_RO, 0), 0 }, + { UDATA (NULL,UNIT_ATTABLE+UNIT_ROABLE+UNIT_RO, 0), 0 }, + { UDATA (NULL,UNIT_ATTABLE+UNIT_ROABLE+UNIT_RO, 0), 0 }, + { UDATA (NULL,UNIT_ATTABLE+UNIT_ROABLE+UNIT_RO, 0), 0 } +}; + +MTAB i2716_mod[] = { + { 0 } +}; + +DEBTAB i2716_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE i2716_dev = { + "I2716", /* name */ + i2716_unit, /* units */ + NULL, /* registers */ + i2716_mod, /* modifiers */ + I2716_NUM, /* numunits */ + 16, /* aradix */ + 32, /* awidth */ + 1, /* aincr */ + 16, /* dradix */ + 8, /* dwidth */ + NULL, /* examine */ + NULL, /* deposit */ + &i2716_reset, /* reset */ + NULL, /* boot */ + &i2716_attach, /* attach */ + NULL, /* detach */ + NULL, /* ctxt */ + DEV_DEBUG, /* flags */ + 0, /* dctrl */ + i2716_debug, /* debflags */ + NULL, /* msize */ + NULL /* lname */ +}; + +/* global variables */ + +/* i2716_attach - attach file to EPROM unit + force EPROM reset at completion */ + +t_stat i2716_attach (UNIT *uptr, char *cptr) +{ + int32 j, c; + t_stat r; + FILE *fp; + + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_attach: cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_attach: Error\n"); + return r; + } + if (i2716_dev.dctrl & DEBUG_read) + printf("\tOpen file\n"); + fp = fopen(uptr->filename, "rb"); /* open EPROM file */ + if (fp == NULL) { + printf("i2716%d: Unable to open ROM file %s\n", uptr - i2716_dev.units, uptr->filename); + printf("\tNo ROM image loaded!!!\n"); + return SCPE_OK; + } + if (i2716_dev.dctrl & DEBUG_read) + printf("\tRead file\n"); + j = 0; /* load EPROM file */ + c = fgetc(fp); + while (c != EOF) { + *(uint8 *)(uptr->filebuf + j++) = c & 0xFF; + c = fgetc(fp); + if (j > 2048) { + printf("\tImage is too large - Load truncated!!!\n"); + break; + } + } + if (i2716_dev.dctrl & DEBUG_read) + printf("\tClose file\n"); + fclose(fp); +// printf("i2716%d: %d bytes of ROM image %s loaded\n",uptr - i2716_dev.units, j, uptr->filename); + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_attach: Done\n"); + return SCPE_OK; +} + +/* EPROM reset */ + +t_stat i2716_reset (DEVICE *dptr) +{ + int32 i, j, c, base; + t_stat r; + UNIT *uptr; + + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_reset: \n"); + for (i = 0; i < I2716_NUM; i++) { /* init all units */ + uptr = i2716_dev.units + i; + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716 %d unit.flags=%08X\n", i, uptr->flags); + uptr->capac = 2048; + uptr->u3 = 2048 * i; + base = get_base(); + if (uptr->filebuf == NULL) { /* no buffer allocated */ + uptr->filebuf = malloc(2048); /* allocate EPROM buffer */ + if (uptr->filebuf == NULL) { + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_reset: Malloc error\n"); + return SCPE_MEM; + } + } + if (base == 0) { +// printf("i2716%d: Not enabled on MP-A2\n", i); + continue; + } +// printf("i2716%d: Initializing [%04X-%04XH]\n", +// i, base+uptr->u3, base+uptr->u3 + uptr->capac); +// if ((uptr->flags & UNIT_ATT) == 0) { +// printf("i2716%d: No file attached\n", i); +// } + } + if (i2716_dev.dctrl & DEBUG_flow) + printf("i2716_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + EPROM memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 i2716_get_mbyte(int32 offset) +{ + int32 i, val, org, len; + UNIT *uptr; + + for (i = 0; i < I2716_NUM; i++) { /* find addressed unit */ + uptr = i2716_dev.units + i; + org = uptr->u3; + len = uptr->capac - 1; + if ((offset >= org) && (offset < (org + len))) { + if (uptr->filebuf == NULL) { + if (i2716_dev.dctrl & DEBUG_read) + printf("i2716_get_mbyte: EPROM not configured\n"); + return 0xFF; + } else { + val = *(uint8 *)(uptr->filebuf + (offset - org)); + if (i2716_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } + } + } + if (i2716_dev.dctrl & DEBUG_read) + printf("i2716_get_mbyte: Out of range\n"); + return 0xFF; +} + +/* end of i2716.c */ diff --git a/swtp6800/common/m6800.c b/swtp6800/common/m6800.c new file mode 100644 index 00000000..806913a4 --- /dev/null +++ b/swtp6800/common/m6800.c @@ -0,0 +1,2020 @@ +/* m6800.c: SWTP 6800 CPU simulator + + Copyright (c) 2005-2011, William Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + cpu Motorola M6800 CPU + + The register state for the M6800 CPU is: + + A<0:7> Accumulator A + B<0:7> Accumulator B + IX<0:15> Index Register + CCR<0:7> Condition Code Register + HF half-carry flag + IF interrupt flag + NF negative flag + ZF zero flag + VF overflow flag + CF carry flag + PC<0:15> program counter + SP<0:15> Stack Pointer + + The M6800 is an 8-bit CPU, which uses 16-bit registers to address + up to 64KB of memory. + + The 72 basic instructions come in 1, 2, and 3-byte flavors. + + This routine is the instruction decode routine for the M6800. + It is called from the CPU board simulator 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: + + WAI instruction + I/O error in I/O simulator + Invalid OP code (if ITRAP is set on CPU) + Invalid mamory address (if MTRAP is set on CPU) + + 2. Interrupts. + There are 4 types of interrupt, and in effect they do a + hardware CALL instruction to one of 4 possible high memory addresses. + + 3. Non-existent memory. + On the SWTP 6800, reads to non-existent memory + return 0FFH, and writes are ignored. +*/ + +#include + +#include "swtp_defs.h" + +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_MSTOP (UNIT_V_UF+1) /* Stop on Invalid memory? */ +#define UNIT_MSTOP (1 << UNIT_V_MSTOP) + +/* Flag values to set proper positions in CCR */ +#define HF 0x20 +#define IF 0x10 +#define NF 0x08 +#define ZF 0x04 +#define VF 0x02 +#define CF 0x01 + +/* Macros to handle the flags in the CCR */ +#define CCR_ALWAYS_ON (0xC0) /* for 6800 */ +#define CCR_MSK (HF|IF|NF|ZF|VF|CF) +#define TOGGLE_FLAG(FLAG) (CCR ^= FLAG) +#define SET_FLAG(FLAG) (CCR |= FLAG) +#define CLR_FLAG(FLAG) (CCR &= ~FLAG) +#define GET_FLAG(FLAG) (CCR & FLAG) +#define COND_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) +#define COND_SET_FLAG_N(VAR) \ + if (VAR & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) +#define COND_SET_FLAG_Z(VAR) \ + if (VAR == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) +#define COND_SET_FLAG_H(VAR) \ + if (VAR & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) +#define COND_SET_FLAG_C(VAR) \ + if (VAR & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) +#define COND_SET_FLAG_V(COND) \ + if (COND) SET_FLAG(VF); else CLR_FLAG(VF) + +/* local global variables */ + +int32 A = 0; /* Accumulator A */ +int32 B = 0; /* Accumulator B */ +int32 IX = 0; /* Index register */ +int32 SP = 0; /* Stack pointer */ +int32 CCR = CCR_ALWAYS_ON | IF; /* Condition Code Register */ +int32 saved_PC = 0; /* Program counter */ +int32 PC; /* global for the helper routines */ +int32 INTE = 0; /* Interrupt Enable */ +int32 int_req = 0; /* Interrupt request */ + +int32 mem_fault = 0; /* memory fault flag */ + +extern int32 sim_int_char; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +/* function prototypes */ + +t_stat m6800_reset (DEVICE *dptr); +void dump_regs(void); +void dump_regs1(void); +int32 fetch_byte(int32 flag); +int32 fetch_word(void); +uint8 pop_byte(void); +uint16 pop_word(void); +void push_byte(uint8 val); +void push_word(uint16 val); +void go_rel(int32 cond); +int32 get_rel_addr(void); +int32 get_dir_val(void); +int32 get_dir_addr(void); +int32 get_indir_val(void); +int32 get_indir_addr(void); +int32 get_ext_val(void); +int32 get_ext_addr(void); +int32 get_flag(int32 flag); +void condevalVa(int32 op1, int32 op2); +void condevalVs(int32 op1, int32 op2); + +/* external routines */ + +extern void CPU_BD_put_mbyte(int32 addr, int32 val); +extern void CPU_BD_put_mword(int32 addr, int32 val); +extern int32 CPU_BD_get_mbyte(int32 addr); +extern int32 CPU_BD_get_mword(int32 addr); +extern int32 sim_switches; + +/* CPU data structures + + m6800_dev CPU device descriptor + m6800_unit CPU unit descriptor + m6800_reg CPU register list + m6800_mod CPU modifiers list */ + +UNIT m6800_unit = { UDATA (NULL, 0, 0) }; + +REG m6800_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (A, A, 8) }, + { HRDATA (B, B, 8) }, + { HRDATA (IX, IX, 16) }, + { HRDATA (SP, SP, 16) }, + { HRDATA (CCR, CCR, 8) }, + { FLDATA (INTE, INTE, 16) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB m6800_mod[] = { + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { UNIT_MSTOP, UNIT_MSTOP, "MTRAP", "MTRAP", NULL }, + { UNIT_MSTOP, 0, "NOMTRAP", "NOMTRAP", NULL }, + { 0 } }; + +DEBTAB m6800_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE m6800_dev = { + "CPU", //name + &m6800_unit, //units + m6800_reg, //registers + m6800_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &m6800_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + m6800_debug, //debflags + NULL, //msize + NULL //lname +}; + +static const char *opcode[] = { +"???", "NOP", "???", "???", //0x00 +"???", "???", "TAP", "TPA", +"INX", "DEX", "CLV", "SEV", +"CLC", "SEC", "CLI", "SEI", +"SBA", "CBA", "???", "???", //0x10 +"???", "???", "TAB", "TBA", +"???", "DAA", "???", "ABA", +"???", "???", "???", "???", +"BRA", "???", "BHI", "BLS", //0x20 +"BCC", "BCS", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"TSX", "INS", "PULA", "PULB", //0x30 +"DES", "TXS", "PSHA", "PSHB", +"???", "RTS", "???", "RTI", +"???", "???", "WAI", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"ASLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"ASLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "???", //0x80 +"ANDA", "BITA", "LDAA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "BSR", "LDS", "???", +"SUBA", "CMPA", "SBCA", "???", //0x90 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "???", "LDS", "STS", +"SUBA", "CMPA", "SBCA", "???", //0xA0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX X", "JSR X", "LDS X", "STS X", +"SUBA", "CMPA", "SBCA", "???", //0xB0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "JSR", "LDS", "STS", +"SUBB", "CMPB", "SBCB", "???", //0xC0 +"ANDB", "BITB", "LDAB", "???", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "???", +"SUBB", "CMPB", "SBCB", "???", //0xD0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xE0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xF0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +}; + +int32 oplen[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +/* simulator instruction decode routine */ + +int32 sim_instr (void) +{ + extern int32 sim_interval; + int32 IR, OP, DAR, reason, hi, lo, op1; + + PC = saved_PC & ADDRMASK; /* load local PC */ + reason = 0; + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ +// dump_regs1(); + if (sim_interval <= 0) /* check clock queue */ + if (reason = sim_process_event ()) + break; + if (mem_fault) { /* memory fault? */ + mem_fault = 0; /* reset fault flag */ + reason = STOP_MEMORY; + break; + } + if (int_req > 0) { /* interrupt? */ + /* 6800 interrupts not implemented yet. None were used, + on a standard SWTP 6800. All I/O is programmed. */ + } /* end interrupt */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + IR = OP = fetch_byte(0); /* fetch instruction */ + sim_interval--; + + /* The Big Instruction Decode Switch */ + + switch (IR) { + + case 0x01: /* NOP */ + break; + case 0x06: /* TAP */ + CCR = A; + break; + case 0x07: /* TPA */ + A = CCR; + break; + case 0x08: /* INX */ + IX = (IX + 1) & ADDRMASK; + COND_SET_FLAG_Z(IX); + break; + case 0x09: /* DEX */ + IX = (IX - 1) & ADDRMASK; + COND_SET_FLAG_Z(IX); + break; + case 0x0A: /* CLV */ + CLR_FLAG(VF); + break; + case 0x0B: /* SEV */ + SET_FLAG(VF); + break; + case 0x0C: /* CLC */ + CLR_FLAG(CF); + break; + case 0x0D: /* SEC */ + SET_FLAG(CF); + break; + case 0x0E: /* CLI */ + CLR_FLAG(IF); + break; + case 0x0F: /* SEI */ + SET_FLAG(IF); + break; + case 0x10: /* SBA */ + op1 = A; + A = A - B; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_C(A); + condevalVs(B, op1); + A &= 0xFF; + break; + case 0x11: /* CBA */ + lo = A - B; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, A); + break; + case 0x16: /* TAB */ + B = A; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0x17: /* TBA */ + A = B; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0x19: /* DAA */ + DAR = A & 0x0F; + op1 = get_flag(CF); + if (DAR > 9 || get_flag(CF)) { + DAR += 6; + A &= 0xF0; + A |= (DAR & 0x0F); + COND_SET_FLAG(DAR & 0x10,CF); + } + DAR = (A >> 4) & 0x0F; + if (DAR > 9 || get_flag(CF)) { + DAR += 6; + if (get_flag(CF)) + DAR++; + A &= 0x0F; + A |= (DAR << 4); + } + COND_SET_FLAG(op1,CF); + if ((DAR << 4) & 0x100) + SET_FLAG(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + A &= 0xFF; + break; + case 0x1B: /* ABA */ + A += B; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_C(A); + condevalVa(A, B); + A &= 0xFF; + break; + case 0x20: /* BRA rel */ + go_rel(1); + break; + case 0x22: /* BHI rel */ + go_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* BLS rel */ + go_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* BCC rel */ + go_rel(!get_flag(CF)); + break; + case 0x25: /* BCS rel */ + go_rel(get_flag(CF)); + break; + case 0x26: /* BNE rel */ + go_rel(!get_flag(ZF)); + break; + case 0x27: /* BEQ rel */ + go_rel(get_flag(ZF)); + break; + case 0x28: /* BVC rel */ + go_rel(!get_flag(VF)); + break; + case 0x29: /* BVS rel */ + go_rel(get_flag(VF)); + break; + case 0x2A: /* BPL rel */ + go_rel(!get_flag(NF)); + break; + case 0x2B: /* BMI rel */ + go_rel(get_flag(NF)); + break; + case 0x2C: /* BGE rel */ + go_rel(!(get_flag(NF) ^ get_flag(VF))); + break; + case 0x2D: /* BLT rel */ + go_rel(get_flag(NF) ^ get_flag(VF)); + break; + case 0x2E: /* BGT rel */ + go_rel(!(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)))); + break; + case 0x2F: /* BLE rel */ + go_rel(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF))); + break; + case 0x30: /* TSX */ + IX = (SP + 1) & ADDRMASK; + break; + case 0x31: /* INS */ + SP = (SP + 1) & ADDRMASK; + break; + case 0x32: /* PUL A */ + A = pop_byte(); + break; + case 0x33: /* PUL B */ + B = pop_byte(); + break; + case 0x34: /* DES */ + SP = (SP - 1) & ADDRMASK; + break; + case 0x35: /* TXS */ + SP = (IX - 1) & ADDRMASK; + break; + case 0x36: /* PSH A */ + push_byte(A); + break; + case 0x37: /* PSH B */ + push_byte(B); + break; + case 0x39: /* RTS */ + PC = pop_word(); + break; + case 0x3B: /* RTI */ + CCR = pop_byte(); + B = pop_byte(); + A = pop_byte(); + IX = pop_word(); + PC = pop_word(); + break; + case 0x3E: /* WAI */ + push_word(PC); + push_word(IX); + push_byte(A); + push_byte(B); + push_byte(CCR); + if (get_flag(IF)) { + reason = STOP_HALT; + continue; + } else { + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFE) & ADDRMASK; + } + break; + case 0x3F: /* SWI */ + push_word(PC); + push_word(IX); + push_byte(A); + push_byte(B); + push_byte(CCR); + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFB) & ADDRMASK; + break; + case 0x40: /* NEG A */ + A = (0 - A) & 0xFF; + COND_SET_FLAG_V(A & 0x80); + COND_SET_FLAG(A,CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x43: /* COM A */ + A = ~A & 0xFF; + CLR_FLAG(VF); + SET_FLAG(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x44: /* LSR A */ + COND_SET_FLAG(A & 0x01,CF); + A = (A >> 1) & 0xFF; + CLR_FLAG(NF); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x46: /* ROR A */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x01,CF); + A = (A >> 1) & 0xFF; + if (hi) + A |= 0x80; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x47: /* ASR A */ + COND_SET_FLAG(A & 0x01,CF); + lo = A & 0x80; + A = (A >> 1) & 0xFF; + A |= lo; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x48: /* ASL A */ + COND_SET_FLAG(A & 0x80,CF); + A = (A << 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x49: /* ROL A */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x80,CF); + A = (A << 1) & 0xFF; + if (hi) + A |= 0x01; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x4A: /* DEC A */ + COND_SET_FLAG_V(A == 0x80); + A = (A - 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4C: /* INC A */ + COND_SET_FLAG_V(A == 0x7F); + A = (A + 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4D: /* TST A */ + lo = (A - 0) & 0xFF; + CLR_FLAG(VF); + CLR_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x4F: /* CLR A */ + A = 0; + CLR_FLAG(NF); + CLR_FLAG(VF); + CLR_FLAG(CF); + SET_FLAG(ZF); + break; + case 0x50: /* NEG B */ + B = (0 - B) & 0xFF; + COND_SET_FLAG_V(B & 0x80); + COND_SET_FLAG(B,CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x53: /* COM B */ + B = ~B; + B &= 0xFF; + CLR_FLAG(VF); + SET_FLAG(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x54: /* LSR B */ + COND_SET_FLAG(B & 0x01,CF); + B = (B >> 1) & 0xFF; + CLR_FLAG(NF); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x56: /* ROR B */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x01,CF); + B = (B >> 1) & 0xFF; + if (hi) + B |= 0x80; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x57: /* ASR B */ + COND_SET_FLAG(B & 0x01,CF); + lo = B & 0x80; + B = (B >> 1) & 0xFF; + B |= lo; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x58: /* ASL B */ + COND_SET_FLAG(B & 0x80,CF); + B = (B << 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x59: /* ROL B */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x80,CF); + B = (B << 1) & 0xFF; + if (hi) + B |= 0x01; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x5A: /* DEC B */ + COND_SET_FLAG_V(B == 0x80); + B = (B - 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5C: /* INC B */ + COND_SET_FLAG_V(B == 0x7F); + B = (B + 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5D: /* TST B */ + lo = (B - 0) & 0xFF; + CLR_FLAG(VF); + CLR_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x5F: /* CLR B */ + B = 0; + CLR_FLAG(NF); + CLR_FLAG(VF); + CLR_FLAG(CF); + SET_FLAG(ZF); + break; + case 0x60: /* NEG ind */ + DAR = get_indir_addr(); + lo = (0 - CPU_BD_get_mbyte(DAR)) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_V(lo & 0x80); + COND_SET_FLAG(lo,CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x63: /* COM ind */ + DAR = get_indir_addr(); + lo = ~CPU_BD_get_mbyte(DAR); + lo &= 0xFF; + CPU_BD_put_mbyte(DAR, lo); + CLR_FLAG(VF); + SET_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x64: /* LSR ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + lo >>= 1; + CPU_BD_put_mbyte(DAR, lo); + CLR_FLAG(NF); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x66: /* ROR ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + hi = get_flag(CF); + COND_SET_FLAG(lo & 0x01,CF); + lo >>= 1; + if (hi) + lo |= 0x80; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x67: /* ASR ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + lo = (lo & 0x80) | (lo >> 1); + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x68: /* ASL ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x80,CF); + lo <<= 1; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x69: /* ROL ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + hi = get_flag(CF); + COND_SET_FLAG(lo & 0x80,CF); + lo <<= 1; + if (hi) + lo |= 0x01; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x6A: /* DEC ind */ + DAR = get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG_V(lo == 0x80); + lo = (lo - 1) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x6C: /* INC ind */ + DAR= get_indir_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG_V(lo == 0x7F); + lo = (lo + 1) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x6D: /* TST ind */ + lo = (get_indir_val() - 0) & 0xFF; + CLR_FLAG(VF); + CLR_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x6E: /* JMP ind */ + PC = get_indir_addr(); + break; + case 0x6F: /* CLR ind */ + CPU_BD_put_mbyte(get_indir_addr(), 0); + CLR_FLAG(NF); + CLR_FLAG(VF); + CLR_FLAG(CF); + SET_FLAG(ZF); + break; + case 0x70: /* NEG ext */ + DAR = get_ext_addr(); + lo = (0 - CPU_BD_get_mbyte(DAR)) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_V(lo & 0x80); + CLR_FLAG(CF); + if (lo) + SET_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x73: /* COM ext */ + DAR = get_ext_addr(); + lo = ~CPU_BD_get_mbyte(DAR); + lo &= 0xFF; + CPU_BD_put_mbyte(DAR, lo); + CLR_FLAG(VF); + SET_FLAG(CF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x74: /* LSR ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + lo >>= 1; + CPU_BD_put_mbyte(DAR, lo); + CLR_FLAG(NF); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x76: /* ROR ext */ + DAR = get_ext_addr(); + hi = get_flag(CF); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + lo >>= 1; + if (hi) + lo |= 0x80; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x77: /* ASR ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x01,CF); + hi = lo & 0x80; + lo >>= 1; + lo |= hi; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x78: /* ASL ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG(lo & 0x80,CF); + lo <<= 1; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x79: /* ROL ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + hi = get_flag(CF); + COND_SET_FLAG(lo & 0x80,CF); + lo <<= 1; + if (hi) + lo |= 0x01; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); + break; + case 0x7A: /* DEC ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG_V(lo == 0x80); + lo = (lo - 1) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x7C: /* INC ext */ + DAR = get_ext_addr(); + lo = CPU_BD_get_mbyte(DAR); + COND_SET_FLAG_V(lo == 0x7F); + lo = (lo + 1) & 0xFF; + CPU_BD_put_mbyte(DAR, lo); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x7D: /* TST ext */ + lo = CPU_BD_get_mbyte(get_ext_addr()) - 0; + CLR_FLAG(VF); + CLR_FLAG(CF); + COND_SET_FLAG_N(lo); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0x7E: /* JMP ext */ + PC = get_ext_addr() & ADDRMASK; + break; + case 0x7F: /* CLR ext */ + CPU_BD_put_mbyte(get_ext_addr(), 0); + CLR_FLAG(NF); + CLR_FLAG(VF); + CLR_FLAG(CF); + SET_FLAG(ZF); + break; + case 0x80: /* SUB A imm */ + op1 = get_dir_addr(); + A = A - op1; + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x81: /* CMP A imm */ + op1 = get_dir_addr(); + lo = A - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(lo, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0x82: /* SBC A imm */ + op1 = get_dir_addr(); + A = A - op1 - get_flag(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x84: /* AND A imm */ + A = (A & get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x85: /* BIT A imm */ + lo = (A & get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x86: /* LDA A imm */ + A = get_dir_addr(); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x88: /* EOR A imm */ + A = (A ^ get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x89: /* ADC A imm */ + op1 = get_dir_addr(); + A = A + op1 + get_flag(CF); + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x8A: /* ORA A imm */ + A = (A | get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x8B: /* ADD A imm */ + op1 = get_dir_addr(); + A = A + op1; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x8C: /* CPX imm */ + op1 = IX - get_ext_addr(); + COND_SET_FLAG_Z(op1); + COND_SET_FLAG_N(op1 >> 8); + COND_SET_FLAG_V(op1 & 0x10000); + break; + case 0x8D: /* BSR rel */ + lo = get_rel_addr(); + push_word(PC); + PC = PC + lo; + PC &= ADDRMASK; + break; + case 0x8E: /* LDS imm */ + SP = get_ext_addr(); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0x90: /* SUB A dir */ + op1 = get_dir_val(); + A = A - op1; + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x91: /* CMP A dir */ + op1 = get_dir_val(); + lo = A - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(A, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0x92: /* SBC A dir */ + op1 = get_dir_val(); + A = A - op1 - get_flag(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x94: /* AND A dir */ + A = (A & get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x95: /* BIT A dir */ + lo = (A & get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0x96: /* LDA A dir */ + A = get_dir_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x97: /* STA A dir */ + CPU_BD_put_mbyte(get_dir_addr(), A); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x98: /* EOR A dir */ + A = (A ^ get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x99: /* ADC A dir */ + op1 = get_dir_val(); + A = A + op1 + get_flag(CF); + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x9A: /* ORA A dir */ + A = (A | get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x9B: /* ADD A dir */ + op1 = get_dir_val(); + A = A + op1; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0x9C: /* CPX dir */ + op1 = IX - CPU_BD_get_mword(get_dir_addr()); + COND_SET_FLAG_Z(op1); + COND_SET_FLAG_N(op1 >> 8); + COND_SET_FLAG_V(op1 & 0x10000); + break; + case 0x9E: /* LDS dir */ + SP = CPU_BD_get_mword(get_dir_addr()); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0x9F: /* STS dir */ + CPU_BD_put_mword(get_dir_addr(), SP); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xA0: /* SUB A ind */ + op1 = get_indir_val(); + A = A - op1; + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xA1: /* CMP A ind */ + op1 = get_indir_val(); + lo = A - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(A, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xA2: /* SBC A ind */ + op1 = get_indir_val(); + A = A - op1 - get_flag(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xA4: /* AND A ind */ + A = (A & get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA5: /* BIT A ind */ + lo = (A & get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xA6: /* LDA A ind */ + A = get_indir_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA7: /* STA A ind */ + CPU_BD_put_mbyte(get_indir_addr(), A); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA8: /* EOR A ind */ + A = (A ^ get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA9: /* ADC A ind */ + op1 = get_indir_val(); + A = A + op1 + get_flag(CF); + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xAA: /* ORA A ind */ + A = (A | get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xAB: /* ADD A ind */ + op1 = get_indir_val(); + A = A + op1; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xAC: /* CPX ind */ + op1 = (IX - get_indir_addr()) & ADDRMASK; + COND_SET_FLAG_Z(op1); + COND_SET_FLAG_N(op1 >> 8); + COND_SET_FLAG_V(op1 & 0x10000); + break; + case 0xAD: /* JSR ind */ + DAR = get_indir_addr(); + push_word(PC); + PC = DAR; + break; + case 0xAE: /* LDS ind */ + SP = CPU_BD_get_mword(get_indir_addr()); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xAF: /* STS ind */ + CPU_BD_put_mword(get_indir_addr(), SP); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xB0: /* SUB A ext */ + op1 = get_ext_val(); + A = A - op1; + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xB1: /* CMP A ext */ + op1 = get_ext_val(); + lo = A - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(A, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xB2: /* SBC A ext */ + op1 = get_ext_val(); + A = A - op1 - get_flag(CF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVs(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xB4: /* AND A ext */ + A = (A & get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB5: /* BIT A ext */ + lo = (A & get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xB6: /* LDA A ext */ + A = get_ext_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB7: /* STA A ext */ + CPU_BD_put_mbyte(get_ext_addr(), A); + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB8: /* EOR A ext */ + A = (A ^ get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB9: /* ADC A ext */ + op1 = get_ext_val(); + A = A + op1 + get_flag(CF); + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xBA: /* ORA A ext */ + A = (A | get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xBB: /* ADD A ext */ + op1 = get_ext_val(); + A = A + op1; + COND_SET_FLAG_H(A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_C(A); + condevalVa(A, op1); + A &= 0xFF; + COND_SET_FLAG_Z(A); + break; + case 0xBC: /* CPX ext */ + op1 = (IX - CPU_BD_get_mword(get_ext_addr()));// & ADDRMASK; + COND_SET_FLAG_Z(op1); + COND_SET_FLAG_N(op1 >> 8); + COND_SET_FLAG_V(op1 & 0x10000); + break; + case 0xBD: /* JSR ext */ + DAR = get_ext_addr(); + push_word(PC); + PC = DAR; + break; + case 0xBE: /* LDS ext */ + SP = CPU_BD_get_mword(get_ext_addr()); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xBF: /* STS ext */ + CPU_BD_put_mword(get_ext_addr(), SP); + COND_SET_FLAG_N(SP >> 8); + COND_SET_FLAG_Z(SP); + CLR_FLAG(VF); + break; + case 0xC0: /* SUB B imm */ + op1 = get_dir_addr(); + B = B - op1; + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xC1: /* CMP B imm */ + op1 = get_dir_addr(); + lo = B - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xC2: /* SBC B imm */ + op1 = get_dir_addr(); + B = B - op1 - get_flag(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xC4: /* AND B imm */ + B = (B & get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC5: /* BIT B imm */ + lo = (B & get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xC6: /* LDA B imm */ + B = get_dir_addr(); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC8: /* EOR B imm */ + B = (B ^ get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC9: /* ADC B imm */ + op1 = get_dir_addr(); + B = B + op1 + get_flag(CF); + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xCA: /* ORA B imm */ + B = (B | get_dir_addr()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xCB: /* ADD B imm */ + op1 = get_dir_addr(); + B = B + op1; + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xCE: /* LDX imm */ + IX = get_ext_addr(); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xD0: /* SUB B dir */ + op1 = get_dir_val(); + B = B - op1; + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xD1: /* CMP B dir */ + op1 = get_dir_val(); + lo = B - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, op1); + break; + case 0xD2: /* SBC B dir */ + op1 = get_dir_val(); + B = B - op1 - get_flag(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xD4: /* AND B dir */ + B = (B & get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD5: /* BIT B dir */ + lo = (B & get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xD6: /* LDA B dir */ + B = get_dir_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD7: /* STA B dir */ + CPU_BD_put_mbyte(get_dir_addr(), B); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD8: /* EOR B dir */ + B = (B ^ get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD9: /* ADC B dir */ + op1 = get_dir_val(); + B = B + op1 + get_flag(CF); + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xDA: /* ORA B dir */ + B = (B | get_dir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xDB: /* ADD B dir */ + op1 = get_dir_val(); + B = B + op1; + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xDE: /* LDX dir */ + IX = CPU_BD_get_mword(get_dir_addr()); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xDF: /* STX dir */ + CPU_BD_put_mword(get_dir_addr(), IX); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xE0: /* SUB B ind */ + op1 = get_indir_val(); + B = B - op1; + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xE1: /* CMP B ind */ + op1 = get_indir_val(); + lo = B - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xE2: /* SBC B ind */ + op1 = get_indir_val(); + B = B - op1 - get_flag(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xE4: /* AND B ind */ + B = (B & get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE5: /* BIT B ind */ + lo = (B & get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xE6: /* LDA B ind */ + B = get_indir_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE7: /* STA B ind */ + CPU_BD_put_mbyte(get_indir_addr(), B); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE8: /* EOR B ind */ + B = (B ^ get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE9: /* ADC B ind */ + op1 = get_indir_val(); + B = B + op1 + get_flag(CF); + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xEA: /* ORA B ind */ + B = (B | get_indir_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xEB: /* ADD B ind */ + op1 = get_indir_val(); + B = B + op1; + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xEE: /* LDX ind */ + IX = CPU_BD_get_mword(get_indir_addr()); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xEF: /* STX ind */ + CPU_BD_put_mword(get_indir_addr(), IX); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xF0: /* SUB B ext */ + op1 = get_ext_val(); + B = B - op1; + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xF1: /* CMP B ext */ + op1 = get_ext_val(); + lo = B - op1; + COND_SET_FLAG_N(lo); + COND_SET_FLAG_C(lo); + condevalVs(B, op1); + lo &= 0xFF; + COND_SET_FLAG_Z(lo); + break; + case 0xF2: /* SBC B ext */ + op1 = get_ext_val(); + B = B - op1 - get_flag(CF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVs(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xF4: /* AND B ext */ + B = (B & get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF5: /* BIT B ext */ + lo = (B & get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(lo); + COND_SET_FLAG_Z(lo); + break; + case 0xF6: /* LDA B ext */ + B = get_ext_val(); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF7: /* STA B ext */ + CPU_BD_put_mbyte(get_ext_addr(), B); + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF8: /* EOR B ext */ + B = (B ^ get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF9: /* ADC B ext */ + op1 = get_ext_val(); + B = B + op1 + get_flag(CF); + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xFA: /* ORA B ext */ + B = (B | get_ext_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xFB: /* ADD B ext */ + op1 = get_ext_val(); + B = B + op1; + COND_SET_FLAG_H(B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_C(B); + condevalVa(B, op1); + B &= 0xFF; + COND_SET_FLAG_Z(B); + break; + case 0xFE: /* LDX ext */ + IX = CPU_BD_get_mword(get_ext_addr()); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + case 0xFF: /* STX ext */ + CPU_BD_put_mword(get_ext_addr(), IX); + COND_SET_FLAG_N(IX >> 8); + COND_SET_FLAG_Z(IX); + CLR_FLAG(VF); + break; + + default: { /* Unassigned */ + if (m6800_unit.flags & UNIT_OPSTOP) { + reason = STOP_OPCODE; + PC--; + } + break; + } + } + } + /* Simulation halted - lets dump all the registers! */ + dump_regs(); + saved_PC = PC; + return reason; +} + +/* dump the working registers */ + +void dump_regs(void) +{ + printf("\r\nPC=%04X SP=%04X IX=%04X ", PC, SP, IX); + printf("A=%02X B=%02X CCR=%02X", A, B, CCR); +} + +void dump_regs1(void) +{ + printf("PC=%04X SP=%04X IX=%04X ", PC, SP, IX); + printf("A=%02X B=%02X CCR=%02X\n", A, B, CCR); +} + +/* fetch an instruction or byte */ +int32 fetch_byte(int32 flag) +{ + uint8 val; + + val = CPU_BD_get_mbyte(PC) & 0xFF; /* fetch byte */ + if (m6800_dev.dctrl & DEBUG_asm) { /* display source code */ + switch (flag) { + case 0: /* opcode fetch */ + printf("\n%04X %s", PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + printf("0%02XH", val); + break; + } + } + PC = (PC + 1) & ADDRMASK; /* increment PC */ + return val; +} + +/* fetch a word */ +int32 fetch_word(void) +{ + uint16 val; + + val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ + val |= CPU_BD_get_mbyte(PC + 1) & 0xFF; /* fetch low byte */ + if (m6800_dev.dctrl & DEBUG_asm) + printf("0%04XH", val); + PC = (PC + 2) & ADDRMASK; /* increment PC */ + return val; +} + +/* push a byte to the stack */ +void push_byte(uint8 val) +{ + CPU_BD_put_mbyte(SP, val & 0xFF); + SP = (SP - 1) & ADDRMASK; +} + +/* push a word to the stack */ +void push_word(uint16 val) +{ + push_byte(val & 0xFF); + push_byte(val >> 8); +} + +/* pop a byte from the stack */ +uint8 pop_byte(void) +{ + register uint8 res; + + SP = (SP + 1) & ADDRMASK; + res = CPU_BD_get_mbyte(SP); + return res; +} + +/* pop a word from the stack */ +uint16 pop_word(void) +{ + register uint16 res; + + res = pop_byte() << 8; + res |= pop_byte(); + return res; +} + +/* This routine does the jump to relative offset if the condition is + met. Otherwise, execution continues at the current PC. */ + +void go_rel(int32 cond) +{ + int32 temp; + + temp = get_rel_addr(); + if (cond) + PC += temp; + PC &= ADDRMASK; +} + +/* returns the relative offset sign-extended */ + +int32 get_rel_addr(void) +{ + int32 temp; + + temp = fetch_byte(1); + if (temp & 0x80) + temp |= 0xFF00; + return temp & ADDRMASK; +} + +/* returns the value at the direct address pointed to by PC */ + +int32 get_dir_val(void) +{ + return CPU_BD_get_mbyte(get_dir_addr()); +} + +/* returns the direct address pointed to by PC */ + +int32 get_dir_addr(void) +{ + int32 temp; + + temp = fetch_byte(1); + return temp & 0xFF; +} + +/* returns the value at the indirect address pointed to by PC */ + +int32 get_indir_val(void) +{ + return CPU_BD_get_mbyte(get_indir_addr()); +} + +/* returns the indirect address pointed to by PC or immediate byte */ + +int32 get_indir_addr(void) +{ + int32 temp; + + temp = (fetch_byte(1) + IX) & ADDRMASK; + return temp; +} + +/* returns the value at the extended address pointed to by PC */ + +int32 get_ext_val(void) +{ + return CPU_BD_get_mbyte(get_ext_addr()); +} + +/* returns the extended address pointed to by PC or immediate word */ + +int32 get_ext_addr(void) +{ + int32 temp; + + temp = fetch_word(); + return temp; +} + +/* return 1 for flag set or 0 for flag clear */ + +int32 get_flag(int32 flg) +{ + if (CCR & flg) + return 1; + else + return 0; +} + +/* test and set V for addition */ + +void condevalVa(int32 op1, int32 op2) +{ + if (get_flag(CF)) + COND_SET_FLAG_V(((op1 & 0x80) && (op2 & 0x80)) || ( + (op1 & 0x80 == 0) && (op2 & 0x80 == 0))); +} + +/* test and set V for subtraction */ + +void condevalVs(int32 op1, int32 op2) +{ + if (get_flag(CF)) + COND_SET_FLAG_V(((op1 & 0x80) && (op2 & 0x80 == 0)) || + ((op1 & 0x80 == 0) && (op2 & 0x80))); +} + +/* calls from the simulator */ + +/* Reset routine */ + +t_stat m6800_reset (DEVICE *dptr) +{ + CCR = CCR_ALWAYS_ON | IF; + int_req = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + saved_PC = CPU_BD_get_mword(0xFFFE); +// if (saved_PC == 0xFFFF) +// printf("No EPROM image found - M6800 reset incomplete!\n"); +// else +// printf("EPROM vector=%04X\n", saved_PC); + return SCPE_OK; +} + + +/* This is the dumper/loader. This command uses the -h to signify a + hex dump/load vice a binary one. If no address is given to load, it + takes the address from the hex record or the current PC for binary. +*/ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + CPU_BD_put_mbyte(addr, i); + addr++; + cnt++; + } // end while + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code + for M6800 +*/ + +int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) +{ + int32 i, inst, inst1; + + if (sw & SWMASK ('D')) { // dump memory + for (i=0; i<16; i++) + fprintf(of, "%02X ", val[i]); + fprintf(of, " "); + for (i=0; i<16; i++) + if (isprint(val[i])) + fprintf(of, "%c", val[i]); + else + fprintf(of, "."); + return -15; + } else if (sw & SWMASK ('M')) { // dump instruction mnemonic + inst = val[0]; + if (!oplen[inst]) { // invalid opcode + fprintf(of, "%02X", inst); + return 0; + } + inst1 = inst & 0xF0; + fprintf (of, "%s", opcode[inst]); // mnemonic + if (strlen(opcode[inst]) == 3) + fprintf(of, " "); + if (inst1 == 0x20 || inst == 0x8D) { // rel operand + inst1 = val[1]; + if (val[1] & 0x80) + inst1 |= 0xFF00; + fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); + } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand + if ((inst & 0x0F) < 0x0C) + fprintf(of, " #$%02X", val[1]); + else + fprintf(of, " #$%02X%02X", val[1], val[2]); + } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand + fprintf(of, " %d,X", val[1]); + else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand + fprintf(of, " $%02X%02X", val[1], val[2]); + return (-(oplen[inst] - 1)); + } else + 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) +{ + return (-2); +} + +/* end of m6800.c */ diff --git a/swtp6800/common/m6810.c b/swtp6800/common/m6810.c new file mode 100644 index 00000000..382b6794 --- /dev/null +++ b/swtp6800/common/m6810.c @@ -0,0 +1,146 @@ +/* m6810.c: Motorola m6810 RAM emulator + + Copyright (c) 2011, William A. Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated m6810 RAM device on a CPU board. The + byte get and put routines use an offset into the RAM image to locate the + proper byte. This allows another device to set the base address for the + M6810. +*/ + +#include +#include "swtp_defs.h" + +/* function prototypes */ + +t_stat m6810_reset (DEVICE *dptr); +int32 m6810_get_mbyte(int32 offset); +void m6810_put_mbyte(int32 offset, int32 val); + +/* SIMH RAM Standard I/O Data Structures */ + +UNIT m6810_unit = { UDATA (NULL, UNIT_BINK, 128), + 0 }; + +MTAB m6810_mod[] = { + { 0 } +}; + +DEBTAB m6810_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE m6810_dev = { + "M6810", //name + &m6810_unit, //units + NULL, //registers + m6810_mod, //modifiers + 1, //numunits + 16, //aradix + 32, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &m6810_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + m6810_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* global variables */ + +/* m6810_reset */ + +t_stat m6810_reset (DEVICE *dptr) +{ + if (m6810_dev.dctrl & DEBUG_flow) + printf("m6810_reset: \n"); + if (m6810_unit.filebuf == NULL) { + m6810_unit.filebuf = malloc(128); + if (m6810_unit.filebuf == NULL) { + printf("m6810_reset: Malloc error\n"); + return SCPE_MEM; + } + m6810_unit.capac = 128; + } + if (m6810_dev.dctrl & DEBUG_flow) + printf("m6810_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + RAM memory read or write is issued. +*/ + +/* get a byte from memory - from offset from start of RAM*/ + +int32 m6810_get_mbyte(int32 offset) +{ + int32 val, org, len; + + if (m6810_dev.dctrl & DEBUG_read) + printf("m6810_get_mbyte: offset=%04X\n", offset); + if (offset < m6810_unit.capac) { + val = *(uint8 *)(m6810_unit.filebuf + offset) & 0xFF; + if (m6810_dev.dctrl & DEBUG_read) + printf("val=%04X\n", val); + return val; + } else { + if (m6810_dev.dctrl & DEBUG_read) + printf("m6810_get_mbyte: out of range\n"); + return 0xFF; + } +} + +/* put a byte to memory */ + +void m6810_put_mbyte(int32 offset, int32 val) +{ + if (m6810_dev.dctrl & DEBUG_write) + printf("m6810_put_mbyte: offset=%04X, val=%02X\n", offset, val); + if (offset < m6810_unit.capac) { + *(uint8 *)(m6810_unit.filebuf + offset) = val & 0xFF; + return; + } else { + if (m6810_dev.dctrl & DEBUG_write) + printf("m6810_put_mbyte: out of range\n"); + return; + } +} + +/* end of m6810.c */ diff --git a/swtp6800/common/mp-8m.c b/swtp6800/common/mp-8m.c new file mode 100644 index 00000000..8b6e9b9a --- /dev/null +++ b/swtp6800/common/mp-8m.c @@ -0,0 +1,209 @@ +/* mp-8m.c: SWTP 8K Byte Memory Card emulator + + Copyright (c) 2011, William A. Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support 6 simulated MP-8M memory cards on an SS-50 system. + + Each unit uses a dynamically allocated 8192 byte buffer to hold the data. + Each unit contains the base address in mp_8m_unit.u3. The unit capacity is + held in mp_8m_unit.capac. Each unit can be enabled or disabled to reconfigure + the RAM for the system. +*/ + +#include +#include "swtp_defs.h" + +#define MP_8M_NUM 6 /* number of MP-*m boards */ + +/* prototypes */ + +t_stat mp_8m_reset (DEVICE *dptr); +int32 mp_8m_get_mbyte(int32 addr); +int32 mp_8m_get_mword(int32 addr); +void mp_8m_put_mbyte(int32 addr, int32 val); +void mp_8m_put_mword(int32 addr, int32 val); + +/* isbc064 Standard I/O Data Structures */ + +UNIT mp_8m_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 }, + { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_DISABLE, 0),0 } +}; + +MTAB mp_8m_mod[] = { + { 0 } +}; + +DEBTAB mp_8m_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE mp_8m_dev = { + "MP-8M", //name + mp_8m_unit, //units + NULL, //registers + mp_8m_mod, //modifiers + MP_8M_NUM, //numunits + 16, //aradix + 8, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposite + &mp_8m_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + mp_8m_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat mp_8m_reset (DEVICE *dptr) +{ + int32 i, j, val; + UNIT *uptr; + + if (mp_8m_dev.dctrl & DEBUG_flow) + printf("mp_8m_reset: \n"); + for (i = 0; i < MP_8M_NUM; i++) { /* init all units */ + uptr = mp_8m_dev.units + i; + if (mp_8m_dev.dctrl & DEBUG_flow) + printf("MP-8M %d unit.flags=%08X\n", i, uptr->flags); + uptr->capac = 0x2000; + if (i < 4) + uptr->u3 = 0x2000 * i; + else + uptr->u3 = 0x2000 * (i + 1); + if (uptr->filebuf == NULL) { + uptr->filebuf = malloc(0x2000); + if (uptr->filebuf == NULL) { + printf("mp_8m_reset: Malloc error\n"); + return SCPE_MEM; + } + for (j=0; j<8192; j++) { /* fill pattern for testing */ + val = (0xA0 | i); + *(uint8 *)(uptr->filebuf + j) = val & 0xFF; + } + } + if (mp_8m_dev.dctrl & DEBUG_flow) + printf("MP-8M %d initialized at [%04X-%04XH]\n", i, uptr->u3, + uptr->u3 + uptr->capac - 1); + } + if (mp_8m_dev.dctrl & DEBUG_flow) + printf("mp_8m_reset: Done\n"); + return SCPE_OK; +} + +/* I/O instruction handlers, called from the mp-b2 module when an + external memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 mp_8m_get_mbyte(int32 addr) +{ + int32 val, org, len; + int32 i; + UNIT *uptr; + + if (mp_8m_dev.dctrl & DEBUG_read) + printf("mp_8m_get_mbyte: addr=%04X", addr); + for (i = 0; i < MP_8M_NUM; i++) { /* find addressed unit */ + uptr = mp_8m_dev.units + i; + org = uptr->u3; + len = uptr->capac - 1; + if ((addr >= org) && (addr <= org + len)) { + val = *(uint8 *)(uptr->filebuf + (addr - org)); + if (mp_8m_dev.dctrl & DEBUG_read) + printf(" val=%04X\n", val); + return (val & 0xFF); + } + } + if (mp_8m_dev.dctrl & DEBUG_read) + printf("mp_8m_get_mbyte: Out of range\n"); + return 0xFF; /* multibus has active high pullups */ +} + +/* get a word from memory */ + +int32 mp_8m_get_mword(int32 addr) +{ + int32 val; + + val = (mp_8m_get_mbyte(addr) << 8); + val |= mp_8m_get_mbyte(addr+1); + return val; +} + +/* put a byte into memory */ + +void mp_8m_put_mbyte(int32 addr, int32 val) +{ + int32 org, len, type; + int32 i; + UNIT *uptr; + + if (mp_8m_dev.dctrl & DEBUG_write) + printf("mp_8m_put_mbyte: addr=%04X, val=%02X", addr, val); + for (i = 0; i < MP_8M_NUM; i++) { /* find addressed unit */ + uptr = mp_8m_dev.units + i; + org = uptr->u3; + len = uptr->capac - 1; + if ((addr >= org) && (addr < org + len)) { + *(uint8 *)(uptr->filebuf + (addr - org)) = val & 0xFF; + if (mp_8m_dev.dctrl & DEBUG_write) + printf("\n"); + return; + } + } + if (mp_8m_dev.dctrl & DEBUG_write) + printf("mp_8m_put_mbyte: Out of range\n"); +} + +/* put a word into memory */ + +void mp_8m_put_mword(int32 addr, int32 val) +{ + mp_8m_put_mbyte(addr, val >> 8); + mp_8m_put_mbyte(addr+1, val); +} + +/* end of mp-8m.c */ diff --git a/swtp6800/common/mp-a.c b/swtp6800/common/mp-a.c new file mode 100644 index 00000000..6dd77509 --- /dev/null +++ b/swtp6800/common/mp-a.c @@ -0,0 +1,211 @@ +/* mp-a.c: SWTP MP-A M6800 CPU simulator + + Copyright (c) 2011, William Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + The MP-A CPU Board contains the following devices [mp-a.c]: + M6800 processor [m6800.c]. + M6810 128 byte RAM at 0xA000 [m6810.c]. + M6830, SWTBUG, or custom boot ROM at 0xE000 [bootrom.c]. + Interface to the SS-50 bus and the MP-B2 Mother Board for I/O + and memory boards [mp-b2.c]. + Note: The file names of the emulator source programs for each device are + contained in "[]". +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_SWT (UNIT_V_UF) /* on SWTBUG, off MIKBUG */ +#define UNIT_SWT (1 << UNIT_V_SWT) +#define UNIT_V_RAM (UNIT_V_UF+1) /* off disables 6810 RAM */ +#define UNIT_RAM (1 << UNIT_V_RAM) + +/* local global variables */ + +/* function prototypes */ + +int32 CPU_BD_get_mbyte(int32 addr); +int32 CPU_BD_get_mword(int32 addr); +void CPU_BD_put_mbyte(int32 addr, int32 val); +void CPU_BD_put_mword(int32 addr, int32 val); + +/* external routines */ + +/* MP-B2 bus routines */ +extern int32 MB_get_mbyte(int32 addr); +extern int32 MB_get_mword(int32 addr); +extern void MB_put_mbyte(int32 addr, int32 val); +extern void MB_put_mword(int32 addr, int32 val); + +/* M6810 bus routines */ +extern int32 m6810_get_mbyte(int32 addr); +extern void m6810_put_mbyte(int32 addr, int32 val); + +/* BOOTROM bus routines */ +extern UNIT BOOTROM_unit; +extern int32 BOOTROM_get_mbyte(int32 offset); + +/* MP-A data structures + + CPU_BD_dev MP-A2 device descriptor + CPU_BD_unit MP-A2 unit descriptor + CPU_BD_reg MP-A2 register list + CPU_BD_mod MP-A2 modifiers list */ + +UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; + +REG CPU_BD_reg[] = { + { NULL } +}; + +MTAB CPU_BD_mod[] = { + { UNIT_SWT, UNIT_SWT, "SWT", "SWT", NULL }, + { UNIT_SWT, 0, "NOSWT", "NOSWT", NULL }, + { UNIT_RAM, UNIT_RAM, "RAM", "RAM", NULL }, + { UNIT_RAM, 0, "NORAM", "NORAM", NULL }, + { 0 } +}; + +DEBTAB CPU_BD_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE CPU_BD_dev = { + "MP-A", //name + &CPU_BD_unit, //units + CPU_BD_reg, //registers + CPU_BD_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + CPU_BD_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* get a byte from memory */ + +int32 CPU_BD_get_mbyte(int32 addr) +{ + int32 val; + + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0xA000: + if (CPU_BD_unit.flags & UNIT_RAM) { + val = m6810_get_mbyte(addr - 0xA000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: m6810 val=%02X\n", val); + return val; + } else { + val = MB_get_mbyte(addr) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: m6810 val=%02X\n", val); + return val; + } + case 0xE000: + val = BOOTROM_get_mbyte(addr - 0xE000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: EPROM=%02X\n", val); + return val; + case 0xF000: + val = BOOTROM_get_mbyte(addr - (0x10000 - BOOTROM_unit.capac)) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: EPROM=%02X\n", val); + return val; + default: + val = MB_get_mbyte(addr) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: mp_b2 val=%02X\n", val); + return val; + } +} + +/* get a word from memory */ + +int32 CPU_BD_get_mword(int32 addr) +{ + int32 val; + + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mword: addr=%04X\n", addr); + val = (CPU_BD_get_mbyte(addr) << 8); + val |= CPU_BD_get_mbyte(addr+1); + val &= 0xFFFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void CPU_BD_put_mbyte(int32 addr, int32 val) +{ + if (CPU_BD_dev.dctrl & DEBUG_write) + printf("CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); + switch(addr & 0xF000) { + case 0xA000: + if (CPU_BD_unit.flags & UNIT_RAM) { + m6810_put_mbyte(addr - 0xA000, val); + return; + } else { + MB_put_mbyte(addr, val); + return; + } + default: + MB_put_mbyte(addr, val); + return; + } +} + +/* put a word to memory */ + +void CPU_BD_put_mword(int32 addr, int32 val) +{ + if (CPU_BD_dev.dctrl & DEBUG_write) + printf("CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); + CPU_BD_put_mbyte(addr, val >> 8); + CPU_BD_put_mbyte(addr+1, val); +} + +/* end of mp-a.c */ diff --git a/swtp6800/common/mp-a2.c b/swtp6800/common/mp-a2.c new file mode 100644 index 00000000..21805dcb --- /dev/null +++ b/swtp6800/common/mp-a2.c @@ -0,0 +1,263 @@ +/* mp-a2.c: SWTP MP-A2 M6800 CPU simulator + + Copyright (c) 2011, William Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + The MP-A2 CPU Board contains the following devices [mp-a2.c]: + M6800 processor [m6800.c]. + M6810 128 byte RAM at 0xA000 [m6810.c]. + M6830, SWTBUG, or custom boot ROM at 0xE000 [bootrom.c]. + 4 ea 2716 EPROMs at either 0xC000, 0xC800, 0xD000 and 0xD800 (LO_PROM)or + 0xE000, 0xE800, 0xF000 and 0xF800 (HI_PROM) [eprom.c]. + Interface to the SS-50 bus and the MP-B2 Mother Board for I/O + and memory boards [mp-b2.c]. + Note: The file names of the emulator source programs for each device are + contained in "[]". +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_USER_D (UNIT_V_UF) /* user defined switch */ +#define UNIT_USER_D (1 << UNIT_V_USER_D) +#define UNIT_V_4K_8K (UNIT_V_UF+1) /* off if HI_PROM and only 2K EPROM */ +#define UNIT_4K_8K (1 << UNIT_V_4K_8K) +#define UNIT_V_SWT (UNIT_V_UF+2) /* on SWTBUG, off MIKBUG */ +#define UNIT_SWT (1 << UNIT_V_SWT) +#define UNIT_V_8K (UNIT_V_UF+3) /* off if HI_PROM and only 2K or 4k EPROM */ +#define UNIT_8K (1 << UNIT_V_8K) +#define UNIT_V_RAM (UNIT_V_UF+4) /* off disables 6810 RAM */ +#define UNIT_RAM (1 << UNIT_V_RAM) +#define UNIT_V_LO_PROM (UNIT_V_UF+5) /* on EPROMS @ C000-CFFFH, off no EPROMS */ +#define UNIT_LO_PROM (1 << UNIT_V_LO_PROM) +#define UNIT_V_HI_PROM (UNIT_V_UF+6) /* on EPROMS @ F000-FFFFH, off fo LO_PROM, MON, or no EPROMS */ +#define UNIT_HI_PROM (1 << UNIT_V_HI_PROM) +#define UNIT_V_MON (UNIT_V_UF+7) /* on for monitor vectors in high memory */ +#define UNIT_MON (1 << UNIT_V_MON) + +/* local global variables */ + +/* function prototypes */ + +int32 get_base(void); +int32 CPU_BD_get_mbyte(int32 addr); +int32 CPU_BD_get_mword(int32 addr); +void CPU_BD_put_mbyte(int32 addr, int32 val); +void CPU_BD_put_mword(int32 addr, int32 val); + +/* external routines */ + +/* MP-B2 bus routines */ +extern int32 MB_get_mbyte(int32 addr); +extern int32 MB_get_mword(int32 addr); +extern void MB_put_mbyte(int32 addr, int32 val); +extern void MB_put_mword(int32 addr, int32 val); + +/* M6810 bus routines */ +extern int32 m6810_get_mbyte(int32 addr); +extern void m6810_put_mbyte(int32 addr, int32 val); + +/* BOOTROM bus routines */ +extern UNIT BOOTROM_unit; +extern int32 BOOTROM_get_mbyte(int32 offset); + +/* I2716 bus routines */ +extern int32 i2716_get_mbyte(int32 offset); + +/* MP-A2 data structures + + CPU_BD_dev MP-A2 device descriptor + CPU_BD_unit MP-A2 unit descriptor + CPU_BD_reg MP-A2 register list + CPU_BD_mod MP-A2 modifiers list */ + +UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; + +REG CPU_BD_reg[] = { + { NULL } +}; + +MTAB CPU_BD_mod[] = { + { UNIT_USER_D, UNIT_USER_D, "USER_D", "USER_D", NULL }, + { UNIT_USER_D, 0, "NOUSER_D", "NOUSER_D", NULL }, + { UNIT_4K_8K, UNIT_4K_8K, "4K_8K", "4K_8K", NULL }, + { UNIT_4K_8K, 0, "NO4K_8K", "NO4K_8K", NULL }, + { UNIT_SWT, UNIT_SWT, "SWT", "SWT", NULL }, + { UNIT_SWT, 0, "NOSWT", "NOSWT", NULL }, + { UNIT_8K, UNIT_8K, "8K", "8K", NULL }, + { UNIT_8K, 0, "NO8K", "NO8K", NULL }, + { UNIT_RAM, UNIT_RAM, "RAM", "RAM", NULL }, + { UNIT_RAM, 0, "NORAM", "NORAM", NULL }, + { UNIT_LO_PROM, UNIT_LO_PROM, "LO_PROM", "LO_PROM", NULL }, + { UNIT_LO_PROM, 0, "NOLO_PROM", "NOLO_PROM", NULL }, + { UNIT_HI_PROM, UNIT_HI_PROM, "HI_PROM", "HI_PROM", NULL }, + { UNIT_HI_PROM, 0, "NOHI_PROM", "NOHI_PROM", NULL }, + { UNIT_MON, UNIT_MON, "MON", "MON", NULL }, + { UNIT_MON, 0, "NOMON", "NOMON", NULL }, + { 0 } +}; + +DEBTAB CPU_BD_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE CPU_BD_dev = { + "MP-A2", //name + &CPU_BD_unit, //units + CPU_BD_reg, //registers + CPU_BD_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + CPU_BD_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* get base address of 2716's */ + +int32 get_base(void) +{ + if (CPU_BD_unit.flags & UNIT_LO_PROM) + return 0xC000; + else if (CPU_BD_unit.flags & UNIT_HI_PROM) + return 0xF000; + return 0; +} + +/* get a byte from memory */ + +int32 CPU_BD_get_mbyte(int32 addr) +{ + int32 val; + + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0xA000: + if (CPU_BD_unit.flags & UNIT_RAM) { + val = m6810_get_mbyte(addr - 0xA000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: m6810 val=%02X\n", val); + return val; + } else { + val = MB_get_mbyte(addr) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: m6810 val=%02X\n", val); + return val; + } + case 0xC000: + if (CPU_BD_unit.flags & UNIT_LO_PROM) { + val = i2716_get_mbyte(addr - 0xC000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: 2716=%02X\n", val); + return val; + } else + return 0xFF; + break; + case 0xE000: + val = BOOTROM_get_mbyte(addr - 0xE000) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: EPROM=%02X\n", val); + return val; + case 0xF000: + if (CPU_BD_unit.flags & UNIT_MON) { + val = BOOTROM_get_mbyte(addr - (0x10000 - BOOTROM_unit.capac)) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: EPROM=%02X\n", val); + return val; + } + default: + val = MB_get_mbyte(addr) & 0xFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mbyte: mp_b2 val=%02X\n", val); + return val; + } +} + +/* get a word from memory */ + +int32 CPU_BD_get_mword(int32 addr) +{ + int32 val; + + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mword: addr=%04X\n", addr); + val = (CPU_BD_get_mbyte(addr) << 8); + val |= CPU_BD_get_mbyte(addr+1); + val &= 0xFFFF; + if (CPU_BD_dev.dctrl & DEBUG_read) + printf("CPU_BD_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void CPU_BD_put_mbyte(int32 addr, int32 val) +{ + if (CPU_BD_dev.dctrl & DEBUG_write) + printf("CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); + switch(addr & 0xF000) { + case 0xA000: + if (CPU_BD_unit.flags & UNIT_RAM) { + m6810_put_mbyte(addr - 0xA000, val); + return; + } else { + MB_put_mbyte(addr, val); + return; + } + default: + MB_put_mbyte(addr, val); + return; + } +} + +/* put a word to memory */ + +void CPU_BD_put_mword(int32 addr, int32 val) +{ + if (CPU_BD_dev.dctrl & DEBUG_write) + printf("CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); + CPU_BD_put_mbyte(addr, val >> 8); + CPU_BD_put_mbyte(addr+1, val); +} + +/* end of mp-a2.c */ diff --git a/swtp6800/common/mp-b2.c b/swtp6800/common/mp-b2.c new file mode 100644 index 00000000..7b93d7d5 --- /dev/null +++ b/swtp6800/common/mp-b2.c @@ -0,0 +1,322 @@ +/* mp-b2.c: SWTP SS-50/SS-30 MP-B2 Mother Board + + Copyright (c) 2011, William A. Beech + + 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 + WILLIAM A. BEECH 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 William A. Beech shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_RAM_0000 (UNIT_V_UF) /* MP-8M board 0 enable */ +#define UNIT_RAM_0000 (1 << UNIT_V_RAM_0000) +#define UNIT_V_RAM_2000 (UNIT_V_UF+1) /* MP-8M board 1 enable */ +#define UNIT_RAM_2000 (1 << UNIT_V_RAM_2000) +#define UNIT_V_RAM_4000 (UNIT_V_UF+2) /* MP-8M board 2 enable */ +#define UNIT_RAM_4000 (1 << UNIT_V_RAM_4000) +#define UNIT_V_RAM_6000 (UNIT_V_UF+3) /* MP-8M board 3 enable */ +#define UNIT_RAM_6000 (1 << UNIT_V_RAM_6000) +#define UNIT_V_RAM_A000 (UNIT_V_UF+4) /* MP-8M board 4 enable */ +#define UNIT_RAM_A000 (1 << UNIT_V_RAM_A000) +#define UNIT_V_RAM_C000 (UNIT_V_UF+5) /* MP-8M board 5 enable */ +#define UNIT_RAM_C000 (1 << UNIT_V_RAM_C000) + +/* function prototypes */ + +/* empty I/O device routine */ +int32 nulldev(int32 io, int32 data); + +/* SS-50 bus routines */ +int32 MB_get_mbyte(int32 addr); +int32 MB_get_mword(int32 addr); +void MB_put_mbyte(int32 addr, int32 val); +void MB_put_mword(int32 addr, int32 val); + +/* MP-8M bus routines */ +extern int32 mp_8m_get_mbyte(int32 addr); +extern void mp_8m_put_mbyte(int32 addr, int32 val); + +/* SS-50 I/O address space functions */ + +/* MP-S serial I/O routines */ +extern int32 sio0s(int32 io, int32 data); +extern int32 sio0d(int32 io, int32 data); +extern int32 sio1s(int32 io, int32 data); +extern int32 sio1d(int32 io, int32 data); + +/* DC-4 FDC I/O routines */ +extern int32 fdcdrv(int32 io, int32 data); +extern int32 fdccmd(int32 io, int32 data); +extern int32 fdctrk(int32 io, int32 data); +extern int32 fdcsec(int32 io, int32 data); +extern int32 fdcdata(int32 io, int32 data); + +/* This is the I/O configuration table. There are 32 possible +device addresses, if a device is plugged into a port it's routine +address is here, 'nulldev' means no device is available +*/ + +struct idev { + int32 (*routine)(); +}; + +struct idev dev_table[32] = { + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 0 8000-8003 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 1 8004-8007 */ +/* sio1x routines just return the last value read on the matching + sio0x routine. SWTBUG tests for the MP-C with most port reads! */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 2 8008-800B*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 3 800C-800F*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 4 8010-8013*/ + {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 5 8014-8017*/ + {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /*Port 6 8018-801B*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /*Port 7 801C-801F*/ +}; + +/* dummy i/o device */ + +int32 nulldev(int32 io, int32 data) +{ + if (io == 0) + return (0xFF); + return 0; +} + +/* Mother Board data structures + + MB_dev Mother Board device descriptor + MB_unit Mother Board unit descriptor + MB_reg Mother Board register list + MB_mod Mother Board modifiers list +*/ + +UNIT MB_unit = { + UDATA (NULL, 0, 0) +}; + +REG MB_reg[] = { + { NULL } +}; + +MTAB MB_mod[] = { + { UNIT_RAM_0000, UNIT_RAM_0000, "BD0 On", "BD0", NULL }, + { UNIT_RAM_0000, 0, "BD0 Off", "NOBD0", NULL }, + { UNIT_RAM_2000, UNIT_RAM_2000, "BD1 On", "BD1", NULL }, + { UNIT_RAM_2000, 0, "BD1 Off", "NOBD1", NULL }, + { UNIT_RAM_4000, UNIT_RAM_4000, "BD2 On", "BD2", NULL }, + { UNIT_RAM_4000, 0, "BD2 Off", "NOBD2", NULL }, + { UNIT_RAM_6000, UNIT_RAM_6000, "BD3 On", "BD3", NULL }, + { UNIT_RAM_6000, 0, "BD3 Off", "NOBD3", NULL }, + { UNIT_RAM_A000, UNIT_RAM_A000, "BD4 On", "BD4", NULL }, + { UNIT_RAM_A000, 0, "BD4 Off", "NOBD4", NULL }, + { UNIT_RAM_C000, UNIT_RAM_C000, "BD5 On", "BD5", NULL }, + { UNIT_RAM_C000, 0, "BD5 Off", "NOBD5", NULL }, + { 0 } +}; + +DEBTAB MB_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE MB_dev = { + "MP-B2", //name + &MB_unit, //units + MB_reg, //registers + MB_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + NULL, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + MB_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* get a byte from memory */ + +int32 MB_get_mbyte(int32 addr) +{ + int32 val; + + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0x0000: + case 0x1000: + if (MB_unit.flags & UNIT_RAM_0000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0x2000: + case 0x3000: + if (MB_unit.flags & UNIT_RAM_2000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0x4000: + case 0x5000: + if (MB_unit.flags & UNIT_RAM_4000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0x6000: + case 0x7000: + if (MB_unit.flags & UNIT_RAM_6000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0x8000: + val = (dev_table[addr - 0x8000].routine(0, 0)) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: I/O addr=%04X val=%02X\n", addr, val); + return val; + case 0xA000: + case 0xB000: + if (MB_unit.flags & UNIT_RAM_A000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + case 0xC000: + case 0xD000: + if (MB_unit.flags & UNIT_RAM_C000) { + val = mp_8m_get_mbyte(addr) & 0xFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mbyte: mp_8m val=%02X\n", val); + return val; + } else + return 0xFF; + default: + return 0xFF; + } +} + +/* get a word from memory */ + +int32 MB_get_mword(int32 addr) +{ + int32 val; + + + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mword: addr=%04X\n", addr); + val = (MB_get_mbyte(addr) << 8); + val |= MB_get_mbyte(addr+1); + val &= 0xFFFF; + if (MB_dev.dctrl & DEBUG_read) + printf("MB_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void MB_put_mbyte(int32 addr, int32 val) +{ + if (MB_dev.dctrl & DEBUG_write) + printf("MB_put_mbyte: addr=%04X, val=%02X\n", addr, val); + switch(addr & 0xF000) { + case 0x0000: + case 0x1000: + if (MB_unit.flags & UNIT_RAM_0000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0x2000: + case 0x3000: + if (MB_unit.flags & UNIT_RAM_2000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0x4000: + case 0x5000: + if (MB_unit.flags & UNIT_RAM_4000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0x6000: + case 0x7000: + if (MB_unit.flags & UNIT_RAM_6000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0x8000: + dev_table[addr - 0x8000].routine(1, val); + return; + case 0xA000: + case 0xB000: + if (MB_unit.flags & UNIT_RAM_A000) { + mp_8m_put_mbyte(addr, val); + return; + } + case 0xC000: + case 0xD000: + if (MB_unit.flags & UNIT_RAM_C000) { + mp_8m_put_mbyte(addr, val); + return; + } + default: + return; + } +} + +/* put a word to memory */ + +void MB_put_mword(int32 addr, int32 val) +{ + if (MB_dev.dctrl & DEBUG_write) + printf("MB_ptt_mword: addr=%04X, val=%04X\n", addr, val); + MB_put_mbyte(addr, val >> 8); + MB_put_mbyte(addr+1, val); +} + +/* end of mp-b2.c */ diff --git a/swtp6800/common/mp-s.c b/swtp6800/common/mp-s.c new file mode 100644 index 00000000..6c9c12a3 --- /dev/null +++ b/swtp6800/common/mp-s.c @@ -0,0 +1,330 @@ +/* mp-s.c: SWTP MP-S serial I/O card emulator + + Copyright (c) 2005-2011, William Beech + + 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 + Willaim Beech 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + These functions support a simulated SWTP MP-S interface card. + The card contains one M6850 ACIA. The ACIA implements one complete + serial port. It provides 7 or 8-bit ASCII RS-232 interface to Terminals + or 20 mA current loop interface to a model 33 or 37 Teletype. It is not + compatible with baudot Teletypes. Baud rates from 110 to 1200 are + switch selectable from S! on the MP-S. The ACIA ports appear at all + 4 addresses. This fact is used by SWTBUG to determine the presence of the + MP-S vice MP-C serial card. The ACIA interrupt request line can be connected + to the IRQ or NMI interrupt lines by a jumper on the MP-S. + + All I/O is via either programmed I/O or interrupt controlled I/O. + It has a status port and a data port. A write to the status port + can select some options for the device (0x03 will reset the port). + A read of the status port gets the port status: + + +---+---+---+---+---+---+---+---+ + | I | P | O | F |CTS|DCD|TXE|RXF| + +---+---+---+---+---+---+---+---+ + + RXF - A 1 in this bit position means a character has been received + on the data port and is ready to be read. + TXE - A 1 in this bit means the port is ready to receive a character + on the data port and transmit it out over the serial line. + + A read to the data port gets the buffered character, a write + to the data port writes the character to the device. +*/ + +#include +#include +#include "swtp_defs.h" + +#define UNIT_V_TTY (UNIT_V_UF) // TTY or ANSI mode +#define UNIT_TTY (1 << UNIT_V_TTY) + +/* local global variables */ + +int32 ptr_stopioe = 0; // stop on error +int32 ptp_stopioe = 0; // stop on error +int32 odata; +int32 status; + +int32 ptp_flag = 0; +int32 ptr_flag = 0; + +/* function prototypes */ + +t_stat sio_svc (UNIT *uptr); +t_stat ptr_svc (UNIT *uptr); +t_stat ptp_svc (UNIT *uptr); +t_stat sio_reset (DEVICE *dptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptp_reset (DEVICE *dptr); +int32 sio0s(int32 io, int32 data); +int32 sio0d(int32 io, int32 data); +int32 sio1s(int32 io, int32 data); +int32 sio1d(int32 io, int32 data); + +/* sio data structures + + sio_dev SIO device descriptor + sio_unit SIO unit descriptor + sio_reg SIO register list + sio_mod SIO modifiers list */ + +UNIT sio_unit = { UDATA (&sio_svc, 0, 0), KBD_POLL_WAIT +}; + +REG sio_reg[] = { + { ORDATA (DATA, sio_unit.buf, 8) }, + { ORDATA (STAT, sio_unit.u3, 8) }, + { NULL } +}; + +MTAB sio_mod[] = { + { UNIT_TTY, UNIT_TTY, "TTY", "TTY", NULL }, + { UNIT_TTY, 0, "ANSI", "ANSI", NULL }, + { 0 } +}; + +DEVICE sio_dev = { + "MP-S", &sio_unit, sio_reg, sio_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &sio_reset, + NULL, NULL, NULL +}; + +/* paper tape reader data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_reg PTR register list + ptr_mod PTR modifiers list */ + +UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT +}; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, NULL, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptr_reset, + NULL, NULL, NULL +}; + +/* paper tape punch data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_reg PTP register list + ptp_mod PTP modifiers list */ + +UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT +}; +DEVICE ptp_dev = { + "PTP", &ptp_unit, NULL, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptp_reset, + NULL, NULL, NULL +}; + +/* console input service routine */ + +int32 sio_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&sio_unit, sio_unit.wait); // continue poll + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; // no char or error? + sio_unit.buf = temp & 0xFF; // Save char + sio_unit.u3 |= 0x01; // Set RXF flag + /* Do any special character handling here */ + sio_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape reader input service routine */ + +int32 ptr_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&ptr_unit, ptr_unit.wait); // continue poll + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; // no char or error? + ptr_unit.buf = temp & 0xFF; // Save char + ptr_unit.u3 |= 0x01; // Set RXF flag + /* Do any special character handling here */ + ptr_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape punch output service routine */ + +int32 ptp_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +/* Reset console */ + +int32 sio_reset (DEVICE *dptr) +{ + sio_unit.buf = 0; // Data buffer + sio_unit.u3 = 0x02; // Status buffer + sim_activate (&sio_unit, sio_unit.wait); // activate unit + return SCPE_OK; +} + +/* Reset paper tape reader */ + +int32 ptr_reset (DEVICE *dptr) +{ + ptr_unit.buf = 0; + ptr_unit.u3 = 0x02; + sim_activate (&ptr_unit, ptr_unit.wait); // activate unit +// sim_cancel (&ptr_unit); // deactivate unit + return SCPE_OK; +} + +/* Reset paper tape punch */ + +int32 ptp_reset (DEVICE *dptr) +{ + ptp_unit.buf = 0; + ptp_unit.u3 = 0x02; + sim_activate (&ptp_unit, ptp_unit.wait); // activate unit +// sim_cancel (&ptp_unit); // deactivate unit + return SCPE_OK; +} + +/* I/O instruction handlers, called from the MP-B2 module when a + read or write occur to addresses 0x8004-0x8007. */ + +int32 sio0s(int32 io, int32 data) +{ + if (io == 0) { // control register read + if (ptr_flag) { // reader enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) { // attached? + ptr_unit.u3 &= 0xFE; // no, clear RXF flag + ptr_flag = 0; // clear reader flag + printf("Reader not attached to file\n"); + } else { // attached + if (feof(ptr_unit.fileref)) { // EOF + ptr_unit.u3 &= 0xFE; // clear RXF flag + ptr_flag = 0; // clear reader flag + } else // not EOF + ptr_unit.u3 |= 0x01; // set ready + } + return (status = ptr_unit.u3); // return ptr status + } else { + return (status = sio_unit.u3); // return console status + } + } else { // control register write + if (data == 0x03) { // reset port! + sio_unit.u3 = 0x02; // reset console + sio_unit.buf = 0; + sio_unit.pos = 0; + ptr_unit.u3 = 0x02; // reset reader + ptr_unit.buf = 0; + ptr_unit.pos = 0; + ptp_unit.u3 = 0x02; // reset punch + ptp_unit.buf = 0; + ptp_unit.pos = 0; + } + return (status = 0); // invalid io + } +} + +int32 sio0d(int32 io, int32 data) +{ + if (io == 0) { // data register read + if (ptr_flag) { // RDR enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? + return 0; // no, done +// printf("ptr_unit.u3=%02X\n", ptr_unit.u3); + if ((ptr_unit.u3 & 0x01) == 0) { // yes, more data? +// printf("Returning old %02X\n", odata); // no, return previous byte + return (odata & 0xFF); + } + if ((odata = getc(ptr_unit.fileref)) == EOF) { // end of file? +// printf("Got EOF\n"); + ptr_unit.u3 &= 0xFE; // clear RXF flag + return (odata = 0); // no data + } +// printf("Returning new %02X\n", odata); + ptr_unit.pos++; // step character count + ptr_unit.u3 &= 0xFE; // clear RXF flag + return (odata & 0xFF); // return character + } else { + sio_unit.u3 &= 0xFE; // clear RXF flag + return (odata = sio_unit.buf); // return next char + } + } else { // data register write + if (isprint(data) || data == '\r' || data == '\n') { // printable? + sim_putchar(data); // print character on console + if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached? + putc(data, ptp_unit.fileref); + ptp_unit.pos++; // step character counter + } + } else { // DC1-DC4 control Reader/Punch + switch (data) { + case 0x11: // PTR on + ptr_flag = 1; + ptr_unit.u3 |= 0x01; +// printf("Reader on\n"); + break; + case 0x12: // PTP on + ptp_flag = 1; + ptp_unit.u3 |= 0x02; +// printf("Punch on\n"); + break; + case 0x13: // PTR off + ptr_flag = 0; +// printf("Reader off-%d bytes read\n", ptr_unit.pos); + break; + case 0x14: // PTP off + ptp_flag = 0; +// printf("Punch off-%d bytes written\n", ptp_unit.pos); + break; + default: // ignore all other characters + break; + } + } + } + return (odata = 0); +} + +/* because each port appears at 2 addresses and this fact is used + to determine if it is a MP-C or MP-S repeatedly in the SWTBUG + monitor, this code assures that reads of the high ports return + the same data as was read the last time on the low ports. +*/ + +int32 sio1s(int32 io, int32 data) +{ + return status; +} + +int32 sio1d(int32 io, int32 data) +{ + return odata; +} + +/* end of mp-s.c */ \ No newline at end of file diff --git a/swtp6800/swtp6800/mp-a2_sys.c b/swtp6800/swtp6800/mp-a2_sys.c new file mode 100644 index 00000000..8a043061 --- /dev/null +++ b/swtp6800/swtp6800/mp-a2_sys.c @@ -0,0 +1,87 @@ +/* mp-a_sys.c: SWTP 6800 system interface + + Copyright (c) 2005, William Beech + + 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 + WILLIAM A BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE CPU_BD_dev; +extern DEVICE m6800_dev; +extern REG m6800_reg[]; +extern DEVICE BOOTROM_dev; +extern DEVICE m6810_dev; +extern DEVICE i2716_dev; + +extern DEVICE MB_dev; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE mp_8m_dev; +extern DEVICE dsk_dev; + +/* 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[] = "SWTP 6800, V2, MP-A2 CPU Board"; + +REG *sim_PC = &m6800_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &CPU_BD_dev, + &m6800_dev, + &BOOTROM_dev, + &m6810_dev, + &i2716_dev, + &MB_dev, + &sio_dev, + &ptr_dev, + &ptp_dev, + &mp_8m_dev, + &dsk_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode", + "Invalid Memory" +}; + +/* end of mp-a_sys.c */ diff --git a/swtp6800/swtp6800/mp-a_sys.c b/swtp6800/swtp6800/mp-a_sys.c new file mode 100644 index 00000000..4460b781 --- /dev/null +++ b/swtp6800/swtp6800/mp-a_sys.c @@ -0,0 +1,85 @@ +/* mp-a_sys.c: SWTP 6800 system interface + + Copyright (c) 2005, William Beech + + 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 + WILLIAM A BEECH 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 William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE CPU_BD_dev; +extern DEVICE m6800_dev; +extern REG m6800_reg[]; +extern DEVICE BOOTROM_dev; +extern DEVICE m6810_dev; + +extern DEVICE MB_dev; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE mp_8m_dev; +extern DEVICE dsk_dev; + +/* 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[] = "SWTP 6800, V2, MP-A CPU Board"; + +REG *sim_PC = &m6800_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &CPU_BD_dev, + &m6800_dev, + &BOOTROM_dev, + &m6810_dev, + &MB_dev, + &sio_dev, + &ptr_dev, + &ptp_dev, + &mp_8m_dev, + &dsk_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode", + "Invalid Memory" +}; + +/* end of mp-a_sys.c */ diff --git a/swtp6800/swtp6800/swtbug.bin b/swtp6800/swtp6800/swtbug.bin new file mode 100644 index 0000000000000000000000000000000000000000..8cef56ad69bb15ad2ce9f2c3e0e24b140853491c GIT binary patch literal 1024 zcmXX_U1%It6uxtJvOBxkb$65Pv`uZjHJh25lyuhy!c?K5-R{~FQL;!v9u%LXF-aea zJ`|nZ!7zx)sTN;bIYHfdDIy5jmyQv%Ln-OB1rb_7W_BTY5KXI?)NPsdZtA^oe>mrS z_dDOYCqOb!U~HbGWYKPpz&l1+X~EluroLe0l?N3}LcU7tSb}Ha&;=~1QHv}SMUvQq z4=}0THjhJIZ~P4LIwl}e$7cdeXi$EI4;jYy$&WF)jY+M*$3k*3XK4L&F{1l-b^j_n zl4`^dm2FM;&w%avS76iSC?gyK@_hbkFtueQRL^*m9Ts4%nj0E7qDNvzdZ=K?!(-Km zRwM9LjY#ZE_y_(r8TLuM9`yM5B zdKD$JZ8s&iD%y>O8d;`1Vy~i^A&Z!4i?AaCcgf9#6*|*36Xq;!PY+O%;36!+Ct$*Y zi<0f#2(V|#?^pM71{|x6u?oiFyc)6_AKJ~b-7LBOWgZHe+q}yajM(1VpTazmBx$Mn zNcn@Ua)5bK*2F|?7a^pa7ki(cvLYJ~Fg#D#nC+F?DDu_z-jHjArcjkvhueaf@&Z9MJuD1I(p*AWlI~BO$GDkx81&ixJykScwnCcO>!euB>~TaUni+@xhxcs%7gaXt zO#$K{nbZ+B2v9R@@m&j$wy^-WSFr0_Jhg@5UszB?BQ-$H +#include "../../sim_defs.h" // simulator defs /* Memory */ -#define MAXMEMSIZE 65536 // max memory size -#define MEMSIZE (cpu_unit.capac)// actual memory size -#define ADDRMASK (MAXMEMSIZE - 1)// address mask +#define MAXMEMSIZE 65536 // max memory size +#define MEMSIZE (m6800_unit.capac) // actual memory size +#define ADDRMASK (MAXMEMSIZE - 1) // address mask #define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_all 0xFFFF + /* Simulator stop codes */ -#define STOP_RSRV 1 // must be 1 -#define STOP_HALT 2 // HALT-really WAI -#define STOP_IBKPT 3 // breakpoint -#define STOP_OPCODE 4 // invalid opcode -#define STOP_MEMORY 5 // invalid memory address +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address From e0d8de9de731978289f64e8c1692341d29f56cdc Mon Sep 17 00:00:00 2001 From: Bill Beech Date: Sun, 8 Jul 2012 15:50:41 -0700 Subject: [PATCH 100/112] Replaced SWTBUG.BIN, fixed error in common/mp-s.c, and removed debugging statements from common.m6800.c. This version works in GIT release 4.0. --- swtp6800/common/m6800.c | 4 +++- swtp6800/common/mp-s.c | 22 +++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/swtp6800/common/m6800.c b/swtp6800/common/m6800.c index 806913a4..c0df27e0 100644 --- a/swtp6800/common/m6800.c +++ b/swtp6800/common/m6800.c @@ -318,8 +318,10 @@ int32 sim_instr (void) while (reason == 0) { /* loop until halted */ // dump_regs1(); if (sim_interval <= 0) /* check clock queue */ - if (reason = sim_process_event ()) + if (reason = sim_process_event ()) { +// printf("sim_process_event()=%08X\n", reason); break; + } if (mem_fault) { /* memory fault? */ mem_fault = 0; /* reset fault flag */ reason = STOP_MEMORY; diff --git a/swtp6800/common/mp-s.c b/swtp6800/common/mp-s.c index 6c9c12a3..345569ec 100644 --- a/swtp6800/common/mp-s.c +++ b/swtp6800/common/mp-s.c @@ -1,6 +1,6 @@ -/* mp-s.c: SWTP MP-S serial I/O card emulator +/* mp-s.c: SWTP MP-S serial I/O card simulator - Copyright (c) 2005-2011, William Beech + Copyright (c) 2005-2012, William Beech Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -136,6 +136,7 @@ DEVICE ptr_dev = { UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT }; + DEVICE ptp_dev = { "PTP", &ptp_unit, NULL, NULL, 1, 10, 31, 1, 8, 8, @@ -149,13 +150,17 @@ int32 sio_svc (UNIT *uptr) { int32 temp; +// printf("+++sio_svc() sio_unit.wait=%08X\n", sio_unit.wait); sim_activate (&sio_unit, sio_unit.wait); // continue poll - if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) { +// printf("sim_poll_kbd()=%08X\n", temp); return temp; // no char or error? + } sio_unit.buf = temp & 0xFF; // Save char sio_unit.u3 |= 0x01; // Set RXF flag /* Do any special character handling here */ sio_unit.pos++; // step character count +// printf("SCPE_OK with sio_unit.pos=%08X\n", sio_unit.pos); return SCPE_OK; } @@ -165,6 +170,7 @@ int32 ptr_svc (UNIT *uptr) { int32 temp; +// printf("+++ptr_svc()\n"); sim_activate (&ptr_unit, ptr_unit.wait); // continue poll if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; // no char or error? @@ -179,6 +185,7 @@ int32 ptr_svc (UNIT *uptr) int32 ptp_svc (UNIT *uptr) { +// printf("+++ptp_svc()\n"); return SCPE_OK; } @@ -188,6 +195,7 @@ int32 sio_reset (DEVICE *dptr) { sio_unit.buf = 0; // Data buffer sio_unit.u3 = 0x02; // Status buffer + sio_unit.wait = 10000; sim_activate (&sio_unit, sio_unit.wait); // activate unit return SCPE_OK; } @@ -198,8 +206,8 @@ int32 ptr_reset (DEVICE *dptr) { ptr_unit.buf = 0; ptr_unit.u3 = 0x02; - sim_activate (&ptr_unit, ptr_unit.wait); // activate unit -// sim_cancel (&ptr_unit); // deactivate unit +// sim_activate (&ptr_unit, ptr_unit.wait); // activate unit + sim_cancel (&ptr_unit); // deactivate unit return SCPE_OK; } @@ -209,8 +217,8 @@ int32 ptp_reset (DEVICE *dptr) { ptp_unit.buf = 0; ptp_unit.u3 = 0x02; - sim_activate (&ptp_unit, ptp_unit.wait); // activate unit -// sim_cancel (&ptp_unit); // deactivate unit +// sim_activate (&ptp_unit, ptp_unit.wait); // activate unit + sim_cancel (&ptp_unit); // deactivate unit return SCPE_OK; } From 2a9ac8a830a57500c85a76028a1442c822ae73e2 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 10 Jul 2012 13:18:03 -0700 Subject: [PATCH 101/112] VHD Performance enhancementsDaa: optimize BAT updates when writing to previously unwritten data blocks data block alignment for optimal behavior on Advance Format host disks (4096 sectors) --- sim_disk.c | 88 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/sim_disk.c b/sim_disk.c index fedfa427..8397c15b 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -2902,11 +2902,11 @@ if (!hVHD) { } LocatorPosition = NtoHll (hVHD->Dynamic.TableOffset)+BytesPerSector*((NtoHl (hVHD->Dynamic.MaxTableEntries)*sizeof(*hVHD->BAT)+BytesPerSector-1)/BytesPerSector); hVHD->Dynamic.Checksum = 0; -RelativeParentVHDPath = calloc (1, BytesPerSector+1); -FullParentVHDPath = calloc (1, BytesPerSector+1); -RelativeParentVHDPathBuffer = calloc (1, BytesPerSector); -FullParentVHDPathBuffer = calloc (1, BytesPerSector); -FullVHDPath = calloc (1, BytesPerSector+1); +RelativeParentVHDPath = calloc (1, BytesPerSector+2); +FullParentVHDPath = calloc (1, BytesPerSector+2); +RelativeParentVHDPathBuffer = calloc (1, BytesPerSector+2); +FullParentVHDPathBuffer = calloc (1, BytesPerSector+2); +FullVHDPath = calloc (1, BytesPerSector+2); ExpandToFullPath (szParentVHDPath, FullParentVHDPath, BytesPerSector); for (i=0; i < strlen (FullParentVHDPath); i++) hVHD->Dynamic.ParentUnicodeName[i*2+1] = FullParentVHDPath[i]; @@ -3240,8 +3240,13 @@ while (sects) { } SectorsInWrite = 1; if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) { - void *BitMap = NULL; + uint8 *BitMap = NULL; + uint32 BitMapBufferSize = VHD_DATA_BLOCK_ALIGNMENT; + uint8 *BitMapBuffer = NULL; void *BlockData = NULL; + uint8 *BATUpdateBufferAddress; + uint32 BATUpdateBufferSize; + uint64 BATUpdateStorageAddress; if (!hVHD->Parent && BufferIsZeros(buf, SectorSize)) goto IO_Done; @@ -3249,28 +3254,51 @@ while (sects) { BlockOffset = sim_fsize_ex (hVHD->File); if (((int64)BlockOffset) == -1) return SCPE_IOERR; - BitMap = malloc(BitMapSectors*SectorSize); + if (BitMapSectors*SectorSize > BitMapBufferSize) + BitMapBufferSize = BitMapSectors*SectorSize; + BitMapBuffer = calloc(1, BitMapBufferSize + SectorSize*SectorsPerBlock); + if (BitMapBufferSize > BitMapSectors*SectorSize) + BitMap = BitMapBuffer + BitMapBufferSize-BitMapBytes; + else + BitMap = BitMapBuffer; memset(BitMap, 0xFF, BitMapBytes); BlockOffset -= sizeof(hVHD->Footer); - /* align the data portion of the block to the desired alignment */ - /* compute the address of the data portion of the block */ - BlockOffset += BitMapSectors*SectorSize; - /* round up this address to the desired alignment */ - BlockOffset += VHD_DATA_BLOCK_ALIGNMENT-1; - BlockOffset &= ~(VHD_DATA_BLOCK_ALIGNMENT-1); - /* the actual block address is the beginning of the block bitmap */ + if (0 == (BlockOffset & ~(VHD_DATA_BLOCK_ALIGNMENT-1))) + { // Already aligned, so use padded BitMapBuffer + if (WriteFilePosition(hVHD->File, + BitMapBuffer, + BitMapBufferSize + SectorSize*SectorsPerBlock, + NULL, + BlockOffset)) { + free (BitMapBuffer); + return SCPE_IOERR; + } + BlockOffset += BitMapBufferSize; + } + else + { + // align the data portion of the block to the desired alignment + // compute the address of the data portion of the block + BlockOffset += BitMapSectors*SectorSize; + // round up this address to the desired alignment + BlockOffset += VHD_DATA_BLOCK_ALIGNMENT-1; + BlockOffset &= ~(VHD_DATA_BLOCK_ALIGNMENT-1); + BlockOffset -= BitMapSectors*SectorSize; + if (WriteFilePosition(hVHD->File, + BitMap, + SectorSize * (BitMapSectors + SectorsPerBlock), + NULL, + BlockOffset)) { + free (BitMapBuffer); + return SCPE_IOERR; + } + BlockOffset += BitMapSectors*SectorSize; + } + free(BitMapBuffer); + BitMapBuffer = BitMap = NULL; + /* the BAT block address is the beginning of the block bitmap */ BlockOffset -= BitMapSectors*SectorSize; hVHD->BAT[BlockNumber] = NtoHl((uint32)(BlockOffset/SectorSize)); - if (WriteFilePosition(hVHD->File, - BitMap, - BitMapSectors*SectorSize, - NULL, - BlockOffset)) { - free (BitMap); - return SCPE_IOERR; - } - free(BitMap); - BitMap = NULL; BlockOffset += SectorSize * (SectorsPerBlock + BitMapSectors); if (WriteFilePosition(hVHD->File, &hVHD->Footer, @@ -3278,11 +3306,17 @@ while (sects) { NULL, BlockOffset)) goto Fatal_IO_Error; + BATUpdateBufferAddress = ((uint8 *)hVHD->BAT) + + (((((size_t)&hVHD->BAT[BlockNumber]) - ((size_t)hVHD->BAT) + VHD_DATA_BLOCK_ALIGNMENT - 1)/VHD_DATA_BLOCK_ALIGNMENT)*VHD_DATA_BLOCK_ALIGNMENT); + BATUpdateBufferSize = SectorSize*((sizeof(*hVHD->BAT)*NtoHl(hVHD->Dynamic.MaxTableEntries)+511)/512); + if (BATUpdateBufferSize > VHD_DATA_BLOCK_ALIGNMENT) + BATUpdateBufferSize = VHD_DATA_BLOCK_ALIGNMENT; + BATUpdateStorageAddress = NtoHll(hVHD->Dynamic.TableOffset) + BATUpdateBufferAddress - ((uint8 *)hVHD->BAT); if (WriteFilePosition(hVHD->File, - hVHD->BAT, - SectorSize*((sizeof(*hVHD->BAT)*NtoHl(hVHD->Dynamic.MaxTableEntries)+511)/512), + BATUpdateBufferAddress, + BATUpdateBufferSize, NULL, - NtoHll(hVHD->Dynamic.TableOffset))) + BATUpdateStorageAddress)) goto Fatal_IO_Error; if (hVHD->Parent) { /* Need to populate data block contents from parent VHD */ From fd1cd463f9af989b39868fb2c62c58401358e2be Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 10 Jul 2012 13:26:08 -0700 Subject: [PATCH 102/112] Added UNIT_IDLE to timer threads for RQ B, C and D controllers. - Sergey Oboguev --- PDP11/pdp11_rq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index e860a866..e96c667b 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -894,7 +894,7 @@ UNIT rqb_unit[] = { (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, + { UDATA (&rq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) }, { UDATA (&rq_quesvc, UNIT_DIS, 0) } }; @@ -966,7 +966,7 @@ UNIT rqc_unit[] = { (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, + { UDATA (&rq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) }, { UDATA (&rq_quesvc, UNIT_DIS, 0) } }; @@ -1038,7 +1038,7 @@ UNIT rqd_unit[] = { (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, + { UDATA (&rq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) }, { UDATA (&rq_quesvc, UNIT_DIS, 0) } }; From 938450bbf5c07d5b113cb9efc8b1e4f231889a90 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 10 Jul 2012 13:32:41 -0700 Subject: [PATCH 103/112] Added display of warning produced by pcap_findalldevs() where a warning message is provided when no devices are available (OSX). - Sergey Oboguev --- sim_ether.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sim_ether.c b/sim_ether.c index 90d3bcd7..82d6a391 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -3159,6 +3159,7 @@ pcap_if_t* dev; char errbuf[PCAP_ERRBUF_SIZE]; memset(list, 0, max*sizeof(*list)); +errbuf[0] = '\0'; /* retrieve the device list */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { char* msg = "Eth: error in pcap_findalldevs: %s\r\n"; @@ -3166,6 +3167,11 @@ if (pcap_findalldevs(&alldevs, errbuf) == -1) { if (sim_log) fprintf (sim_log, msg, errbuf); } else { + if (errbuf[0]) { + char* msg = "Eth: pcap_findalldevs warning: %s\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + } /* copy device list into the passed structure */ for (i=0, dev=alldevs; dev && (i < max); dev=dev->next, ++i) { if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; From f66175beea2e21b5103517926e35a644a737fce9 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 10 Jul 2012 13:47:17 -0700 Subject: [PATCH 104/112] Added support to avoid the mkdir BIN race condition in parallel make --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 2f465e53..372dbe41 100644 --- a/makefile +++ b/makefile @@ -269,7 +269,7 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) NETWORK_OPT = $(NETWORK_CCDEFS) endif ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi)) - MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi + MKDIRBIN = mkdir -p BIN endif else #Win32 Environments (via MinGW32) From ffa52ab3fd961d2cf238a5ed9f28ec0fcc6dfb8a Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 10 Jul 2012 16:14:30 -0700 Subject: [PATCH 105/112] Changed the display of the contents of the error message buffer to only do so if no devices were returned at all --- sim_ether.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sim_ether.c b/sim_ether.c index 82d6a391..e49d0a5c 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -3167,11 +3167,6 @@ if (pcap_findalldevs(&alldevs, errbuf) == -1) { if (sim_log) fprintf (sim_log, msg, errbuf); } else { - if (errbuf[0]) { - char* msg = "Eth: pcap_findalldevs warning: %s\r\n"; - printf (msg, errbuf); - if (sim_log) fprintf (sim_log, msg, errbuf); - } /* copy device list into the passed structure */ for (i=0, dev=alldevs; dev && (i < max); dev=dev->next, ++i) { if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; @@ -3190,6 +3185,13 @@ else { /* Add any host specific devices and/or validate those already found */ i = eth_host_devices(i, max, list); +/* If no devices were found and an error message was left in the buffer, display it */ +if ((i == 0) && (errbuf[0])) { + char* msg = "Eth: pcap_findalldevs warning: %s\r\n"; + printf (msg, errbuf); + if (sim_log) fprintf (sim_log, msg, errbuf); + } + /* return device count */ return i; } From 5fcd6a7960df2eb0ebf0c516fe4bac1abd16216d Mon Sep 17 00:00:00 2001 From: Bill Beech Date: Wed, 11 Jul 2012 11:59:15 -0700 Subject: [PATCH 106/112] Updated several file to remove "egregious" errors --- swtp6800/common/bootrom.c | 10 +++--- swtp6800/common/dc-4.c | 9 +++-- swtp6800/common/i2716.c | 7 ++-- swtp6800/common/m6800.c | 76 +++++++++++++++++++-------------------- swtp6800/common/m6810.c | 10 +++--- swtp6800/common/mp-8m.c | 8 ++--- 6 files changed, 57 insertions(+), 63 deletions(-) diff --git a/swtp6800/common/bootrom.c b/swtp6800/common/bootrom.c index 608ecae0..c3ecc6e8 100644 --- a/swtp6800/common/bootrom.c +++ b/swtp6800/common/bootrom.c @@ -144,7 +144,7 @@ t_stat BOOTROM_config (UNIT *uptr, int32 val, char *cptr, void *desc) if (val == UNIT_NONE) BOOTROM_unit.capac = 0; /* set EPROM size */ else - BOOTROM_unit.capac = 0x200 << (val >> UNIT_V_MSIZE) - 1; /* set EPROM size */ + BOOTROM_unit.capac = 0x200 << ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ if (BOOTROM_unit.filebuf) { /* free buffer */ free (BOOTROM_unit.filebuf); BOOTROM_unit.filebuf = NULL; @@ -161,9 +161,9 @@ t_stat BOOTROM_config (UNIT *uptr, int32 val, char *cptr, void *desc) t_stat BOOTROM_reset (DEVICE *dptr) { - int j, c; + t_addr j; + int c; FILE *fp; - t_stat r; if (BOOTROM_dev.dctrl & DEBUG_flow) printf("BOOTROM_reset: \n"); @@ -195,7 +195,7 @@ t_stat BOOTROM_reset (DEVICE *dptr) j = 0; /* load EPROM file */ c = fgetc(fp); while (c != EOF) { - *(uint8 *)(BOOTROM_unit.filebuf + j++) = c & 0xFF; + *((uint8 *)(BOOTROM_unit.filebuf) + j++) = c & 0xFF; c = fgetc(fp); if (j > BOOTROM_unit.capac) { printf("\tImage is too large - Load truncated!!!\n"); @@ -222,7 +222,7 @@ int32 BOOTROM_get_mbyte(int32 offset) } if (BOOTROM_dev.dctrl & DEBUG_read) printf("BOOTROM_get_mbyte: offset=%04X\n", offset); - val = *(uint8 *)(BOOTROM_unit.filebuf + offset) & 0xFF; + val = *((uint8 *)(BOOTROM_unit.filebuf) + offset) & 0xFF; if (BOOTROM_dev.dctrl & DEBUG_read) printf("BOOTROM_get_mbyte: Normal val=%02X\n", val); return val; diff --git a/swtp6800/common/dc-4.c b/swtp6800/common/dc-4.c index d4379808..80cfd54d 100644 --- a/swtp6800/common/dc-4.c +++ b/swtp6800/common/dc-4.c @@ -368,7 +368,6 @@ t_stat dsk_reset (DEVICE *dptr) int32 fdcdrv(int32 io, int32 data) { static long pos; - char buf[128]; if (io) { /* write to DC-4 drive register */ if (dsk_dev.dctrl & DEBUG_write) @@ -394,9 +393,9 @@ int32 fdcdrv(int32 io, int32 data) sim_fread(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ - spt = *(uint8 *)(dsk_unit[cur_dsk].filebuf + MAXSEC) & 0xFF; + spt = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXSEC) & 0xFF; heds = 0; - cpd = *(uint8 *)(dsk_unit[cur_dsk].filebuf + MAXCYL) & 0xFF; + cpd = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXCYL) & 0xFF; trksiz = spt * SECSIZ; dsksiz = trksiz * cpd; if (dsk_dev.dctrl & DEBUG_read) @@ -538,7 +537,7 @@ int32 fdcdata(int32 io, int32 data) if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes to buffer */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdata: Writing byte %d of %02X", dsk_unit[cur_dsk].pos, data); - *(uint8 *)(dsk_unit[cur_dsk].filebuf + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ + *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ dsk_unit[cur_dsk].pos++; /* step counter */ if (dsk_unit[cur_dsk].pos == SECSIZ) { dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); @@ -555,7 +554,7 @@ int32 fdcdata(int32 io, int32 data) if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes from buffer */ if (dsk_dev.dctrl & DEBUG_read) printf("\nfdcdata: Reading byte %d u3=%02X", dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); - val = *(uint8 *)(dsk_unit[cur_dsk].filebuf + dsk_unit[cur_dsk].pos) & 0xFF; + val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF; dsk_unit[cur_dsk].pos++; /* step counter */ if (dsk_unit[cur_dsk].pos == SECSIZ) { /* done? */ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ diff --git a/swtp6800/common/i2716.c b/swtp6800/common/i2716.c index 77d4f61e..5395055e 100644 --- a/swtp6800/common/i2716.c +++ b/swtp6800/common/i2716.c @@ -130,7 +130,7 @@ t_stat i2716_attach (UNIT *uptr, char *cptr) j = 0; /* load EPROM file */ c = fgetc(fp); while (c != EOF) { - *(uint8 *)(uptr->filebuf + j++) = c & 0xFF; + *((uint8 *)(uptr->filebuf) + j++) = c & 0xFF; c = fgetc(fp); if (j > 2048) { printf("\tImage is too large - Load truncated!!!\n"); @@ -150,8 +150,7 @@ t_stat i2716_attach (UNIT *uptr, char *cptr) t_stat i2716_reset (DEVICE *dptr) { - int32 i, j, c, base; - t_stat r; + int32 i, base; UNIT *uptr; if (i2716_dev.dctrl & DEBUG_flow) @@ -207,7 +206,7 @@ int32 i2716_get_mbyte(int32 offset) printf("i2716_get_mbyte: EPROM not configured\n"); return 0xFF; } else { - val = *(uint8 *)(uptr->filebuf + (offset - org)); + val = *((uint8 *)(uptr->filebuf) + (offset - org)); if (i2716_dev.dctrl & DEBUG_read) printf(" val=%04X\n", val); return (val & 0xFF); diff --git a/swtp6800/common/m6800.c b/swtp6800/common/m6800.c index c0df27e0..c7f8bf02 100644 --- a/swtp6800/common/m6800.c +++ b/swtp6800/common/m6800.c @@ -77,7 +77,7 @@ #define UNIT_V_MSTOP (UNIT_V_UF+1) /* Stop on Invalid memory? */ #define UNIT_MSTOP (1 << UNIT_V_MSTOP) -/* Flag values to set proper positions in CCR */ +/* Flag values to set proper positions in CCR */ #define HF 0x20 #define IF 0x10 #define NF 0x08 @@ -85,7 +85,7 @@ #define VF 0x02 #define CF 0x01 -/* Macros to handle the flags in the CCR */ +/* Macros to handle the flags in the CCR */ #define CCR_ALWAYS_ON (0xC0) /* for 6800 */ #define CCR_MSK (HF|IF|NF|ZF|VF|CF) #define TOGGLE_FLAG(FLAG) (CCR ^= FLAG) @@ -105,7 +105,7 @@ #define COND_SET_FLAG_V(COND) \ if (COND) SET_FLAG(VF); else CLR_FLAG(VF) -/* local global variables */ +/* local global variables */ int32 A = 0; /* Accumulator A */ int32 B = 0; /* Accumulator B */ @@ -122,7 +122,7 @@ int32 mem_fault = 0; /* memory fault flag */ extern int32 sim_int_char; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -/* function prototypes */ +/* function prototypes */ t_stat m6800_reset (DEVICE *dptr); void dump_regs(void); @@ -145,7 +145,7 @@ int32 get_flag(int32 flag); void condevalVa(int32 op1, int32 op2); void condevalVs(int32 op1, int32 op2); -/* external routines */ +/* external routines */ extern void CPU_BD_put_mbyte(int32 addr, int32 val); extern void CPU_BD_put_mword(int32 addr, int32 val); @@ -153,12 +153,12 @@ extern int32 CPU_BD_get_mbyte(int32 addr); extern int32 CPU_BD_get_mword(int32 addr); extern int32 sim_switches; -/* CPU data structures +/* CPU data structures - m6800_dev CPU device descriptor - m6800_unit CPU unit descriptor - m6800_reg CPU register list - m6800_mod CPU modifiers list */ + m6800_dev CPU device descriptor + m6800_unit CPU unit descriptor + m6800_reg CPU register list + m6800_mod CPU modifiers list */ UNIT m6800_unit = { UDATA (NULL, 0, 0) }; @@ -303,8 +303,6 @@ int32 oplen[256] = { 3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 }; -/* simulator instruction decode routine */ - int32 sim_instr (void) { extern int32 sim_interval; @@ -318,10 +316,8 @@ int32 sim_instr (void) while (reason == 0) { /* loop until halted */ // dump_regs1(); if (sim_interval <= 0) /* check clock queue */ - if (reason = sim_process_event ()) { -// printf("sim_process_event()=%08X\n", reason); + if (reason = sim_process_event ()) break; - } if (mem_fault) { /* memory fault? */ mem_fault = 0; /* reset fault flag */ reason = STOP_MEMORY; @@ -1742,7 +1738,7 @@ int32 fetch_byte(int32 flag) { uint8 val; - val = CPU_BD_get_mbyte(PC) & 0xFF; /* fetch byte */ + val = CPU_BD_get_mbyte(PC) & 0xFF; /* fetch byte */ if (m6800_dev.dctrl & DEBUG_asm) { /* display source code */ switch (flag) { case 0: /* opcode fetch */ @@ -1762,7 +1758,7 @@ int32 fetch_word(void) { uint16 val; - val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ + val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ val |= CPU_BD_get_mbyte(PC + 1) & 0xFF; /* fetch low byte */ if (m6800_dev.dctrl & DEBUG_asm) printf("0%04XH", val); @@ -1804,8 +1800,8 @@ uint16 pop_word(void) return res; } -/* This routine does the jump to relative offset if the condition is - met. Otherwise, execution continues at the current PC. */ +/* this routine does the jump to relative offset if the condition is + met. Otherwise, execution continues at the current PC. */ void go_rel(int32 cond) { @@ -1817,7 +1813,7 @@ void go_rel(int32 cond) PC &= ADDRMASK; } -/* returns the relative offset sign-extended */ +/* returns the relative offset sign-extended */ int32 get_rel_addr(void) { @@ -1829,14 +1825,14 @@ int32 get_rel_addr(void) return temp & ADDRMASK; } -/* returns the value at the direct address pointed to by PC */ +/* returns the value at the direct address pointed to by PC */ int32 get_dir_val(void) { return CPU_BD_get_mbyte(get_dir_addr()); } -/* returns the direct address pointed to by PC */ +/* returns the direct address pointed to by PC */ int32 get_dir_addr(void) { @@ -1846,14 +1842,14 @@ int32 get_dir_addr(void) return temp & 0xFF; } -/* returns the value at the indirect address pointed to by PC */ +/* returns the value at the indirect address pointed to by PC */ int32 get_indir_val(void) { return CPU_BD_get_mbyte(get_indir_addr()); } -/* returns the indirect address pointed to by PC or immediate byte */ +/* returns the indirect address pointed to by PC or immediate byte */ int32 get_indir_addr(void) { @@ -1863,14 +1859,14 @@ int32 get_indir_addr(void) return temp; } -/* returns the value at the extended address pointed to by PC */ +/* returns the value at the extended address pointed to by PC */ int32 get_ext_val(void) { return CPU_BD_get_mbyte(get_ext_addr()); } -/* returns the extended address pointed to by PC or immediate word */ +/* returns the extended address pointed to by PC or immediate word */ int32 get_ext_addr(void) { @@ -1880,7 +1876,7 @@ int32 get_ext_addr(void) return temp; } -/* return 1 for flag set or 0 for flag clear */ +/* return 1 for flag set or 0 for flag clear */ int32 get_flag(int32 flg) { @@ -1890,27 +1886,27 @@ int32 get_flag(int32 flg) return 0; } -/* test and set V for addition */ +/* test and set V for addition */ void condevalVa(int32 op1, int32 op2) { if (get_flag(CF)) COND_SET_FLAG_V(((op1 & 0x80) && (op2 & 0x80)) || ( - (op1 & 0x80 == 0) && (op2 & 0x80 == 0))); + ((op1 & 0x80) == 0) && ((op2 & 0x80) == 0))); } -/* test and set V for subtraction */ +/* test and set V for subtraction */ void condevalVs(int32 op1, int32 op2) { if (get_flag(CF)) - COND_SET_FLAG_V(((op1 & 0x80) && (op2 & 0x80 == 0)) || - ((op1 & 0x80 == 0) && (op2 & 0x80))); + COND_SET_FLAG_V(((op1 & 0x80) && ((op2 & 0x80) == 0)) || + (((op1 & 0x80) == 0) && (op2 & 0x80))); } -/* calls from the simulator */ +/* calls from the simulator */ -/* Reset routine */ +/* Reset routine */ t_stat m6800_reset (DEVICE *dptr) { @@ -1926,9 +1922,9 @@ t_stat m6800_reset (DEVICE *dptr) } -/* This is the dumper/loader. This command uses the -h to signify a - hex dump/load vice a binary one. If no address is given to load, it - takes the address from the hex record or the current PC for binary. +/* This is the dumper/loader. This command uses the -h to signify a + hex dump/load vice a binary one. If no address is given to load, it + takes the address from the hex record or the current PC for binary. */ int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) @@ -1946,7 +1942,7 @@ int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) return (SCPE_OK); } -/* Symbolic output +/* Symbolic output Inputs: *of = output stream @@ -2002,7 +1998,7 @@ int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) return SCPE_ARG; } -/* Symbolic input +/* Symbolic input Inputs: *cptr = pointer to input string @@ -2019,4 +2015,4 @@ int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) return (-2); } -/* end of m6800.c */ +/* end of m6800.c */ diff --git a/swtp6800/common/m6810.c b/swtp6800/common/m6810.c index 382b6794..3bb5660a 100644 --- a/swtp6800/common/m6810.c +++ b/swtp6800/common/m6810.c @@ -111,12 +111,12 @@ t_stat m6810_reset (DEVICE *dptr) int32 m6810_get_mbyte(int32 offset) { - int32 val, org, len; + int32 val; if (m6810_dev.dctrl & DEBUG_read) printf("m6810_get_mbyte: offset=%04X\n", offset); - if (offset < m6810_unit.capac) { - val = *(uint8 *)(m6810_unit.filebuf + offset) & 0xFF; + if (((t_addr)offset) < m6810_unit.capac) { + val = *((uint8 *)(m6810_unit.filebuf) + offset) & 0xFF; if (m6810_dev.dctrl & DEBUG_read) printf("val=%04X\n", val); return val; @@ -133,8 +133,8 @@ void m6810_put_mbyte(int32 offset, int32 val) { if (m6810_dev.dctrl & DEBUG_write) printf("m6810_put_mbyte: offset=%04X, val=%02X\n", offset, val); - if (offset < m6810_unit.capac) { - *(uint8 *)(m6810_unit.filebuf + offset) = val & 0xFF; + if ((t_addr)offset < m6810_unit.capac) { + *((uint8 *)(m6810_unit.filebuf) + offset) = val & 0xFF; return; } else { if (m6810_dev.dctrl & DEBUG_write) diff --git a/swtp6800/common/mp-8m.c b/swtp6800/common/mp-8m.c index 8b6e9b9a..9126b05a 100644 --- a/swtp6800/common/mp-8m.c +++ b/swtp6800/common/mp-8m.c @@ -120,7 +120,7 @@ t_stat mp_8m_reset (DEVICE *dptr) } for (j=0; j<8192; j++) { /* fill pattern for testing */ val = (0xA0 | i); - *(uint8 *)(uptr->filebuf + j) = val & 0xFF; + *((uint8 *)(uptr->filebuf) + j) = val & 0xFF; } } if (mp_8m_dev.dctrl & DEBUG_flow) @@ -151,7 +151,7 @@ int32 mp_8m_get_mbyte(int32 addr) org = uptr->u3; len = uptr->capac - 1; if ((addr >= org) && (addr <= org + len)) { - val = *(uint8 *)(uptr->filebuf + (addr - org)); + val = *((uint8 *)(uptr->filebuf) + (addr - org)); if (mp_8m_dev.dctrl & DEBUG_read) printf(" val=%04X\n", val); return (val & 0xFF); @@ -177,7 +177,7 @@ int32 mp_8m_get_mword(int32 addr) void mp_8m_put_mbyte(int32 addr, int32 val) { - int32 org, len, type; + int32 org, len; int32 i; UNIT *uptr; @@ -188,7 +188,7 @@ void mp_8m_put_mbyte(int32 addr, int32 val) org = uptr->u3; len = uptr->capac - 1; if ((addr >= org) && (addr < org + len)) { - *(uint8 *)(uptr->filebuf + (addr - org)) = val & 0xFF; + *((uint8 *)(uptr->filebuf) + (addr - org)) = val & 0xFF; if (mp_8m_dev.dctrl & DEBUG_write) printf("\n"); return; From fc3c1812bf47936335bab7077af628e8cbe46a5c Mon Sep 17 00:00:00 2001 From: Bill Beech Date: Wed, 11 Jul 2012 12:00:57 -0700 Subject: [PATCH 107/112] Fixed nested sim_defs.h problem --- swtp6800/swtp6800/swtp_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swtp6800/swtp6800/swtp_defs.h b/swtp6800/swtp6800/swtp_defs.h index 9a935403..2466a5c0 100644 --- a/swtp6800/swtp6800/swtp_defs.h +++ b/swtp6800/swtp6800/swtp_defs.h @@ -25,7 +25,7 @@ Copyright (c) 2005-2012, William Beech */ #include -#include "../../sim_defs.h" // simulator defs +#include "sim_defs.h" // simulator defs /* Memory */ From 908ad1308e66c2a2301870d4965c56fd1b062333 Mon Sep 17 00:00:00 2001 From: Bill Beech Date: Wed, 11 Jul 2012 12:23:03 -0700 Subject: [PATCH 108/112] Corrected copyright dates on all files --- swtp6800/common/bootrom.c | 6 +++--- swtp6800/common/dc-4.c | 26 +++++++++++++------------- swtp6800/common/i2716.c | 2 +- swtp6800/common/m6800.c | 2 +- swtp6800/common/m6810.c | 2 +- swtp6800/common/mp-8m.c | 2 +- swtp6800/common/mp-a.c | 2 +- swtp6800/common/mp-a2.c | 2 +- swtp6800/common/mp-b2.c | 2 +- swtp6800/swtp6800/mp-a2_sys.c | 2 +- swtp6800/swtp6800/mp-a_sys.c | 2 +- 11 files changed, 25 insertions(+), 25 deletions(-) diff --git a/swtp6800/common/bootrom.c b/swtp6800/common/bootrom.c index c3ecc6e8..d3e8d6e1 100644 --- a/swtp6800/common/bootrom.c +++ b/swtp6800/common/bootrom.c @@ -1,6 +1,6 @@ /* bootrom.c: Boot ROM simulator for Motorola processors - Copyright (c) 2010-2011, William A. Beech + Copyright (c) 2010-2012, William A. Beech Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,8 +24,8 @@ in this Software without prior written authorization from William A. Beech. These functions support a single simulated 2704 to 2764 EPROM device on - an 8-bit computer system.. This device allows the the device buffer to - be loaded from a binary file containing the emulated EPROM code. + an 8-bit computer system.. This device allows the buffer to be loaded from + a binary file containing the emulated EPROM code. These functions support a simulated 2704, 2708, 2716, 2732 or 2764 EPROM device on a CPU board. The byte get and put routines use an offset into diff --git a/swtp6800/common/dc-4.c b/swtp6800/common/dc-4.c index 80cfd54d..e6935baf 100644 --- a/swtp6800/common/dc-4.c +++ b/swtp6800/common/dc-4.c @@ -1,6 +1,6 @@ /* dc4.c: SWTP DC-4 FDC Simulator - Copyright (c) 2005-2011, William A. Beech + Copyright (c) 2005-2012, William A. Beech Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -551,18 +551,18 @@ int32 fdcdata(int32 io, int32 data) } return 0; } else { /* read byte from fdc */ - if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes from buffer */ - if (dsk_dev.dctrl & DEBUG_read) - printf("\nfdcdata: Reading byte %d u3=%02X", dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); - val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF; - dsk_unit[cur_dsk].pos++; /* step counter */ - if (dsk_unit[cur_dsk].pos == SECSIZ) { /* done? */ - dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ - if (dsk_dev.dctrl & DEBUG_write) - printf("\nfdcdata: Sector read complete"); - } - return val; - } else + if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes from buffer */ + if (dsk_dev.dctrl & DEBUG_read) + printf("\nfdcdata: Reading byte %d u3=%02X", dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); + val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF; + dsk_unit[cur_dsk].pos++; /* step counter */ + if (dsk_unit[cur_dsk].pos == SECSIZ) { /* done? */ + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ + if (dsk_dev.dctrl & DEBUG_write) + printf("\nfdcdata: Sector read complete"); + } + return val; + } else return 0; } } diff --git a/swtp6800/common/i2716.c b/swtp6800/common/i2716.c index 5395055e..b429d812 100644 --- a/swtp6800/common/i2716.c +++ b/swtp6800/common/i2716.c @@ -1,6 +1,6 @@ /* i2716.c: Intel 2716 EPROM simulator for 8-bit processors - Copyright (c) 2011, William A. Beech + Copyright (c) 2011-2012, William A. Beech 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/swtp6800/common/m6800.c b/swtp6800/common/m6800.c index c7f8bf02..43a6e08a 100644 --- a/swtp6800/common/m6800.c +++ b/swtp6800/common/m6800.c @@ -1,6 +1,6 @@ /* m6800.c: SWTP 6800 CPU simulator - Copyright (c) 2005-2011, William Beech + Copyright (c) 2005-2012, William Beech 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/swtp6800/common/m6810.c b/swtp6800/common/m6810.c index 3bb5660a..a752fb2b 100644 --- a/swtp6800/common/m6810.c +++ b/swtp6800/common/m6810.c @@ -1,6 +1,6 @@ /* m6810.c: Motorola m6810 RAM emulator - Copyright (c) 2011, William A. Beech + Copyright (c) 2011-2012, William A. Beech 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/swtp6800/common/mp-8m.c b/swtp6800/common/mp-8m.c index 9126b05a..69f5bb9d 100644 --- a/swtp6800/common/mp-8m.c +++ b/swtp6800/common/mp-8m.c @@ -1,6 +1,6 @@ /* mp-8m.c: SWTP 8K Byte Memory Card emulator - Copyright (c) 2011, William A. Beech + Copyright (c) 2011-2012, William A. Beech 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/swtp6800/common/mp-a.c b/swtp6800/common/mp-a.c index 6dd77509..b6517bac 100644 --- a/swtp6800/common/mp-a.c +++ b/swtp6800/common/mp-a.c @@ -1,6 +1,6 @@ /* mp-a.c: SWTP MP-A M6800 CPU simulator - Copyright (c) 2011, William Beech + Copyright (c) 2011-2012, William Beech 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/swtp6800/common/mp-a2.c b/swtp6800/common/mp-a2.c index 21805dcb..e333a7f4 100644 --- a/swtp6800/common/mp-a2.c +++ b/swtp6800/common/mp-a2.c @@ -1,6 +1,6 @@ /* mp-a2.c: SWTP MP-A2 M6800 CPU simulator - Copyright (c) 2011, William Beech + Copyright (c) 2011-2012, William Beech 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/swtp6800/common/mp-b2.c b/swtp6800/common/mp-b2.c index 7b93d7d5..fef0b2c6 100644 --- a/swtp6800/common/mp-b2.c +++ b/swtp6800/common/mp-b2.c @@ -1,6 +1,6 @@ /* mp-b2.c: SWTP SS-50/SS-30 MP-B2 Mother Board - Copyright (c) 2011, William A. Beech + Copyright (c) 2011-2012, William A. Beech 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/swtp6800/swtp6800/mp-a2_sys.c b/swtp6800/swtp6800/mp-a2_sys.c index 8a043061..0d917255 100644 --- a/swtp6800/swtp6800/mp-a2_sys.c +++ b/swtp6800/swtp6800/mp-a2_sys.c @@ -1,6 +1,6 @@ /* mp-a_sys.c: SWTP 6800 system interface - Copyright (c) 2005, William Beech + Copyright (c) 2005-2012, William Beech 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/swtp6800/swtp6800/mp-a_sys.c b/swtp6800/swtp6800/mp-a_sys.c index 4460b781..6929709a 100644 --- a/swtp6800/swtp6800/mp-a_sys.c +++ b/swtp6800/swtp6800/mp-a_sys.c @@ -1,6 +1,6 @@ /* mp-a_sys.c: SWTP 6800 system interface - Copyright (c) 2005, William Beech + Copyright (c) 2005-2012, William Beech Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), From 0f2ed31b33a67f5304ec288054a17cc497ba3a8f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 19 Jul 2012 13:30:31 -0700 Subject: [PATCH 109/112] Fix UDATA macro to reflect prior changes in the unit data structure. This fixes any reference to the macro which may supply an initial wait time to the unit structure after using the UDATA macro. --- sim_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim_defs.h b/sim_defs.h index 4c4d1f5c..3d32500e 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -515,7 +515,7 @@ struct sim_fileref { /* The following macros define structure contents */ -#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,0 +#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,NULL,0,0 #if defined (__STDC__) || defined (_WIN32) #define ORDATA(nm,loc,wd) #nm, &(loc), 8, (wd), 0, 1 From 715bc12d3b7295a3953ed3e1b6bd9eb99c027a56 Mon Sep 17 00:00:00 2001 From: Andrea Bonomi Date: Tue, 21 Aug 2012 12:50:27 +0200 Subject: [PATCH 110/112] show default & set default command added Hello, I fixed the show/set default commands and tested on the following host platform: OSX(x64), Linux(arm), FreeBSD(x86), Windows(x64), OpenVMS(VAX). The commands are very simple and the code is the same for all the *nix and VMS, and it is a little different for Windows. Andrea --- scp.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/scp.c b/scp.c index 3dcad038..d9b7d2f5 100644 --- a/scp.c +++ b/scp.c @@ -219,6 +219,11 @@ #include #include #include +#if defined(_WIN32) +#include +#else +#include +#endif #include #if defined(HAVE_DLOPEN) /* Dynamic Readline support */ @@ -328,6 +333,7 @@ t_stat set_dev_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat ssh_break (FILE *st, char *cptr, int32 flg); +t_stat set_default_cmd (int32 flg, char *cptr); t_stat show_cmd_fi (FILE *ofile, int32 flag, char *cptr); t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); @@ -341,6 +347,7 @@ t_stat show_dev_logicals (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char * t_stat show_dev_modifiers (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_dev_show_commands (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_default (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_on (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_device (FILE *st, DEVICE *dptr, int32 flag); @@ -638,6 +645,7 @@ static CTAB cmd_table[] = { " enable console debugging to the\n" " specified destination {LOG,STDOUT or filename)\n" "set console NODEBUG disable console debugging\n" + "set default

set the default directory\n" "set log log_file specify the log destination\n" " (STDOUT,DEBUG or filename)\n" "set nolog disables any currently active logging\n" @@ -687,6 +695,7 @@ static CTAB cmd_table[] = { "sh{ow} th{rottle} show simulation rate\n" "sh{ow} a{synch} show asynchronouse I/O state\n" "sh{ow} ve{rsion} show simulator version\n" + "sh{ow} def{ault} show current directory\n" "sh{ow} RADIX show device display radix\n" "sh{ow} DEBUG show device debug flags\n" "sh{ow} MODIFIERS show device modifiers\n" @@ -1755,6 +1764,7 @@ C1TAB *ctbr, *glbr; static CTAB set_glob_tab[] = { { "CONSOLE", &sim_set_console, 0 }, { "BREAK", &brk_cmd, SSH_ST }, + { "DEFAULT", &set_default_cmd, 1 }, { "NOBREAK", &brk_cmd, SSH_CL }, { "TELNET", &sim_set_telnet, 0 }, /* deprecated */ { "NOTELNET", &sim_set_notelnet, 0 }, /* deprecated */ @@ -2034,6 +2044,7 @@ static SHTAB show_glob_tab[] = { { "NAMES", &show_log_names, 0 }, { "SHOW", &show_show_commands, 0 }, { "VERSION", &show_version, 1 }, + { "DEFAULT", &show_default, 0 }, { "CONSOLE", &sim_show_console, 0 }, { "BREAK", &show_break, 0 }, { "LOG", &sim_show_log, 0 }, /* deprecated */ @@ -2540,6 +2551,38 @@ if (dptr->modifiers) { return SCPE_OK; } +/* Show/change the current working directiory commands */ + +t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +#if defined(_WIN32) +char *wd = _getcwd(NULL, 0); +fprintf (st, "%s\n", wd); +free(wd); +#else +char buffer[PATH_MAX]; +char *wd = getcwd(buffer, PATH_MAX); +fprintf (st, "%s\n", wd); +#endif +return SCPE_OK; +} + +t_stat set_default_cmd (int32 flg, char *cptr) +{ +if ((!cptr) || (*cptr == 0)) + return SCPE_2FARG; +sim_trim_endspc(cptr); +#if defined(_WIN32) +if (_chdir(cptr) != 0) { +#else +if (chdir(cptr) != 0) { +#endif + printf("Unable to change to: %s\n", cptr); + return SCPE_IOERR & SCPE_NOMESSAGE; +} +return SCPE_OK; +} + /* Breakpoint commands */ t_stat brk_cmd (int32 flg, char *cptr) From a1a6a8a40d932b57d7e680efe036fa6323d77876 Mon Sep 17 00:00:00 2001 From: Andrea Bonomi Date: Thu, 23 Aug 2012 17:18:31 +0200 Subject: [PATCH 111/112] show_default fix --- scp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/scp.c b/scp.c index d9b7d2f5..edfe1b6c 100644 --- a/scp.c +++ b/scp.c @@ -2555,15 +2555,13 @@ return SCPE_OK; t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { -#if defined(_WIN32) -char *wd = _getcwd(NULL, 0); -fprintf (st, "%s\n", wd); -free(wd); -#else char buffer[PATH_MAX]; +#if defined(_WIN32) +char *wd = _getcwd(buffer, PATH_MAX); +#else char *wd = getcwd(buffer, PATH_MAX); -fprintf (st, "%s\n", wd); #endif +fprintf (st, "%s\n", wd); return SCPE_OK; } From 405c70bccd6f9584478ee99e726eda5669ed340c Mon Sep 17 00:00:00 2001 From: Andrea Bonomi Date: Tue, 28 Aug 2012 07:40:42 +0200 Subject: [PATCH 112/112] set default/show default commands fix --- scp.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/scp.c b/scp.c index edfe1b6c..3cdc678a 100644 --- a/scp.c +++ b/scp.c @@ -2556,11 +2556,7 @@ return SCPE_OK; t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { char buffer[PATH_MAX]; -#if defined(_WIN32) -char *wd = _getcwd(buffer, PATH_MAX); -#else char *wd = getcwd(buffer, PATH_MAX); -#endif fprintf (st, "%s\n", wd); return SCPE_OK; } @@ -2570,11 +2566,7 @@ t_stat set_default_cmd (int32 flg, char *cptr) if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; sim_trim_endspc(cptr); -#if defined(_WIN32) -if (_chdir(cptr) != 0) { -#else if (chdir(cptr) != 0) { -#endif printf("Unable to change to: %s\n", cptr); return SCPE_IOERR & SCPE_NOMESSAGE; }