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/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..1dfc5fa6 --- /dev/null +++ b/0readme_39.txt @@ -0,0 +1,213 @@ +Notes For V3.9 + + +The makefile now works for all *nix platforms and with cygwin and MinGW32 +on Windows. It will automatically detect the availability of libpcap +components and build network capable simulators if they are available. + + +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) + - 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 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) + + +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 lead editor. After this +release, the source is moving to a public repository: + +https://github.com/markpizz/simh + +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. +Included in the beta simulators package. + +3.26 Alpha + +Incomplete; essentially just an EV-5 (21164) chip emulator. Included +in the beta simulators package. + +3.27 SAGE + +Incomplete. Included in the beta simulators package. + +3.28 SC1 + +Internal simulator for SiCortex supercomputer; intended as an example +of implementing an SMP system in the current SimH structure. Included +in the beta simulators package. + + +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/0readme_ethernet.txt b/0readme_ethernet.txt index 6916cfac..379c28ab 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: @@ -206,7 +207,7 @@ Building on Windows: The contents of the windows-build directory can be downloaded from: - https://github.com/downloads/markpizz/simh/windows-build.zip + https://github.com/downloads/simh/simh/windows-build.zip There are Windows batch files provided to initiate compiles using the MinGW @@ -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/ALTAIR/altair_cpu.c b/ALTAIR/altair_cpu.c index 4a837c8b..196893c4 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: @@ -107,7 +108,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 */ @@ -312,7 +313,7 @@ int32 sim_instr (void) while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) break; + if ((reason = sim_process_event ())) break; } if (int_req > 0) { /* interrupt? */ diff --git a/ALTAIR/altair_dsk.c b/ALTAIR/altair_dsk.c index 64ef739c..1d1f092c 100644 --- a/ALTAIR/altair_dsk.c +++ b/ALTAIR/altair_dsk.c @@ -218,8 +218,8 @@ int32 dsk10(int32 io, int32 data) cur_disk = data & 0x0F; if (data & 0x80) { cur_flags[cur_disk] = 0; /* Disable drive */ - cur_sect[cur_disk = 0377]; - cur_byte[cur_disk = 0377]; + cur_sect[cur_disk] = 0377; + cur_byte[cur_disk] = 0377; return (0); } cur_flags[cur_disk] = 0x1A; /* Enable: head move true */ diff --git a/AltairZ80/altairz80_cpu.c b/AltairZ80/altairz80_cpu.c index 5c19ed64..e645b7c3 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, @@ -1772,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? */ @@ -1780,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; } @@ -1867,6 +1870,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 +1930,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 +6463,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 1d9f22d9..a09c74bd 100644 Binary files a/AltairZ80/altairz80_doc.pdf and b/AltairZ80/altairz80_doc.pdf differ 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..fb76b774 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) @@ -115,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); @@ -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,21 +836,30 @@ 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; } -static t_stat toBool(char tf, int *result) { +static t_stat toBool(char tf, int32 *result) { if (tf == 'T') { *result = TRUE; return SCPE_OK; @@ -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..bf7451da 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; + uint32 flags = 0; + uint32 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..7438039c 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,7 +410,7 @@ 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: @@ -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; } @@ -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..a8879cb0 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; } @@ -549,12 +536,7 @@ static void VFDHD_Command(void) unsigned int i, checksum; uint32 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); @@ -621,12 +603,7 @@ static void VFDHD_Command(void) } else { /* Perform a Write operation */ uint32 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..f3992603 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; @@ -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, @@ -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"); } } @@ -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/GRI/gri_cpu.c b/GRI/gri_cpu.c index 547b2139..e173f306 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 @@ -421,7 +421,7 @@ ao_update (); /* update AO */ while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } 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..d09a0654 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 @@ -424,7 +424,7 @@ reason = 0; while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } @@ -458,7 +458,7 @@ if (chan_req) { /* channel request? */ t = iotab[dev] (ioOTA, 0, Read (ad), dev); /* output word */ if ((t & IOT_SKIP) == 0) return STOP_DMAER; - if (r = (t >> IOT_V_REASON)) + if ((r = (t >> IOT_V_REASON))) return r; } if (Q_DMA (i)) { /* DMA? */ @@ -528,7 +528,7 @@ if (hst_lnt) { /* instr hist? */ switch (I_GETOP (MB)) { /* case on <1:6> */ case 001: case 021: case 041: case 061: /* JMP */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; PCQ_ENTRY; /* save PC */ PC = NEWA (PC, Y); /* set new PC */ @@ -537,7 +537,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 002: case 022: case 042: case 062: /* LDA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; if (dp) { /* double prec? */ AR = Read (Y & ~1); /* get doubleword */ @@ -548,13 +548,13 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 003: case 023: case 043: case 063: /* ANA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; AR = AR & Read (Y); break; case 004: case 024: case 044: case 064: /* STA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; Write (Y, AR); /* store A */ if (dp) { /* double prec? */ @@ -564,13 +564,13 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 005: case 025: case 045: case 065: /* ERA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; AR = AR ^ Read (Y); break; case 006: case 026: case 046: case 066: /* ADD */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; if (dp) { /* double prec? */ t1 = GETDBL_S (AR, BR); /* get A'B */ @@ -583,7 +583,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 007: case 027: case 047: case 067: /* SUB */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; if (dp) { /* double prec? */ t1 = GETDBL_S (AR, BR); /* get A'B */ @@ -596,7 +596,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 010: case 030: case 050: case 070: /* JST */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; MB = NEWA (Read (Y), PC); /* merge old PC */ Write (Y, MB); @@ -605,7 +605,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 011: case 031: case 051: case 071: /* CAS */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; MB = Read (Y); if (AR == MB) @@ -615,7 +615,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 012: case 032: case 052: case 072: /* IRS */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; MB = (Read (Y) + 1) & DMASK; /* incr, rewrite */ Write (Y, MB); @@ -624,7 +624,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 013: case 033: case 053: case 073: /* IMA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; MB = Read (Y); Write (Y, AR); /* A to mem */ @@ -632,13 +632,13 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 015: case 055: /* STX */ - if (reason = Ea (MB & ~IDX, &Y)) /* eff addr */ + if ((reason = Ea (MB & ~IDX, &Y))) /* eff addr */ break; Write (Y, XR); /* store XR */ break; case 035: case 075: /* LDX */ - if (reason = Ea (MB & ~IDX, &Y)) /* eff addr */ + if ((reason = Ea (MB & ~IDX, &Y))) /* eff addr */ break; XR = Read (Y); /* load XR */ M[M_XR] = XR; /* update mem too */ @@ -646,7 +646,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ case 016: case 036: case 056: case 076: /* MPY */ if (cpu_unit.flags & UNIT_HSA) { /* installed? */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; t1 = SEXT (AR) * SEXT (Read (Y)); PUTDBL_Z (t1); @@ -657,7 +657,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ case 017: case 037: case 057: case 077: /* DIV */ if (cpu_unit.flags & UNIT_HSA) { /* installed? */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; t2 = SEXT (Read (Y)); /* divr */ if (t2) { /* divr != 0? */ @@ -826,7 +826,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 003: /* "long right arot" */ - if (reason = stop_inst) /* stop on undef? */ + if ((reason = stop_inst)) /* stop on undef? */ break; for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ C = BR & 1; /* C = last out */ @@ -859,7 +859,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 007: /* "short right arot" */ - if (reason = stop_inst) /* stop on undef? */ + if ((reason = stop_inst)) /* stop on undef? */ break; for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ C = AR & 1; /* C = last out */ @@ -899,7 +899,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 013: /* "long left arot" */ - if (reason = stop_inst) /* stop on undef? */ + if ((reason = stop_inst)) /* stop on undef? */ break; for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ AR = (AR << 1) | ((BR >> 14) & 1); @@ -935,7 +935,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 017: /* "short left arot" */ - if (reason = stop_inst) /* stop on undef? */ + if ((reason = stop_inst)) /* stop on undef? */ break; for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ if ((AR & SIGN) != ((AR << 1) & SIGN)) C = 1; @@ -1003,7 +1003,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ AR = (AR << 8) & DMASK; else if (MB == 0141340) /* ICA */ AR = ((AR << 8) | (AR >> 8)) & DMASK; - else if (reason = stop_inst) + else if ((reason = stop_inst)) break; else AR = Operate (MB, AR); /* undefined */ break; @@ -1500,7 +1500,7 @@ for (i = 0; i < DEV_MAX; i++) iotab[i] = NULL; for (i = 0; i < (DMA_MAX + DMC_MAX); i++) chan_map[i] = 0; -for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ +for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */ continue; diff --git a/H316/h316_dp.c b/H316/h316_dp.c index 0a8df9af..533c3a86 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 @@ -215,7 +216,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; @@ -615,7 +617,7 @@ switch (uptr->FNC) { /* case on function */ case FNC_RCA: /* read current addr */ if (h >= dp_tab[dp_ctype].surf) /* invalid head? */ return dp_done (1, STA_ADRER); /* error */ - if (r = dp_rdtrk (uptr, dpxb, uptr->CYL, h)) /* get track; error? */ + if ((r = dp_rdtrk (uptr, dpxb, uptr->CYL, h))) /* get track; error? */ return r; dp_rptr = 0; /* init rec ptr */ if (dpxb[dp_rptr + REC_LNT] == 0) /* unformated? */ @@ -720,7 +722,7 @@ switch (uptr->FNC) { /* case on function */ case FNC_RW: /* read/write */ if (h >= dp_tab[dp_ctype].surf) /* invalid head? */ return dp_done (1, STA_ADRER); /* error */ - if (r = dp_rdtrk (uptr, dpxb, uptr->CYL, h)) /* get track; error? */ + if ((r = dp_rdtrk (uptr, dpxb, uptr->CYL, h))) /* get track; error? */ return r; if (!dp_findrec (dp_cw2)) /* find rec; error? */ return dp_done (1, STA_ADRER); /* address error */ @@ -748,7 +750,7 @@ switch (uptr->FNC) { /* case on function */ if (dp_cw1 & CW1_RW) { /* write? */ if (dp_sta & STA_RDY) /* timing failure? */ return dp_wrdone (uptr, STA_DTRER); /* yes, error */ - if (r = dp_wrwd (uptr, dp_buf)) /* wr word, error? */ + if ((r = dp_wrwd (uptr, dp_buf))) /* wr word, error? */ return r; if (dp_eor) { /* transfer done? */ dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; @@ -853,7 +855,7 @@ if (dp_wptr < (lnt + REC_MAXEXT)) { } dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; /* write csum */ dpxb[dp_rptr + lnt + REC_OVHD] = 0; /* zap rest of track */ -if (r = dp_wrdone (uptr, STA_UNSER)) /* dump track */ +if ((r = dp_wrdone (uptr, STA_UNSER))) /* dump track */ return r; return STOP_DPOVR; } @@ -1015,7 +1017,7 @@ for (c = cntr = 0; c < dp_tab[dp_ctype].cyl; c++) { else tbuf[rptr + REC_ADDR] = (c << 8) + (h << 3) + i; rptr = rptr + nw + REC_OVHD; } - if (r = dp_wrtrk (uptr, tbuf, c, h)) + if ((r = dp_wrtrk (uptr, tbuf, c, h))) return r; } } @@ -1041,7 +1043,7 @@ if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; for (c = 0; c < dp_tab[dp_ctype].cyl; c++) { for (h = 0; h < dp_tab[dp_ctype].surf; h++) { - if (r = dp_rdtrk (uptr, tbuf, c, h)) + if ((r = dp_rdtrk (uptr, tbuf, c, h))) return r; rptr = 0; rlnt = tbuf[rptr + REC_LNT]; diff --git a/H316/h316_fhd.c b/H316/h316_fhd.c index df2c9aac..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. @@ -72,7 +73,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_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 5ca516f4..22ceb6b4 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 @@ -82,7 +83,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 */ @@ -369,17 +371,17 @@ switch (uptr->FNC) { /* case on function */ return SCPE_OK; case FNC_WEOF: /* write file mark */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* sched end motion */ case FNC_FSR: /* space fwd rec */ - if (st = sim_tape_sprecf (uptr, &tbc)) /* space fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) /* space fwd, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* sched end motion */ case FNC_BSR: /* space rev rec */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* sched end motion */ @@ -453,7 +455,7 @@ switch (uptr->FNC) { /* case on function */ mt_wrwd (uptr, mt_buf); else mt_rdy = 0; /* rdy must be clr */ if (mt_ptr) { /* any data? */ - if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) /* write, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)))/* write, err? */ r = mt_map_err (uptr, st); /* map error */ } break; /* sched end motion */ diff --git a/H316/h316_stddev.c b/H316/h316_stddev.c index 456df262..beb3585c 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 @@ -390,7 +390,7 @@ t_stat r; if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOFNC; -if (r = attach_unit (uptr, cptr)) +if ((r = attach_unit (uptr, cptr))) return r; if (sim_switches & SWMASK ('A')) /* -a? ASCII */ uptr->flags |= UNIT_ASC; diff --git a/H316/h316_sys.c b/H316/h316_sys.c index ca4ff61e..c9b6e54e 100644 --- a/H316/h316_sys.c +++ b/H316/h316_sys.c @@ -364,11 +364,11 @@ switch (j) { /* case on class */ case I_V_MRF: case I_V_MRX: /* mem ref */ cptr = get_glyph (cptr, gbuf, ','); /* get next field */ - if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */ + if ((k = (strcmp (gbuf, "C") == 0))) { /* C specified? */ val[0] = val[0] | SC; cptr = get_glyph (cptr, gbuf, 0); } - else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */ + else if ((k = (strcmp (gbuf, "Z") == 0))) { /* Z specified? */ cptr = get_glyph (cptr, gbuf, ','); } d = get_uint (gbuf, 8, X_AMASK, &r); /* construe as addr */ diff --git a/HP2100/hp2100_baci.c b/HP2100/hp2100_baci.c index 779edf96..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-2008, 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,9 @@ 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 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 +323,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 */ @@ -354,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); @@ -372,7 +371,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); @@ -382,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 @@ -400,13 +402,17 @@ t_stat baci_detach (UNIT *uptr); ten millisecond period. */ -DIB baci_dib = { BACI, &baci_io }; - 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 */ +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 */ + }; REG baci_reg[] = { { ORDATA (IBUF, baci_ibuf, 16), REG_FIT }, @@ -438,12 +444,13 @@ 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 (SC, baci_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, baci_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -464,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 } }; @@ -494,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 */ @@ -526,232 +534,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; } @@ -779,8 +788,8 @@ return 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, @@ -847,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? */ @@ -931,7 +940,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 */ @@ -973,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 */ @@ -1002,7 +1015,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 +1096,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 +1163,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 +1188,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); @@ -1198,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 @@ -1209,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 71448791..117dd525 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: 2012-05-07 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" @@ -4385,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. @@ -4432,7 +4434,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. @@ -4711,7 +4713,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 +4724,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 +5067,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 +5210,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 +5321,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 +5353,956 @@ 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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +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.9-0. + + + +227. PROBLEM: The 13037 disc controller 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.9-0. + + + +228. PROBLEM: The 13037 disc controller 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.9-0. + + + +229. PROBLEM: The 13037 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.9-0. + + + +230. PROBLEM: The 13037 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.9-0. + + + +231. PROBLEM: The 13037 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.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 around 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. 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. + + + +243. 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. + + + +244. 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. + + + +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. + + + +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. + + + +247. PROBLEM: The ICD disc read end-of-track delay is not optimal. + + VERSION: 3.9-0 + + OBSERVATION: To avoid End of Cylinder errors when reading the last sector + of a track, the ICD controller must delay more than the usual intersector + time to allow the OS driver to send an Untalk if a read is to be + terminated. Currently, the longer delay is used if an end-of-cylinder + condition is present. However, the delay is needed only if the resulting + seek attempt would cause an error if the read is continued; the normal + delay should be used if the seek is permitted and would succeed. + + Also, if the host does send an Untalk during this time, the longer delay + should be cancelled, and command termination should be scheduled for + immediate processing. + + CAUSE: Suboptimal implementation. + + RESOLUTION: Modify "end_read" (hp_disclib.c) to use the longer time only + if the seek would fail, and modify "complete_read" (hp2100_di_da.c) to + cancel the intersector delay and schedule the completion phase immediately. + + STATUS: Patches prepared 2012-05-07. diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 8a20b98e..3dbe7bf8 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-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,24 @@ 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 + 09-May-12 JDB Separated assignments from conditional expressions + 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 + 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 +457,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 +549,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 +577,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 +589,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 +600,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 +670,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 +684,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[] = { @@ -707,17 +732,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 }, @@ -815,13 +840,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 +864,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 +920,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 +952,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 +1050,26 @@ 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 */ +for (i = 0; sim_devices [i] != NULL; i++) { /* loop thru dev */ + dptr = sim_devices [i]; + 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 +1123,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 +1132,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 +1282,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 +1326,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 +1336,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 +1360,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 +1376,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 +1434,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 +1470,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 +1485,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 +1497,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 +1534,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 +1555,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 +1593,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 +1605,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 +1617,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 +1630,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 +1718,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 +1760,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 +1828,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 +1847,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 +1894,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 +1947,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 +2011,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 +2027,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 +2102,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 +2144,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; } @@ -2198,13 +2446,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? */ + } } @@ -2265,14 +2515,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 +2673,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 +2694,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 +2729,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 +2820,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 +2878,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 +2953,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 +2968,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 +3077,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 = (CHANNEL) 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 +3153,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 = (CHANNEL) 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 +3265,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 +3439,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 +3453,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) @@ -3105,7 +3465,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; @@ -3121,33 +3481,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 +3496,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 +3505,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 = (CHANNEL) 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 +3579,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 +3608,53 @@ 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) +for (i = 0; sim_devices [i] != NULL; i++) { + dptr = sim_devices [i]; + 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++) { - if (conflicts[i] > 1) { - k = conflicts[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); - for (j = 0; dptr = sim_devices[j]; j++) { - dibp = (DIB *) dptr->ctxt; - if (dibp && !(dptr->flags & DEV_DIS) && (i == dibp->devno)) { - if (k < conflicts[i]) { + + if (sim_log) + fprintf (sim_log, "Select code %o conflict:", i); + + for (j = 0; sim_devices [j] != NULL; j++) { + dptr = sim_devices [j]; + 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 +3691,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 +3706,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 +3717,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 +3750,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 +3943,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 +3970,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 */ @@ -3645,7 +3988,7 @@ switch (sel) { break; case 3: /* DS boot */ - ibl_copy (ds_rom,dev); + ibl_copy (ds_rom, dev); break; } @@ -3657,11 +4000,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 +4015,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..a7769901 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-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,8 @@ CPU0 User microcode and unimplemented firmware options + 09-May-12 JDB Separated assignments from conditional expressions + 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 +83,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: @@ -98,6 +99,7 @@ 105521 105301 "Closed loop" (trap cell handler) 105522 105302 [unknown] [test] 105524 105304 [self test] + -- 105310 7974 boot loader ROM extension Notes: @@ -128,9 +130,11 @@ uint32 entry; entry = IR & 017; /* mask to entry point */ -if (op_ds[entry] != OP_N) - if (reason = cpu_ops (op_ds[entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_ds [entry] != OP_N) { + reason = cpu_ops (op_ds[entry], op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* did the evaluation fail? */ + return reason; /* return the reason for failure */ + } switch (entry) { /* decode IR<3:0> */ @@ -180,33 +184,33 @@ 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 */ } switch ((IR >> 4) & 037) { /* decode IR<8:4> */ -/* case 000: /* 105000-105017 */ -/* return cpu_user_00 (IR, intrq); /* uncomment to handle instruction */ +/* case 000: ** 105000-105017 */ +/* return cpu_user_00 (IR, intrq); ** uncomment to handle instruction */ -/* case 001: /* 105020-105037 */ -/* return cpu_user_01 (IR, intrq); /* uncomment to handle instruction */ +/* case 001: ** 105020-105037 */ +/* return cpu_user_01 (IR, intrq); ** uncomment to handle instruction */ -/* case 0nn: /* other cases as needed */ -/* return cpu_user_nn (IR, intrq); /* uncomment to handle instruction */ +/* case 0nn: ** other cases as needed */ +/* return cpu_user_nn (IR, intrq); ** uncomment to handle instruction */ case 020: /* 10x400-10x417 */ return cpu_user_20 (IR, intrq); /* call sample dispatcher */ -/* case 021: /* 10x420-10x437 */ -/* return cpu_user_21 (IR, intrq); /* uncomment to handle instruction */ +/* case 021: ** 10x420-10x437 */ +/* return cpu_user_21 (IR, intrq); ** uncomment to handle instruction */ -/* case 0nn: /* other cases as needed */ -/* return cpu_user_nn (IR, intrq); /* uncomment to handle instruction */ +/* case 0nn: ** other cases as needed */ +/* return cpu_user_nn (IR, intrq); ** uncomment to handle instruction */ default: /* others undefined */ reason = stop_inst; @@ -242,20 +246,22 @@ uint32 entry; entry = IR & 017; /* mask to entry point */ -if (op_user_20 [entry] != OP_N) - if (reason = cpu_ops (op_user_20 [entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_user_20 [entry] != OP_N) { + reason = cpu_ops (op_user_20 [entry], op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* did the evaluation fail? */ + return reason; /* return the reason for failure */ + } switch (entry) { /* decode IR<4:0> */ case 000: /* 10x400 */ -/* break; /* uncomment to handle instruction */ +/* break; ** uncomment to handle instruction */ case 001: /* 10x401 */ -/* break; /* uncomment to handle instruction */ +/* break; ** uncomment to handle instruction */ -/* case 0nn: /* other cases as needed */ -/* break; /* uncomment to handle instruction */ +/* case 0nn: ** other cases as needed */ +/* break; ** uncomment to handle instruction */ default: /* others undefined */ reason = stop_inst; diff --git a/HP2100/hp2100_cpu1.c b/HP2100/hp2100_cpu1.c index d176db83..0096e6e6 100644 --- a/HP2100/hp2100_cpu1.c +++ b/HP2100/hp2100_cpu1.c @@ -1,6 +1,6 @@ /* hp2100_cpu1.c: HP 2100/1000 EAU simulator and UIG dispatcher - 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,6 +25,7 @@ CPU1 Extended arithmetic and optional microcode dispatchers + 09-May-12 JDB Separated assignments from conditional expressions 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Moved option-present tests to UIG dispatchers Call "user microcode" dispatcher for unclaimed UIG instructions @@ -245,14 +246,15 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ case 010: /* MPY 100200 (OP_K) */ MPY: - if (reason = cpu_ops (OP_K, op, intrq)) /* get operand */ - break; - sop1 = SEXT (AR); /* sext AR */ - sop2 = SEXT (op[0].word); /* sext mem */ - sop1 = sop1 * sop2; /* signed mpy */ - BR = (sop1 >> 16) & DMASK; /* to BR'AR */ - AR = sop1 & DMASK; - O = 0; /* no overflow */ + reason = cpu_ops (OP_K, op, intrq); /* get operand */ + if (reason == SCPE_OK) { /* successful eval? */ + sop1 = SEXT (AR); /* sext AR */ + sop2 = SEXT (op[0].word); /* sext mem */ + sop1 = sop1 * sop2; /* signed mpy */ + BR = (sop1 >> 16) & DMASK; /* to BR'AR */ + AR = sop1 & DMASK; + O = 0; /* no overflow */ + } break; default: /* others undefined */ @@ -262,9 +264,11 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ break; case 0201: /* DIV 100400 (OP_K) */ - if (reason = cpu_ops (OP_K, op, intrq)) /* get operand */ + reason = cpu_ops (OP_K, op, intrq); /* get operand */ + if (reason != SCPE_OK) /* eval failed? */ break; - if (rs = qs = BR & SIGN) { /* save divd sign, neg? */ + rs = qs = BR & SIGN; /* save divd sign */ + if (rs) { /* neg? */ AR = (~AR + 1) & DMASK; /* make B'A pos */ BR = (~BR + (AR == 0)) & DMASK; /* make divd pos */ } @@ -317,17 +321,19 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ break; case 0210: /* DLD 104200 (OP_D) */ - if (reason = cpu_ops (OP_D, op, intrq)) /* get operand */ - break; - AR = (op[0].dword >> 16) & DMASK; /* load AR */ - BR = op[0].dword & DMASK; /* load BR */ + reason = cpu_ops (OP_D, op, intrq); /* get operand */ + if (reason == SCPE_OK) { /* successful eval? */ + AR = (op[0].dword >> 16) & DMASK; /* load AR */ + BR = op[0].dword & DMASK; /* load BR */ + } break; case 0211: /* DST 104400 (OP_A) */ - if (reason = cpu_ops (OP_A, op, intrq)) /* get operand */ - break; - WriteW (op[0].word, AR); /* store AR */ - WriteW ((op[0].word + 1) & VAMASK, BR); /* store BR */ + reason = cpu_ops (OP_A, op, intrq); /* get operand */ + if (reason == SCPE_OK) { /* successful eval? */ + WriteW (op[0].word, AR); /* store AR */ + WriteW ((op[0].word + 1) & VAMASK, BR); /* store BR */ + } break; default: /* should never get here */ @@ -733,9 +739,11 @@ uint32 i, MA; for (i = 0; i < OP_N_F; i++) { flags = pattern & OP_M_FLAGS; /* get operand pattern */ - if (flags >= OP_ADR) /* address operand? */ - if (reason = resolve (ReadW (PC), &MA, irq)) /* resolve indirects */ + if (flags >= OP_ADR) { /* address operand? */ + reason = resolve (ReadW (PC), &MA, irq); /* resolve indirects */ + if (reason != SCPE_OK) /* resolution failed? */ return reason; + } switch (flags) { case OP_NUL: /* null operand */ diff --git a/HP2100/hp2100_cpu2.c b/HP2100/hp2100_cpu2.c index e5dac17c..a55cf656 100644 --- a/HP2100/hp2100_cpu2.c +++ b/HP2100/hp2100_cpu2.c @@ -1,6 +1,6 @@ /* hp2100_cpu2.c: HP 2100/1000 FP/DMS/EIG/IOP instructions - 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"), @@ -26,6 +26,7 @@ CPU2 Floating-point, dynamic mapping, extended, and I/O processor instructions + 09-May-12 JDB Separated assignments from conditional expressions 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) 05-Aug-08 JDB Updated mp_dms_jmp calling sequence @@ -243,9 +244,12 @@ uint32 i, t, mapi, mapj; absel = (IR & I_AB)? 1: 0; /* get A/B select */ entry = IR & 037; /* mask to entry point */ -if (op_dms[entry] != OP_N) - if (reason = cpu_ops (op_dms[entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_dms [entry] != OP_N) { + reason = cpu_ops (op_dms [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } switch (entry) { /* decode IR<3:0> */ @@ -609,9 +613,12 @@ int32 sop1, sop2; absel = (IR & I_AB)? 1: 0; /* get A/B select */ entry = IR & 037; /* mask to entry point */ -if (op_eig[entry] != OP_N) - if (reason = cpu_ops (op_eig[entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_eig [entry] != OP_N) { + reason = cpu_ops (op_eig [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } switch (entry) { /* decode IR<4:0> */ @@ -988,9 +995,12 @@ else if (entry <= 057) /* IR = 10x440-457? */ entry = entry - 060; /* offset 10x460-477 */ -if (op_iop[entry] != OP_N) - if (reason = cpu_ops (op_iop[entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_iop [entry] != OP_N) { + reason = cpu_ops (op_iop [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } switch (entry) { /* decode IR<5:0> */ diff --git a/HP2100/hp2100_cpu3.c b/HP2100/hp2100_cpu3.c index 028e6857..3e201aea 100644 --- a/HP2100/hp2100_cpu3.c +++ b/HP2100/hp2100_cpu3.c @@ -25,6 +25,7 @@ CPU3 Fast FORTRAN and Double Integer instructions + 09-May-12 JDB Separated assignments from conditional expressions 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) 05-Aug-08 JDB Updated mp_dms_jmp calling sequence @@ -185,17 +186,23 @@ int32 i; entry = IR & 037; /* mask to entry point */ if (UNIT_CPU_MODEL != UNIT_1000_F) { /* 2100/M/E-Series? */ - if (op_ffp_e[entry] != OP_N) - if (reason = cpu_ops (op_ffp_e[entry], op, intrq)) /* get instruction operands */ - return reason; + if (op_ffp_e [entry] != OP_N) { + reason = cpu_ops (op_ffp_e [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } } #if defined (HAVE_INT64) /* int64 support available */ else { /* F-Series */ - if (op_ffp_f[entry] != OP_N) - if (reason = cpu_ops (op_ffp_f[entry], op, intrq)) /* get instruction operands */ - return reason; + if (op_ffp_f [entry] != OP_N) { + reason = cpu_ops (op_ffp_f [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } switch (entry) { /* decode IR<4:0> */ @@ -417,7 +424,8 @@ switch (entry) { /* decode IR<4:0> */ sa = op[0].word - 1; da = ReadW (sa); /* get jump target */ - if (reason = resolve (da, &MA, intrq)) { /* resolve indirects */ + reason = resolve (da, &MA, intrq); /* resolve indirects */ + if (reason != SCPE_OK) { /* resolution failed? */ PC = err_PC; /* irq restarts instruction */ break; } @@ -435,7 +443,8 @@ switch (entry) { /* decode IR<4:0> */ op[1].word = op[1].word + /* compute element offset */ (op[2].word - 1) * op[3].word; else { /* 3-dim access */ - if (reason = cpu_ops (OP_KK, op2, intrq)) { /* get 1st, 2nd ranges */ + reason = cpu_ops (OP_KK, op2, intrq); /* get 1st, 2nd ranges */ + if (reason != SCPE_OK) { /* evaluation failed? */ PC = err_PC; /* irq restarts instruction */ break; } @@ -461,7 +470,8 @@ switch (entry) { /* decode IR<4:0> */ for (j = 0; j < sc; j++) { MA = ReadW (sa++); /* get addr of actual */ - if (reason = resolve (MA, &MA, intrq)) { /* resolve indirect */ + reason = resolve (MA, &MA, intrq); /* resolve indirect */ + if (reason != SCPE_OK) { /* resolution failed? */ PC = err_PC; /* irq restarts instruction */ break; } @@ -643,9 +653,11 @@ t_stat reason = SCPE_OK; entry = IR & 017; /* mask to entry point */ -if (op_dbi[entry] != OP_N) - if (reason = cpu_ops (op_dbi[entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_dbi[entry] != OP_N) { + reason = cpu_ops (op_dbi [entry], op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } switch (entry) { /* decode IR<3:0> */ diff --git a/HP2100/hp2100_cpu4.c b/HP2100/hp2100_cpu4.c index acc39862..ea294664 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,8 @@ CPU4 Floating Point Processor and Scientific Instruction Set + 09-May-12 JDB Separated assignments from conditional expressions + 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 @@ -259,9 +261,12 @@ else entry = opcode & 0177; /* map to <6:0> */ -if (op_fpp[entry] != OP_N) - if (reason = cpu_ops (op_fpp[entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_fpp [entry] != OP_N) { + reason = cpu_ops (op_fpp [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } switch (entry) { /* decode IR<6:0> */ case 0000: /* FAD 105000 (OP_RF) */ @@ -598,9 +603,12 @@ static const OP t_one = { { 0040000, 0000000, 0000000, 0000002 } }; /* DEY 1. entry = IR & 017; /* mask to entry point */ -if (op_sis[entry] != OP_N) - if (reason = cpu_ops (op_sis[entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_sis [entry] != OP_N) { + reason = cpu_ops (op_sis [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } switch (entry) { /* decode IR<3:0> */ @@ -1074,7 +1082,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 +1094,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..31c381c6 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-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,9 @@ CPU5 RTE-6/VM and RTE-IV firmware option instructions + 09-May-12 JDB Separated assignments from conditional expressions + 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) 30-Jul-08 JDB Redefined ABORT to pass address, moved def to hp2100_cpu.h @@ -647,9 +650,11 @@ t_bool debug = DEBUG_PRI (cpu_dev, DEB_VMA); entry = IR & 017; /* mask to entry point */ pattern = op_vma[entry]; /* get operand pattern */ -if (pattern != OP_N) - if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ - return reason; +if (pattern != OP_N) { + reason = cpu_ops (pattern, op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } if (debug) { /* debugging? */ fprintf (sim_deb, ">>CPU VMA: IR = %06o (", IR); /* print preamble and IR */ @@ -796,6 +801,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). @@ -811,10 +822,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 = ReadW(dtbl++); /* # dimensions */ +ndim = ReadW(dtbl++); /* # dimensions */ +ndim = SEXT(ndim); /* sign extend */ if (ndim < 0) return FALSE; /* invalid? */ *sum = 0; /* accu for index calc */ @@ -970,7 +982,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; i>CPU EMA: PC = %06o, IR = %06o (", err_PC,IR); /* print preamble and IR */ diff --git a/HP2100/hp2100_cpu6.c b/HP2100/hp2100_cpu6.c index f0a464de..b3dc34aa 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-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,8 @@ CPU6 RTE-6/VM OS instructions + 09-May-12 JDB Separated assignments from conditional expressions + 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 +260,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 */ } } @@ -392,9 +394,12 @@ static t_bool tbg_tick = FALSE; /* set if processing TBG entry = IR & 017; /* mask to entry point */ pattern = op_os[entry]; /* get operand pattern */ -if (pattern != OP_N) - if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ - return reason; +if (pattern != OP_N) { + reason = cpu_ops (pattern, op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } tbg_tick = tbg_tick || (IR == 0105357) && iotrap; /* set TBG interrupting flag */ @@ -543,7 +548,9 @@ switch (entry) { /* decode IR<3:0> */ for (i = 0; i < count; i++) { ma = ReadW (PC); /* get operand address */ - if (reason = resolve (ma, &ma, intrq)) { /* resolve indirect */ + reason = resolve (ma, &ma, intrq); /* resolve indirect */ + + if (reason != SCPE_OK) { /* resolution failed? */ PC = err_PC; /* IRQ restarts instruction */ break; } @@ -600,11 +607,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 */ @@ -709,8 +716,10 @@ switch (entry) { /* decode IR<3:0> */ ma = ReadW (sa); /* get addr of actual */ sa = (sa + 1) & VAMASK; /* increment address */ - if (reason = resolve (ma, &ma, intrq)) { /* resolve indirect */ - PC = err_PC; /* irq restarts instruction */ + reason = resolve (ma, &ma, intrq); /* resolve indirect */ + + if (reason != SCPE_OK) { /* resolution failed? */ + PC = err_PC; /* irq restarts instruction */ break; } diff --git a/HP2100/hp2100_cpu7.c b/HP2100/hp2100_cpu7.c index daf9df21..84fb1163 100644 --- a/HP2100/hp2100_cpu7.c +++ b/HP2100/hp2100_cpu7.c @@ -1,7 +1,7 @@ /* hp2100_cpu7.c: HP 1000 VIS and SIGNAL/1000 microcode Copyright (c) 2008, Holger Veit - 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"), @@ -26,6 +26,8 @@ CPU7 Vector Instruction Set and SIGNAL firmware + 09-May-12 JDB Separated assignments from conditional expressions + 06-Feb-12 JDB Corrected "opsize" parameter type in vis_abs 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-Apr-08 JDB Updated SIGNAL code from Holger @@ -192,7 +194,7 @@ 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 */ @@ -382,16 +384,18 @@ if (entry==0) { /* retrieve sub opcode subcode = AR; /* for reentry */ PC = (PC + 1) & VAMASK; /* bump to real argument list */ pattern = (subcode & 0400) ? OP_AAKAKK : OP_AKAKAKK; /* scalar or vector operation */ -} + } -if (pattern != OP_N) +if (pattern != OP_N) { if (op_ftnret[entry]) { /* most VIS instrs ignore RTN addr */ ret = ReadOp(PC, in_s); rtn = rtn1 = ret.word; /* but save it just in case */ PC = (PC + 1) & VAMASK; /* move to next argument */ + } + reason = cpu_ops (pattern, op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ } - if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ - return reason; if (debug) { /* debugging? */ fprintf (sim_deb, ">>CPU VIS: IR = %06o/%06o (", /* print preamble and IR */ @@ -651,9 +655,11 @@ t_bool debug = DEBUG_PRI (cpu_dev, DEB_SIG); entry = IR & 017; /* mask to entry point */ -if (op_signal[entry] != OP_N) - if (reason = cpu_ops (op_signal[entry], op, intrq)) /* get instruction operands */ - return reason; +if (op_signal [entry] != OP_N) { + reason = cpu_ops (op_signal [entry], op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } if (debug) { /* debugging? */ fprintf (sim_deb, ">>CPU SIG: IR = %06o (", IR); /* print preamble and IR */ diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index b0e8ff40..9ee83e32 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-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,15 @@ 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. + 12-May-12 JDB Added pragmas to suppress logical operator precedence warnings + 12-Feb-12 JDB Added MA device select code assignment + Added ma_boot_ext() declaration + 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 @@ -66,6 +75,15 @@ #include "sim_defs.h" /* simulator defns */ +/* Required to quell clang precedence warnings */ + +#if defined (__GNUC__) +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wlogical-op-parentheses" +#endif + + /* Simulator stop and notification codes */ #define STOP_RSRV 1 /* must be 1 */ @@ -128,87 +146,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 */ @@ -235,63 +184,270 @@ typedef enum { ioNONE, /* no signal asserted */ #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 DI_MA 045 /* 12821A Disc Interface with Amigo mag tape devices */ + +#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 */ +#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 */ 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 */ @@ -314,11 +470,14 @@ 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); +extern int32 sync_poll (POLLMODE poll_mode); +extern t_stat ma_boot_ext (uint32 SR); #endif diff --git a/HP2100/hp2100_di.c b/HP2100/hp2100_di.c new file mode 100644 index 00000000..98cc4ef0 --- /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 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 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; 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 + 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 modules for the tape and disc devices contain the + device simulations and the device portions of the HP-IB simulations. + + 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 control an + Amigo disc and an Amigo tape connected to 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 currently 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 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 */ +#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 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 */ +#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 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 + 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 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 + 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 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, 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 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 the card state */ + +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate the next signal */ + + switch (signal) { /* dispatch an I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + 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 the 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 the 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) { /* 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) { /* 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; /* the card state does not change */ + } + } + + 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; + + 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 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 the last transfer was odd */ + + 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; + + 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 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 the 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) { /* is the card in data mode? */ + if (signal_set & ioEDT) /* if end of DCPC transfer */ + di_card->edt = SET; /* set the EDT flip-flop */ + + 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 the 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) { /* 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 { /* 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)) + fprintf (sim_deb, ">>%s cmds: SRQ cleared\n", + dptrs [card]->name); + + di_card->srq = CLEAR; /* clear SRQ */ + update_required = FALSE; /* the card state does not change */ + } + } + } + + else { /* the card is in control mode */ + 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 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 */ + + else if ((data /* if packed mode */ + & (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; /* then ATN is not driven */ + } + + else /* the card is not talking */ + deny = BUS_ATN | BUS_EOI; /* so ATN and EOI are disabled */ + + + 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 the bus */ + + if (FIFO_FULL) /* is the FIFO full? */ + if (data & CNTL_LSTN) /* is card now listening? */ + assert |= BUS_NRFD; /* listener and a full FIFO asserts NRFD */ + + 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 */ + if (data & CNTL_REN) /* REN control */ + assert |= BUS_REN; /* output is */ + else /* coupled to */ + deny |= BUS_REN; /* the 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 the IFC timer by calculating */ + sim_gtime () + IFC_TIMEOUT; /* the IFC stop time (now + 100 microseconds) */ + } + } + + 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 the bus */ + + 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 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 the 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 the lines driven by the control register */ + + if (di_card->cntl_register & (CNTL_NRFD | CNTL_LSTN)) /* if asserting NRFD or listening */ + deny |= BUS_NRFD; /* then deny because we're clearing */ + + di_card->cntl_register = 0; /* clear the control word register */ + di_card->control = CLEAR; /* clear control */ + di_card->srq = CLEAR; /* clear SRQ */ + + master_reset (card); /* perform a master reset */ + + di_bus_control (card, CONTROLLER, 0, deny); /* update the bus control state */ + update_state (card); /* update the 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 is given, */ + fputs (", master reset\n", sim_deb); /* then report a master reset */ + else + fputc ('\n', sim_deb); + } + + if (signal_set & ioCLF) /* if ioCLF is given, */ + master_reset (card); /* then do a 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 the standard PRL signal */ + setstdIRQ (di [card]); /* set the standard IRQ signal */ + + 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 the flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove the current signal from the 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 + performs 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 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; /* get the DIB pointer */ +const CARD_ID card = (CARD_ID) (dibptr->card_index); /* get the card number */ + +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) /* if not there */ + return SCPE_IERR; /* then this is a programming error! */ + else /* found it */ + 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 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 the 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 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. +*/ + +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 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) { /* 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 { /* 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); + + 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 /* the address is valid; change it */ + | SET_BUSADR (new_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) /* 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; +} + + +/* 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) { /* 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 { /* 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 */ + } + +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 the cable connected for diagnostics? */ + fputs ("diagnostic cable", st); /* report it */ +else /* the cable is connected for device 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 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 + 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 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 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 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 + 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. + + The return value indicates 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) /* 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 mode */ + && (di [other].cntl_register & CNTL_LSTN)) /* and is listening */ + accepted = di_bus_accept (other, data); /* call the interface acceptor for the other 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 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 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 the 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 the new control state */ + +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 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 */ + +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) /* 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) { /* 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 the other card of the new control state */ + responded = TRUE; /* and note that there was a responder */ + } + } + + else { /* this is a normal run */ + update_state (card); /* update the card for the new control state */ + + 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 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 the 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) /* was a 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 the poll response? */ + di [card].poll_response |= PPR (address); /* set the response bit */ + + 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 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) + 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 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 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 + 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) /* 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; /* the card response is disabled, so just use devices */ + +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 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) { /* 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 the card FIFO with the responses */ + fifo_load (card, (uint16) response, diag_access); /* (hardware feature) */ + + update_state (card); /* update the 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 that 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 the data byte into the FIFO */ +update_state (card); /* and update the card state */ +return TRUE; /* indicate that 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 the bus control lines */ +update_state (card); /* update the 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 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, a 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 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 the 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 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 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 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 /* is an IFC in progress? */ + && di_card->ifc_timer != 0.0 /* and I am timing? */ + && 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 the card a listener? */ + if (di_card->cntl_register & CNTL_NRFD /* if explicitly requested */ + || 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 the card is ready for data */ + deny |= BUS_NRFD; /* so deny NRFD */ + +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 the current SRQ state */ + +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; /* otherwise, 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 /* 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 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 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 the 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 the load ignored */ + } + +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 is enabled, */ + && di_card->bus_cntl & BUS_EOI) /* and data was tagged with EOI? */ + || (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 was seen */ + di_card->status_register &= ~STAT_LBI; /* so clear the last byte in status */ + } + +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) /* is this the end of the data transfer? */ + tag = tag | TAG_EDT; /* set the EDT tag */ + + +index = (di_card->fifo_reg->qptr /* calculate the index */ + + di_card->fifo_count) % FIFO_SIZE; /* of the next available location */ + +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 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 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) { /* is the card in packed mode? */ + di_card->ibp = upper; /* set the upper byte as next */ + + di_card->fifo [index] = /* merge the data and tag values */ + tag | di_card->fifo [index] | SET_LOWER (data); + } + else /* the card is in unpacked mode */ + di_card->fifo [index] = /* position this byte */ + tag | SET_LOWER (data); /* and store with the tag */ + } + +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 { /* 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 the 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 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 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 */ + +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) { /* 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? */ + di_card->eor = SET; /* set */ + else /* or clear */ + di_card->eor = CLEAR; /* the end-of-record flip-flop */ + } + +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 */ + 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) /* is the card in the packed mode? */ + di_card->obp = upper; /* set the upper byte as next */ + } + +else /* must be a 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) /* 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 is EOI control enabled? */ + di_card->bus_cntl |= BUS_EOI; /* assert EOI on the bus */ + else + di_card->bus_cntl &= ~BUS_EOI; /* deny EOI on the bus */ + + 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; + + 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) /* are any control signals 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..08171b21 --- /dev/null +++ b/HP2100/hp2100_di.h @@ -0,0 +1,300 @@ +/* hp2100_di.h: HP 12821A HP-IB Disc Interface simulator 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 should 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 /* count of card IDs */ + } CARD_ID; + + +/* Device flags and accessors (bits 7-0 are reserved for disc/tape flags) */ + +#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 07 /* 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 (bits 7-0 are reserved for disc/tape flags) */ + +#define UNIT_V_BUSADR (UNIT_V_UF + 8) /* bits 10-8: unit HP-IB address */ + +#define UNIT_M_BUSADR 07 /* 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 line state bit flags. + + NOTE that these flags align with the corresponding flags in the DI status + register, so don't change the numerical values! +*/ + +#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 addresses */ + +#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, /* upper byte selected */ + lower /* lower byte selected */ + } 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 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 */ + + double ifc_timer; /* 100 microsecond IFC timer */ + } DI_STATE; + + +/* Disc interface VM global register definitions. + + These definitions should be included 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. + + These definitions should be included 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..9ce38860 --- /dev/null +++ b/HP2100/hp2100_di_da.c @@ -0,0 +1,2137 @@ +/* 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 + + 07-May-12 JDB Cancel the intersector delay if an untalk is received + 29-Mar-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 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 + 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 + 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 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 just head unloads from head loads and + 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. + + 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. + + 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 + --- --- -- -------------------------------- + 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. + + 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; + +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) }, /* 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 [] = { + DI_REGS (da), + + { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) }, + + { BRDATA (DSJ, if_dsj, 10, 2, DA_UNITS) }, + { 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 }, + + { 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 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 executing. + + 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_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 + 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; 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 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 + 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 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 + 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 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 the interface state */ + + case command_wait: /* command is waiting */ + release_interface = TRUE; /* release the interface at then end if it's 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) /* 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 || /* do we have normal completion */ + cvptr->status == drive_attention) /* or drive attention? */ + break; /* we're done */ + + else { /* if the status is abnormal */ + if_dsj [unit] = 1; /* an error has occurred */ + + command_class = dl_classify (*cvptr); /* classify the command */ + + 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) { /* 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) { /* are we starting the data phase? */ + cvptr->length = cvptr->length * 2; /* convert the buffer length to bytes */ + + 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 the response in the buffer */ + cvptr->length = 2; /* return two bytes */ + + 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)) + 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 completion */ + if_state [unit] = idle; /* the 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; /* the 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 the card ready for data? */ + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + 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 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 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 */ + + 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 /* the 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 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 { /* the transfer is complete */ + if_state [unit] = idle; /* the command is complete */ + di_poll_response (da, unit, SET); /* enable the 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; /* the 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 asserts */ + + if (cvptr->eod == SET) /* is the transfer 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; + + + 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; /* the 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)) { /* 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) + 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 the 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'))) /* 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 */ + 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 the DSJ for power up complete */ + } + +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 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 bus." 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 int32 unit = uptr - da_unit; /* calculate the unit number */ + +result = dl_attach (&icd_cntlr [unit], uptr, cptr); /* attach the drive */ + +if (result == SCPE_OK) /* was the 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 if + the detach is successful. +*/ + +t_stat da_detach (UNIT *uptr) +{ +t_stat result; +const int32 unit = uptr - da_unit; /* calculate the unit number */ + +result = dl_detach (&icd_cntlr [unit], uptr); /* detach the drive */ + +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 */ + } + +return result; +} + + +/* Boot an Amigo disc drive. + + 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: + + 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) /* 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 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 */ + +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 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) { /* 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? */ + 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 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 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 + 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, 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 + 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 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 is asserted or an Unlisten is received. + + - 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 Write Data secondary + does nothing. The unexpected secondary is executed normally. + + - 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 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 + 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 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 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, 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 + 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. +*/ + +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) { /* 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 the unit from talking */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "listen %d", message_address); + } + + else if (message_address == BUS_UNADDRESS) { /* is it an Unlisten? */ + di [da].listeners = 0; /* clear all of the listeners */ + + stopped_listening = TRUE; /* UNL stops the unit from listening */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + strcpy (action, "unlisten"); + } + + else /* other listen addresses */ + accepted = FALSE; /* are 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) { /* 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; /* 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 { /* it is some other talker (or Untalk) */ + di [da].talker &= ~(1 << unit); /* clear my talker bit */ + + stopped_talking = TRUE; /* UNT or OTA stops the unit from talking */ + + if (message_address != BUS_UNADDRESS) /* other talk addresses */ + accepted = FALSE; /* are not accepted */ + + else /* it's an 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 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 */ + + 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 { /* 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 */ + } + + initiated = TRUE; /* log the command or abort initiation */ + break; + + case 0x08: /* disc commands */ + 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 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 up the command */ + if_state [unit] = parameter_wait; /* a parameter must follow */ + icd_cntlr [unit].length = 1; /* set to expect one (unused) byte */ + break; + + case 0x1E: /* Write Loopback */ + 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 up the command */ + if_state [unit] = parameter_wait; /* a parameter must follow */ + icd_cntlr [unit].length = 1; /* set to expect the test ID byte */ + break; + + 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 */ + 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 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 */ + 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; /* the command is 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 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 up the command */ + if_state [unit] = read_xfer; /* data will be going */ + break; + + case 0x1E: /* Read Loopback */ + 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 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 was received */ + 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 for execution */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ + initiated = TRUE; /* log the command initiation */ + } + + else /* unaddressed secondaries */ + accepted = FALSE; /* are 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 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 */ + + 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 is denied) */ + switch (if_state [unit]) { /* dispatch the interface state */ + + case opcode_wait: /* waiting 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 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 */ + } + + 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: /* waiting 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: /* 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: /* sinking 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 the 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) /* was 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; /* 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 */ + 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 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)) /* 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 */ +} + + + +/* Amigo disc local utility routines */ + + +/* Start a command with parameters. + + 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 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 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 Initiate Self Test require parameters, so they will be the only + other commands that must be started here.) + + + Implementation notes: + + 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 other than as an indication of success or failure. +*/ + +static t_bool start_command (uint32 unit) +{ +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 the command is executing */ + return TRUE; /* activate the unit */ + + else { /* if we must wait */ + da_unit [unit].wait = 0; /* for another secondary, */ + return FALSE; /* then 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 the 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. + + 3. If an auto-seek will be needed to continue the read, but the seek will + fail, then an extra delay is inserted before the service call to start + the next sector. Once an Untalk is received, this delay is no longer + needed, so it is cancelled before rescheduling the service routine. +*/ + +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 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 */ + + sim_cancel (&da_unit [unit]); /* cancel the EOT delay */ + da_unit [unit].wait = icd_cntlr [unit].data_time; /* reschedule for completion */ + } + +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 flag */ + + 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 flag */ + 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) +{ +int32 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..c9382484 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-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 - No simulation +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 @@ -127,10 +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 +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 @@ -1237,6 +1239,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 ------------------------ @@ -3397,6 +3498,546 @@ system. +-------------------------------------------------- +VISOD - Vector Instruction Set Firmware Diagnostic +-------------------------------------------------- + +TESTED DEVICE: CPU (hp2100_cpu7.c) + +BINARY FILE: 12824-16002 Rev. 2026 + +HOST SYSTEM: RTE-IVB Rev. 5010 + +CONFIGURATION: sim> set CPU 1000-F + sim> set CPU VIS + sim> go + +TEST REPORT: VIS ON-LINE 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> set DA1 7906H + sim> set DA1 FORMAT + sim> attach DA1 scratch.U1.7906H.disc + 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 ? 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 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. + 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 40 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 49 head 1 (track 99) + DIAG : First and last spares on LU: + 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 49 head 1 (track 99) + DIAG : Default test tracks: + 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. + DIAG : Test track preambles are OK. + + DIAG : Beginning part 2 of diagnostic. + + DIAG : operation parameters/results spd cs ds DSJ + 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 49 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 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 + 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 49 hd 0 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 138 0 0 40 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 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 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 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 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 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 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 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 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 49 hd 3 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 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 49 hd 0 sec 47 0 37 40 0 + DIAG : READ FULL SECTOR length 140 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 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 49 hd 0 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 49 hd 0 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 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 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 + + 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 49 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 1 0 0 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 49 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 4 0 0 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 49 hd 0 sec 0 0 37 40 0 + DIAG : VERIFY sector count 16 0 0 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 49 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ length 128 0 0 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 49 hd 1 sec 0 0 37 40 0 + DIAG : WRITE FULL SECTOR length 138 0 0 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 + + 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 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 + + 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 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 + + 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 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 49 hd 1 sec 0 0 37 40 0 + DIAG : READ FULL SECTOR length 3 0 0 40 0 + DIAG : decode preamble cy 49 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 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 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 49 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 49 hd 0 sec 0 0 37 140 0 + DIAG : STEP 89 PASSED + + DIAG : operation parameters/results spd cs ds DSJ + 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 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 49 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 49 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. + + + ------------------------------------------------ #EMA - Extended Memory Array Firmware Diagnostic ------------------------------------------------ @@ -3416,6 +4057,26 @@ 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 ------------------------------------------------ @@ -3445,46 +4106,6 @@ TEST RESULT: Passed. --------------------------------------------------- -VISOD - Vector Instruction Set Firmware Diagnostic --------------------------------------------------- - -TESTED DEVICE: CPU (hp2100_cpu7.c) - -BINARY FILE: 12824-16002 Rev. 2026 - -HOST SYSTEM: RTE-IVB Rev. 5010 - -CONFIGURATION: sim> set CPU 1000-F - sim> set CPU VIS - sim> go - -TEST REPORT: VIS 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. - - - --------------------------------------- SDIAG - SIGNAL/1000 Firmware Diagnostic --------------------------------------- diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index 86e4ed6c..3b3f2bcc 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-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,11 @@ DP 12557A 2871 disk subsystem 13210A 7900 disk subsystem + 09-May-12 JDB Separated assignments from conditional expressions + 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 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -129,7 +134,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) @@ -169,11 +174,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 */ @@ -186,7 +191,7 @@ #define STA_PROT 0002000 /* protected (13210) */ #define STA_SKI 0001000 /* incomplete NI (u) */ #define STA_SKE 0000400 /* seek error */ -/* 0000200 /* unused */ +/* 0000200 (unused) */ #define STA_NRDY 0000100 /* not ready (d) */ #define STA_EOC 0000040 /* end of cylinder */ #define STA_AER 0000020 /* addr error */ @@ -206,12 +211,21 @@ #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 */ +/* 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 */ @@ -223,10 +237,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 +255,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 +279,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,19 +293,20 @@ 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 (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 } }; @@ -322,10 +341,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 +361,8 @@ 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 (SC, dpc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, dpc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -357,8 +377,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 } }; @@ -389,112 +409,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 +537,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; } @@ -668,7 +695,8 @@ void dp_goc (int32 fnc, int32 drv, int32 time) { int32 t; -if (t = sim_is_active (&dpc_unit[drv])) { /* still seeking? */ +t = sim_is_active (&dpc_unit[drv]); +if (t) { /* still seeking? */ sim_cancel (&dpc_unit[drv]); /* stop seek */ dpc_sta[drv] = dpc_sta[drv] & ~STA_BSY; /* clear busy */ time = time + t; /* include seek time */ @@ -712,12 +740,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 +755,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 +794,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 +805,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 +817,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 */ @@ -833,11 +861,11 @@ 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 */ - 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 +880,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 +891,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? */ @@ -880,10 +908,13 @@ switch (uptr->FNC) { /* case function */ dpc_rarh = dpc_rarh ^ 1; /* incr head */ dpc_eoc = ((dpc_rarh & 1) == 0); /* calc eoc */ } - if (err = fseek (uptr->fileref, da * sizeof (int16), - SEEK_SET)) break; + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (err) /* error? */ + break; fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) break; + err = ferror (uptr->fileref); + if (err) /* error? */ + break; } dpd_ibuf = dpxb[dp_ptr++]; /* get word */ if (dp_ptr >= DP_NUMWD) { /* end of sector? */ @@ -893,17 +924,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 */ @@ -927,16 +958,19 @@ switch (uptr->FNC) { /* case function */ dpc_rarh = dpc_rarh ^ 1; /* incr head */ dpc_eoc = ((dpc_rarh & 1) == 0); /* calc eoc */ } - if (err = fseek (uptr->fileref, da * sizeof (int16), - SEEK_SET)) break; + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (err) /* error? */ + break; fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) break; /* error? */ + err = ferror (uptr->fileref); + if (err) /* error? */ + break; 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 +980,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 +1000,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; @@ -1029,7 +1060,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 */ @@ -1037,10 +1068,10 @@ 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.devno, ioENF, 0); /* set flag */ + dpcio (&dpc_dib, ioENF, 0); /* set flag */ } return SCPE_OK; } @@ -1052,13 +1083,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; } @@ -1067,8 +1103,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; } @@ -1144,7 +1183,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..4ca85689 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-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,10 @@ DQ 12565A 2883 disk system + 09-May-12 JDB Separated assignments from conditional expressions + 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 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -97,7 +101,7 @@ #define CW_V_FNC 12 /* function */ #define CW_M_FNC 017 #define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC) -/* 000 /* unused */ +/* 000 (unused) */ #define FNC_STA 001 /* status check */ #define FNC_RCL 002 /* recalibrate */ #define FNC_SEEK 003 /* seek */ @@ -144,10 +148,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 +162,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 +183,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 +205,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,19 +219,20 @@ 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 (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 } }; @@ -252,10 +263,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 +279,8 @@ 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 (SC, dqc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, dqc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -277,8 +289,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 } }; @@ -293,93 +305,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 +406,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; } @@ -518,7 +531,9 @@ void dq_goc (int32 fnc, int32 drv, int32 time) { int32 t; -if (t = sim_is_active (&dqc_unit[drv])) { /* still seeking? */ +t = sim_is_active (&dqc_unit[drv]); + +if (t) { /* still seeking? */ sim_cancel (&dqc_unit[drv]); /* cancel */ time = time + t; /* include seek time */ } @@ -562,11 +577,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 +590,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 +625,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 +678,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 */ +drv = uptr - dqc_unit; /* get drive no */ 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 +699,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 +719,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 +728,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? */ @@ -730,10 +743,13 @@ switch (uptr->FNC) { /* case function */ dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */ if (dqc_rars == 0) /* wrap? incr head */ dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1; - if (err = fseek (uptr->fileref, da * sizeof (int16), - SEEK_SET)) break; + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (err) + break; fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) break; + err = ferror (uptr->fileref); + if (err) + break; } dqd_ibuf = dqxb[dq_ptr++]; /* get word */ if (dq_ptr >= DQ_NUMWD) { /* end of sector? */ @@ -743,17 +759,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 */ @@ -776,16 +792,19 @@ switch (uptr->FNC) { /* case function */ dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */ if (dqc_rars == 0) /* wrap? incr head */ dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1; - if (err = fseek (uptr->fileref, da * sizeof (int16), - SEEK_SET)) return TRUE; + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (err) + break; fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) break; + err = ferror (uptr->fileref); + if (err) + 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 +812,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 +829,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 +964,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..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-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"), @@ -26,6 +26,9 @@ 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 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 +181,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 +197,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 +210,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 +220,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,16 +238,17 @@ 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 (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 } }; @@ -272,7 +280,8 @@ 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 (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 } }; @@ -294,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 } }; @@ -326,82 +335,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 +430,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 +517,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 +533,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 +547,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 +607,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 +733,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..29df4589 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-2008, 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,31 @@ 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 + 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 + 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 + 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 @@ -34,1661 +50,1428 @@ 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 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. - - 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 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. - 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) is 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 */ +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 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; -#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 */ +/* MAC disc state variables */ -#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) +static UNIT ds_unit [DS_UNITS]; /* unit array */ -/* Status 2, ^ = kept in unit status, * = dynamic */ +static CARD_STATE ds; /* card state */ -#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) +static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */ -/* Controller state */ +static CNTLR_VARS mac_cntlr = /* MAC controller */ + { CNTLR_INIT (MAC, buffer, &ds_cntlr) }; -#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 +/* MAC disc global VM routines */ - 7905 48 3 411 =15MB - 7906 48 4 411 =20MB - 7920 48 5 823 =50MB - 7925 64 9 823 =120MB +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); - 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. +/* MAC disc global SCP routines */ - 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 } - }; - -FLIP_FLOP ds_control = CLEAR; -FLIP_FLOP ds_flag = CLEAR; -FLIP_FLOP ds_flagbuf = CLEAR; -FLIP_FLOP ds_srq = CLEAR; - -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 */ - }; - -DEVICE ds_dev; -uint32 dsio (uint32 select_code, IOSIG signal, uint32 data); -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 adverse effect. + + 2. The modifier DEVNO is deprecated in favor of SC but is retained for + compatibility. */ -DIB ds_dib = { DS, &dsio }; -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) }, /* 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 */ }; -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.devno, 6), REG_HRO }, +static REG ds_reg [] = { + { FLDATA (CMFOL, ds.cmfol, 0) }, + { FLDATA (CMRDY, ds.cmrdy, 0) }, + { 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 }, + { 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. + + 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 + 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 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 + 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. - 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 - SFS tests the flag flip-flop. 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 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 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 + 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 from the current command operation and phase. */ -uint32 dsio (uint32 select_code, IOSIG signal, uint32 data) +uint32 ds_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) { -const IOSIG base_signal = IOBASE (signal); /* derive base signal */ +static const char * const output_state [] = { "Data", "Command" }; +const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : ""); -switch (base_signal) { /* dispatch base I/O signal */ +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; - case ioCLF: /* clear flag flip-flop */ - ds_flag = ds_flagbuf = CLEAR; /* clear flag */ - ds_srq = CLEAR; /* CLF clears SRQ */ - break; +while (working_set) { + signal = IONEXT (working_set); /* isolate the next signal */ + + switch (signal) { /* dispatch the I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + 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 */ - break; + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + 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 */ - break; + case ioSFC: /* skip if flag is clear */ + setSKF (mac_cntlr.state != cntlr_busy); /* skip if the controller is not busy */ + break; - case ioSFS: /* skip if flag is set */ - setstdSKF (ds); - break; + case ioSFS: /* skip if flag is set */ + setstdSKF (ds); /* assert SKF if the flag is set */ + break; - case ioIOI: /* I/O data input */ - data = ds_fifo_read (); - break; + 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 = 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 */ - else - ds_fifo_write (data); /* put in fifo */ - break; + 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 { /* 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 to stop filling */ + } + } + 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 ioPOPIO: /* power-on preset to I/O */ + ds.flag = SET; /* set the flag */ + ds.flagbuf = SET; /* and flag buffer */ + ds.cmrdy = CLEAR; /* clear the command ready flip-flop */ - case ioCRS: /* control reset */ - ds_control = CLEAR; /* clear control */ - ds_cmdf = 0; /* not expecting command */ - ds_clear (); /* do controller CLEAR */ - break; + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [POPIO] Flag set\n", sim_deb); + 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 */ + 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 ioSTC: /* set control flip-flop */ - ds_control = SET; /* set control */ - break; + case ioCLC: /* clear control flip-flop */ + 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 ioEDT: /* end data transfer */ - ds_eod = 1; /* flag end transfer */ - break; + case ioSTC: /* set control flip-flop */ + 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 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.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 ioIAK: /* interrupt acknowledge */ - ds_flagbuf = CLEAR; - break; + case ioSIR: /* set interrupt request */ + 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; - default: /* all other signals */ - break; /* are ignored */ + case ioIAK: /* interrupt acknowledge */ + ds.flagbuf = CLEAR; /* clear the flag */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove the current signal from the 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 (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; +} -if ((signal != ioSIR) && (signal != ioENF)) /* if not IRQ update */ - ds_poll (); /* run the controller */ +/* 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. + + 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 + 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. + + 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 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, 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 + 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 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. + + (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 name of the completed positioning command. + + 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". + + 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. +*/ + +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; +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 */ + +if ((CNTLR_PHASE) uptr->PHASE == data_phase) /* is the drive in the data phase? */ + switch ((CNTLR_OPCODE) uptr->OP) { /* dispatch the current operation */ + + 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 if (FIFO_FULL) /* is the FIFO already full? */ + dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an overrun */ + + 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 */ + } + + 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 */ + } + + else if (FIFO_EMPTY) /* is the FIFO empty? */ + dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an underrun */ + + else { + buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */ + mac_cntlr.length--; /* count it */ + + 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 */ + + 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: /* we were 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) /* 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 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 */ + poll_drives (); /* poll the drives for Attention */ + } + + +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", + 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 */ + 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 */ + unit, dl_opcode_name (MAC, mac_cntlr.opcode)); + } + +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. + + 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. + + + Implementation notes: + + 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. + + In simulation, the flag is set as soon as the parameter is received. +*/ + +t_stat ds_service_controller (UNIT *uptr) +{ +t_stat result; +const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; + +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 */ + + + case clear: + case set_file_mask: + case wakeup: + ds_io (&ds_dib, ioENF, 0); /* complete the operation and set the flag */ + break; + + + default: /* we were 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: /* 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 */ + + 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: /* we were 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)); + } + +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. 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_stat ds_service_timer (UNIT *uptr) +{ +t_stat result; + +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 */ +} + + +/* Reset the simulator. + + 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. + + + 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 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. + + 2. SRQ is denied because neither IFIN nor IFOUT is asserted when the + interface is not selected. +*/ + +t_stat ds_reset (DEVICE *dptr) +{ +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; +} + + +/* 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) +{ +t_stat result; + +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; +} + + +/* 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) +{ +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; +} + + +/* 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 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: + + 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. + + + Implementation notes: + + 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. +*/ + + +const BOOT_ROM ds_rom = { + 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) +{ +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 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 */ + +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 the 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 (and clear the "wait" field) */ + + 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) /* 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; +} + + +/* 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; } -/* Run the controller polling loop, based on ds_state: +/* Clear the FIFO. - IDLE commands and ATN interrupts - WAIT commands only - BUSY nothing + The FIFO is cleared by setting the occupancy counter to zero. */ -void ds_poll (void) +static void fifo_clear (void) { -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; -} +ds.fifo_count = 0; /* clear the FIFO */ - -/* Process a command - ctrl state is either IDLE or WAIT. - - - 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, dtyp, 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_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_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 */ - 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_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; - - case DSC_END: /* end */ - ds_set_idle (); /* idle ctrl */ - break; - } +if (DEBUG_PRI (ds_dev, DEB_BUF)) + fputs (">>DS buf: FIFO cleared\n", sim_deb); return; } -/* Check for attention */ +/* Activate the unit. -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.devno, 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.devno, 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 */ - } - 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 */ - - 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.devno, 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 */ - 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 */ - 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)) break; - /* new sector; error? */ - 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 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; - - 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; - - default: - break; - } - -ds_poll (); -return SCPE_OK; -} - - -/* Schedule timed wait for CPU response - - - Set flag to get CPU attention - - Set specified unit to 'newstate' and schedule - - Schedule timeout */ - -void ds_wait_for_cpu (UNIT *uptr, uint32 newst) -{ -dsio (ds_dib.devno, 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; -} - - -/* Set idle state - - - Controller is set to idle state - - Visible busy is cleared - - Timeout is cancelled */ - -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.devno, 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) */ - -uint32 ds_updds2 (UNIT *uptr) -{ -uint32 sta; -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); -if (sta & DS2_ALLERR) sta = sta | DS2_ERR; /* set error */ -return sta; -} - - -/* 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; -} - - -/* 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; -} - - -/* Start seek - schedule whether in bounds or out of bounds */ - -void ds_start_seek (UNIT *uptr, uint32 cyl, uint32 newst) -{ -int32 t; -uint32 hd, sc; -uint32 dtyp = GET_DTYPE (uptr->flags); - -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 */ - } -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; -} - - -/* Start next sector for read or write - - - 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 */ - -t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy) -{ -uint32 da, hd, sc; -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); - 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? */ - 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 */ - 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? */ - (sc >= drv_tab[dtyp].sc)) { - ds_cmd_done (1, DS1_HSCE); /* no, 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; -} - - -/* Start next sector for read - - - 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; -} - - -/* Start next sector for write - - - 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 */ - -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.devno, 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 */ - -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.devno, 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 - - Otherwises, 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.devno, 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. + The specified unit is activated using the unit's "wait" time. If debugging + is enabled, the activation is logged to the debug file. */ -t_stat ds_reset (DEVICE *dptr) +static t_stat activate_unit (UNIT *uptr) { -dsio (ds_dib.devno, ioPOPIO, 0); /* send POPIO signal */ -ds_srq = CLEAR; /* clear SRQ */ -return SCPE_OK; -} +int32 unit; +t_stat result; +if (DEBUG_PRI (ds_dev, DEB_SERV)) { + unit = uptr - ds_unit; /* calculate the unit number */ -/* Device attach */ - -t_stat ds_attach (UNIT *uptr, char *cptr) -{ -uint32 i, p; -t_stat r; - -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; - } + 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); } -return SCPE_OK; -} - - -/* Device detach */ - -t_stat ds_detach (UNIT *uptr) -{ -ds_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads if attached */ -return detach_unit (uptr); -} - - -/* Load and unload heads */ - -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; -} - - -/* Schedule attention interrupt if CTL set, not restore, and controller idle */ - -void ds_sched_atn (UNIT *uptr) -{ -int32 i; - -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 */ - }; - -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 */ -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; + +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 0ca50848..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-2008, 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,8 @@ 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 19-Mar-08 JDB Reworked "complement" to avoid inlining bug in gcc-4.x @@ -153,7 +155,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 +677,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 +729,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 +781,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 +886,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 +1383,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 @@ -1404,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 69eebc90..32e77f17 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-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,14 @@ IPLI, IPLO 12875A interprocessor link + 09-May-12 JDB Separated assignments from conditional expressions + 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 + 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 +70,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 +95,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 +121,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,42 +159,27 @@ 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 (SC, ipli_dib.select_code, 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", &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 } }; @@ -175,15 +199,16 @@ 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 (SC, iplo_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, iplo_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -206,11 +231,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 +280,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 */ +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; -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 +457,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? */ -card = (uptr == &iplo_unit); /* set card selector */ +else if (nb == 0) /* no data? */ + return SCPE_OK; + +card = (CARD_INDEX) (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 +506,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 +541,15 @@ return TRUE; t_stat ipl_reset (DEVICE *dptr) { UNIT *uptr = dptr->units; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ +CARD_INDEX card = (CARD_INDEX) 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 +575,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 +624,15 @@ 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? */ + t = ipl_check_conn (uptr); + if (t) /* 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 +641,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 +666,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 +770,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..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-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"), @@ -26,6 +26,11 @@ 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 + 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 +63,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 +157,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 +205,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 +224,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 +234,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 +246,8 @@ 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 (SC, lps_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, lps_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -246,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 } }; @@ -260,164 +278,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 +463,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 +510,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 +539,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..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-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,9 @@ 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 Changed CTIME register width to match documentation 22-Jan-07 RMS Added UNIT_TEXT flag @@ -89,9 +92,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 +107,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 +122,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 +130,16 @@ 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 (SC, lpt_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, lpt_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -140,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 } }; @@ -156,101 +164,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 +270,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 +311,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 +334,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..a4d91dd9 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-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,9 @@ 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 14-Nov-08 JDB Cleaned up VC++ size mismatch warnings for zero assignments 03-Oct-08 JDB Fixed logic for ENQ/XOFF transmit wait @@ -103,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. @@ -517,10 +520,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 +585,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); @@ -596,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 @@ -623,18 +627,16 @@ 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, &mpx_io }; - -DEVICE mpx_dev; +DIB mpx_dib = { &mpx_io, MPX }; UNIT mpx_unit [] = { { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 0 */ @@ -682,10 +684,11 @@ 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 (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 }, { NULL } @@ -708,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 } }; @@ -739,14 +743,13 @@ 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 */ 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 +801,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 +1589,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); @@ -1660,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 */ @@ -1909,7 +1907,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 +2019,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 */ @@ -2055,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. @@ -2076,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; } @@ -2232,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. @@ -2242,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 fc0490b7..daf35448 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-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,11 @@ MS 13181A 7970B 800bpi nine track magnetic tape 13183A 7970E 1600bpi nine track magnetic tape + 09-May-12 JDB Separated assignments from conditional expressions + 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 26-Jun-08 JDB Rewrote device I/O to model backplane signals 28-Dec-06 JDB Added ioCRS state to I/O decoders @@ -149,12 +154,21 @@ #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 */ -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 +176,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 +222,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 +253,8 @@ t_stat ms_clear (void); */ DIB ms_dib[] = { - { MSD, &msdio }, - { MSC, &mscio } + { &msdio, MSD }, + { &mscio, MSC } }; #define msd_dib ms_dib[0] @@ -246,19 +264,20 @@ 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 (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 } }; @@ -295,9 +314,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 +330,8 @@ 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 (SC, msc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, msc_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -338,8 +358,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 } }; @@ -362,75 +382,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 +475,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; } @@ -667,12 +691,12 @@ 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 */ - 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 */ @@ -714,7 +738,8 @@ switch (uptr->FNC) { /* case on function */ fprintf (sim_deb, ">>MSC svc: Unit %d wrote initial gap\n", unum); - if (st = ms_write_gap (uptr)) { /* write initial gap; error? */ + st = ms_write_gap (uptr); /* write initial gap*/ + if (st != MTSE_OK) { /* error? */ r = ms_map_err (uptr, st); /* map error */ break; /* terminate operation */ } @@ -724,13 +749,15 @@ switch (uptr->FNC) { /* case on function */ fprintf (sim_deb, ">>MSC svc: Unit %d wrote file mark\n", unum); - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + st = sim_tape_wrtmk (uptr); /* write tmk */ + if (st != MTSE_OK) /* error? */ r = ms_map_err (uptr, st); /* map error */ msc_sta = STA_EOF; /* set EOF status */ break; case FNC_FSR: /* space forward */ - if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ + st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */ + if (st != MTSE_OK) /* error? */ r = ms_map_err (uptr, st); /* map error */ if (tbc & 1) msc_sta = msc_sta | STA_ODD; @@ -738,7 +765,8 @@ switch (uptr->FNC) { /* case on function */ break; case FNC_BSR: /* space reverse */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */ + st = sim_tape_sprecr (uptr, &tbc); /* space rec rev*/ + if (st != MTSE_OK) /* error? */ r = ms_map_err (uptr, st); /* map error */ if (tbc & 1) msc_sta = msc_sta | STA_ODD; @@ -779,12 +807,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; } @@ -808,7 +836,8 @@ switch (uptr->FNC) { /* case on function */ fprintf (sim_deb, ">>MSC svc: Unit %d wrote initial gap\n", unum); - if (st = ms_write_gap (uptr)) { /* write initial gap; error? */ + st = ms_write_gap (uptr); /* write initial gap */ + if (st != MTSE_OK) { /* error? */ r = ms_map_err (uptr, st); /* map error */ break; /* terminate operation */ } @@ -822,8 +851,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; } @@ -832,7 +861,8 @@ switch (uptr->FNC) { /* case on function */ fprintf (sim_deb, ">>MSC svc: Unit %d wrote %d word record\n", unum, ms_ptr / 2); - if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr)) { /* write, err? */ + st = sim_tape_wrrecf (uptr, msxb, ms_ptr); /* write */ + if (st != MTSE_OK) { r = ms_map_err (uptr, st); /* map error */ break; } @@ -853,7 +883,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, @@ -871,7 +901,9 @@ t_stat st; uint32 gap_len = ms_ctype ? GAP_13183 : GAP_13181; /* establish gap length */ uint32 tape_bpi = ms_ctype ? BPI_13183 : BPI_13181; /* establish nominal bpi */ -if (st = sim_tape_wrgap (uptr, gap_len, tape_bpi)) /* write gap */ +st = sim_tape_wrgap (uptr, gap_len, tape_bpi); /* write gap */ + +if (st != MTSE_OK) return ms_map_err (uptr, st); /* map error if failure */ else return SCPE_OK; @@ -882,7 +914,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, @@ -951,7 +983,9 @@ for (i = 0; i < MS_NUMDR; i++) { /* look for write in pro fprintf (sim_deb, ">>MSC rws: Unit %d wrote %d word partial record\n", i, ms_ptr / 2); - if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF)) + st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF); + + if (st != MTSE_OK) ms_map_err (uptr, st); /* discard any error */ ms_ptr = 0; /* clear partial */ @@ -973,17 +1007,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; @@ -1069,7 +1101,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; } @@ -1247,7 +1279,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..3e7cc1cf 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-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,12 @@ MT 12559A 3030 nine track magnetic tape + 09-May-12 JDB Separated assignments from conditional expressions + 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 + 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 +111,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 +134,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 +156,8 @@ t_stat mt_clear (void); */ DIB mt_dib[] = { - { MTD, &mtdio }, - { MTC, &mtcio } + { &mtdio, MTD }, + { &mtcio, MTC } }; #define mtd_dib mt_dib[0] @@ -153,18 +166,19 @@ 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 (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 } }; @@ -190,9 +204,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,17 +214,18 @@ 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 (SC, mtc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, mtc_dib.select_code, 6), REG_HRO }, { NULL } }; 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, "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 } }; @@ -240,63 +255,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 +337,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 +480,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 */ @@ -476,7 +496,8 @@ switch (mtc_fnc) { /* case on function */ return sim_tape_detach (uptr); /* don't set cch flg */ case FNC_WFM: /* write file mark */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + st = sim_tape_wrtmk (uptr); /* write tmk */ + if (st != MTSE_OK) /* error? */ r = mt_map_err (uptr, st); /* map error */ mtc_sta = STA_EOF; /* set EOF status */ break; @@ -485,12 +506,14 @@ switch (mtc_fnc) { /* case on function */ break; case FNC_FSR: /* space forward */ - if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ + st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */ + if (st != MTSE_OK) /* error? */ r = mt_map_err (uptr, st); /* map error */ break; case FNC_BSR: /* space reverse */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */ + st = sim_tape_sprecr (uptr, &tbc); /* space rec rev */ + if (st != MTSE_OK) /* error? */ r = mt_map_err (uptr, st); /* map error */ break; @@ -514,9 +537,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,12 +557,13 @@ 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; } if (mt_ptr) { /* write buffer */ - if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) { /* write, err? */ + st = sim_tape_wrrecf (uptr, mtxb, mt_ptr); /* write */ + if (st != MTSE_OK) { /* error? */ r = mt_map_err (uptr, st); /* map error */ break; /* done */ } @@ -552,7 +576,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; } @@ -608,7 +632,8 @@ t_stat st; if (sim_is_active (&mtc_unit) && /* write in prog? */ (mtc_fnc == FNC_WC) && (mt_ptr > 0)) { /* yes, bad rec */ - if (st = sim_tape_wrrecf (&mtc_unit, mtxb, mt_ptr | MTR_ERF)) + st = sim_tape_wrrecf (&mtc_unit, mtxb, mt_ptr | MTR_ERF); + if (st != MTSE_OK) mt_map_err (&mtc_unit, st); } @@ -626,13 +651,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..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-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"), @@ -25,6 +25,9 @@ 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 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 +268,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 +280,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 +318,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); @@ -322,20 +330,15 @@ 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[] = { - { MUXL, &muxlio }, - { MUXU, &muxuio } + { &muxlio, MUXL }, + { &muxuio, MUXU } }; #define muxl_dib mux_dib[0] @@ -351,6 +354,8 @@ DIB mux_dib[] = { muxl_dev MUXL device descriptor */ +TMXR mux_desc; + DEVICE muxl_dev; UNIT muxl_unit[] = { @@ -373,9 +378,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 +391,8 @@ 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 (SC, muxl_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, muxl_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -402,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 } }; @@ -435,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 @@ -445,12 +456,17 @@ 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 (DEVNO, muxu_dib.devno, 6), REG_HRO }, + { ORDATA (SC, muxu_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, muxu_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -464,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 } }; @@ -494,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 */ @@ -512,24 +529,26 @@ 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 (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 } }; @@ -570,191 +589,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 +789,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 +834,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; } @@ -959,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 */ @@ -1004,8 +1030,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 +1092,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 +1169,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 +1185,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 +1201,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 +1234,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 +1286,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 +1301,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 */ @@ -1316,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 6ce98a00..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, 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,9 @@ 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 18-Jun-08 JDB Created PIF device @@ -103,14 +106,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,26 +141,27 @@ 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 (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 } }; @@ -184,7 +190,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 +215,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 +336,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..edf44c2c 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-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,11 @@ TTY 12531C buffered teleprinter interface CLK 12539C time base generator + 09-May-12 JDB Separated assignments from conditional expressions + 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 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 +130,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 +160,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 +182,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 +201,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 +214,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,23 +223,24 @@ 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 (SC, ptr_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, ptr_dib.select_code, 6), REG_HRO }, { NULL } }; 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 } }; @@ -246,7 +260,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,19 +268,20 @@ 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 (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 } }; @@ -290,7 +305,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 +317,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 +327,8 @@ 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 (SC, tty_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, tty_dib.select_code, 6), REG_HRO }, { NULL } }; @@ -323,8 +339,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 } }; @@ -344,28 +360,29 @@ 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 (SC, clk_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, clk_dib.select_code, 6), REG_HRO }, { NULL } }; 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 } }; @@ -374,7 +391,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" }; @@ -392,78 +410,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 +493,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 +520,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 +545,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 +610,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 +627,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 +716,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 +734,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 +742,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 +903,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 +930,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 */ } @@ -920,7 +943,9 @@ t_stat r; if (tty_mode & TM_PRI) { /* printing? */ c = sim_tt_outcvt (c, TT_GET_MODE (tty_unit[TTO].flags)); if (c >= 0) { /* valid? */ - if (r = sim_putchar_s (c)) return r; /* output char */ + r = sim_putchar_s (c); /* output char */ + if (r != SCPE_OK) + return r; tty_unit[TTO].pos = tty_unit[TTO].pos + 1; } } @@ -932,7 +957,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 +973,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 */ @@ -963,7 +988,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)) @@ -975,7 +1000,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; @@ -1024,105 +1049,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 +1159,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 +1172,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 +1186,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..c8681731 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-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,12 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 09-May-12 JDB Quieted warnings for assignments in conditional expressions + 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 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 +66,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; @@ -76,6 +82,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 @@ -98,8 +105,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, @@ -117,6 +123,7 @@ DEVICE *sim_devices[] = { &muxl_dev, &muxu_dev, &muxc_dev, &ipli_dev, &iplo_dev, &pif_dev, + &da_dev, &dc_dev, NULL }; @@ -602,11 +609,11 @@ if (opcode[i]) { /* found opcode? */ case I_V_MRF: /* mem ref */ cptr = get_glyph (cptr, gbuf, 0); /* get next field */ - if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */ + if ((k = (strcmp (gbuf, "C") == 0))) { /* C specified? */ val[0] = val[0] | I_CP; cptr = get_glyph (cptr, gbuf, 0); } - else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */ + else if ((k = (strcmp (gbuf, "Z") == 0))) { /* Z specified? */ cptr = get_glyph (cptr, gbuf, ','); } if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; @@ -767,24 +774,71 @@ else { /* printable character * } +/* Set select code */ + +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; + +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++, 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) { -DEVICE *dptr = (DEVICE *) desc; -DIB *dibp; -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; -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; -return SCPE_OK; +return hp_setsc (uptr, num, cptr, desc); } @@ -792,14 +846,12 @@ return SCPE_OK; t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc) { -DEVICE *dptr = (DEVICE *) desc; -DIB *dibp; -int32 i; +t_stat result; -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); -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..ea51945e --- /dev/null +++ b/HP2100/hp_disclib.c @@ -0,0 +1,2383 @@ +/* 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. + + 07-May-12 JDB Corrected end-of-track delay time logic + 02-May-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. + + 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 + 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 per-cylinder seek delay time + sector_time intersector delay time + 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: + + 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, 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. + + 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 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. 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 + 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 its "wait" field is not + used. The timer starts when a command other than End, Seek, or Recalibrate + 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 + execution. + + The controller maintains six variables in each drive's unit structure: + + wait -- the current service activation time + 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 + 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 */ + +#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 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: Set File Mask (flags combined) */ + + +#define DL_M_OPCODE 037 /* opcode mask */ +#define DL_M_UNIT 017 /* unit mask */ + +#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) +#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 */ + +#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 /* 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) + +#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 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(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 + 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(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(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 + 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 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. +*/ + +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 the controller status */ + t_bool unit_field; /* command has a unit field */ + 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; + +typedef const DS_PROPS *PRPTR; + +#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 */ + }; + + +/* Auxiliary unit indices */ + +typedef enum { + controller = 0, /* controller unit index */ + timer /* 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 unit; +PRPTR props; +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 = &cmd_props [invalid_opcode]; /* 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->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 */ + +else /* an ICD controller */ + unit = unit_limit; /* uses the supplied unit number */ + +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 (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 = 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) { /* 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; /* the 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 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 + 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 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 + 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 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 + 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 the intersector time (latency) for read and + write commands, and to the controller processing time for all others. + 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) +{ +UNIT *uptr, *rptr; +uint32 unit; +PRPTR props; +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->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->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 */ + } + +else { /* for an ICD controller, */ + unit = 0; /* the unit value is ignored */ + 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 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 */ + } + +else if (uptr) { /* otherwise, we have a valid unit */ + uptr->wait = cvptr->cmd_time; /* most commands use the command delay */ + + 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, */ + uptr->wait = 0; /* set for no unit activation */ + + else { /* otherwise, the unit is idle */ + uptr->STAT &= ~DL_S2ATN; /* clear the drive Attention status */ + + 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 = props->params_out; /* 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 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; /* 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 */ + } + + 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 addresses */ + + 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 (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 */ + + 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 addresses */ + 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 this is a MAC controller, */ + cvptr->retry = GET_FRETRY (cvptr->buffer [0]); /* the retry count 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 by 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 completed 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 + 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 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 + 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 do not generate an 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 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 + 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) 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 status 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); /* then go idle until it 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 */ + 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); /* the controller service handles these */ + break; + + + default: /* we were 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); /* seeks end 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 the 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) /* are there 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); /* the controller service handles these */ + break; + + + default: /* we were 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. 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 + 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); /* 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); /* the 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); /* the command is complete */ + break; + + + case end: + dl_idle_controller (cvptr); /* the command completes with the controller idle */ + break; + + + case wakeup: + dl_end_command (cvptr, unit_available); /* the command completes with Unit Available status */ + break; + + + default: /* we were 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: /* we were 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 any controller activation */ + +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 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. + + 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 (which 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 (which 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 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. +*/ + +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) /* 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 */ + } + +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 and 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) /* 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 */ + 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) +{ +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 /* the type or opcode is illegal */ + 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) +{ +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 /* the type or opcode is illegal, */ + 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) /* if the phase is legal, */ + return phase_name [phase]; /* return the phase name */ +else /* the phase is illegal, */ + return invalid_name; /* so return an error indication */ +} + + + +/* 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 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. +*/ + +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 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 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 available 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; /* the 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) /* we 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) { /* is the end of data indicated? */ + dl_end_command (cvptr, normal_completion); /* complete the command */ + return SCPE_OK; + } + +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 + 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; /* set for no address verification */ + } + +else { /* it's another read command */ + offset = 0; /* data starts at the beginning */ + 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; /* 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 */ + uptr->fileref); + +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 the data error status and stop the simulation */ + +next_sector (cvptr, uptr); /* address the next sector */ + +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 */ +} + + +/* 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 set to allow for the intersector delay. + + + Implementation notes: + + 1. The CPU indicates the end of a read data transfer to an ICD controller by + untalking the drive. The untalk is done by the driver as soon as the + DCPC completion interrupt is processed. However, the time from the final + DCPC transfer through driver entry to the point where the untalk is + asserted on the bus varies from 80 instructions (RTE-6/VM with OS + microcode and the buffer in the system map) to 152 instructions (RTE-IVB + with the buffer in the user map). The untalk must occur before the start + of the next sector, or the drive will begin the data transfer. + + Normally, this is not a problem, as the driver clears the FIFO of any + received data after DCPC completion. However, if the read terminates + after the last sector of a track, and accessing the next sector would + require an intervening seek, and the file mask disables auto-seeking or + an enabled seek would move the positioner beyond the drive limits, then + the controller will indicate an End of Cylinder error if the untalk does + not arrive before the seek is initiated. + + The RTE driver (DVA32) and various utilities that manage the disc + directly (e.g., SWTCH) do not appear to account for these bogus errors, + so the ICD controller hardware must avoid them in some unknown manner. + We work around the issue by extending the intersector delay to allow time + for a potential untalk whenever the next access would otherwise fail. + + Note that this issue does not occur with writes because DCPC completion + asserts EOI concurrently with the final data byte to terminate the + command. +*/ + +static void end_read (CVPTR cvptr, UNIT *uptr) +{ +uint32 limit; + +if (cvptr->eod == SET) /* is the 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 */ + + if (cvptr->eoc == SET && cvptr->type == ICD) { /* seek will be required and controller is ICD? */ + if (!(cvptr->file_mask & DL_FAUTSK)) /* if auto-seek is disabled */ + limit = cvptr->cylinder; /* then the limit is the current cylinder */ + else if (cvptr->file_mask & DL_FDECR) /* else if enabled and decremental seek */ + limit = 0; /* then the limit is cylinder 0 */ + else /* else the enabled limit is the last cylinder */ + limit = drive_props [GET_MODEL (uptr->flags)].cylinders; + + if (cvptr->cylinder == limit) /* is positioner at the limit? */ + uptr->wait = cvptr->eot_time; /* seek will fail; delay to allow CPU to untalk */ + } + } + +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. 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 + 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 address */ + +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)) { /* writing is permitted; position the sector */ + uptr->PHASE = data_phase; /* positioning succeeded; 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. 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 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 + 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 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 the 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 at the current sector. + + The image file is positioned at the byte address corresponding to the drive's + current cylinder and the controller's current head and sector addresses. + Positioning may involve an auto-seek if a prior read or write addressed the + final sector of 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, 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 + 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 + reentered, the read or write will continue on the new cylinder. + + If the EOC flag was not set, the drive's position is checked against the + controller's position if address verification is requested. 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 or verification is not requested, + the CHS addresses are validated against the drive limits. If they are + invalid, Seek Check status is set, and the command is terminated with an + error. + + If the addresses are 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) /* 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) /* 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 */ + + if (uptr->STAT & DL_S2SC) /* did a seek check occur? */ + 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 /* 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 */ + + if (uptr->STAT & DL_S2SC) /* did a seek check occur? */ + 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? */ + || (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 { /* 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 */ + + 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) /* are we 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) /* are we 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 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 + 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); /* 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 the EOC flag */ + +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 */ + } + +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 { /* 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 the 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) /* 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 { /* 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; /* the 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 sequential 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 is set */ +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 or supply an auxiliary unit. + + + 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) /* should we start the timer? */ + sim_activate_abs (cvptr->aux + timer, /* activate the auxiliary unit */ + cvptr->wait_time); + else /* we 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 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 a new 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 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? */ + 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..90b2d82b --- /dev/null +++ b/HP2100/hp_disclib.h @@ -0,0 +1,388 @@ +/* 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. + + 07-May-12 JDB Added end-of-track delay time as a controller variable + 02-May-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_EOT_TIME 160 /* end-of-track delay time */ +#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 drive operation 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 03 /* 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 3- 0: last unit number */ + +#define DL_M_S1UNIT 017 /* unit number 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 check 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 */ + +typedef enum { + MAC = 0, + ICD, + last_type = ICD, /* last valid type */ + type_count /* count of controller types */ + } 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, + invalid_opcode = 020, + read_without_verify = 022, + load_tio_register = 023, + request_disc_address = 024, + end = 025, + wakeup = 026, + last_opcode = wakeup /* last valid opcode */ + } CNTLR_OPCODE; + +#define DL_OPCODE_MASK 037 + + +/* Controller command phases */ + +typedef enum { + start_phase = 0, + data_phase, + end_phase, + last_phase = end_phase /* last valid 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 current index */ + uint32 length; /* data buffer valid length */ + UNIT *aux; /* MAC auxiliary units (controller and timer) */ + int32 eot_time; /* end-of-track read delay time */ + int32 seek_time; /* per-cylinder seek delay time */ + int32 sector_time; /* intersector delay time */ + 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 initialization. + + The 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_EOT_TIME, 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/I1401/i1401_cd.c b/I1401/i1401_cd.c index f1912cf7..7bd64b70 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 */ @@ -184,7 +184,7 @@ t_stat r; if (sim_is_active (&cdr_unit)) { /* busy? */ sim_cancel (&cdr_unit); /* cancel */ - if (r = cdr_svc (&cdr_unit)) /* process */ + if ((r = cdr_svc (&cdr_unit))) /* process */ return r; } if ((cdr_unit.flags & UNIT_ATT) == 0) /* attached? */ diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index b07d272f..fdc787bd 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 @@ -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) }, @@ -546,7 +547,7 @@ while (reason == 0) { /* loop until halted */ saved_IS = IS; /* commit prev instr */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } @@ -1038,7 +1039,7 @@ CHECK_LENGTH: */ case OP_R: /* read */ - if (reason = iomod (ilnt, D, r_mod)) /* valid modifier? */ + if ((reason = iomod (ilnt, D, r_mod))) /* valid modifier? */ break; reason = read_card (ilnt, D); /* read card */ BS = CDR_BUF + CDR_WIDTH; @@ -1048,7 +1049,7 @@ CHECK_LENGTH: break; case OP_W: /* write */ - if (reason = iomod (ilnt, D, w_mod)) /* valid modifier? */ + if ((reason = iomod (ilnt, D, w_mod))) /* valid modifier? */ break; reason = write_line (ilnt, D); /* print line */ BS = LPT_BUF + LPT_WIDTH; @@ -1058,7 +1059,7 @@ CHECK_LENGTH: break; case OP_P: /* punch */ - if (reason = iomod (ilnt, D, p_mod)) /* valid modifier? */ + if ((reason = iomod (ilnt, D, p_mod))) /* valid modifier? */ break; reason = punch_card (ilnt, D); /* punch card */ BS = CDP_BUF + CDP_WIDTH; @@ -1068,7 +1069,7 @@ CHECK_LENGTH: break; case OP_WR: /* write and read */ - if (reason = iomod (ilnt, D, w_mod)) /* valid modifier? */ + if ((reason = iomod (ilnt, D, w_mod))) /* valid modifier? */ break; reason = write_line (ilnt, D); /* print line */ r1 = read_card (ilnt, D); /* read card */ @@ -1081,7 +1082,7 @@ CHECK_LENGTH: break; case OP_WP: /* write and punch */ - if (reason = iomod (ilnt, D, w_mod)) /* valid modifier? */ + if ((reason = iomod (ilnt, D, w_mod))) /* valid modifier? */ break; reason = write_line (ilnt, D); /* print line */ r1 = punch_card (ilnt, D); /* punch card */ @@ -1094,7 +1095,7 @@ CHECK_LENGTH: break; case OP_RP: /* read and punch */ - if (reason = iomod (ilnt, D, NULL)) /* valid modifier? */ + if ((reason = iomod (ilnt, D, NULL))) /* valid modifier? */ break; reason = read_card (ilnt, D); /* read card */ r1 = punch_card (ilnt, D); /* punch card */ @@ -1107,7 +1108,7 @@ CHECK_LENGTH: break; case OP_WRP: /* write, read, punch */ - if (reason = iomod (ilnt, D, w_mod)) /* valid modifier? */ + if ((reason = iomod (ilnt, D, w_mod))) /* valid modifier? */ break; reason = write_line (ilnt, D); /* print line */ r1 = read_card (ilnt, D); /* read card */ @@ -1121,9 +1122,9 @@ CHECK_LENGTH: break; case OP_SS: /* select stacker */ - if (reason = iomod (ilnt, D, ss_mod)) /* valid modifier? */ + if ((reason = iomod (ilnt, D, ss_mod))) /* valid modifier? */ break; - if (reason = select_stack (D)) /* sel stack, error? */ + if ((reason = select_stack (D))) /* sel stack, error? */ break; if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ BRANCH; @@ -1131,7 +1132,7 @@ CHECK_LENGTH: break; case OP_CC: /* carriage control */ - if (reason = carriage_control (D)) /* car ctrl, error? */ + if ((reason = carriage_control (D))) /* car ctrl, error? */ break; if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ BRANCH; @@ -1153,7 +1154,7 @@ CHECK_LENGTH: reason = STOP_INVL; else if (ioind != BCD_PERCNT) /* valid dev addr? */ reason = STOP_INVA; - else if (reason = iomod (ilnt, D, mtf_mod)) /* valid modifier? */ + else if ((reason = iomod (ilnt, D, mtf_mod))) /* valid modifier? */ break; if (dev == IO_MT) /* BCD? */ reason = mt_func (unit, 0, D); diff --git a/I1401/i1401_dp.c b/I1401/i1401_dp.c index 81739b94..d45c8287 100644 --- a/I1401/i1401_dp.c +++ b/I1401/i1401_dp.c @@ -269,7 +269,7 @@ switch (fnc) { /* case on function */ for (;;) { /* loop */ qzr = (--cnt == 0); /* set zero latch */ dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ - if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read sector */ + if ((r = dp_rdsec (uptr, psec, flg, qwc))) /* read sector */ break; cnt = dp_get_cnt (dcf); /* get new count */ if (cnt < 0) /* bad count? */ @@ -278,7 +278,7 @@ switch (fnc) { /* case on function */ break; sec++; psec++; /* next sector */ dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */ - if (r = dp_nexsec (uptr, psec, dcf)) /* find next */ + if ((r = dp_nexsec (uptr, psec, dcf))) /* find next */ break; } break; /* done, clean up */ @@ -289,9 +289,9 @@ switch (fnc) { /* case on function */ for (;;) { /* loop */ qzr = (--cnt == 0); /* set zero latch */ dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ - if (r = dp_rdadr (uptr, psec, flg, qwc)) /* read addr */ + if ((r = dp_rdadr (uptr, psec, flg, qwc))) /* read addr */ break; /* error? */ - if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read data */ + if ((r = dp_rdsec (uptr, psec, flg, qwc))) /* read data */ break; /* error? */ cnt = dp_get_cnt (dcf); /* get new count */ if (cnt < 0) /* bad count? */ @@ -312,13 +312,13 @@ switch (fnc) { /* case on function */ for (;;) { /* loop */ qzr = (--cnt == 0); /* set zero latch */ dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* rewr cnt */ - if (r = dp_wrsec (uptr, psec, flg)) /* write data */ + if ((r = dp_wrsec (uptr, psec, flg))) /* write data */ break; if (qzr) /* zero latch? done */ break; sec++; psec++; /* next sector */ dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */ - if (r = dp_nexsec (uptr, psec, dcf)) /* find next */ + if ((r = dp_nexsec (uptr, psec, dcf))) /* find next */ break; } break; /* done, clean up */ @@ -331,9 +331,9 @@ switch (fnc) { /* case on function */ for (;;) { /* loop */ qzr = (--cnt == 0); /* set zero latch */ dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ - if (r = dp_wradr (uptr, psec, flg)) /* write addr */ + if ((r = dp_wradr (uptr, psec, flg))) /* write addr */ break; - if (r = dp_wrsec (uptr, psec, flg)) /* write data */ + if ((r = dp_wrsec (uptr, psec, flg))) /* write data */ break; if (qzr) /* zero latch? done */ break; diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c index 2d299e4d..99556db6 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/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..df7b8574 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 @@ -451,7 +451,7 @@ int32 i; UNIT *uptr; for (i = 0; i < MT_NUMDR; i++) { /* per drive resets */ - if (uptr = mt_sel_unit (i)) { + if ((uptr = mt_sel_unit (i))) { MT_CLR_PNU (uptr); /* clear pos flag */ } } diff --git a/I1401/i1401_sys.c b/I1401/i1401_sys.c index 43387338..94976277 100644 --- a/I1401/i1401_sys.c +++ b/I1401/i1401_sys.c @@ -1,6 +1,6 @@ /* i1401_sys.c: IBM 1401 simulator interface - Copyright (c) 1993-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"), @@ -23,15 +23,16 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 25-Mar-12 RMS Fixed && -> & in test (Peter Schorn) 20-Sep-05 RMS Revised for new code tables 04-Jan-05 WVS Added address argument support 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 @@ -401,7 +402,7 @@ if (op >= 64) /* successful? */ return SCPE_ARG; val[0] = op | WM; /* store opcode */ cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */ -if (((op_table[op] && IO) && (get_io (gbuf, &val[1]) == SCPE_OK)) || +if (((op_table[op] & IO) && (get_io (gbuf, &val[1]) == SCPE_OK)) || (get_addr (gbuf, &val[1]) == SCPE_OK)) { cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */ if (get_addr (gbuf, &val[4]) == SCPE_OK) { diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c index d7e7cb7a..2e6ba2c4 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 @@ -43,7 +44,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]; @@ -108,7 +109,7 @@ DEVICE cdp_dev = { - Can punch both 11 (-) and 11-0 (uses ]). On input, the nul and nl generated by C are converted to spaces; tabs and line feeds are also converted to spaces. - +*/ /* Card reader (ASCII) to numeric (one digit) */ const char cdr_to_num[128] = { @@ -332,8 +333,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_cpu.c b/I1620/i1620_cpu.c index bf3d761e..49b02106 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: @@ -476,7 +476,7 @@ while (reason == 0) { /* loop until halted */ saved_PC = PC; /* commit prev instr */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } diff --git a/I1620/i1620_dp.c b/I1620/i1620_dp.c index 7dde5d31..c524eac7 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" @@ -206,7 +206,7 @@ switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */ if (psec < 0) /* error? */ CRETIOE (dp_stop, STOP_DACERR); do { /* loop on count */ - if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read sector */ + if ((r = dp_rdsec (uptr, psec, qnr, qwc))) /* read sector */ break; sec++; psec++; /* next sector */ } while ((--cnt > 0) && @@ -216,9 +216,9 @@ switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */ case FNC_TRK: /* read track */ psec = dp_trkop (drv, sec); /* start of track */ for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */ - if (r = dp_rdadr (uptr, psec, qnr, qwc)) /* read addr */ + if ((r = dp_rdadr (uptr, psec, qnr, qwc))) /* read addr */ break; /* error? */ - if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read data */ + if ((r = dp_rdsec (uptr, psec, qnr, qwc))) /* read data */ break; /* error? */ psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); } @@ -231,9 +231,9 @@ switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */ if (psec < 0) /* error? */ CRETIOE (dp_stop, STOP_DACERR); do { /* loop on count */ - if (r = dp_tstgm (M[dp_ba], qnr)) /* start with gm? */ + if ((r = dp_tstgm (M[dp_ba], qnr))) /* start with gm? */ break; - if (r = dp_wrsec (uptr, psec, qnr)) /* write data */ + if ((r = dp_wrsec (uptr, psec, qnr))) /* write data */ break; sec++; psec++; /* next sector */ } while ((--cnt > 0) && @@ -245,11 +245,11 @@ switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */ return STOP_WRADIS; psec = dp_trkop (drv, sec); /* start of track */ for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */ - if (r = dp_tstgm (M[dp_ba], qnr)) /* start with gm? */ + if ((r = dp_tstgm (M[dp_ba], qnr))) /* start with gm? */ break; - if (r = dp_wradr (uptr, psec, qnr)) /* write addr */ + if ((r = dp_wradr (uptr, psec, qnr))) /* write addr */ break; - if (r = dp_wrsec (uptr, psec, qnr)) /* write data */ + if ((r = dp_wrsec (uptr, psec, qnr))) /* write data */ break; psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); } 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 dff4ac06..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 */ @@ -363,7 +364,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..198d29e7 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,9 +124,11 @@ 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, cct[CCT_LNT]; +extern int32 cct_lnt, cct_ptr; +extern uint32 cct[CCT_LNT]; char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; if ((*cptr != 0) || (flag != 0)) @@ -548,7 +552,7 @@ if (I_GETQP (opfl) != I_M_QNP) { /* Q field allowed? */ cptr = get_glyph (cptr, fptr = gbuf, ' '); /* get flag field */ last = -1; /* none yet */ -while (t = *fptr++) { /* loop through */ +while ((t = *fptr++)) { /* loop through */ if ((t < '0') || (t > '9')) /* must be digit */ return SCPE_ARG; t = t - '0'; /* convert */ diff --git a/I1620/i1620_tty.c b/I1620/i1620_tty.c index 648beeef..ac4a1021 100644 --- a/I1620/i1620_tty.c +++ b/I1620/i1620_tty.c @@ -260,7 +260,7 @@ do { *c = 0x7F; else if ((raw == '~') || (raw == '`')) /* flag? mark */ flg = FLAG; - else if (cp = strchr (tti_to_num, raw)) /* legal? */ + else if ((cp = strchr (tti_to_num, raw))) /* legal? */ *c = ((int8) (cp - tti_to_num)) | flg; /* assemble char */ else raw = 007; /* beep! */ tto_write (raw); /* echo */ diff --git a/I7094/i7094_cd.c b/I7094/i7094_cd.c index 88a15ebe..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 @@ -87,7 +88,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_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.c b/I7094/i7094_com.c index 2fd5cf24..8f0d4e7c 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; @@ -1175,7 +1175,7 @@ char name[20]; ln = uptr - coml_dev.units; sprintf (name, val? "Output queue %d": "Input queue %d", ln); lh = val? &com_outq[ln]: &com_inpq[ln]; -if (entc = com_show_qsumm (st, lh, name)) { +if ((entc = com_show_qsumm (st, lh, name))) { for (i = 0, next = lh->head; next != 0; i++, next = com_pkt[next].next) { if ((i % 8) == 0) 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..4dbd5882 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 (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 */ @@ -652,14 +664,14 @@ while (reason == SCPE_OK) { /* loop until error */ } if (sim_interval <= 0) { /* intv cnt expired? */ - if (reason = sim_process_event ()) /* process events */ + 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)) + if ((reason = ch_proc (i))) break; } chtr_pend = chtr_eval (NULL); @@ -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)); @@ -1927,13 +1973,13 @@ while (reason == SCPE_OK) { /* loop until error */ t_stat r; for (i = 0; (i < HALT_IO_LIMIT) && !ch_qidle (); i++) { sim_interval = 0; - if (r = sim_process_event ()) /* process events */ + 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)) + if ((r = ch_proc (j))) return r; } chtr_pend = chtr_eval (NULL); @@ -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; @@ -2393,7 +2438,7 @@ if (pc & HIST_PC) { /* instruction? */ } fputc ('\n', st); /* end line */ } /* end if instruction */ -else if (ch = HIST_CH (pc)) { /* channel? */ +else if ((ch = HIST_CH (pc))) { /* channel? */ fprintf (st, "CH%c ", 'A' + ch - 1); fprintf (st, "%05o ", pc & AMASK); fputs (" ", st); diff --git a/I7094/i7094_cpu1.c b/I7094/i7094_cpu1.c index c5c4ea12..1e3bd402 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,7 +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. - 16-Jul-10 RMS Fixed PSE and MSE user-mode protection (from Dave Pitts) + 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 (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..50b24c35 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,30 @@ drm 7289/7320A "fast" drum - Very little is known about this device; the behavior simulated here is - what is used by CTSS. + 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 + 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. + - LPCR is not implemented. For speed, the entire drum is buffered in memory. */ @@ -57,23 +56,27 @@ #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 */ #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)), \ ((double) DRM_NUMWDS))) +#define GET_PROT(x) ((x[drm_phy] >> (drm_log - 1)) & 1) /* 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 */ @@ -81,21 +84,36 @@ #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 */ + +#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_WDA 13 /* disk address */ +#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_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; @@ -124,22 +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, 2) }, - { ORDATA (DA, drm_da, 18) }, + { ORDATA (STATE, drm_sta, 3) }, + { 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 (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 } @@ -184,32 +200,48 @@ 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 u, l; int32 cp, dp; if (drm_sta == DRM_1ST) { - u = 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? */ - (l == 0) || (l > DRM_NUMLD)) { /* invalid log drum? */ + drm_phy = DRM_GETPHY (val); /* get unit */ + 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 */ 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,41 +256,45 @@ return SCPE_OK; 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 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 */ + /* fall through */ case DRM_DATA: /* data */ if (drm_op) { /* write? */ if (drm_chob_v) /* valid? clear */ 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 */ 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 */ @@ -268,14 +304,14 @@ 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 + 1; -if (drm_da & DRM_SCMASK) +drm_da = (drm_da + 1) & DRM_LDMASK; +if (drm_da != 0) return FALSE; -drm_sta = DRM_EOS; +drm_sta = DRM_EOD; return TRUE; } @@ -285,6 +321,8 @@ 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_dsk.c b/I7094/i7094_dsk.c index 710725f1..70107ca9 100644 --- a/I7094/i7094_dsk.c +++ b/I7094/i7094_dsk.c @@ -693,14 +693,14 @@ trk = uaptr->TRK; /* get access track */ switch (dsk_sta) { /* case on state */ case CHSL_RDS: /* read start */ - if (r = dsk_init_trk (udptr, trk)) { /* read track, err? */ + if ((r = dsk_init_trk (udptr, trk))) { /* read track, err? */ return ((r == ERR_NRCF)? SCPE_OK: r); /* rec not fnd ok */ } dsk_sta = CHSL_RDS|CHSL_2ND; /* next state */ break; case CHSL_RDS|CHSL_2ND: /* read data transmit */ - if (r = dsk_xfer_done (uaptr, dtyp)) { /* transfer done? */ + if ((r = dsk_xfer_done (uaptr, dtyp))) { /* transfer done? */ if (r != ERR_ENDRC) /* error? */ return r; dsk_sta = CHSL_RDS|CHSL_3RD; /* next state */ @@ -721,7 +721,7 @@ switch (dsk_sta) { /* case on state */ break; case CHSL_WRS: /* write start */ - if (r = dsk_init_trk (udptr, trk)) { /* read track, err? */ + if ((r = dsk_init_trk (udptr, trk))) { /* read track, err? */ return ((r == ERR_NRCF)? SCPE_OK: r); /* rec not fnd ok */ } ch_req |= REQ_CH (dsk_ch); /* first request */ @@ -742,7 +742,7 @@ switch (dsk_sta) { /* case on state */ else dsk_buf[dsk_rptr++] = dsk_chob; /* write, store word */ if (dsk_rptr == T1STREC) /* if THA, skip after HA */ dsk_rptr++; - if (r = dsk_xfer_done (uaptr, dtyp)) { /* transfer done? */ + if ((r = dsk_xfer_done (uaptr, dtyp))) { /* transfer done? */ if (r != ERR_ENDRC) /* error? */ return r; dsk_sta = CHSL_WRS|CHSL_3RD; /* next state */ @@ -755,7 +755,7 @@ switch (dsk_sta) { /* case on state */ case CHSL_WRS|CHSL_3RD: /* write done */ if (!dsk_wchk) { /* if write */ - if (r = dsk_wr_trk (udptr, trk)) /* write track; err? */ + if ((r = dsk_wr_trk (udptr, trk))) /* write track; err? */ return r; } if (dsk_qdone (dsk_ch)) /* done? exit */ @@ -846,7 +846,7 @@ switch (dsk_sta) { /* case on state */ if (!dsk_wchk) { /* actual write? */ trk = trk - (trk % dsk_tab[dtyp].trkpc); /* cyl start */ for (i = 0; i < dsk_tab[dtyp].trkpc; i++) { /* do all tracks */ - if (r = dsk_wr_trk (udptr, trk + i)) /* wr track; err? */ + if ((r = dsk_wr_trk (udptr, trk + i))) /* wr track; err? */ return r; } } @@ -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/I7094/i7094_io.c b/I7094/i7094_io.c index 655e7b7f..391debfa 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 @@ -86,7 +88,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); @@ -793,7 +795,7 @@ switch (ch_sta[ch]) { /* case on chan state */ if (ch_dev[ch].flags & DEV_7289) { /* drum channel? */ ir = ReadP (clc); /* read addr */ ch_clc[ch] = CHAINC (clc); /* incr chan pc */ - if (r = ch9_wr (ch, ir, 0)) /* write to dev */ + if ((r = ch9_wr (ch, ir, 0))) /* write to dev */ return r; } else ch_clc[ch] = clc; /* set clc */ @@ -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); @@ -999,7 +1003,7 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ return SCPE_OK; case CH9_SNS: /* sense */ - if (r = ch9_sel (ch, CHSL_SNS)) /* send sense to dev */ + if ((r = ch9_sel (ch, CHSL_SNS))) /* send sense to dev */ return r; ch_flags[ch] |= CHF_PRD; /* prepare to read */ break; /* next command */ @@ -1015,13 +1019,13 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ } ch_flags[ch] &= ~CHF_EOR; /* clear end */ if (ch_op[ch] == CH9_CTLR) { /* CTLR? */ - if (r = ch9_sel (ch, CHSL_RDS)) /* send read sel */ + if ((r = ch9_sel (ch, CHSL_RDS))) /* send read sel */ return r; ch_flags[ch] |= CHF_PRD; /* prep to read */ ch_idf[ch] = 0; } else if (ch_op[ch] == CH9_CTLW) { /* CTLW? */ - if (r = ch9_sel (ch, CHSL_WRS)) /* end write sel */ + if ((r = ch9_sel (ch, CHSL_WRS))) /* end write sel */ return r; ch_flags[ch] |= CHF_PWR; /* prep to write */ } @@ -1031,7 +1035,7 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ if ((ch_wc[ch] == 0) || (ch_flags[ch] & CHF_EOR)) { /* wc == 0 or EOR? */ if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) { ch_flags[ch] &= ~(CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS); - if (r = ch9_wr (ch, 0, CH9DF_STOP)) /* send stop */ + if ((r = ch9_wr (ch, 0, CH9DF_STOP))) /* send stop */ return r; } if (ch_flags[ch] & CHF_EOR) { /* EOR? */ @@ -1051,7 +1055,7 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ ch_flags[ch] &= ~CHF_EOR; /* ignore */ else if (ch_flags[ch] & CHF_RDS) /* read? */ ch9_rd_putw (ch); - else if (r = ch9_wr_getw (ch)) /* no, write */ + else if ((r = ch9_wr_getw (ch))) /* no, write */ return r; if (ch_wc[ch] == 0) /* done? get next */ break; @@ -1160,7 +1164,7 @@ else { /* 7607 write */ case CH6_IOCD: /* IOCD */ if (ch_wc[ch]) { /* wc > 0? */ - if (r = ch6_wr_getw (ch, TRUE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; @@ -1170,7 +1174,7 @@ else { /* 7607 write */ case CH6_IOCP: /* IOCP */ case CH6_IOSP: /* IOSP */ if (ch_wc[ch]) { /* wc > 0? */ - if (r = ch6_wr_getw (ch, FALSE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, FALSE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; @@ -1180,7 +1184,7 @@ else { /* 7607 write */ case CH6_IOCT: /* IOCT */ case CH6_IOST: /* IOST */ if (ch_wc[ch]) { /* wc > 0? */ - if (r = ch6_wr_getw (ch, FALSE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, FALSE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; @@ -1189,7 +1193,7 @@ else { /* 7607 write */ case CH6_IORP: /* IORP */ if (!(ch_flags[ch] & CHF_EOR) && ch_wc[ch]) { /* not EOR? (cdp, lpt) */ - if (r = ch6_wr_getw (ch, TRUE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; @@ -1199,7 +1203,7 @@ else { /* 7607 write */ case CH6_IORT: /* IORT */ if (!(ch_flags[ch] & CHF_EOR) && ch_wc[ch]) { /* not EOR? (cdp, lpt) */ - if (r = ch6_wr_getw (ch, TRUE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; 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 18c34942..dddf2531 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" @@ -72,7 +73,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); @@ -563,7 +564,7 @@ switch (uptr->UST) { /* case on state */ 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 */ + if ((r = mt_map_err (uptr, r))) /* map status */ return r; if (mt_unit[ch] == 0) /* disconnected? */ return SCPE_OK; @@ -735,7 +736,7 @@ 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 */ + if ((r = mt_map_err (uptr, r))) /* map error */ return r; } uptr->UST = CHSL_WRS|CHSL_3RD; /* next state */ 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/Ibm1130/ibm1130_cr.c b/Ibm1130/ibm1130_cr.c index 6d262da4..cc01d941 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 } @@ -2580,7 +2580,8 @@ static t_stat pcr_svc (UNIT *uptr) break; case OP_READING: - if (pcr_nready >= 2) { /* if there is a whole column buffered, simulate column interrupt/* pcr_trigger_interrupt_0 - simulate a read response interrupt so OS will read queued column data */ + if (pcr_nready >= 2) { /* if there is a whole column buffered, simulate column interrupt*/ + /* pcr_trigger_interrupt_0 - simulate a read response interrupt so OS will read queued column data */ pcr_trigger_interrupt_0(); sim_activate(&cr_unit, cr_wait); /* keep checking frequently */ diff --git a/Ibm1130/ibm1130_sca.c b/Ibm1130/ibm1130_sca.c index 1e41d3c8..b0e8e293 100644 --- a/Ibm1130/ibm1130_sca.c +++ b/Ibm1130/ibm1130_sca.c @@ -217,7 +217,7 @@ REG sca_reg[] = { /* DEVICE STATE/SETTABLE PARAMETERS: */ { HRDATA (SCADSW, sca_dsw, 16) }, /* device status word */ { DRDATA (SICHAR, sichar, 8), PV_LEFT }, /* sync/idle character */ { DRDATA (RCVDCHAR, rcvd_char, 8), PV_LEFT }, /* most recently received character */ - { DRDATA (FRAME, sca_frame, 8), PV_LEFT }, /* frame bits (6, 7 or 8) + { DRDATA (FRAME, sca_frame, 8), PV_LEFT }, /* frame bits (6, 7 or 8) */ { DRDATA (SCASTATE, sca_state, 32), PV_LEFT }, /* current state */ { DRDATA (CTIME, sca_cwait, 32), PV_LEFT }, /* inter-character wait */ { DRDATA (ITIME, sca_iwait, 32), PV_LEFT }, /* idle wait (polling interval for socket connects) */ 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; } } diff --git a/Interdata/id16_cpu.c b/Interdata/id16_cpu.c index fdf38ae5..2a5605c2 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: @@ -604,7 +604,7 @@ while (reason == 0) { /* loop until halted */ int32 sr, st; if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; int_eval (); } diff --git a/Interdata/id32_cpu.c b/Interdata/id32_cpu.c index 969b954b..6b874df3 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 @@ -664,7 +664,7 @@ while (reason == 0) { /* loop until halted */ int32 sr, st; if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; int_eval (); } 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_defs.h b/Interdata/id_defs.h index 77b643dd..2afd3446 100644 --- a/Interdata/id_defs.h +++ b/Interdata/id_defs.h @@ -1,6 +1,6 @@ /* id_defs.h: Interdata 16b/32b simulator definitions - Copyright (c) 2000-2010, Robert M. Supnik + Copyright (c) 2000-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 @@ The author gratefully acknowledges the help of Carl Friend and Al Kossow, who provided key documents about the Interdata product line. + 18-Apr-12 RMS Added clock coschedule prototype 22-May-10 RMS Added check for 64b definitions 09-Mar-06 RMS Increased register sets to architectural limit 25-Jan-04 RMS Removed local logging support @@ -483,4 +484,6 @@ t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_sch (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc); +int32 lfc_cosched (int32 wait); + #endif diff --git a/Interdata/id_dp.c b/Interdata/id_dp.c index a62bf33f..cf3f82c2 100644 --- a/Interdata/id_dp.c +++ b/Interdata/id_dp.c @@ -419,7 +419,7 @@ switch (dp_cmd & 0x7) { /* case on func */ if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* sch transfer? */ if (dp_dter (uptr, dp_1st)) /* check xfr err */ return SCPE_OK; - if (r = dp_rds (uptr)) /* read sec, err? */ + if ((r = dp_rds (uptr))) /* read sec, err? */ return r; dp_1st = 0; t = sch_wrmem (dp_dib.sch, dpxb, DP_NUMBY); /* write to memory */ @@ -438,7 +438,7 @@ switch (dp_cmd & 0x7) { /* case on func */ return SCPE_OK; dp_bptr = sch_rdmem (dp_dib.sch, dpxb, DP_NUMBY); /* read from mem */ dp_db = dpxb[dp_bptr - 1]; /* last byte */ - if (r = dp_wds (uptr)) /* write sec, err? */ + if ((r = dp_wds (uptr))) /* write sec, err? */ return r; dp_1st = 0; if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */ diff --git a/Interdata/id_fd.c b/Interdata/id_fd.c index 12654c9c..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,11 +77,11 @@ #define STA_WRP 0x80 /* *write prot */ #define STA_DEF 0x40 /* def track NI */ -#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 */ @@ -329,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..f888ba6a 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 @@ -96,7 +96,7 @@ /* Drive status, ^ = dynamic, * = in unit status */ #define STD_WRP 0x80 /* ^write prot */ -/* 0x40 /* unused */ +/* 0x40 *//* unused */ #define STD_ACH 0x20 /* alt chan busy NI */ #define STD_UNS 0x10 /* *unsafe */ #define STD_NRDY 0x08 /* ^not ready */ @@ -576,7 +576,7 @@ switch (uptr->FNC & CMC_MASK) { /* case on func */ if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */ if (idc_dter (uptr, idc_1st)) /* dte? done */ return SCPE_OK; - if (r = idc_rds (uptr)) /* read sec, err? */ + if ((r = idc_rds (uptr))) /* read sec, err? */ return r; idc_1st = 0; t = sch_wrmem (idc_dib.sch, idcxb, IDC_NUMBY); /* write mem */ @@ -595,7 +595,7 @@ switch (uptr->FNC & CMC_MASK) { /* case on func */ return SCPE_OK; idc_bptr = sch_rdmem (idc_dib.sch, idcxb, IDC_NUMBY); /* read mem */ idc_db = idcxb[idc_bptr - 1]; /* last byte */ - if (r = idc_wds (uptr)) /* write sec, err? */ + if ((r = idc_wds (uptr))) /* write sec, err? */ return r; idc_1st = 0; if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */ diff --git a/Interdata/id_io.c b/Interdata/id_io.c index 98ce4a1d..4ba20a23 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: @@ -358,7 +358,7 @@ if ((r != SCPE_OK) || (newmax == sch_max)) /* err or no chg? */ if (newmax == 0) /* must be > 0 */ return SCPE_ARG; if (newmax < sch_max) { /* reducing? */ - for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ + for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && (dibp->sch >= (int32) newmax)) { /* dev using chan? */ printf ("Device %02X uses channel %d\n", @@ -439,7 +439,7 @@ int32 i, j, t; uint32 r; for (i = t = 0; i < INTSZ; i++) { /* loop thru array */ - if (r = int_req[i] & int_enb[i]) { /* find nz int wd */ + if ((r = int_req[i] & int_enb[i])) { /* find nz int wd */ for (j = 0; j < 32; t++, j++) { if (r & (1u << j)) { int_req[i] = int_req[i] & ~(1u << j); /* clr request */ @@ -630,7 +630,7 @@ for (i = 0; i < (DEVNO / 32); i++) /* Test each device for conflict; add to map; init tables */ -for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ +for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */ continue; 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_mt.c b/Interdata/id_mt.c index fce949fa..f71a5f18 100644 --- a/Interdata/id_mt.c +++ b/Interdata/id_mt.c @@ -368,13 +368,13 @@ switch (uptr->UCMD) { /* case on function */ } if (mt_bptr) { /* any chars? */ - if (st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)) /* write, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)))/* write, err? */ r = mt_map_err (uptr, st); /* map error */ } break; /* record done */ case MTC_WEOF: /* write eof */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ mt_sta = mt_sta | STA_EOF; /* set eof */ if (mt_arm[u]) /* set intr */ @@ -402,7 +402,7 @@ switch (uptr->UCMD) { /* case on function */ break; case MTC_SPCR: /* backspace */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* skip rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* skip rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; } /* end case */ diff --git a/Interdata/id_pas.c b/Interdata/id_pas.c index 15ccf7e3..3e2d105a 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,8 @@ pas Programmable asynchronous line adapter(s) + 18-Apr-12 RMS Revised to use clock coscheduling + 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 @@ -318,7 +320,7 @@ int32 ln, c, out; if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_OK; -sim_activate (uptr, lfc_poll); /* continue poll */ +sim_activate (uptr, lfc_cosched (lfc_poll)); /* continue poll */ ln = tmxr_poll_conn (&pas_desc); /* look for connect */ if (ln >= 0) { /* got one? */ if ((pasl_unit[ln].flags & UNIT_MDM) && /* modem control */ @@ -332,7 +334,7 @@ if (ln >= 0) { /* got one? */ tmxr_poll_rx (&pas_desc); /* poll for input */ for (ln = 0; ln < PAS_ENAB; ln++) { /* loop thru lines */ if (pas_ldsc[ln].conn) { /* connected? */ - if (c = tmxr_getc_ln (&pas_ldsc[ln])) { /* any char? */ + if ((c = tmxr_getc_ln (&pas_ldsc[ln]))) { /* any char? */ pas_sta[ln] = pas_sta[ln] & ~(STA_FR | STA_PF); if (pas_rchp[ln]) pas_sta[ln] = pas_sta[ln] | STA_OVR; @@ -345,7 +347,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 +380,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) { @@ -467,7 +469,7 @@ else { pasl_dev.flags = pasl_dev.flags & ~DEV_DIS; } if (pas_unit.flags & UNIT_ATT) /* master att? */ - sim_activate_abs (&pas_unit, lfc_poll); /* cosched with clock */ + sim_activate (&pas_unit, lfc_poll); else sim_cancel (&pas_unit); /* else stop */ for (i = 0; i < PAS_LINES; i++) pas_reset_ln (i); @@ -483,7 +485,7 @@ t_stat r; r = tmxr_attach (&pas_desc, uptr, cptr); /* attach */ if (r != SCPE_OK) /* error */ return r; -sim_activate_abs (uptr, 100); /* quick poll */ +sim_activate (uptr, 100); /* quick poll */ return SCPE_OK; } 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/Interdata/id_tt.c b/Interdata/id_tt.c index e56f4c7c..64bdc3f3 100644 --- a/Interdata/id_tt.c +++ b/Interdata/id_tt.c @@ -1,6 +1,6 @@ /* id_tt.c: Interdata teletype - Copyright (c) 2000-2008, Robert M. Supnik + Copyright (c) 2000-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 @@ tt console + 18-Apr-12 RMS Revised to use clock coscheduling 18-Jun-07 RMS Added UNIT_IDLE flag to console input 18-Oct-06 RMS Sync keyboard to LFC clock 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode @@ -183,7 +184,8 @@ t_stat tti_svc (UNIT *uptr) { int32 out, temp; -sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_cosched (lfc_poll))); + /* continue poll */ tt_sta = tt_sta & ~STA_BRK; /* clear break */ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return temp; @@ -239,7 +241,7 @@ t_stat tt_reset (DEVICE *dptr) { if (dptr->flags & DEV_DIS) /* dis? cancel poll */ sim_cancel (&tt_unit[TTI]); -else sim_activate_abs (&tt_unit[TTI], KBD_WAIT (tt_unit[TTI].wait, lfc_poll)); +else sim_activate (&tt_unit[TTI], KBD_WAIT (tt_unit[TTI].wait, lfc_poll)); sim_cancel (&tt_unit[TTO]); /* cancel output */ tt_rd = tt_fdpx = 1; /* read, full duplex */ tt_chp = 0; /* no char */ diff --git a/Interdata/id_ttp.c b/Interdata/id_ttp.c index e580d303..660fd469 100644 --- a/Interdata/id_ttp.c +++ b/Interdata/id_ttp.c @@ -1,6 +1,6 @@ /* id_ttp.c: Interdata PASLA console interface - Copyright (c) 2000-2008, Robert M. Supnik + Copyright (c) 2000-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 @@ ttp console (on PAS) + 18-Apr-12 RMS Revised to use clock coscheduling 18-Jun-07 RMS Added UNIT_IDLE flag to console input 18-Oct-06 RMS Sync keyboard to LFC clock 22-Nov-05 RMS Revised for new terminal processing routines @@ -179,7 +180,8 @@ t_stat ttpi_svc (UNIT *uptr) { int32 c, out; -sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_cosched (lfc_poll))); + /* continue poll */ ttp_sta = ttp_sta & ~STA_FR; /* clear break */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; @@ -237,7 +239,7 @@ t_stat ttp_reset (DEVICE *dptr) { if (dptr->flags & DEV_DIS) sim_cancel (&ttp_unit[TTI]); -else sim_activate_abs (&ttp_unit[TTI], KBD_WAIT (ttp_unit[TTI].wait, lfc_poll)); +else sim_activate (&ttp_unit[TTI], KBD_WAIT (ttp_unit[TTI].wait, lfc_poll)); sim_cancel (&ttp_unit[TTO]); CLR_INT (v_TTP); /* clear int */ CLR_ENB (v_TTP); diff --git a/Interdata/id_uvc.c b/Interdata/id_uvc.c index d94b2a65..7ccc070a 100644 --- a/Interdata/id_uvc.c +++ b/Interdata/id_uvc.c @@ -1,6 +1,6 @@ /* id_uvc.c: Interdata universal clock - 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"), @@ -26,6 +26,7 @@ pic precision incremental clock lfc line frequency clock + 18-Apr-12 RMS Added lfc_cosched routine 18-Jun-07 RMS Added UNIT_IDLE flag 18-Oct-06 RMS Changed LFC to be free running, export tmr_poll 23-Jul-05 RMS Fixed {} error in OC @@ -351,12 +352,22 @@ if (lfc_arm) { /* armed? */ return SCPE_OK; } +/* Clock coscheduling routine */ + +int32 lfc_cosched (int32 wait) +{ +int32 t; + +t = sim_is_active (&lfc_unit); +return (t? t - 1: wait); +} + /* Reset routine */ t_stat lfc_reset (DEVICE *dptr) { lfc_poll = sim_rtcn_init (lfc_unit.wait, TMR_LFC); -sim_activate_abs (&lfc_unit, lfc_poll); /* init clock */ +sim_activate (&lfc_unit, lfc_poll); /* init clock */ CLR_INT (v_LFC); /* clear int */ CLR_ENB (v_LFC); /* disable int */ lfc_arm = 0; /* disarm int */ diff --git a/LGP/lgp_cpu.c b/LGP/lgp_cpu.c index 87e040e8..27f2746c 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: @@ -288,7 +288,7 @@ if (lgp21_sov) { /* stop sense pending? * do { if (sim_interval <= 0) { /* check clock queue */ - if (r = sim_process_event ()) + if ((r = sim_process_event ())) break; } @@ -308,7 +308,7 @@ do { PC = (PC + 1) & AMASK; /* increment PC */ sim_interval = sim_interval - 1; - if (r = cpu_one_inst (oPC, IR)) { /* one instr; error? */ + if ((r = cpu_one_inst (oPC, IR))) { /* one instr; error? */ if (r == STOP_STALL) { /* stall? */ PC = oPC; /* back up PC */ delay = r = 0; /* no delay */ @@ -744,7 +744,7 @@ if (cptr) { else inst = IR; while ((r = cpu_one_inst (PC, inst)) == STOP_STALL) { sim_interval = 0; - if (r = sim_process_event ()) + if ((r = sim_process_event ())) return r; } return r; 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/LGP/lgp_stddev.c b/LGP/lgp_stddev.c index 2dba6cc1..f86ac096 100644 --- a/LGP/lgp_stddev.c +++ b/LGP/lgp_stddev.c @@ -394,7 +394,7 @@ t_stat ttr_svc (UNIT *uptr) { t_stat r; -if (r = read_reader (uptr, ttr_stopioe, (int32 *) &tti_buf)) +if ((r = read_reader (uptr, ttr_stopioe, (int32 *) &tti_buf))) return r; if (!(uptr->flags & UNIT_NOCS) && /* cstop enable? */ (tti_buf == FLEX_CSTOP)) /* cond stop? */ @@ -415,7 +415,7 @@ t_stat ptr_svc (UNIT *uptr) { t_stat r; -if (r = read_reader (uptr, ptr_stopioe, &uptr->buf)) +if ((r = read_reader (uptr, ptr_stopioe, &uptr->buf))) return r; if (uptr->buf == FLEX_CSTOP) /* cond stop? */ inp_done = 1; @@ -548,7 +548,7 @@ else { ch = '\b'; else ch = flex_to_ascii[flex | (tto_uc << 6)]; /* cvt flex to ascii */ if (ch > 0) { /* legit? */ - if (r = sim_putchar_s (ch)) /* write char */ + if ((r = sim_putchar_s (ch))) /* write char */ return r; tto_unit[0].pos = tto_unit[0].pos + 1; if (flex == FLEX_CR) { /* cr? */ diff --git a/LGP/lgp_sys.c b/LGP/lgp_sys.c index f445e202..083a3025 100644 --- a/LGP/lgp_sys.c +++ b/LGP/lgp_sys.c @@ -363,7 +363,7 @@ if ((sw & SWMASK ('L')) || /* LGP hex? */ return SCPE_OK; if (islower (c)) c = toupper (c); - if (tptr = strchr (hex_decode, c)) + if ((tptr = strchr (hex_decode, c))) val[0] = (val[0] << 4) | (tptr - hex_decode); else return SCPE_ARG; } @@ -388,7 +388,7 @@ else sgn = 0; cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ if (gbuf[1] != 0) return SCPE_ARG; -if (tptr = strchr (opcode, gbuf[0])) +if ((tptr = strchr (opcode, gbuf[0]))) val[0] = ((tptr - opcode) << I_V_OP) | sgn; /* merge opcode */ else return SCPE_ARG; cptr = get_glyph (cptr, gbuf, 0); /* get address */ diff --git a/NOVA/eclipse_cpu.c b/NOVA/eclipse_cpu.c index 50f0bfcf..c855cc55 100644 --- a/NOVA/eclipse_cpu.c +++ b/NOVA/eclipse_cpu.c @@ -2,7 +2,7 @@ Modified from the original NOVA simulator by Robert Supnik. - Copyright (c) 1998-2006, Charles E Owen + Copyright (c) 1998-2012, Charles E Owen Portions Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a @@ -28,8 +28,9 @@ cpu Eclipse central processor - 07-Jun-06 RMS Fixed bug in DIVS (found by Mark Hittinger) - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 25-Mar-12 RMS Fixed declarations (Mark Pizzolato) + 07-Jun-06 RMS Fixed bug in DIVS (Mark Hittinger) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 25-Aug-05 RMS Fixed DIVS overflow cases 29-Nov-03 CEO Corrected POPJ and Bit operations bugs 26-Nov-03 CEO Added FPU and PIT devices @@ -743,7 +744,7 @@ if (MapInit == 0) { while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } 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_defs.h b/NOVA/nova_defs.h index 1dabed0e..5f5f6ffa 100644 --- a/NOVA/nova_defs.h +++ b/NOVA/nova_defs.h @@ -1,6 +1,6 @@ /* nova_defs.h: NOVA/Eclipse simulator definitions - Copyright (c) 1993-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,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. + 25-Mar-12 RMS Added missing parameters to prototypes (Mark Pizzolato) 22-May-10 RMS Added check for 64b definitions 04-Jul-07 BKR BUSY/DONE/INTR "convenience" macros added, INT_TRAP added for Nova 3, 4 trap instruction handling, diff --git a/NOVA/nova_dkp.c b/NOVA/nova_dkp.c index a89edf6e..f5126f28 100644 --- a/NOVA/nova_dkp.c +++ b/NOVA/nova_dkp.c @@ -25,6 +25,7 @@ dkp moving head disk + 27-Apr-12 RMS Changed ??? string digraphs to ?, per C rules 04-Jul-04 BKR device name changed to DG's DKP from DEC's DP, DEV_SET/CLR/INTR macro use started, fixed 'P' pulse code and secret quirks, @@ -706,7 +707,7 @@ if ( DKP_TRACE(1) ) "write" : ((uptr->FUNC == FCCY_SEEK) ? "seek" - : "" + : "" ) ) ), @@ -871,7 +872,7 @@ do { "read" : ((uptr->FUNC == FCCY_WRITE) ? "write" - : "") + : "") ), (unsigned) (uptr->CYL), (unsigned) (GET_SURF(dkp_ussc, dtype)), @@ -908,7 +909,7 @@ do { if (uptr->FUNC == FCCY_READ) { /* read? */ awc = fxread (tbuf, sizeof(uint16), DKP_NUMWD, uptr->fileref); for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0; - if (err = ferror (uptr->fileref)) + if ((err = ferror (uptr->fileref))) break; for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */ pa = MapAddr (dkp_map, (dkp_ma & AMASK)); @@ -924,7 +925,7 @@ do { dkp_ma = (dkp_ma + 1) & AMASK; } fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) + if ((err = ferror (uptr->fileref))) break; } 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..25a9ec1e 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 @@ -412,7 +412,7 @@ else switch (c) { /* case on command */ mtxb[p++] = M[pa] & 0377; mta_ma = (mta_ma + 1) & AMASK; } - if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) { /* write rec, err? */ r = mta_map_err (uptr, st); /* map error */ mta_ma = (mta_ma - wc) & AMASK; /* restore wc */ } @@ -421,7 +421,7 @@ else switch (c) { /* case on command */ break; case CU_WREOF: /* write eof */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mta_map_err (uptr, st); /* map error */ else mta_upddsta (uptr, uptr->USTAT | STA_EOF | STA_RDY); break; @@ -435,7 +435,7 @@ else switch (c) { /* case on command */ case CU_SPACEF: /* space forward */ do { mta_wc = (mta_wc + 1) & DMASK; /* incr wc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = mta_map_err (uptr, st); /* map error */ break; } @@ -447,7 +447,7 @@ else switch (c) { /* case on command */ case CU_SPACER: /* space reverse */ do { mta_wc = (mta_wc + 1) & DMASK; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = mta_map_err (uptr, st); /* map error */ break; } @@ -493,10 +493,10 @@ if ((uptr->flags & UNIT_ATT) == 0) /* offline? */ change = (uptr->USTAT ^ newsta) & STA_MON; /* changes? */ uptr->USTAT = newsta & STA_DYN; /* update status */ if (change) { -/* if (mta_ep) { /* if polling */ -/* u = uptr - mta_dev.units; /* unit num */ -/* mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT); -/* set polling interupt... +/* if (mta_ep) { *//* if polling */ +/* u = uptr - mta_dev.units; *//* unit num */ +/* mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT); */ +/* set polling interupt... */ /* } */ mta_sta = mta_sta | STA_CHG; /* flag change */ } diff --git a/NOVA/nova_sys.c b/NOVA/nova_sys.c index 4b066f54..36a4cf22 100644 --- a/NOVA/nova_sys.c +++ b/NOVA/nova_sys.c @@ -1,6 +1,6 @@ /* nova_sys.c: NOVA simulator interface - 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"), @@ -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. + 25-Mar-12 RMS Fixed declaration (Mark Pizzolato) 04-Jul-07 BKR DEC's IOF/ION changed to DG's INTDS/INTEN mnemonic, Fixed QTY/ADCV device name, RDSW changed to DDG's READS mnemonic, @@ -41,7 +42,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/NOVA/nova_tt1.c b/NOVA/nova_tt1.c index 0b495651..cffad5e9 100644 --- a/NOVA/nova_tt1.c +++ b/NOVA/nova_tt1.c @@ -184,7 +184,7 @@ int32 temp, newln; if (tt1_ldsc.conn) { /* connected? */ tmxr_poll_rx (&tt_desc); /* poll for input */ - if (temp = tmxr_getc_ln (&tt1_ldsc)) { /* get char */ + if ((temp = tmxr_getc_ln (&tt1_ldsc))) { /* get char */ uptr->buf = temp & 0177; if ((uptr->flags & UNIT_DASHER) && (uptr->buf == '\r')) diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index 40e2a910..d52a6a31 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 @@ -545,7 +546,7 @@ reason = 0; while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; sbs_lvl = sbs_eval (); /* eval sbs system */ } @@ -609,25 +610,25 @@ while (reason == 0) { /* loop until halted */ /* Logical, load, store instructions */ case 001: /* AND */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = AC & MB; break; case 002: /* IOR */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = AC | MB; break; case 003: /* XOR */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = AC ^ MB; break; @@ -637,9 +638,9 @@ while (reason == 0) { /* loop until halted */ reason = STOP_XCT; break; } - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; xct_count = xct_count + 1; /* count XCT's */ IR = MB; /* get instruction */ @@ -647,9 +648,9 @@ while (reason == 0) { /* loop until halted */ case 005: /* LCH */ if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if (reason = Ea_ch (IR, &byno)) /* MA <- eff addr */ + if ((reason = Ea_ch (IR, &byno))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = (MB << byt_shf[byno]) & 0770000; /* extract byte */ } @@ -658,9 +659,9 @@ while (reason == 0) { /* loop until halted */ case 006: /* DCH */ if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if (reason = Ea_ch (IR, &byno)) /* MA <- eff addr */ + if ((reason = Ea_ch (IR, &byno))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; MB = (MB & ~(0770000 >> byt_shf[byno])) | /* insert byte */ ((AC & 0770000) >> byt_shf[byno]); @@ -682,55 +683,55 @@ while (reason == 0) { /* loop until halted */ break; case 010: /* LAC */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = MB; break; case 011: /* LIO */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; IO = MB; break; case 012: /* DAC */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; MB = AC; reason = Write (); break; case 013: /* DAP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; MB = (AC & DAMASK) | (MB & ~DAMASK); reason = Write (); break; case 014: /* DIP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; MB = (AC & ~DAMASK) | (MB & DAMASK); reason = Write (); break; case 015: /* DIO */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; MB = IO; reason = Write (); break; case 016: /* DZM */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; MB = 0; reason = Write (); @@ -754,9 +755,9 @@ while (reason == 0) { /* loop until halted */ case 017: /* TAD */ if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = AC + MB + ((PF & PF_L)? 1: 0); /* AC + opnd + L */ if (AC > DMASK) /* carry? set L */ @@ -768,9 +769,9 @@ while (reason == 0) { /* loop until halted */ break; case 020: /* ADD */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; t = AC; AC = AC + MB; @@ -783,9 +784,9 @@ while (reason == 0) { /* loop until halted */ break; case 021: /* SUB */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; t = AC ^ DMASK; /* complement AC */ AC = t + MB; /* -AC + MB */ @@ -797,9 +798,9 @@ while (reason == 0) { /* loop until halted */ break; case 022: /* IDX */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = MB + 1; if (AC >= DMASK) @@ -809,9 +810,9 @@ while (reason == 0) { /* loop until halted */ break; case 023: /* ISP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = MB + 1; if (AC >= DMASK) @@ -823,18 +824,18 @@ while (reason == 0) { /* loop until halted */ break; case 024: /* SAD */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; if (AC != MB) PC = INCR_ADDR (PC); break; case 025: /* SAS */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; if (AC == MB) PC = INCR_ADDR (PC); @@ -862,7 +863,7 @@ while (reason == 0) { /* loop until halted */ hst[hst_p].ea = PC; } else { /* normal JMP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; PCQ_ENTRY; PC = MA; @@ -870,7 +871,7 @@ while (reason == 0) { /* loop until halted */ break; case 031: /* JSP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; AC = EPC_WORD; PCQ_ENTRY; @@ -888,9 +889,9 @@ while (reason == 0) { /* loop until halted */ */ case 026: /* MUL */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; if (cpu_unit.flags & UNIT_MDV) { /* hardware? */ sign = AC ^ MB; /* result sign */ @@ -918,9 +919,9 @@ while (reason == 0) { /* loop until halted */ break; case 027: /* DIV */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; if (cpu_unit.flags & UNIT_MDV) { /* hardware */ sign = AC ^ MB; /* result sign */ @@ -1361,13 +1362,13 @@ t_stat r; MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */ if (IR & IA) { /* indirect addr? */ if (extm) { /* extend? */ - if (r = Read ()) /* read; err? */ + if ((r = Read ())) /* read; err? */ return r; MA = MB & AMASK; /* one level */ } else { /* multi-level */ for (i = 0; i < ind_max; i++) { /* count indirects */ - if (r = Read ()) /* get ind word */ + if ((r = Read ())) /* get ind word */ return r; MA = (PC & EPCMASK) | (MB & DAMASK); if ((MB & IA) == 0) @@ -1391,12 +1392,12 @@ t_stat r; MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */ if (extm) { /* extend? */ - if (r = Read ()) /* read; err? */ + if ((r = Read ())) /* read; err? */ return r; } else { /* multi-level */ for (i = 0; i < ind_max; i++) { /* count indirects */ - if (r = Read ()) /* get ind word */ + if ((r = Read ())) /* get ind word */ return r; if ((MB & IA) == 0) break; @@ -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_dcs.c b/PDP1/pdp1_dcs.c index dd54ce18..93c9eefc 100644 --- a/PDP1/pdp1_dcs.c +++ b/PDP1/pdp1_dcs.c @@ -251,7 +251,7 @@ if (ln >= 0) { /* got one? */ tmxr_poll_rx (&dcs_desc); /* poll for input */ for (ln = 0; ln < DCS_NUMLIN; ln++) { /* loop thru lines */ if (dcs_ldsc[ln].conn) { /* connected? */ - if (c = tmxr_getc_ln (&dcs_ldsc[ln])) { /* get char */ + if ((c = tmxr_getc_ln (&dcs_ldsc[ln]))) { /* get char */ if (c & SCPE_BREAK) /* break? */ c = 0; else c = sim_tt_inpcvt (c, TT_GET_MODE (dcsl_unit[ln].flags)|TTUF_KSR); 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/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index b73e88c0..37cf218b 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -1,6 +1,6 @@ /* pdp10_cpu.c: PDP-10 CPU simulator - Copyright (c) 1993-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,9 +25,10 @@ cpu KS10 central processor + 25-Mar-12 RMS Added missing parameters to prototypes (Mark Pizzolato) 17-Jul-07 RMS Fixed non-portable usage in SHOW HISTORY 28-Apr-07 RMS Removed clock initialization - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) Fixed warning in MOVNI 16-Aug-05 RMS Fixed C++ declaration and cast problems 10-Nov-04 RMS Added instruction history @@ -704,7 +705,7 @@ pager_tc = FALSE; /* not in trap cycle */ pflgs = 0; /* not in PXCT */ xct_cnt = 0; /* count XCT's */ if (sim_interval <= 0) { /* check clock queue */ - if (i = sim_process_event ()) /* error? stop sim */ + if ((i = sim_process_event ())) /* error? stop sim */ ABORT (i); pi_eval (); /* eval pi system */ } @@ -718,7 +719,7 @@ if (sim_interval <= 0) { /* check clock queue */ if (qintr) { int32 vec, uba; pager_pi = TRUE; /* flag in pi seq */ - if (vec = pi_ub_vec (qintr, &uba)) { /* Unibus interrupt? */ + if ((vec = pi_ub_vec (qintr, &uba))) { /* Unibus interrupt? */ mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */ if (mb == 0) /* invalid? stop */ ABORT (STOP_ZERINT); @@ -864,8 +865,8 @@ case 0037: Write (040, UUOWORD, MM_CUR); /* store op, ac, ea */ /* Floating point, bytes, multiple precision (0100 - 0177) */ -/* case 0100: MUUO /* UJEN */ -/* case 0101: MUUO /* unassigned */ +/* case 0100: MUUO *//* UJEN */ +/* case 0101: MUUO *//* unassigned */ case 0102: if (Q_ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */ inst = Read (ea, MM_OPND); pflgs = pflgs | ac; @@ -878,10 +879,10 @@ case 0103: if (Q_ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) goto XCT; } goto MUUO; -/* case 0104: MUUO /* JSYS (T20) */ +/* case 0104: MUUO *//* JSYS (T20) */ case 0105: AC(ac) = adjsp (AC(ac), ea); break; /* ADJSP */ -/* case 0106: MUUO /* GFMP (KL)*/ -/* case 0107: MUUO /* GFDV (KL) */ +/* case 0106: MUUO *//* GFMP (KL)*/ +/* case 0107: MUUO *//* GFDV (KL) */ case 0110: RD2; dfad (ac, rs, 0); break; /* DFAD */ case 0111: RD2; dfad (ac, rs, 1); break; /* DFSB */ case 0112: RD2; dfmp (ac, rs); break; /* DFMP */ @@ -908,8 +909,8 @@ case 0124: G2AC; WR2; break; /* DMOVEM */ case 0125: G2AC; DMOVN (rs); WR2; DMOVNF; break; /* DMOVNM */ case 0126: RD; fix (ac, mb, 1); break; /* FIXR */ case 0127: RD; AC(ac) = fltr (mb); break; /* FLTR */ -/* case 0130: MUUO /* UFA */ -/* case 0131: MUUO /* DFN */ +/* case 0130: MUUO *//* UFA */ +/* case 0131: MUUO *//* DFN */ case 0132: AC(ac) = fsc (AC(ac), ea); break; /* FSC */ case 0133: if (!ac) /* IBP */ ibp (ea, pflgs); @@ -919,7 +920,7 @@ case 0135: LDB; break; /* LDB */ case 0136: CIBP; DPB; CLRF (F_FPD); break; /* IDBP */ case 0137: DPB; break; /* DPB */ case 0140: RD; AC(ac) = FAD (mb); break; /* FAD */ -/* case 0141: MUUO /* FADL */ +/* case 0141: MUUO *//* FADL */ case 0142: RM; mb = FAD (mb); WR; break; /* FADM */ case 0143: RM; AC(ac) = FAD (mb); WRAC; break; /* FADB */ case 0144: RD; AC(ac) = FADR (mb); break; /* FADR */ @@ -927,7 +928,7 @@ case 0145: AC(ac) = FADR (IMS); break; /* FADRI */ case 0146: RM; mb = FADR (mb); WR; break; /* FADRM */ case 0147: RM; AC(ac) = FADR (mb); WRAC; break; /* FADRB */ case 0150: RD; AC(ac) = FSB (mb); break; /* FSB */ -/* case 0151: MUUO /* FSBL */ +/* case 0151: MUUO *//* FSBL */ case 0152: RM; mb = FSB (mb); WR; break; /* FSBM */ case 0153: RM; AC(ac) = FSB (mb); WRAC; break; /* FSBB */ case 0154: RD; AC(ac) = FSBR (mb); break; /* FSBR */ @@ -935,7 +936,7 @@ case 0155: AC(ac) = FSBR (IMS); break; /* FSBRI */ case 0156: RM; mb = FSBR (mb); WR; break; /* FSBRM */ case 0157: RM; AC(ac) = FSBR (mb); WRAC; break; /* FSBRB */ case 0160: RD; AC(ac) = FMP (mb); break; /* FMP */ -/* case 0161: MUUO /* FMPL */ +/* case 0161: MUUO *//* FMPL */ case 0162: RM; mb = FMP (mb); WR; break; /* FMPM */ case 0163: RM; AC(ac) = FMP (mb); WRAC; break; /* FMPB */ case 0164: RD; AC(ac) = FMPR (mb); break; /* FMPR */ @@ -943,7 +944,7 @@ case 0165: AC(ac) = FMPR (IMS); break; /* FMPRI */ case 0166: RM; mb = FMPR (mb); WR; break; /* FMPRM */ case 0167: RM; AC(ac) = FMPR (mb); WRAC; break; /* FMPRB */ case 0170: RD; if (FDV (mb)) S1AC; break; /* FDV */ -/* case 0171: MUUO /* FDVL */ +/* case 0171: MUUO *//* FDVL */ case 0172: RM; if (FDV (mb)) WR1; break; /* FDVM */ case 0173: RM; if (FDV (mb)) { S1AC; WRAC; } break; /* FDVB */ case 0174: RD; if (FDVR (mb)) S1AC; break; /* FDVR */ @@ -1007,7 +1008,7 @@ case 0250: RM; WRAC; AC(ac) = mb; break; /* EXCH */ case 0251: blt (ac, ea, pflgs); break; /* BLT */ case 0252: AOBAC; if (TGE (AC(ac))) JUMP (ea); break; /* AOBJP */ case 0253: AOBAC; if (TL (AC(ac))) JUMP (ea); break; /* AOBJN */ -/* case 0254: /* shown later /* JRST */ +/* case 0254: *//* shown later *//* JRST */ case 0255: if (flags & (ac << 14)) { /* JFCL */ JUMP (ea); CLRF (ac << 14); @@ -2018,7 +2019,7 @@ int32 test_int (void) int32 t; if (sim_interval <= 0) { /* check queue */ - if (t = sim_process_event ()) /* IO event? */ + if ((t = sim_process_event ())) /* IO event? */ return t; if (pi_eval ()) /* interrupt? */ return (INTERRUPT); diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index a6eea9cb..d076dbd9 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -587,9 +587,9 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* Unibus I/O constants */ #define READ 0 /* PDP11 compatible */ -/* #define READC 1 /* console read */ +/* #define READC 1 *//* console read */ #define WRITE 2 -/* #define WRITEC 3 /* console write */ +/* #define WRITEC 3 *//* console write */ #define WRITEB 4 #define IO_V_UBA 18 /* UBA in I/O addr */ #define IO_N_UBA 16 /* max num of UBA's */ diff --git a/PDP10/pdp10_fe.c b/PDP10/pdp10_fe.c index 43df088c..97cbb20d 100644 --- a/PDP10/pdp10_fe.c +++ b/PDP10/pdp10_fe.c @@ -1,6 +1,6 @@ /* pdp10_fe.c: PDP-10 front end (console terminal) simulator - Copyright (c) 1993-2007, 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 @@ fe KS10 console front end + 18-Apr-12 RMS Added clock coscheduling 18-Jun-07 RMS Added UNIT_IDLE flag to console input 17-Oct-06 RMS Synced keyboard to clock for idling 28-May-04 RMS Removed SET FE CTRL-C @@ -142,7 +143,8 @@ t_stat fei_svc (UNIT *uptr) { int32 temp; -sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll))); + /* continue poll */ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return temp; if (temp & SCPE_BREAK) /* ignore break */ @@ -161,7 +163,7 @@ t_stat fe_reset (DEVICE *dptr) fei_unit.buf = feo_unit.buf = 0; M[FE_CTYIN] = M[FE_CTYOUT] = 0; apr_flg = apr_flg & ~(APRF_ITC | APRF_CON); -sim_activate_abs (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll)); +sim_activate (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll)); return SCPE_OK; } diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c index b37e8039..e71f773c 100644 --- a/PDP10/pdp10_ksio.c +++ b/PDP10/pdp10_ksio.c @@ -401,7 +401,7 @@ uint32 pa = (uint32) ea; int32 i, n, val; DIB *dibp; -for (i = 0; dibp = dib_tab[i]; i++ ) { +for (i = 0; (dibp = dib_tab[i]); i++ ) { if ((pa >= dibp->ba) && (pa < (dibp->ba + dibp->lnt))) { dibp->rd (&val, pa, READ); @@ -418,7 +418,7 @@ uint32 pa = (uint32) ea; int32 i, n; DIB *dibp; -for (i = 0; dibp = dib_tab[i]; i++ ) { +for (i = 0; (dibp = dib_tab[i]); i++ ) { if ((pa >= dibp->ba) && (pa < (dibp->ba + dibp->lnt))) { dibp->wr ((int32) val, pa, mode); diff --git a/PDP10/pdp10_lp20.c b/PDP10/pdp10_lp20.c index 64f2ccba..fec1cda6 100644 --- a/PDP10/pdp10_lp20.c +++ b/PDP10/pdp10_lp20.c @@ -58,10 +58,10 @@ #define TX_DMASK 07777 #define TX_V_FL 8 /* flags */ #define TX_M_FL 017 -/* define TX_INTR 04000 /* interrupt */ +/* define TX_INTR 04000 *//* interrupt */ #define TX_DELH 02000 /* delimiter */ -/* define TX_XLAT 01000 /* translate */ -/* define TX_DVFU 00400 /* DAVFU */ +/* define TX_XLAT 01000 *//* translate */ +/* define TX_DVFU 00400 *//* DAVFU */ #define TX_SLEW 00020 /* chan vs slew */ #define TX_VMASK 00017 /* spacing mask */ #define TX_CHR 0 /* states: pr char */ @@ -563,7 +563,7 @@ lp20_unit.pos = ftell (lp20_unit.fileref); /* print 'n' newlines */ if (dvuadv) /* update DAVFU ptr */ dvptr = (dvptr + cnt) % dvlnt; if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */ - if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */ + if ((lppagc = (lppagc - 1) & PAGC_MASK)) { /* decr page cntr */ lpcsa = lpcsa & ~CSA_PZRO; /* update status */ return TRUE; } @@ -592,7 +592,7 @@ for (i = 0; i < dvlnt; i++) { /* search DAVFU */ lp20_adv (1, FALSE); fputc ('\f', lp20_unit.fileref); /* print form feed */ lp20_unit.pos = ftell (lp20_unit.fileref); - if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */ + if ((lppagc = (lppagc - 1) & PAGC_MASK)) { /* decr page cntr */ lpcsa = lpcsa & ~CSA_PZRO; /* update status */ return TRUE; } diff --git a/PDP10/pdp10_mdfp.c b/PDP10/pdp10_mdfp.c index 2aab8688..bf986e9d 100644 --- a/PDP10/pdp10_mdfp.c +++ b/PDP10/pdp10_mdfp.c @@ -493,7 +493,7 @@ if (a.fhi >= 2 * b.fhi) { /* will divide work? */ SETF (F_AOV | F_DCK | F_FOV | F_T1); return FALSE; } -if (savhi = a.fhi) { /* dvd = 0? quo = 0 */ +if ((savhi = a.fhi)) { /* dvd = 0? quo = 0 */ a.sign = a.sign ^ b.sign; /* result sign */ a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */ a.fhi = a.fhi / (b.fhi >> (FP_N_FHI + 1)); /* do divide */ diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index ad55f313..a5997728 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -951,7 +951,7 @@ switch (uptr->FUNC) { /* case on function */ if ((rpcs2 & CS2_UAI) == 0) ba = ba + 4; } - if (fc10 = twc10 & (RP_NUMWD - 1)) { /* fill? */ + if ((fc10 = twc10 & (RP_NUMWD - 1))) { /* fill? */ fc10 = RP_NUMWD - fc10; for (i = 0; i < fc10; i++) dbuf[twc10 + i] = 0; diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 78b1d2c0..24ec2d48 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 }; @@ -119,7 +118,7 @@ const char *sim_stop_messages[] = { #define EXE_DIR 01776 /* EXE directory */ #define EXE_VEC 01775 /* EXE entry vec */ #define EXE_PDV 01774 /* EXE ignored */ -#define EXE_END 01777 /* EXE end +#define EXE_END 01777 /* EXE end */ /* RIM10 loader diff --git a/PDP10/pdp10_tim.c b/PDP10/pdp10_tim.c index 726e06f4..c15cd503 100644 --- a/PDP10/pdp10_tim.c +++ b/PDP10/pdp10_tim.c @@ -1,6 +1,6 @@ /* pdp10_tim.c: PDP-10 tim subsystem simulator - Copyright (c) 1993-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 @@ tim timer subsystem + 18-Apr-12 RMS Removed absolute scheduling on reset 18-Jun-07 RMS Added UNIT_IDLE flag 03-Nov-06 RMS Rewritten to support idling 29-Oct-06 RMS Added clock coscheduling function @@ -239,7 +240,7 @@ tim_period = 0; /* clear timer */ tim_ttg = 0; apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */ tmr_poll = sim_rtc_init (tim_unit.wait); /* init timer */ -sim_activate_abs (&tim_unit, tmr_poll); /* activate unit */ +sim_activate (&tim_unit, tmr_poll); /* activate unit */ tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ return SCPE_OK; } diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index 0e73ec13..6be277b8 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -833,7 +833,7 @@ switch (fnc) { /* case on function */ case FNC_SPACEF: /* space forward */ do { tufc = (tufc + 1) & 0177777; /* incr fc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = tu_map_err (uptr, st, 0); /* map error */ break; } @@ -847,7 +847,7 @@ switch (fnc) { /* case on function */ case FNC_SPACER: /* space reverse */ do { tufc = (tufc + 1) & 0177777; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = tu_map_err (uptr, st, 0); /* map error */ break; } @@ -859,7 +859,7 @@ switch (fnc) { /* case on function */ break; case FNC_WREOF: /* write end of file */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = tu_map_err (uptr, st, 0); /* map error */ tufs = tufs | FS_ATA; break; @@ -889,7 +889,7 @@ switch (fnc) { /* case on function */ if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr)) tufs = tufs | FS_ID; /* PE BOT? ID burst */ TXFR (ba, wc, 0); /* validate transfer */ - if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */ + if ((st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR))) {/* read fwd */ if (st == MTSE_TMK) /* TMK also sets FCE */ set_tuer (ER_FCE); r = tu_map_err (uptr, st, 1); /* map error */ @@ -936,7 +936,7 @@ switch (fnc) { /* case on function */ } /* end for */ if (j < fc) /* short record? */ fc = j; - if (st = sim_tape_wrrecf (uptr, xbuf, fc)) /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, xbuf, fc))) /* write rec, err? */ r = tu_map_err (uptr, st, 1); /* map error */ else { tufc = (tufc + fc) & 0177777; @@ -951,7 +951,7 @@ switch (fnc) { /* case on function */ case FNC_WCHKR: /* wcheck = read */ tufc = 0; /* clear frame count */ TXFR (ba, wc, 1); /* validate xfer rev */ - if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */ + if ((st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR))) {/* read rev */ if (st == MTSE_TMK) /* TMK also sets FCE */ set_tuer (ER_FCE); r = tu_map_err (uptr, st, 1); /* map error */ diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c index 9c7fe51b..9f78f1bd 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: @@ -1134,7 +1134,7 @@ switch (op) { /* case on opcode */ result = (A2ADR << 16) | A2LNT; /* op in VAX format */ CVTLx: dst = Dstr0; /* clear result */ - if (dst.sign = GET_SIGN_L (result)) + if ((dst.sign = GET_SIGN_L (result))) result = (~result + 1) & 0xFFFFFFFF; for (i = 1; (i < (DSTRLNT * 8)) && result; i++) { digit = result % 10; @@ -1267,7 +1267,7 @@ for (i = 0; i < DSTRLNT; i++) { /* loop thru value */ mask = 0xFFFFFFFF; if (dst->val[i] & mask) /* test for ovflo */ V = 1; - if (dst->val[i] = dst->val[i] & ~mask) /* test nz */ + if ((dst->val[i] = dst->val[i] & ~mask)) /* test nz */ Z = 0; } dst->sign = dst->sign & ~unsignedtab[type] & ~(Z & ~V); @@ -1523,7 +1523,7 @@ uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin) { int32 i, s, nc; -if (s = sc * 4) { +if ((s = sc * 4)) { for (i = DSTRMAX; i >= 0; i--) { nc = (dsrc->val[i] << (32 - s)) & 0xFFFFFFFF; dsrc->val[i] = ((dsrc->val[i] >> s) | @@ -1548,7 +1548,7 @@ int32 i, s; uint32 nc, cin; cin = 0; -if (s = sc * 4) { +if ((s = sc * 4)) { for (i = 0; i < DSTRLNT; i++) { nc = dsrc->val[i] >> (32 - s); dsrc->val[i] = ((dsrc->val[i] << s) | cin) & 0xFFFFFFFF; diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 670a37ca..7f8eac70 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,21 @@ 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) + 29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato) + 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 +49,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 +83,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 @@ -304,7 +306,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[]; @@ -730,7 +732,7 @@ while (reason == 0) { if (trap_req) { /* check traps, ints */ trapea = 0; /* assume srch fails */ - if (t = trap_req & TRAP_ALL) { /* if a trap */ + if ((t = trap_req & TRAP_ALL)) { /* if a trap */ for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) { if ((t >> trapnum) & 1) { /* trap set? */ trapea = trap_vec[trapnum]; /* get vec, clr */ @@ -1291,7 +1293,7 @@ while (reason == 0) { break; case 070: /* CSM */ - if (CPUT (HAS_CSM) && (MMR3 & MMR3_CSM) || (cm != MD_KER)) { + if ((CPUT (HAS_CSM) && (MMR3 & MMR3_CSM)) || (cm != MD_KER)) { dst = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); PSW = get_PSW () & ~PSW_CC; /* PSW, cc = 0 */ STACKFILE[cm] = SP; diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index c30d5a88..faf5a2b2 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 @@ -1075,7 +1075,7 @@ t_stat r; for (i = 0; cnf_tab[i].dib != NULL; i++) { /* loop thru config tab */ if (((cnf_tab[i].cpum == 0) || (cpu_type & cnf_tab[i].cpum)) && ((cnf_tab[i].optm == 0) || (cpu_opt & cnf_tab[i].optm))) { - if (r = build_ubus_tab (&cpu_dev, cnf_tab[i].dib)) /* add to dispatch tab */ + if ((r = build_ubus_tab (&cpu_dev, cnf_tab[i].dib)))/* add to dispatch tab */ return r; } } diff --git a/PDP11/pdp11_cr.c b/PDP11/pdp11_cr.c index d8ee8258..521f3edd 100644 --- a/PDP11/pdp11_cr.c +++ b/PDP11/pdp11_cr.c @@ -589,7 +589,7 @@ static t_bool readCardASCII ( FILE *fp, char *ccard, char *acard ) { - int c, col; + int c = 0, col; assert (colStart < colEnd); assert (colStart >= 1); diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c index 1228538e..1c653fe8 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-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 @@ dci,dco DC11 terminal input/output + 18-Apr-2012 RMS Modified to use clock coscheduling + 17-Aug-2011 RMS Added AUTOCONFIGURE modifier 19-Nov-2008 RMS Revised for common TMXR show routines Revised to autoconfigure vectors @@ -175,6 +177,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", @@ -364,7 +368,7 @@ int32 ln, c, temp; if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_OK; -sim_activate (uptr, tmxr_poll); /* continue poll */ +sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */ ln = tmxr_poll_conn (&dcx_desc); /* look for connect */ if (ln >= 0) { /* got one? */ dcx_ldsc[ln].rcve = 1; /* set rcv enb */ diff --git a/PDP11/pdp11_dl.c b/PDP11/pdp11_dl.c index 00dff0ec..ec8cc9ab 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-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 @@ dli,dlo DL11 terminal input/output + 18-Apr-2012 RMS Modified to use clock coscheduling + 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 +144,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", @@ -327,7 +331,7 @@ int32 ln, c, temp; if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_OK; -sim_activate (uptr, tmxr_poll); /* continue poll */ +sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */ ln = tmxr_poll_conn (&dlx_desc); /* look for connect */ if (ln >= 0) { /* got one? rcv enb */ dlx_ldsc[ln].rcve = 1; @@ -342,7 +346,7 @@ if (ln >= 0) { /* got one? rcv enb */ tmxr_poll_rx (&dlx_desc); /* poll for input */ for (ln = 0; ln < DLX_LINES; ln++) { /* loop thru lines */ if (dlx_ldsc[ln].conn) { /* connected? */ - if (temp = tmxr_getc_ln (&dlx_ldsc[ln])) { /* get char */ + if ((temp = tmxr_getc_ln (&dlx_ldsc[ln]))) { /* get char */ if (temp & SCPE_BREAK) /* break? */ c = DLIBUF_ERR|DLIBUF_RBRK; else c = sim_tt_inpcvt (temp, TT_GET_MODE (dlo_unit[ln].flags)); diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index c0610364..5e96a6de 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 @@ -157,7 +157,7 @@ uint32 dz_rxi = 0; /* rcv interrupts */ uint32 dz_txi = 0; /* xmt interrupts */ int32 dz_mctl = 0; /* modem ctrl enabled */ int32 dz_auto = 0; /* autodiscon enabled */ -TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { 0 }; /* line descriptors */ +TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { {0} }; /* line descriptors */ TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, dz_ldsc }; /* mux descriptor */ /* debugging bitmaps */ @@ -435,7 +435,7 @@ if (t) { /* any enabled? */ dz_update_rcvi (); /* upd rcv intr */ tmxr_poll_tx (&dz_desc); /* poll output */ dz_update_xmti (); /* upd xmt intr */ - sim_activate (uptr, tmxr_poll); /* reactivate */ + sim_activate (uptr, clk_cosched (tmxr_poll)); /* reactivate */ } return SCPE_OK; } diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 1f18ac9a..fe7c9660 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 @@ -438,7 +438,7 @@ switch ((IR >> 8) & 017) { /* decode IR<11:8> */ else fac.l = ReadI (GeteaFP (dstspec, leni), dstspec, leni); fac.h = 0; if (fac.l) { - if (sign = GET_SIGN_L (fac.l)) + if ((sign = GET_SIGN_L (fac.l))) fac.l = (fac.l ^ 0xFFFFFFFF) + 1; for (i = 0; GET_SIGN_L (fac.l) == 0; i++) fac.l = fac.l << 1; diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index 0e25886a..7d949d07 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 @@ -60,7 +61,7 @@ #else /* PDP-11 version */ #include "pdp11_defs.h" -extern int32 cpu_opt; +extern uint32 cpu_opt; #endif extern uint16 *M; @@ -886,7 +887,7 @@ switch (fnc) { /* case on function */ err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); if (uptr->FNC == FNC_WRITE) { /* write? */ if (hkcs2 & CS2_UAI) { /* no addr inc? */ - if (t = Map_ReadW (ba, 2, &comp)) { /* get 1st wd */ + if ((t = Map_ReadW (ba, 2, &comp))) { /* get 1st wd */ wc = 0; /* NXM, no xfr */ hkcs2 = hkcs2 | CS2_NEM; /* set nxm err */ } @@ -894,7 +895,7 @@ switch (fnc) { /* case on function */ hkxb[i] = comp; } else { /* normal */ - if (t = Map_ReadW (ba, wc << 1, hkxb)) { /* get buf */ + if ((t = Map_ReadW (ba, wc << 1, hkxb))) {/* get buf */ wc = wc - (t >> 1); /* NXM, adj wc */ hkcs2 = hkcs2 | CS2_NEM; /* set nxm err */ } @@ -914,13 +915,13 @@ switch (fnc) { /* case on function */ for ( ; i < wc; i++) /* fill buf */ hkxb[i] = 0; if (hkcs2 & CS2_UAI) { /* no addr inc? */ - if (t = Map_WriteW (ba, 2, &hkxb[wc - 1])) { + if ((t = Map_WriteW (ba, 2, &hkxb[wc - 1]))) { wc = 0; /* NXM, no xfr */ hkcs2 = hkcs2 | CS2_NEM; /* set nxm err */ } } else { /* normal */ - if (t = Map_WriteW (ba, wc << 1, hkxb)) { /* put buf */ + if ((t = Map_WriteW (ba, wc << 1, hkxb))) {/* put buf */ wc = wc - (t >> 1); /* NXM, adj wc */ hkcs2 = hkcs2 | CS2_NEM; /* set nxm err */ } diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index 45c08891..9df2b78f 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,21 @@ 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 + 27-Mar-12 RMS Fixed order of int_internal (Jordi Guillaumes i Pons) + 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 @@ -52,7 +54,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; @@ -81,8 +84,8 @@ static const int32 pirq_bit[7] = { }; static const int32 int_internal[IPL_HLVL] = { - INT_INTERNAL7, INT_INTERNAL6, INT_INTERNAL5, INT_INTERNAL4, - INT_INTERNAL3, INT_INTERNAL2, INT_INTERNAL1, 0 + 0, INT_INTERNAL1, INT_INTERNAL2, INT_INTERNAL3, + INT_INTERNAL4, INT_INTERNAL5, INT_INTERNAL6, INT_INTERNAL7 }; /* I/O page lookup and linkage routines @@ -370,17 +373,17 @@ init_ubus_tab (); /* init Unibus tables */ init_mbus_tab (); /* init Massbus tables */ for (i = 0; i < 7; i++) /* seed PIRQ intr */ int_vec[i + 1][pirq_bit[i]] = VEC_PIRQ; -if (r = cpu_build_dib ()) /* build CPU entries */ +if ((r = cpu_build_dib ())) /* build CPU entries */ return r; for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ if (dptr->flags & DEV_MBUS) { /* Massbus? */ - if (r = build_mbus_tab (dptr, dibp)) /* add to Mbus tab */ + if ((r = build_mbus_tab (dptr, dibp))) /* add to Mbus tab */ return r; } else { /* no, Unibus */ - if (r = build_ubus_tab (dptr, dibp)) /* add to Unibus tab */ + if ((r = build_ubus_tab (dptr, dibp))) /* add to Unibus tab */ return r; } } /* end if enabled */ diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index 7ca23fb9..167d5d10 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -219,7 +219,7 @@ return show_vec (st, uptr, ((mp->lines * 2) / arg), desc); void init_ubus_tab (void) { -int32 i, j; +size_t i, j; for (i = 0; i < IPL_HLVL; i++) { /* clear intr tab */ for (j = 0; j < 32; j++) { diff --git a/PDP11/pdp11_ke.c b/PDP11/pdp11_ke.c index 711c1c30..c82ddeef 100644 --- a/PDP11/pdp11_ke.c +++ b/PDP11/pdp11_ke.c @@ -252,7 +252,7 @@ switch (PA & 017) { /* decode PA<3:0> */ data = data & 077; /* 6b shift count */ if (data != 0) { t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */ - if (sign = GET_SIGN_W (ke_AC)) /* sext operand */ + if ((sign = GET_SIGN_W (ke_AC))) /* sext operand */ t32 = t32 | ~017777777777; if (data < 32) { /* [1,31] - left */ sout = (t32 >> (32 - data)) | (-sign << data); @@ -282,7 +282,7 @@ switch (PA & 017) { /* decode PA<3:0> */ data = data & 077; /* 6b shift count */ if (data != 0) { t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */ - if (sign = GET_SIGN_W (ke_AC)) /* sext operand */ + if ((sign = GET_SIGN_W (ke_AC))) /* sext operand */ t32 = t32 | ~017777777777; if (data < 32) { /* [1,31] - left */ sout = (t32 >> (31 - data)) | (-sign << data); diff --git a/PDP11/pdp11_mscp.h b/PDP11/pdp11_mscp.h index 9dd07c90..b000df7d 100644 --- a/PDP11/pdp11_mscp.h +++ b/PDP11/pdp11_mscp.h @@ -211,7 +211,7 @@ #define CMD_REFL 2 /* ref # */ #define CMD_REFH 3 #define CMD_UN 4 /* unit # */ -/* 5 /* reserved */ +/* 5 *//* reserved */ #define CMD_OPC 6 /* opcode */ #define CMD_MOD 7 /* modifier */ @@ -256,14 +256,14 @@ /* Flush - 10 W status (8 undefined) */ #define FLU_LNT 32 -/* 8 - 15 /* reserved */ +/* 8 - 15 *//* reserved */ #define FLU_POSL 16 /* position */ #define FLU_POSH 17 /* Write tape mark - 10W status (8 undefined) */ #define WTM_LNT 32 -/* 8 - 15 /* reserved */ +/* 8 - 15 *//* reserved */ #define WTM_POSL 16 /* position */ #define WTM_POSH 17 @@ -399,8 +399,8 @@ #define RW_BAH 11 #define RW_MAPL 12 /* map table */ #define RW_MAPH 13 -/* 14 /* reserved */ -/* 15 /* reserved */ +/* 14 *//* reserved */ +/* 15 *//* reserved */ /* Disk specific parameters */ 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 8e632683..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 @@ -158,7 +159,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_rk.c b/PDP11/pdp11_rk.c index 2b7c089c..d870ca8f 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 @@ -545,13 +545,13 @@ if (wc && (err == 0)) { /* seek ok? */ rkxb[i] = 0; } if (rkcs & RKCS_INH) { /* incr inhibit? */ - if (t = Map_WriteW (ma, 2, &rkxb[wc - 1])) { /* store last */ + if ((t = Map_WriteW (ma, 2, &rkxb[wc - 1]))) {/* store last */ rker = rker | RKER_NXM; /* NXM? set flag */ wc = 0; /* no transfer */ } } else { /* normal store */ - if (t = Map_WriteW (ma, wc << 1, rkxb)) { /* store buf */ + if ((t = Map_WriteW (ma, wc << 1, rkxb))) { /* store buf */ rker = rker | RKER_NXM; /* NXM? set flag */ wc = wc - t; /* adj wd cnt */ } @@ -560,7 +560,7 @@ if (wc && (err == 0)) { /* seek ok? */ case RKCS_WRITE: /* write */ if (rkcs & RKCS_INH) { /* incr inhibit? */ - if (t = Map_ReadW (ma, 2, &comp)) { /* get 1st word */ + if ((t = Map_ReadW (ma, 2, &comp))) { /* get 1st word */ rker = rker | RKER_NXM; /* NXM? set flag */ wc = 0; /* no transfer */ } @@ -568,7 +568,7 @@ if (wc && (err == 0)) { /* seek ok? */ rkxb[i] = comp; } else { /* normal fetch */ - if (t = Map_ReadW (ma, wc << 1, rkxb)) { /* get buf */ + if ((t = Map_ReadW (ma, wc << 1, rkxb))) { /* get buf */ rker = rker | RKER_NXM; /* NXM? set flg */ wc = wc - t; /* adj wd cnt */ } @@ -584,7 +584,7 @@ if (wc && (err == 0)) { /* seek ok? */ case RKCS_WCHK: /* write check */ i = fxread (rkxb, sizeof (int16), wc, uptr->fileref); - if (err = ferror (uptr->fileref)) { /* read error? */ + if ((err = ferror (uptr->fileref))) { /* read error? */ wc = 0; /* no transfer */ break; } diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 19944926..107b8077 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,8 +25,21 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk - 10-Oct-09 RMS Added debug support - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 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 (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 @@ -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 *, int32, void *); +t_stat rl_set_load (UNIT *, int32, char *, 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, int32 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, (long)(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, int32 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, 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, int32 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, int32 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_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 e0c54727..e96c667b 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 @@ -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) @@ -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 } }; @@ -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) } }; @@ -1442,7 +1442,7 @@ DEVICE *dptr = rq_devmap[cp->cnum]; sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_abo\n"); tpkt = 0; /* set no mtch */ -if (uptr = rq_getucb (cp, lu)) { /* get unit */ +if ((uptr = rq_getucb (cp, lu))) { /* get unit */ if (uptr->cpkt && /* curr pkt? */ (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */ tpkt = uptr->cpkt; /* save match */ @@ -1455,8 +1455,8 @@ if (uptr = rq_getucb (cp, lu)) { /* get unit */ tpkt = uptr->pktq; /* save match */ uptr->pktq = cp->pak[tpkt].link; /* unlink */ } - else if (prv = uptr->pktq) { /* srch pkt q */ - while (tpkt = cp->pak[prv].link) { /* walk list */ + else if ((prv = uptr->pktq)) { /* srch pkt q */ + while ((tpkt = cp->pak[prv].link)) { /* walk list */ if (GETP32 (tpkt, RSP_REFL) == ref) { /* match? unlink */ cp->pak[prv].link = cp->pak[tpkt].link; break; @@ -1486,7 +1486,7 @@ UNIT *uptr; sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_avl\n"); -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ +if ((uptr = rq_getucb (cp, lu))) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */ return OK; @@ -1546,7 +1546,7 @@ if (cp->pak[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ cp->pak[pkt].d[RSP_UN] = lu; } } -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ +if ((uptr = rq_getucb (cp, lu))) { /* unit exist? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */ else if (uptr->flags & UNIT_ONL) /* online */ @@ -1583,7 +1583,7 @@ UNIT *uptr; sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_onl\n"); -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ +if ((uptr = rq_getucb (cp, lu))) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */ return OK; @@ -1626,7 +1626,7 @@ else { cmd = GETP (pkt, CMD_OPC, OPC); /* get opcode */ cp->cflgs = (cp->cflgs & CF_RPL) | /* hack ctrl flgs */ cp->pak[pkt].d[SCC_CFL]; - if (cp->htmo = cp->pak[pkt].d[SCC_TMO]) /* set timeout */ + if ((cp->htmo = cp->pak[pkt].d[SCC_TMO])) /* set timeout */ cp->htmo = cp->htmo + 2; /* if nz, round up */ cp->pak[pkt].d[SCC_CFL] = cp->cflgs; /* return flags */ cp->pak[pkt].d[SCC_TMO] = RQ_DCTMO; /* ctrl timeout */ @@ -1655,7 +1655,7 @@ UNIT *uptr; sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_suc\n"); -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ +if ((uptr = rq_getucb (cp, lu))) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */ return OK; @@ -1686,7 +1686,7 @@ UNIT *uptr; sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_fmt\n"); -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ +if ((uptr = rq_getucb (cp, lu))) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */ return OK; @@ -1722,7 +1722,7 @@ UNIT *uptr; sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_rw(lu=%d, pkt=%d, queue=%s)\n", lu, pkt, q?"yes" : "no"); -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ +if ((uptr = rq_getucb (cp, lu))) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_rw - queued\n"); rq_enqt (cp, &uptr->pktq, pkt); /* do later */ @@ -1769,7 +1769,7 @@ if (bc & 1) /* odd byte cnt? */ return (ST_HST | SB_HST_OC); if (bc & 0xF0000000) /* 'reasonable' bc? */ return (ST_CMD | I_BCNT); -/* if (lbn & 0xF0000000) return (ST_CMD | I_LBN); /* 'reasonable' lbn? */ +/* if (lbn & 0xF0000000) return (ST_CMD | I_LBN); *//* 'reasonable' lbn? */ if (lbn >= maxlbn) { /* accessing RCT? */ if (lbn >= (maxlbn + drv_tab[dtyp].rcts)) /* beyond copy 1? */ return (ST_CMD | I_LBN); /* lbn err */ @@ -1794,16 +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; -if (elapsed > rq_xtime) - sim_activate (uptr, 0); -else - sim_activate (uptr, rq_xtime-elapsed); +/* Reschedule for the appropriate delay */ +sim_activate_notbefore (uptr, uptr->iostarttime+rq_xtime); } /* Unit service for data transfer commands */ @@ -1857,7 +1854,7 @@ if (!uptr->io_complete) { /* Top End (I/O Initiation) Processing */ else if (cmd == OP_WR) { /* write? */ t = Map_ReadW (ba, tbc, uptr->rqxb); /* fetch buffer */ - if (abc = tbc - t) { /* any xfer? */ + if ((abc = tbc - t)) { /* any xfer? */ wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; for (i = (abc >> 1); i < wwc; i++) ((uint16 *)(uptr->rqxb))[i] = 0; @@ -1892,7 +1889,7 @@ else { /* Bottom End (After I/O processing) */ else { sim_disk_data_trace(uptr, uptr->rqxb, bl, tbc, "sim_disk_rdsect", DBG_DAT & rq_devmap[cp->cnum]->dctrl, DBG_REQ); if ((cmd == OP_RD) && !err) { /* read? */ - if (t = Map_WriteW (ba, tbc, uptr->rqxb)) { /* store, nxm? */ + if ((t = Map_WriteW (ba, tbc, uptr->rqxb))) {/* store, nxm? */ PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */ PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */ if (rq_hbe (cp, uptr)) /* post err log */ @@ -2113,6 +2110,7 @@ return rq_putpkt (cp, pkt, TRUE); t_bool rq_deqf (MSC *cp, int32 *pkt) { +*pkt = 0; if (cp->freq == 0) /* no free pkts?? */ return rq_fatal (cp, PE_NSR); cp->pbsy = cp->pbsy + 1; /* cnt busy pkts */ @@ -2163,6 +2161,7 @@ t_bool rq_getpkt (MSC *cp, int32 *pkt) { uint32 addr, desc; +*pkt = 0; if (!rq_getdesc (cp, &cp->cq, &desc)) /* get cmd desc */ return ERR; if ((desc & UQ_DESC_OWN) == 0) { /* none */ @@ -2225,6 +2224,7 @@ t_bool rq_getdesc (MSC *cp, struct uq_ring *ring, uint32 *desc) uint32 addr = ring->ba + ring->idx; uint16 d[2]; +*desc = 0; if (Map_ReadW (addr, 4, d)) /* fetch desc */ return rq_fatal (cp, PE_QRE); /* err? dead */ *desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); @@ -2487,7 +2487,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; @@ -2564,6 +2564,7 @@ rq_clrint (cp); /* clr intr req */ for (i = 0; i < (RQ_NUMDR + 2); i++) { /* init units */ uptr = dptr->units + i; sim_cancel (uptr); /* clr activity */ + sim_disk_reset (uptr); uptr->cnum = cidx; /* set ctrl index */ uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); uptr->uf = 0; /* clr unit flags */ @@ -2745,11 +2746,11 @@ if ((uptr->flags & UNIT_ONL) == 0) { if (uptr->cpkt) { fprintf (st, "Unit %d current ", u); rq_show_pkt (st, cp, uptr->cpkt); - if (pkt = uptr->pktq) { + if ((pkt = uptr->pktq)) { do { fprintf (st, "Unit %d queued ", u); rq_show_pkt (st, cp, pkt); - } while (pkt = cp->pak[pkt].link); + } while ((pkt = cp->pak[pkt].link)); } } else fprintf (st, "Unit %d queues are empty\n", u); @@ -2776,7 +2777,7 @@ if (val & RQ_SH_RI) { rq_show_ring (st, &cp->rq); } if (val & RQ_SH_FR) { - if (pkt = cp->freq) { + if ((pkt = cp->freq)) { for (i = 0; pkt != 0; i++, pkt = cp->pak[pkt].link) { if (i == 0) fprintf (st, "Free queue = %d", pkt); @@ -2789,11 +2790,11 @@ if (val & RQ_SH_FR) { else fprintf (st, "Free queue is empty\n"); } if (val & RQ_SH_RS) { - if (pkt = cp->rspq) { + if ((pkt = cp->rspq)) { do { fprintf (st, "Response "); rq_show_pkt (st, cp, pkt); - } while (pkt = cp->pak[pkt].link); + } while ((pkt = cp->pak[pkt].link)); } else fprintf (st, "Response queue is empty\n"); } diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index bba47ec4..f4267b61 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -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..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 @@ -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_stddev.c b/PDP11/pdp11_stddev.c index ed6ce6e1..c20a0168 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -1,6 +1,6 @@ /* pdp11_stddev.c: PDP-11 standard I/O devices 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"), @@ -26,13 +26,14 @@ tti,tto DL11 terminal input/output clk KW11L (and other) line frequency clock + 18-Apr-12 RMS Modified to use clock coscheduling 20-May-08 RMS Standardized clock delay at 1mips 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock 29-Oct-06 RMS Synced keyboard and clock 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 +47,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 @@ -287,7 +288,8 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, KBD_WAIT (uptr->wait, tmr_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmr_poll))); + /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; if (c & SCPE_BREAK) /* break? */ @@ -307,7 +309,7 @@ t_stat tti_reset (DEVICE *dptr) tti_unit.buf = 0; tti_csr = 0; CLR_INT (TTI); -sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); +sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); return SCPE_OK; } @@ -475,7 +477,7 @@ clk_tps = clk_default; /* set default tps */ clk_csr = CSR_DONE; /* set done */ CLR_INT (CLK); sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init line clock */ -sim_activate_abs (&clk_unit, clk_unit.wait); /* activate unit */ +sim_activate (&clk_unit, clk_unit.wait); /* activate unit */ tmr_poll = clk_unit.wait; /* set timer poll */ tmxr_poll = clk_unit.wait; /* set mux poll */ return SCPE_OK; diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 17ac0423..b0b358cf 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -1,6 +1,6 @@ /* pdp11_sys.c: PDP-11 simulator interface - Copyright (c) 1993-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"), @@ -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. + 29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato) 19-Nov-08 RMS Moved I/O support routines to I/O library 15-May-08 RMS Added KE11-A, DC11 support Renamed DL11 @@ -30,13 +31,13 @@ 25-Jan-08 RMS Added RC11, KG11A support from 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 @@ -992,7 +993,7 @@ switch (j) { /* case on class */ disp = (disp - addr) & 0177777; else return SCPE_ARG; } - if ((disp & 1) || (disp > 0400) && (disp < 0177402)) + if ((disp & 1) || ((disp > 0400) && (disp < 0177402))) return SCPE_ARG; val[0] = val[0] | (((disp - 2) >> 1) & 0377); break; diff --git a/PDP11/pdp11_ta.c b/PDP11/pdp11_ta.c index 822a2a30..f777eff9 100644 --- a/PDP11/pdp11_ta.c +++ b/PDP11/pdp11_ta.c @@ -397,13 +397,13 @@ switch (uptr->FNC) { /* case on function */ case TACS_WRITE|TACS_3RD: /* write CRC */ if (ta_bptr) { /* anything to write? */ - if (st = sim_tape_wrrecf (uptr, ta_xb, ta_bptr)) /* write, err? */ + if ((st = sim_tape_wrrecf (uptr, ta_xb, ta_bptr)))/* write, err? */ r = ta_map_err (uptr, st); /* map error */ } break; /* op done */ case TACS_WFG: /* write file gap */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = ta_map_err (uptr, st); /* map error */ break; @@ -413,7 +413,7 @@ switch (uptr->FNC) { /* case on function */ break; case TACS_SRB: /* space rev blk */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */ r = ta_map_err (uptr, st); /* map error */ break; @@ -425,7 +425,7 @@ switch (uptr->FNC) { /* case on function */ break; case TACS_SFB: /* space fwd blk */ - if (st = sim_tape_sprecf (uptr, &tbc)) /* space rev, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rev, err? */ r = ta_map_err (uptr, st); /* map error */ ta_cs |= TACS_CRC; /* CRC sets, no err */ break; diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index 1b67b4ce..1af3df29 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 @@ -992,7 +992,7 @@ switch (fnc) { /* at speed, check fnc * if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; } -/* else /* ignore hdr */ +/* else *//* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); DT_SETDONE; /* set done */ break; diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index e6af932c..e8430b17 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 @@ -378,7 +377,7 @@ if (f == MTC_UNLOAD) { /* unload? */ } else if (f == MTC_REWIND) /* rewind */ uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */ -/* else /* uncomment this else if rewind/unload don't set done */ +/* else *//* uncomment this else if rewind/unload don't set done */ tm_cmd = tm_cmd & ~MTC_DONE; /* clear done */ CLR_INT (TM); /* clear int */ sim_activate (uptr, tm_time); /* start io */ @@ -440,7 +439,7 @@ switch (f) { /* case on function */ tm_sta = tm_sta | STA_RLE; if (tbc < cbc) /* use smaller */ cbc = tbc; - if (t = Map_WriteB (xma, cbc, tmxb)) { /* copy buf to mem */ + if ((t = Map_WriteB (xma, cbc, tmxb))) { /* copy buf to mem */ tm_sta = tm_sta | STA_NXM; /* NXM, set err */ cbc = cbc - t; /* adj byte cnt */ } @@ -450,13 +449,13 @@ switch (f) { /* case on function */ case MTC_WRITE: /* write */ case MTC_WREXT: /* write ext gap */ - if (t = Map_ReadB (xma, cbc, tmxb)) { /* copy mem to buf */ + if ((t = Map_ReadB (xma, cbc, tmxb))) { /* copy mem to buf */ tm_sta = tm_sta | STA_NXM; /* NXM, set err */ cbc = cbc - t; /* adj byte cnt */ if (cbc == 0) /* no xfr? done */ break; } - if (st = sim_tape_wrrecf (uptr, tmxb, cbc)) /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, tmxb, cbc))) /* write rec, err? */ r = tm_map_err (uptr, st); /* map error */ else { xma = (xma + cbc) & 0777777; /* inc bus addr */ @@ -465,14 +464,14 @@ switch (f) { /* case on function */ break; case MTC_WREOF: /* write eof */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = tm_map_err (uptr, st); /* map error */ break; case MTC_SPACEF: /* space forward */ do { tm_bc = (tm_bc + 1) & 0177777; /* incr wc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* spc rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* spc rec fwd, err? */ r = tm_map_err (uptr, st); /* map error */ break; } @@ -482,7 +481,7 @@ switch (f) { /* case on function */ case MTC_SPACER: /* space reverse */ do { tm_bc = (tm_bc + 1) & 0177777; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* spc rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* spc rec rev, err? */ r = tm_map_err (uptr, st); /* map error */ break; } diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 2fbf5ed9..95d76ba2 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 @@ -48,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 @@ -62,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 */ @@ -82,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" @@ -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 }, @@ -823,13 +828,13 @@ else if (mdf & ~tq_cmf[cmd]) { /* invalid mod? */ sts = ST_CMD | I_MODF; /* ill mods */ } else { /* valid cmd */ - if (uptr = tq_getucb (lu)) { /* valid unit? */ + if ((uptr = tq_getucb (lu))) { /* valid unit? */ if (q && (tq_cmf[cmd] & CMF_SEQ) && /* queueing, seq, */ (uptr->cpkt || uptr->pktq)) { /* and active? */ tq_enqt (&uptr->pktq, pkt); /* do later */ return OK; } -/* if (tq_cmf[cmd] & MD_CDL) /* clr cch lost? */ +/* if (tq_cmf[cmd] & MD_CDL) *//* clr cch lost? */ /* uptr->flags = uptr->flags & ~UNIT_CDL; */ if ((mdf & MD_CSE) && (uptr->flags & UNIT_SXC)) /* clr ser exc? */ uptr->flags = uptr->flags & ~UNIT_SXC; @@ -904,7 +909,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_abo\n"); tpkt = 0; /* set no mtch */ -if (uptr = tq_getucb (lu)) { /* get unit */ +if ((uptr = tq_getucb (lu))) { /* get unit */ if (uptr->cpkt && /* curr pkt? */ (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */ tpkt = uptr->cpkt; /* save match */ @@ -917,8 +922,8 @@ if (uptr = tq_getucb (lu)) { /* get unit */ tpkt = uptr->pktq; /* save match */ uptr->pktq = tq_pkt[tpkt].link; /* unlink */ } - else if (prv = uptr->pktq) { /* srch pkt q */ - while (tpkt = tq_pkt[prv].link) { /* walk list */ + else if ((prv = uptr->pktq)) { /* srch pkt q */ + while ((tpkt = tq_pkt[prv].link)) { /* walk list */ if (GETP32 (tpkt, RSP_REFL) == ref) { /* match ref? */ tq_pkt[prv].link = tq_pkt[tpkt].link; /* unlink */ break; @@ -948,7 +953,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_avl\n"); -if (uptr = tq_getucb (lu)) { /* unit exist? */ +if ((uptr = tq_getucb (lu))) { /* unit exist? */ if (uptr->flags & UNIT_SXC) /* ser exc pending? */ sts = ST_SXC; else { @@ -1007,7 +1012,7 @@ if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ tq_pkt[pkt].d[RSP_UN] = lu; } } -if (uptr = tq_getucb (lu)) { /* unit exist? */ +if ((uptr = tq_getucb (lu))) { /* unit exist? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */ else if (uptr->flags & UNIT_ONL) /* online */ @@ -1034,7 +1039,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_onl\n"); -if (uptr = tq_getucb (lu)) { /* unit exist? */ +if ((uptr = tq_getucb (lu))) { /* unit exist? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */ else if (uptr->flags & UNIT_ONL) /* already online? */ @@ -1065,7 +1070,7 @@ if (tq_pkt[pkt].d[SCC_MSV]) /* MSCP ver = 0? */ else { tq_cflgs = (tq_cflgs & CF_RPL) | /* hack ctrl flgs */ tq_pkt[pkt].d[SCC_CFL]; - if (tq_htmo = tq_pkt[pkt].d[SCC_TMO]) /* set timeout */ + if ((tq_htmo = tq_pkt[pkt].d[SCC_TMO])) /* set timeout */ tq_htmo = tq_htmo + 2; /* if nz, round up */ tq_pkt[pkt].d[SCC_CFL] = tq_cflgs; /* return flags */ tq_pkt[pkt].d[SCC_TMO] = TQ_DCTMO; /* ctrl timeout */ @@ -1091,7 +1096,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_suc\n"); -if (uptr = tq_getucb (lu)) { /* unit exist? */ +if ((uptr = tq_getucb (lu))) { /* unit exist? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */ else { @@ -1115,7 +1120,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_flu\n"); -if (uptr = tq_getucb (lu)) /* unit exist? */ +if ((uptr = tq_getucb (lu))) /* unit exist? */ sts = tq_mot_valid (uptr, OP_FLU); /* validate req */ else sts = ST_OFL; /* offline */ tq_putr (pkt, OP_FLU | OP_END, tq_efl (uptr), sts, FLU_LNT, UQ_TYP_SEQ); @@ -1133,7 +1138,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_erase\n"); -if (uptr = tq_getucb (lu)) { /* unit exist? */ +if ((uptr = tq_getucb (lu))) { /* unit exist? */ sts = tq_mot_valid (uptr, cmd); /* validity checks */ if (sts == ST_SUC) { /* ok? */ uptr->cpkt = pkt; /* op in progress */ @@ -1157,7 +1162,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_wtm\n"); -if (uptr = tq_getucb (lu)) { /* unit exist? */ +if ((uptr = tq_getucb (lu))) { /* unit exist? */ objp = uptr->objp; /* position op */ sts = tq_mot_valid (uptr, OP_WTM); /* validity checks */ if (sts == ST_SUC) { /* ok? */ @@ -1183,7 +1188,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_pos\n"); -if (uptr = tq_getucb (lu)) { /* unit exist? */ +if ((uptr = tq_getucb (lu))) { /* unit exist? */ objp = uptr->objp; /* position op */ sts = tq_mot_valid (uptr, OP_POS); /* validity checks */ if (sts == ST_SUC) { /* ok? */ @@ -1219,7 +1224,7 @@ UNIT *uptr; sim_debug(DBG_TRC, &tq_dev, "tq_rw\n"); -if (uptr = tq_getucb (lu)) { /* unit exist? */ +if ((uptr = tq_getucb (lu))) { /* unit exist? */ objp = uptr->objp; /* position op */ sts = tq_mot_valid (uptr, cmd); /* validity checks */ if (sts == ST_SUC) { /* ok? */ @@ -1275,16 +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; -if (elapsed > tq_xtime) - sim_activate (uptr, 0); -else - sim_activate (uptr, tq_xtime-elapsed); +/* Reschedule for the appropriate delay */ +sim_activate_notbefore (uptr, uptr->iostarttime+tq_xtime); } @@ -1361,7 +1363,7 @@ switch (cmd) { /* case on command */ } else wbc = res->tbc; if (cmd == OP_RD) { /* read? */ - if (t = Map_WriteB (ba, wbc, res->tqxb)) { /* store, nxm? */ + if ((t = Map_WriteB (ba, wbc, res->tqxb))) {/* store, nxm? */ PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */ if (tq_hbe (uptr, ba + wbc - t)) /* post err log */ tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, res->tbc); @@ -1400,7 +1402,7 @@ switch (cmd) { /* case on command */ case OP_WR: /* write */ if (!io_complete) { /* Top half processing */ - if (t = Map_ReadB (ba, bc, res->tqxb)) { /* fetch buf, nxm? */ + if ((t = Map_ReadB (ba, bc, res->tqxb))) { /* fetch buf, nxm? */ PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */ if (tq_hbe (uptr, ba + bc - t)) /* post err log */ tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); @@ -2020,7 +2022,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) @@ -2289,11 +2291,11 @@ if ((uptr->flags & UNIT_ONL) == 0) { if (uptr->cpkt) { fprintf (st, "Unit %d current ", u); tq_show_pkt (st, uptr->cpkt); - if (pkt = uptr->pktq) { + if ((pkt = uptr->pktq)) { do { fprintf (st, "Unit %d queued ", u); tq_show_pkt (st, pkt); - } while (pkt = tq_pkt[pkt].link); + } while ((pkt = tq_pkt[pkt].link)); } } else fprintf (st, "Unit %d queues are empty\n", u); @@ -2318,7 +2320,7 @@ if (val & TQ_SH_RI) { tq_show_ring (st, &tq_rq); } if (val & TQ_SH_FR) { - if (pkt = tq_freq) { + if ((pkt = tq_freq)) { for (i = 0; pkt != 0; i++, pkt = tq_pkt[pkt].link) { if (i == 0) fprintf (st, "Free queue = %d", pkt); @@ -2331,11 +2333,11 @@ if (val & TQ_SH_FR) { else fprintf (st, "Free queue is empty\n"); } if (val & TQ_SH_RS) { - if (pkt = tq_rspq) { + if ((pkt = tq_rspq)) { do { fprintf (st, "Response "); tq_show_pkt (st, pkt); - } while (pkt = tq_pkt[pkt].link); + } while ((pkt = tq_pkt[pkt].link)); } else fprintf (st, "Response queue is empty\n"); } diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index 01a5b0fe..5966a062 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"), @@ -25,8 +25,9 @@ ts TS11/TSV05 magtape + 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) 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 +60,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: @@ -96,7 +97,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" @@ -489,7 +490,7 @@ do { fc = (fc - 1) & DMASK; /* decr wc */ if (upd) msgrfc = fc; - if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rec fwd, err? */ return ts_map_status (st); /* map status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ } while (fc != 0); @@ -532,7 +533,7 @@ do { fc = (fc - 1) & DMASK; /* decr wc */ if (upd) msgrfc = fc; - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rec rev, err? */ return ts_map_status (st); /* map status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ } while (fc != 0); @@ -665,7 +666,7 @@ else { return TC5; } } -if (st = sim_tape_wrrecf (uptr, tsxb, fc)) /* write rec, err? */ +if ((st = sim_tape_wrrecf (uptr, tsxb, fc))) /* write rec, err? */ return ts_map_status (st); /* return status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ msgrfc = 0; @@ -678,7 +679,7 @@ int32 ts_wtmk (UNIT *uptr) { t_stat st; -if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ +if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ return ts_map_status (st); /* return status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ if (sim_tape_eot (&ts_unit)) /* EOT on write? */ diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index f4b2144f..d0ced0a9 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 @@ -647,7 +647,7 @@ switch (fnc) { /* case on function */ case FNC_SPACEF: /* space forward */ do { tufc = (tufc + 1) & 0177777; /* incr fc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = tu_map_err (drv, st, 0); /* map error */ break; } @@ -660,7 +660,7 @@ switch (fnc) { /* case on function */ case FNC_SPACER: /* space reverse */ do { tufc = (tufc + 1) & 0177777; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = tu_map_err (drv, st, 0); /* map error */ break; } @@ -671,7 +671,7 @@ switch (fnc) { /* case on function */ break; case FNC_WREOF: /* write end of file */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = tu_map_err (drv, st, 0); /* map error */ break; @@ -687,7 +687,7 @@ switch (fnc) { /* case on function */ tufc = 0; /* clear frame count */ if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr)) tufs = tufs | FS_ID; /* PE BOT? ID burst */ - if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */ + if ((st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR))) {/* read fwd */ if (st == MTSE_TMK) /* tmk also sets FCE */ tu_set_er (ER_FCE); r = tu_map_err (drv, st, 1); /* map error */ @@ -739,7 +739,7 @@ switch (fnc) { /* case on function */ } tbc = xbc; } - if (st = sim_tape_wrrecf (uptr, xbuf, tbc)) /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, xbuf, tbc))) /* write rec, err? */ r = tu_map_err (drv, st, 1); /* map error */ else { tufc = (tufc + tbc) & 0177777; @@ -751,7 +751,7 @@ switch (fnc) { /* case on function */ case FNC_READR: /* read reverse */ case FNC_WCHKR: /* wcheck = read */ tufc = 0; /* clear frame count */ - if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */ + if ((st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR))) {/* read rev */ if (st == MTSE_TMK) /* tmk also sets FCE */ tu_set_er (ER_FCE); r = tu_map_err (drv, st, 1); /* map error */ diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index da8e472a..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 @@ -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/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index f3b3ce1f..4937fe4d 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -606,7 +606,7 @@ void xq_make_checksum(CTLR* xq) /* checksum calculation routine detailed in vaxboot.zip/xqbtdrivr.mar */ uint32 checksum = 0; const uint32 wmask = 0xFFFF; - int i; + size_t i; for (i = 0; i < sizeof(ETH_MAC); i += 2) { checksum <<= 1; @@ -685,7 +685,7 @@ t_stat xq_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc) { CTLR* xq = xq_unit2ctlr(uptr); char buffer[20]; - int i; + size_t i; if (xq->var->mode == XQ_T_DELQA_PLUS) { eth_mac_fmt(&xq->var->init.phys, buffer); @@ -702,7 +702,7 @@ t_stat xq_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc) fprintf(st, "Filters:\n"); for (i=0; ivar->setup.macs[i], buffer); - fprintf(st, " [%2d]: %s\n", i, buffer); + fprintf(st, " [%2d]: %s\n", (int)i, buffer); } if (xq->var->setup.multicast) fprintf(st, "All Multicast Receive Mode\n"); @@ -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]; @@ -1188,7 +1187,7 @@ t_stat xq_process_setup(CTLR* xq) xq->var->setup.multicast = (0 != (len & XQ_SETUP_MC)); xq->var->setup.promiscuous = (0 != (len & XQ_SETUP_PM)); - if (led = (len & XQ_SETUP_LD) >> 2) { + if ((led = (len & XQ_SETUP_LD) >> 2)) { switch (led) { case 1: xq->var->setup.l1 = 0; break; case 2: xq->var->setup.l2 = 0; break; @@ -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; } @@ -2075,6 +2073,9 @@ t_stat xq_process_bootrom (CTLR* xq) /* set to next bdl (implicit chain) */ xq->var->rbdl_ba += 12; break; + + default: + break; } /* switch */ /* --------------------------- Done, finish up -----------------------------*/ @@ -2139,12 +2140,12 @@ void xq_start_receiver(CTLR* xq) /* start the read service timer or enable asynch reading as appropriate */ if (xq->var->must_poll) - sim_activate(xq->unit, (sim_idle_enab ? tmxr_poll : (tmr_poll*clk_tps)/xq->var->poll)); + sim_activate(xq->unit, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll)); else if ((xq->var->poll == 0) || (xq->var->mode == XQ_T_DELQA_PLUS)) eth_set_async(xq->var->etherface, xq->var->coalesce_latency_ticks); else - sim_activate(xq->unit, (sim_idle_enab ? tmxr_poll : (tmr_poll*clk_tps)/xq->var->poll)); + sim_activate(xq->unit, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll)); } void xq_stop_receiver(CTLR* xq) @@ -2250,7 +2251,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 +2266,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 +2304,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; @@ -2520,7 +2520,7 @@ t_stat xq_svc(UNIT* uptr) /* resubmit service timer */ if ((xq->var->must_poll) || (xq->var->poll && (xq->var->mode != XQ_T_DELQA_PLUS))) - sim_activate(uptr, (sim_idle_enab ? tmxr_poll : (tmr_poll*clk_tps)/xq->var->poll)); + sim_activate(uptr, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll)); return SCPE_OK; } @@ -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) { @@ -2611,6 +2614,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 +2627,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); @@ -2797,7 +2806,7 @@ void xq_debug_setup(CTLR* xq) void xq_debug_turbo_setup(CTLR* xq) { - int i; + size_t i; char buffer[64] = ""; if (!(sim_deb && (xq->dev->dctrl & DBG_SET))) diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index 05bccaed..8ef1cd7b 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -105,6 +105,7 @@ extern FILE *sim_log; t_stat xu_rd(int32* data, int32 PA, int32 access); t_stat xu_wr(int32 data, int32 PA, int32 access); t_stat xu_svc(UNIT * uptr); +t_stat xu_tmrsvc(UNIT * uptr); t_stat xu_reset (DEVICE * dptr); t_stat xu_attach (UNIT * uptr, char * cptr); t_stat xu_detach (UNIT * uptr); @@ -132,7 +133,8 @@ DIB xua_dib = { IOBA_XU, IOLN_XU, &xu_rd, &xu_wr, 1, IVCL (XU), VEC_XU, {&xu_int} }; UNIT xua_unit[] = { - { UDATA (&xu_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) } /* receive timer */ + { UDATA (&xu_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) }, /* receive timer */ + { UDATA (&xu_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) } }; struct xu_device xua = { @@ -185,7 +187,7 @@ DEBTAB xu_debug[] = { DEVICE xu_dev = { "XU", xua_unit, xua_reg, xu_mod, - 1, XU_RDX, 8, 1, XU_RDX, 8, + 2, XU_RDX, 8, 1, XU_RDX, 8, &xu_ex, &xu_dep, &xu_reset, NULL, &xu_attach, &xu_detach, &xua_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, @@ -553,10 +555,7 @@ 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; /* First pump any queued packets into the system */ if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING)) @@ -568,37 +567,46 @@ 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 */ if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING)) xu_process_receive(xu); - /* send identity packet when timer expires */ - if (--xu->var->idtmr <= 0) { - if ((xu->var->mode & MODE_DMNT) == 0) /* if maint msg is not disabled */ - status = xu_system_id(xu, mop_multicast, 0); /* then send ID packet */ - xu->var->idtmr = XU_ID_TIMER_VAL * one_second; /* reset timer */ - } - - /* has one second timer expired? if so, update stats and reset timer */ - if (++xu->var->sectmr >= XU_SERVICE_INTERVAL) { - upd_stat16 (&xu->var->stats.secs, 1); - xu->var->sectmr = 0; - } - /* resubmit service timer if controller not halted */ switch (xu->var->pcsr1 & PCSR1_STATE) { case STATE_READY: case STATE_RUNNING: - sim_activate(&xu->unit[0], tmxr_poll); + sim_activate(&xu->unit[0], clk_cosched(tmxr_poll)); break; }; return SCPE_OK; } +t_stat xu_tmrsvc(UNIT* uptr) +{ + CTLR* xu = xu_unit2ctlr(uptr); + const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00}; + const int one_second = clk_tps * tmr_poll; + + /* send identity packet when timer expires */ + if (--xu->var->idtmr <= 0) { + if ((xu->var->mode & MODE_DMNT) == 0) /* if maint msg is not disabled */ + xu_system_id(xu, mop_multicast, 0); /* then send ID packet */ + xu->var->idtmr = XU_ID_TIMER_VAL; /* reset timer */ + } + + /* update stats */ + upd_stat16 (&xu->var->stats.secs, 1); + + /* resubmit service timer */ + sim_activate(uptr, one_second); + + return SCPE_OK; +} + void xu_write_callback (CTLR* xu, int status) { xu->var->write_buffer.status = status; @@ -627,7 +635,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,13 +675,17 @@ 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) { sim_activate_abs(&xu->unit[0], clk_cosched (tmxr_poll)); + + /* start service timer */ + if (xu->var->etherface) + sim_activate_abs(&xu->unit[1], tmr_poll * clk_tps); } /* clear load_server address */ @@ -708,7 +719,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 +806,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 +933,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 */ @@ -1030,7 +1041,7 @@ void xu_process_receive(CTLR* xu) sim_debug(DBG_TRC, xu->dev, "xu_process_receive(), buffers: %d\n", xu->var->rrlen); -/* xu_dump_rxring(xu); /* debug receive ring */ +/* xu_dump_rxring(xu); *//* debug receive ring */ /* process only when in the running state, and host buffers are available */ if ((state != STATE_RUNNING) || no_buffers) @@ -1202,7 +1213,7 @@ void xu_process_transmit(CTLR* xu) t_stat rstatus, wstatus; sim_debug(DBG_TRC, xu->dev, "xu_process_transmit()\n"); -/* xu_dump_txring(xu); /* debug receive ring */ +/* xu_dump_txring(xu); *//* debug receive ring */ for (;;) { @@ -1339,7 +1350,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 +1378,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; @@ -1571,7 +1581,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) { @@ -1587,6 +1600,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; @@ -1603,12 +1618,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..7bf7ab28 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 @@ -604,7 +604,7 @@ while (reason == 0) { /* loop until halted */ int32 link_init, fill; if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; api_int = api_eval (&int_pend); /* eval API */ } @@ -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_defs.h b/PDP18B/pdp18b_defs.h index eef82cf6..9a997886 100644 --- a/PDP18B/pdp18b_defs.h +++ b/PDP18B/pdp18b_defs.h @@ -1,6 +1,6 @@ /* pdp18b_defs.h: 18b PDP simulator definitions - Copyright (c) 1993-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,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-Apr-12 RMS Added clk_cosched prototype 22-May-10 RMS Added check for 64b definitions 30-Oct-06 RMS Added infinite loop stop 14-Jan-04 RMS Revised IO device call interface @@ -495,4 +496,6 @@ typedef struct { t_stat set_devno (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_devno (FILE *st, UNIT *uptr, int32 val, void *desc); +int32 clk_cosched (int32 wait); + #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_dt.c b/PDP18B/pdp18b_dt.c index 9b422fec..6b78f81b 100644 --- a/PDP18B/pdp18b_dt.c +++ b/PDP18B/pdp18b_dt.c @@ -1147,7 +1147,7 @@ switch (fnc) { /* at speed, check fnc * if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; } -/* /* ignore hdr */ + /* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); if (M[DT_WC] == 0) dt_substate = DTO_WCO; diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index 1a22c4c2..0f2f8a04 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 @@ -143,7 +144,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; @@ -248,7 +253,7 @@ switch (fop) { /* case on subop */ break; case FOP_SUB: /* subtract */ - if (sta = fp15_opnd (fir, ar, &fmb)) /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fadd (fir, &fma, &fmb, 1); /* yes, fp sub */ @@ -257,7 +262,7 @@ switch (fop) { /* case on subop */ case FOP_RSUB: /* reverse sub */ fmb = fma; /* FMB <- FMA */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fadd (fir, &fma, &fmb, 1); /* yes, fp sub */ @@ -265,7 +270,7 @@ switch (fop) { /* case on subop */ break; case FOP_MUL: /* multiply */ - if (sta = fp15_opnd (fir, ar, &fmb)) /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fmul (fir, &fma, &fmb); /* yes, fp mul */ @@ -273,9 +278,9 @@ switch (fop) { /* case on subop */ break; case FOP_DIV: /* divide */ - if (sta = fp15_opnd (fir, ar, &fmb)) /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ break; - if (sta = fp15_opnd (fir, ar, &fmb)) break; /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb)))break; /* fetch op to FMB */ if (fir & FI_FP) /* fp? */ sta = fp15_fdiv (fir, &fma, &fmb); /* yes, fp div */ else sta = fp15_idiv (fir, &fma, &fmb); /* no, int div */ @@ -283,7 +288,7 @@ switch (fop) { /* case on subop */ case FOP_RDIV: /* reverse divide */ fmb = fma; /* FMB <- FMA */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fdiv (fir, &fma, &fmb); /* yes, fp div */ @@ -291,7 +296,7 @@ switch (fop) { /* case on subop */ break; case FOP_LD: /* load */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; fp15_asign (fir, &fma); /* modify A sign */ if (fir & FI_FP) /* fp? */ @@ -304,7 +309,7 @@ switch (fop) { /* case on subop */ break; case FOP_FLT: /* float */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; fma.exp = 35; fp15_asign (fir, &fma); /* adjust A sign */ @@ -312,13 +317,13 @@ switch (fop) { /* case on subop */ break; case FOP_FIX: /* fix */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; sta = fp15_fix (fir, &fma); /* fix */ break; case FOP_LFMQ: /* load FMQ */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; dp_swap (&fma, &fmq); /* swap FMA, FMQ */ fp15_asign (fir, &fma); /* adjust A sign */ @@ -332,7 +337,7 @@ switch (fop) { /* case on subop */ sta = Write (ar, dat, WR); } else { /* no, load */ - if (sta = Read (ar, &dat, RD)) + if ((sta = Read (ar, &dat, RD))) break; fguard = (dat >> JEA_V_GUARD) & 1; jea = dat & JEA_EAMASK; @@ -340,7 +345,7 @@ switch (fop) { /* case on subop */ break; case FOP_ADD: /* add */ - if (sta = fp15_opnd (fir, ar, &fmb)) /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fadd (fir, &fma, &fmb, 0); /* yes, fp add */ @@ -424,7 +429,7 @@ t_stat sta; fguard = 0; /* clear guard */ if (ir & FI_FP) { /* fp? */ - if (sta = fp15_norm (ir, a, NULL, 0)) /* normalize */ + if ((sta = fp15_norm (ir, a, NULL, 0))) /* normalize */ return sta; if (ir & FI_DP) { /* dp? */ wd[0] = a->exp & DMASK; /* exponent */ 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_mt.c b/PDP18B/pdp18b_mt.c index 22d190cf..db4d598f 100644 --- a/PDP18B/pdp18b_mt.c +++ b/PDP18B/pdp18b_mt.c @@ -353,7 +353,7 @@ switch (f) { /* case on function */ mtxb[p++] = M[xma] & 0377; } } /* end for */ - if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) /* write rec, err? */ r = mt_map_err (uptr, st); /* map error */ else { M[MT_CA] = (M[MT_CA] + wc) & DMASK; /* advance mem addr */ @@ -363,7 +363,7 @@ switch (f) { /* case on function */ break; case FN_WREOF: - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ else uptr->USTAT = STA_EOF; mt_cu = mt_cu & ~CU_ERASE; /* clear erase flag */ @@ -372,7 +372,7 @@ switch (f) { /* case on function */ case FN_SPACEF: /* space forward */ do { M[MT_WC] = (M[MT_WC] + 1) & DMASK; /* inc WC */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = mt_map_err (uptr, st); /* map error */ break; } @@ -382,7 +382,7 @@ switch (f) { /* case on function */ case FN_SPACER: /* space reverse */ do { M[MT_WC] = (M[MT_WC] + 1) & DMASK; /* inc WC */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; } 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..78cfeba3 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -1,6 +1,6 @@ /* pdp18b_stddev.c: 18b PDP's standard devices - Copyright (c) 1993-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"), @@ -29,6 +29,8 @@ tto teleprinter clk clock + 18-Apr-12 RMS Added clk_cosched routine + Revised clk and tti scheduling 18-Jun-07 RMS Added UNIT_IDLE to console input, clock 18-Oct-06 RMS Added PDP-15 programmable duplex control Fixed handling of non-printable characters in KSR mode @@ -53,7 +55,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 @@ -477,6 +479,16 @@ int32 clk_iors (void) return (TST_INT (CLK)? IOS_CLK: 0); } +/* Clock coscheduling routine */ + +int32 clk_cosched (int32 wait) +{ +int32 t; + +t = sim_is_active (&clk_unit); +return (t? t - 1: wait); +} + /* Reset routine */ t_stat clk_reset (DEVICE *dptr) @@ -582,7 +594,7 @@ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ if (ptr_state == 0) { /* ASCII */ if (ptr_unit.flags & UNIT_RASCII) { /* want parity? */ ptr_unit.buf = temp = temp & 0177; /* parity off */ - while (temp = temp & (temp - 1)) + while ((temp = temp & (temp - 1))) ptr_unit.buf = ptr_unit.buf ^ 0200; /* count bits */ ptr_unit.buf = ptr_unit.buf ^ 0200; /* set even parity */ } @@ -1002,7 +1014,8 @@ t_stat tti_svc (UNIT *uptr) #if defined (KSR28) /* Baudot... */ int32 in, c, out; -sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll))); + /* continue poll */ if (tti_2nd) { /* char waiting? */ uptr->buf = tti_2nd; /* return char */ tti_2nd = 0; /* not waiting */ @@ -1037,7 +1050,8 @@ else { #else /* ASCII... */ int32 c, out; -sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll))); + /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; out = c & 0177; /* mask echo to 7b */ @@ -1068,12 +1082,14 @@ return (TST_INT (TTI)? IOS_TTI: 0); t_stat tti_reset (DEVICE *dptr) { -tti_unit.buf = 0; /* clear buffer */ -tti_2nd = 0; -tty_shift = 0; /* clear state */ -tti_fdpx = 0; /* clear dpx mode */ CLR_INT (TTI); /* clear flag */ -sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); +if (!sim_is_running) { /* RESET (not CAF)? */ + tti_unit.buf = 0; /* clear buffer */ + tti_2nd = 0; + tty_shift = 0; /* clear state */ + tti_fdpx = 0; /* clear dpx mode */ + } +sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); return SCPE_OK; } diff --git a/PDP18B/pdp18b_sys.c b/PDP18B/pdp18b_sys.c index c843e949..86bedcf5 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" @@ -1010,7 +1009,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ break; case I_V_OPR: /* operate */ - if (sp = (inst & 03730)) + if ((sp = (inst & 03730))) fprintf (of, "%s", opcode[i]); fprint_opr (of, inst & 014047, I_V_OPR, sp); break; diff --git a/PDP18B/pdp18b_tt1.c b/PDP18B/pdp18b_tt1.c index 300830d5..d29bde0e 100644 --- a/PDP18B/pdp18b_tt1.c +++ b/PDP18B/pdp18b_tt1.c @@ -1,6 +1,6 @@ /* pdp18b_ttx.c: PDP-9/15 additional terminals 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,6 +25,7 @@ ttix,ttox LT15/LT19 terminal input/output + 18-Apr-12 RMS Revised to use clock coscheduling 19-Nov-08 RMS Revised for common TMXR show routines 18-Jun-07 RMS Added UNIT_IDLE flag 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode @@ -214,14 +215,14 @@ int32 ln, c, temp; if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_OK; -sim_activate (uptr, tmxr_poll); /* continue poll */ +sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */ ln = tmxr_poll_conn (&ttx_desc); /* look for connect */ if (ln >= 0) /* got one? rcv enab */ ttx_ldsc[ln].rcve = 1; tmxr_poll_rx (&ttx_desc); /* poll for input */ for (ln = 0; ln < TTX_MAXL; ln++) { /* loop thru lines */ if (ttx_ldsc[ln].conn) { /* connected? */ - if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */ + if ((temp = tmxr_getc_ln (&ttx_ldsc[ln]))) { /* get char */ if (temp & SCPE_BREAK) /* break? */ c = 0; else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags) | TTUF_KSR); diff --git a/PDP8/pdp8_clk.c b/PDP8/pdp8_clk.c index f19d982d..968ac229 100644 --- a/PDP8/pdp8_clk.c +++ b/PDP8/pdp8_clk.c @@ -1,6 +1,6 @@ /* pdp8_clk.c: PDP-8 real-time clock simulator - Copyright (c) 1993-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 @@ clk real time clock + 18-Apr-12 RMS Added clock coscheduling 18-Jun-07 RMS Added UNIT_IDLE flag 01-Mar-03 RMS Aded SET/SHOW CLK FREQ support 04-Oct-02 RMS Added DIB, device number support @@ -43,6 +44,8 @@ extern int32 int_req, int_enable, dev_done, stop_inst; int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = 16000; /* term mux poll */ +extern int32 sim_is_running; + int32 clk (int32 IR, int32 AC); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); @@ -150,6 +153,16 @@ tmxr_poll = t; /* set mux poll */ return SCPE_OK; } +/* Clock coscheduling routine */ + +int32 clk_cosched (int32 wait) +{ +int32 t; + +t = sim_is_active (&clk_unit); +return (t? t - 1: wait); +} + /* Reset routine */ t_stat clk_reset (DEVICE *dptr) @@ -159,9 +172,11 @@ int32 t; dev_done = dev_done & ~INT_CLK; /* clear done, int */ int_req = int_req & ~INT_CLK; int_enable = int_enable & ~INT_CLK; /* clear enable */ -t = sim_rtcn_init (clk_unit.wait, TMR_CLK); -sim_activate_abs (&clk_unit, t); /* activate unit */ -tmxr_poll = t; +if (!sim_is_running) { /* RESET (not CAF)? */ + t = sim_rtcn_init (clk_unit.wait, TMR_CLK); + sim_activate (&clk_unit, t); /* activate unit */ + tmxr_poll = t; + } return SCPE_OK; } diff --git a/PDP8/pdp8_cpu.c b/PDP8/pdp8_cpu.c index c327c41a..98ad5846 100644 --- a/PDP8/pdp8_cpu.c +++ b/PDP8/pdp8_cpu.c @@ -344,7 +344,7 @@ reason = 0; while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } diff --git a/PDP8/pdp8_ct.c b/PDP8/pdp8_ct.c index 9f5f1e27..31ac1e75 100644 --- a/PDP8/pdp8_ct.c +++ b/PDP8/pdp8_ct.c @@ -270,7 +270,7 @@ switch (IR & 07) { /* decode IR<9:11> */ case 6: /* KGOA */ ct_df = 0; /* clear data flag */ - if (uptr = ct_busy ()) /* op in progress? */ + if ((uptr = ct_busy ())) /* op in progress? */ AC = ct_go_cont (uptr, AC); /* yes */ else AC = ct_go_start (AC); /* no, start */ ct_updsta (NULL); @@ -433,7 +433,7 @@ switch (uptr->FNC) { /* case on function */ case SRA_CRC: /* CRC */ if (ct_write) { /* write? */ - if (st = sim_tape_wrrecf (uptr, ct_xb, ct_bptr)) /* write, err? */ + if ((st = sim_tape_wrrecf (uptr, ct_xb, ct_bptr)))/* write, err? */ r = ct_map_err (uptr, st); /* map error */ break; /* write done */ } @@ -452,7 +452,7 @@ switch (uptr->FNC) { /* case on function */ break; /* read done */ case SRA_WFG: /* write file gap */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = ct_map_err (uptr, st); /* map error */ break; @@ -462,7 +462,7 @@ switch (uptr->FNC) { /* case on function */ break; case SRA_SRB: /* space rev blk */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */ r = ct_map_err (uptr, st); /* map error */ break; diff --git a/PDP8/pdp8_defs.h b/PDP8/pdp8_defs.h index 1cebab76..5d2ee547 100644 --- a/PDP8/pdp8_defs.h +++ b/PDP8/pdp8_defs.h @@ -1,6 +1,6 @@ /* pdp8_defs.h: PDP-8 simulator definitions - Copyright (c) 1993-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,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. + 18-Apr-12 RMS Removed separate timer for additional terminals; + added clock_cosched prototype 22-May-10 RMS Added check for 64b definitions 21-Aug-07 RMS Added FPP8 support 13-Dec-06 RMS Added TA8E support @@ -78,7 +80,6 @@ /* Timers */ #define TMR_CLK 0 /* timer 0 = clock */ -#define TMR_TTX 1 /* timer 1 = TTx */ /* Device information block */ @@ -209,4 +210,6 @@ typedef struct { t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc); +int32 clk_cosched (int32 wait); + #endif diff --git a/PDP8/pdp8_dt.c b/PDP8/pdp8_dt.c index 8c452eae..2b0ffe9b 100644 --- a/PDP8/pdp8_dt.c +++ b/PDP8/pdp8_dt.c @@ -964,7 +964,7 @@ switch (fnc) { /* at speed, check fnc * if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; } -/* /* ignore hdr */ + /* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); if (M[DT_WC] == 0) dt_substate = DTO_WCO; 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_mt.c b/PDP8/pdp8_mt.c index 914c8619..844f414c 100644 --- a/PDP8/pdp8_mt.c +++ b/PDP8/pdp8_mt.c @@ -120,7 +120,7 @@ #define STA_CPE (00002 << 12) /* compare error */ #define STA_ILL (00001 << 12) /* illegal */ #define STA_9TK 00040 /* 9 track */ -/* #define STA_BAD 00020 /* bad tape?? */ +/* #define STA_BAD 00020 *//* bad tape?? */ #define STA_INC 00010 /* increment error */ #define STA_LAT 00004 /* lateral par error */ #define STA_CRC 00002 /* CRC error */ @@ -453,7 +453,7 @@ switch (f) { /* case on function */ mtxb[p++] = M[xma] & 077; } } - if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) { /* write rec, err? */ r = mt_map_err (uptr, st); /* map error */ xma = GET_EMA (mt_cu) + mt_ca; /* restore xma */ } @@ -461,14 +461,14 @@ switch (f) { /* case on function */ break; case FN_WREOF: - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ break; case FN_SPACEF: /* space forward */ do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* stop */ } @@ -478,7 +478,7 @@ switch (f) { /* case on function */ case FN_SPACER: /* space reverse */ do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* stop */ } 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/PDP8/pdp8_tt.c b/PDP8/pdp8_tt.c index 8ae9b168..9f39b5d1 100644 --- a/PDP8/pdp8_tt.c +++ b/PDP8/pdp8_tt.c @@ -1,6 +1,6 @@ /* pdp8_tt.c: PDP-8 console terminal 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 @@ tti,tto KL8E terminal input/output + 18-Apr-12 RMS Revised to use clock coscheduling 18-Jun-07 RMS Added UNIT_IDLE flag to console input 18-Oct-06 RMS Synced keyboard to clock 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode @@ -44,7 +45,7 @@ #include extern int32 int_req, int_enable, dev_done, stop_inst; -extern int32 tmxr_poll; +extern int32 tmxr_poll, sim_is_running; int32 tti (int32 IR, int32 AC); int32 tto (int32 IR, int32 AC); @@ -175,7 +176,8 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll))); + /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; if (c & SCPE_BREAK) /* break? */ @@ -195,7 +197,8 @@ tti_unit.buf = 0; dev_done = dev_done & ~INT_TTI; /* clear done, int */ int_req = int_req & ~INT_TTI; int_enable = int_enable | INT_TTI; /* set enable */ -sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); +if (!sim_is_running) /* RESET (not CAF)? */ + sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); return SCPE_OK; } diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index 8c0ca6ed..5c335a48 100644 --- a/PDP8/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -1,6 +1,6 @@ /* pdp8_ttx.c: PDP-8 additional terminals simulator - Copyright (c) 1993-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 @@ ttix,ttox PT08/KL8JA terminal input/output + 18-Apr-12 RMS Revised to use clock coscheduling 19-Nov-08 RMS Revised for common TMXR show routines 07-Jun-06 RMS Added UNIT_IDLE flag 06-Jul-06 RMS Fixed bug in DETACH routine @@ -60,6 +61,7 @@ #define TTX_GETLN(x) (((x) >> 4) & TTX_MASK) extern int32 int_req, int_enable, dev_done, stop_inst; +extern int32 tmxr_poll, sim_is_running; uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */ uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */ @@ -224,15 +226,14 @@ int32 ln, c, temp; if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_OK; -temp = sim_rtcn_calb (ttx_tps, TMR_TTX); /* calibrate */ -sim_activate (uptr, temp); /* continue poll */ +sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */ ln = tmxr_poll_conn (&ttx_desc); /* look for connect */ if (ln >= 0) /* got one? rcv enb*/ ttx_ldsc[ln].rcve = 1; tmxr_poll_rx (&ttx_desc); /* poll for input */ for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */ if (ttx_ldsc[ln].conn) { /* connected? */ - if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */ + if ((temp = tmxr_getc_ln (&ttx_ldsc[ln]))) { /* get char */ if (temp & SCPE_BREAK) /* break? */ c = 0; else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags)); @@ -249,15 +250,11 @@ return SCPE_OK; t_stat ttix_reset (DEVICE *dptr) { -int32 t, ln, itto; +int32 ln, itto; ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ -if (ttix_unit.flags & UNIT_ATT) { /* if attached, */ - if (!sim_is_active (&ttix_unit)) { - t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); - sim_activate (&ttix_unit, t); /* activate */ - } - } +if (ttix_unit.flags & UNIT_ATT) /* if attached, */ + sim_activate (&ttix_unit, tmxr_poll); /* activate */ else sim_cancel (&ttix_unit); /* else stop */ for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */ ttix_buf[ln] = 0; /* clear buf, */ @@ -358,14 +355,12 @@ return SCPE_OK; t_stat ttx_attach (UNIT *uptr, char *cptr) { -int32 t; t_stat r; r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */ if (r != SCPE_OK) /* error */ return r; -t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init calib */ -sim_activate (uptr, t); /* start poll */ +sim_activate (uptr, tmxr_poll); /* start poll */ return SCPE_OK; } diff --git a/S3/s3_cd.c b/S3/s3_cd.c index 5221c775..d63d783f 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 @@ -40,8 +41,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); @@ -279,7 +280,7 @@ t_stat r; if (sim_is_active (&cdr_unit)) { /* busy? */ sim_cancel (&cdr_unit); /* cancel */ - if (r = cdr_svc (&cdr_unit)) return r; /* process */ + if ((r = cdr_svc (&cdr_unit))) return r; /* process */ } if (((cdp_unit.flags & UNIT_ATT) != 0 || diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c index 0574d15b..e3f06482 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 @@ -381,7 +383,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); @@ -525,7 +527,7 @@ reason = 0; while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) break; + if ((reason = sim_process_event ())) break; } if (int_req) { /* interrupt? */ diff --git a/S3/s3_disk.c b/S3/s3_disk.c index d3588cfd..f0a2ed20 100644 --- a/S3/s3_disk.c +++ b/S3/s3_disk.c @@ -298,7 +298,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) addr++; } - if ((sect == 55) ) { /* HJS MODS */ + if (sect == 55) { /* HJS MODS */ S = sect; N = nsects - i - 2; if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ @@ -349,7 +349,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) diskerr[disk] |= 0x0800; break; } - if ((sect == 55) ) { /* HJS MODS */ + if (sect == 55) { /* HJS MODS */ S = sect; N = nsects - i - 2; if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ @@ -392,7 +392,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) diskerr[disk] |= 0x0400; break; } - if ((sect == 55) ) { /* HJS MODS */ + if (sect == 55) { /* HJS MODS */ S = sect; N = nsects - i - 2; if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ @@ -434,7 +434,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) diskerr[disk] |= 0x0400; break; } - if ((sect == 55) ) { + if (sect == 55) { S = sect; N = nsects - i - 2; if (N > 0) diskerr[disk] |= 0x0020; @@ -486,7 +486,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) found[disk] = 1; if (res == data) break; - if ((sect == 55) ) { /* HJS MODS */ + if (sect == 55) { /* HJS MODS */ S = sect; N = nsects - i - 2; if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ diff --git a/S3/s3_lp.c b/S3/s3_lp.c index cf21a127..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 */ @@ -41,7 +42,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 @@ -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 0fa2c1ee..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 @@ -41,7 +43,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_cpu.c b/SDS/sds_cpu.c index a8f87db7..f045b6e7 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -385,14 +385,14 @@ while (reason == 0) { /* loop until halted */ } if (sim_interval <= 0) { /* event queue? */ - if (reason = sim_process_event ()) /* process */ + if ((reason = sim_process_event ())) /* process */ break; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ } if (chan_req) { /* channel request? */ - if (reason = chan_process ()) /* process */ + if ((reason = chan_process ())) /* process */ break; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ @@ -506,7 +506,7 @@ if (inst & I_POP) { /* POP? */ } else { /* normal POP */ dat = (OV << 23) | dat; /* ov in <0> */ - if (r = Write (0, dat)) + if ((r = Write (0, dat))) return r; } } @@ -525,49 +525,49 @@ switch (op) { /* case on opcode */ /* Loads and stores */ case LDA: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &A)) /* get operand */ + if ((r = Read (va, &A))) /* get operand */ return r; break; case LDB: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &B)) /* get operand */ + if ((r = Read (va, &B))) /* get operand */ return r; break; case LDX: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &X)) /* get operand */ + if ((r = Read (va, &X))) /* get operand */ return r; break; case STA: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Write (va, A)) /* write operand */ + if ((r = Write (va, A))) /* write operand */ return r; break; case STB: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Write (va, B)) /* write operand */ + if ((r = Write (va, B))) /* write operand */ return r; break; case STX: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Write (va, X)) /* write operand */ + if ((r = Write (va, X))) /* write operand */ return r; break; case EAX: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; if (nml_mode || usr_mode) /* normal or user? */ X = (X & ~VA_MASK) | (va & VA_MASK); /* only 14b */ @@ -575,11 +575,11 @@ switch (op) { /* case on opcode */ break; case XMA: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; - if (r = Write (va, A)) /* write A */ + if ((r = Write (va, A))) /* write A */ return r; A = dat; /* load A */ break; @@ -587,95 +587,95 @@ switch (op) { /* case on opcode */ /* Arithmetic and logical */ case ADD: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = Add24 (A, dat, 0); /* add */ break; case ADC: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; OV = 0; /* clear overflow */ A = Add24 (A, dat, X >> 23); /* add with carry */ break; case SUB: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = Add24 (A, dat ^ DMASK, 1); /* subtract */ break; case SUC: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; OV = 0; /* clear overflow */ A = Add24 (A, dat ^ DMASK, X >> 23); /* sub with carry */ break; case ADM: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; dat = AddM24 (dat, A); /* mem + A */ - if (r = Write (va, dat)) /* rewrite */ + if ((r = Write (va, dat))) /* rewrite */ return r; break; case MIN: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; dat = AddM24 (dat, 1); /* mem + 1 */ - if (r = Write (va, dat)) /* rewrite */ + if ((r = Write (va, dat))) /* rewrite */ return r; break; case MUL: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; Mul48 (A, dat); /* multiply */ break; case DIV: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; Div48 (A, B, dat); /* divide */ break; case ETR: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = A & dat; /* and */ break; case MRG: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = A | dat; /* or */ break; case EOR: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = A ^ dat; /* xor */ break; @@ -683,75 +683,75 @@ switch (op) { /* case on opcode */ /* Skips */ case SKE: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (A == dat) /* if A = op, skip */ P = (P + 1) & VA_MASK; break; case SKG: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (SXT (A) > SXT (dat)) /* if A > op, skip */ P = (P + 1) & VA_MASK; break; case SKM: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (((A ^ dat) & B) == 0) /* if A = op masked */ P = (P + 1) & VA_MASK; break; case SKA: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if ((A & dat) == 0) /* if !(A & op), skip */ P = (P + 1) & VA_MASK; break; case SKB: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if ((B & dat) == 0) /* if !(B & op), skip */ P = (P + 1) & VA_MASK; break; case SKN: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (dat & SIGN) /* if op < 0, skip */ P = (P + 1) & VA_MASK; break; case SKR: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; dat = AddM24 (dat, DMASK); /* decr operand */ - if (r = Write (va, dat)) /* rewrite */ + if ((r = Write (va, dat))) /* rewrite */ return r; if (dat & SIGN) /* if op < 0, skip */ P = (P + 1) & VA_MASK; break; case SKD: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (SXT_EXP (B) < SXT_EXP (dat)) { /* B < dat? */ X = (dat - B) & DMASK; /* X = dat - B */ @@ -774,29 +774,29 @@ switch (op) { /* case on opcode */ exu_cnt = exu_cnt + 1; /* count chained EXU */ if (exu_cnt > exu_lim) /* too many? */ return STOP_EXULIM; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; inst = dat; goto EXU_LOOP; case BRU: if (nml_mode && (inst & I_IND)) api_dismiss (); /* normal BRU*, dism */ - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; PCQ_ENTRY; P = va & VA_MASK; /* branch */ break; case BRX: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; X = (X + 1) & DMASK; /* incr X */ if (X & I_IND) { /* bit 9 set? */ - if (r = Read (va, &dat)) /* test dest access */ + if ((r = Read (va, &dat))) /* test dest access */ return r; PCQ_ENTRY; P = va & VA_MASK; /* branch */ @@ -804,22 +804,22 @@ switch (op) { /* case on opcode */ break; case BRM: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; dat = (EM3 << 18) | (EM2 << 15) | pc; /* form return word */ if (!nml_mode && !usr_mode) /* monitor mode? */ dat = dat | (mode << 23) | (OV << 21); else dat = dat | (OV << 23); /* normal or user */ - if (r = Write (va, dat)) /* write ret word */ + if ((r = Write (va, dat))) /* write ret word */ return r; PCQ_ENTRY; P = (va + 1) & VA_MASK; /* branch */ break; case BRR: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; PCQ_ENTRY; P = (dat + 1) & VA_MASK; /* branch */ @@ -837,9 +837,9 @@ switch (op) { /* case on opcode */ case BRI: if (!nml_mode && usr_mode) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; api_dismiss (); /* dismiss hi api */ PCQ_ENTRY; @@ -909,7 +909,7 @@ switch (op) { /* case on opcode */ /* Shifts */ case RSH: - if (r = EaSh (inst, &va)) /* decode eff addr */ + if ((r = EaSh (inst, &va))) /* decode eff addr */ return r; shf_op = I_GETSHFOP (va); /* get eff op */ sc = va & I_SHFMSK; /* get eff count */ @@ -934,7 +934,7 @@ switch (op) { /* case on opcode */ break; case LSH: - if (r = EaSh (inst, &va)) /* decode eff addr */ + if ((r = EaSh (inst, &va))) /* decode eff addr */ return r; shf_op = I_GETSHFOP (va); /* get eff op */ sc = va & I_SHFMSK; /* get eff count */ @@ -989,11 +989,11 @@ switch (op) { /* case on opcode */ case MIW: case MIY: if (!nml_mode && usr_mode) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; - if (r = op_miwy (inst, dat)) /* process inst */ + if ((r = op_miwy (inst, dat))) /* process inst */ return r; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ @@ -1002,11 +1002,11 @@ switch (op) { /* case on opcode */ case WIM: case YIM: if (!nml_mode && usr_mode) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = op_wyim (inst, &dat)) /* process inst */ + if ((r = op_wyim (inst, &dat))) /* process inst */ return r; - if (r = Write (va, dat)) + if ((r = Write (va, dat))) return r; /* write result */ int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ @@ -1015,7 +1015,7 @@ switch (op) { /* case on opcode */ case EOM: case EOD: if (!nml_mode && usr_mode) /* priv inst */ return MM_PRVINS; - if (r = op_eomd (inst)) /* process inst */ + if ((r = op_eomd (inst))) /* process inst */ return r; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ @@ -1025,11 +1025,11 @@ switch (op) { /* case on opcode */ case POT: if (!nml_mode && usr_mode) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; - if (r = op_pot (dat)) /* process inst */ + if ((r = op_pot (dat))) /* process inst */ return r; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ @@ -1038,11 +1038,11 @@ switch (op) { /* case on opcode */ case PIN: if (!nml_mode && usr_mode) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = op_pin (&dat)) /* process inst */ + if ((r = op_pin (&dat))) /* process inst */ return r; - if (r = Write (va, dat)) /* write result */ + if ((r = Write (va, dat))) /* write result */ return r; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ @@ -1051,7 +1051,7 @@ switch (op) { /* case on opcode */ case SKS: if (!nml_mode && usr_mode) /* priv inst */ return MM_PRVINS; - if (r = op_sks (inst, &dat)) /* process inst */ + if ((r = op_sks (inst, &dat))) /* process inst */ return r; if (dat) P = (P + 1) & VA_MASK; @@ -1085,7 +1085,7 @@ for (i = 0; i < ind_lim; i++) { /* count indirects */ hst[hst_p].ea = *addr; return SCPE_OK; } - if (r = Read (va, &wd)) /* read ind; fails? */ + if ((r = Read (va, &wd))) /* read ind; fails? */ return r; va = (va & VA_USR) | (wd & XVA_MASK); } @@ -1112,7 +1112,7 @@ for (i = 0; i < ind_lim; i++) { /* count indirects */ } if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK); - if (r = Read (va, &wd)) /* read ind; fails? */ + if ((r = Read (va, &wd))) /* read ind; fails? */ return r; va = (va & VA_USR) | (wd & XVA_MASK); } @@ -1569,12 +1569,12 @@ if (op == MIN) /* incr */ else if (op == SKR) /* decr */ val = DMASK; else return STOP_RTCINS; /* can't do it */ -if (r = Ea (inst, &va)) /* decode eff addr */ +if ((r = Ea (inst, &va))) /* decode eff addr */ return r; -if (r = Read (va, &dat)) /* get operand */ +if ((r = Read (va, &dat))) /* get operand */ return r; dat = AddM24 (dat, val); /* mem +/- 1 */ -if (r = Write (va, dat)) /* rewrite */ +if ((r = Write (va, dat))) /* rewrite */ return r; if (dat == 0) /* set clk sync int */ int_req = int_req | INT_RTCS; diff --git a/SDS/sds_dsk.c b/SDS/sds_dsk.c index cf9d41ea..22d0a7a3 100644 --- a/SDS/sds_dsk.c +++ b/SDS/sds_dsk.c @@ -204,7 +204,7 @@ switch (fnc) { /* case on function */ case IO_READ: xfr_req = xfr_req & ~XFR_DSK; /* clr xfr req */ if (dsk_bptr >= dsk_blnt) { /* no more data? */ - if (r = dsk_read_buf (inst)) /* read sector */ + if ((r = dsk_read_buf (inst))) /* read sector */ return r; } dsk_wptr = dsk_bptr >> 2; /* word pointer */ @@ -219,7 +219,7 @@ switch (fnc) { /* case on function */ case IO_WRITE: xfr_req = xfr_req & ~XFR_DSK; /* clr xfr req */ if (dsk_bptr >= (DSK_NUMWD * 4)) { /* full? */ - if (r = dsk_write_buf (inst)) /* write sector */ + if ((r = dsk_write_buf (inst))) /* write sector */ return r; } dsk_wptr = dsk_bptr >> 2; /* word pointer */ diff --git a/SDS/sds_io.c b/SDS/sds_io.c index 241d7ce7..bd0b01f4 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" @@ -79,9 +81,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[]; @@ -333,7 +336,7 @@ switch (mod) { chan_mode[ch] = chan_uar[ch] = 0; if (ch >= CHAN_E) chan_mode[ch] = CHM_CE; - if (r = dev_dsp[dev][ch] (IO_CONN, inst, NULL)) /* connect */ + if ((r = dev_dsp[dev][ch] (IO_CONN, inst, NULL)))/* connect */ return r; if ((inst & I_IND) || (ch >= CHAN_C)) { /* C-H? alert ilc */ alert = POT_ILCY + ch; @@ -955,7 +958,7 @@ for (i = 0; i < NUM_CHAN; i++) { /* Test each device for conflict; add to map; init tables */ -for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ +for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */ continue; diff --git a/SDS/sds_lp.c b/SDS/sds_lp.c index 0de82e70..cbef5249 100644 --- a/SDS/sds_lp.c +++ b/SDS/sds_lp.c @@ -177,7 +177,7 @@ switch (fnc) { /* case function */ t = I_GETSKCND (inst); /* sks cond */ if (((t == 020) && (!CHP (7, lpt_cct[lpt_ccp]))) || /* 14062: !ch 7 */ ((t == 010) && (lpt_unit.flags & UNIT_ATT)) || /* 12062: !online */ - (t == 004) && !lpt_err) /* 11062: !err */ + ((t == 004) && !lpt_err)) /* 11062: !err */ *dat = 1; break; diff --git a/SDS/sds_mt.c b/SDS/sds_mt.c index f7590eec..3e398ac5 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 */ @@ -234,14 +235,14 @@ switch (fnc) { /* case function */ case IO_DISC: /* disconnect */ sim_cancel (uptr); /* no more xfr's */ if (inst & DEV_OUT) { /* write? */ - if (r = mt_wrend (inst)) /* end record */ + if ((r = mt_wrend (inst))) /* end record */ return r; } break; case IO_WREOR: /* write eor */ chan_set_flag (mt_dib.chan, CHF_EOR); /* set eor flg */ - if (r = mt_wrend (inst)) /* end record */ + if ((r = mt_wrend (inst))) /* end record */ return r; mt_gap = 1; /* in gap */ sim_activate (uptr, mt_gtime); /* start timer */ diff --git a/SDS/sds_mux.c b/SDS/sds_mux.c index ef6203fd..8cc7023a 100644 --- a/SDS/sds_mux.c +++ b/SDS/sds_mux.c @@ -363,7 +363,7 @@ if (ln >= 0) { /* got one? */ 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 = tmxr_getc_ln (&mux_ldsc[ln]))) { /* get char */ if (mux_sta[ln] & MUX_SCHP) /* already got one? */ mux_sta[ln] = mux_sta[ln] | MUX_SOVR; /* overrun */ else mux_sta[ln] = mux_sta[ln] | MUX_SCHP; /* char pending */ diff --git a/SDS/sds_stddev.c b/SDS/sds_stddev.c index 7899228b..13877418 100644 --- a/SDS/sds_stddev.c +++ b/SDS/sds_stddev.c @@ -395,7 +395,7 @@ t_stat r = SCPE_OK; if (ptp_ldr) { /* need leader? */ for (i = 0; i < 12; i++) { /* punch leader */ - if (r = ptp_out (0)) + if ((r = ptp_out (0))) break; } } diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index cd87ea82..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" @@ -154,7 +156,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/VAX/vax730_rb.c b/VAX/vax730_rb.c index 18aebbaf..fa0f4f25 100644 --- a/VAX/vax730_rb.c +++ b/VAX/vax730_rb.c @@ -535,7 +535,7 @@ if ((func >= RBCS_READ) && (err == 0)) { /* read (no hdr)? */ err = ferror (uptr->fileref); for ( ; i < wc; i++) /* fill buffer */ rbxb[i] = 0; - if (t = Map_WriteW (ma, wc << 1, rbxb)) { /* store buffer */ + if ((t = Map_WriteW (ma, wc << 1, rbxb))) { /* store buffer */ rbcs = rbcs | RBCS_ERR | RBCS_NXM; /* nxm */ wc = wc - t; /* adjust wc */ } @@ -543,7 +543,7 @@ if ((func >= RBCS_READ) && (err == 0)) { /* read (no hdr)? */ if ((func == RBCS_WRITE) && (err == 0)) { /* write? */ sim_debug(DBG_CMD, &rb_dev, "Write, CYL=%d, TRK=%d, SECT=%d, WC=%d, DA=%d\n", GET_CYL(rbda), GET_TRACK(rbda), GET_SECT(rbda), wc, da); - if (t = Map_ReadW (ma, wc << 1, rbxb)) { /* fetch buffer */ + if ((t = Map_ReadW (ma, wc << 1, rbxb))) { /* fetch buffer */ rbcs = rbcs | RBCS_ERR | RBCS_NXM; /* nxm */ wc = wc - t; /* adj xfer lnt */ } diff --git a/VAX/vax730_stddev.c b/VAX/vax730_stddev.c index 8960fe2e..293afaeb 100644 --- a/VAX/vax730_stddev.c +++ b/VAX/vax730_stddev.c @@ -1093,7 +1093,7 @@ switch (td_state) { /* case on state */ if (td_txsize > 0) td_state = TD_WRITE1; else { /* check whole number of blocks written */ - if (td_olen = (512 - (td_offset % 512)) != 512) { + if ((td_olen = (512 - (td_offset % 512)) != 512)) { for (i = 0; i < td_olen; i++) fbuf[da + i] = 0; /* zero fill */ da = da + td_olen; diff --git a/VAX/vax730_sys.c b/VAX/vax730_sys.c index 3b1b78b7..799bea7e 100644 --- a/VAX/vax730_sys.c +++ b/VAX/vax730_sys.c @@ -35,7 +35,7 @@ #include "vax_defs.h" #ifndef DONT_USE_INTERNAL_ROM -#include "vax780_vmb_exe.h" +#include "vax_vmb_exe.h" #endif static char cpu_boot_cmd[CBUFSIZE] = { 0 }; /* boot command */ @@ -146,7 +146,7 @@ CTAB vax730_cmd[] = { - internal device interrupts (CPU, console, clock, console storage) - external device interrupts (Unibus) -/* Find highest priority vectorable interrupt */ + Find highest priority vectorable interrupt */ int32 eval_int (void) { @@ -499,7 +499,7 @@ uint32 ba; t_stat r; regptr = get_glyph (ptr, gbuf, 0); /* get glyph */ -if (slptr = strchr (gbuf, '/')) { /* found slash? */ +if ((slptr = strchr (gbuf, '/'))) { /* found slash? */ regptr = strchr (ptr, '/'); /* locate orig */ *slptr = 0; /* zero in string */ } @@ -553,11 +553,11 @@ if (r != SCPE_OK) { #ifndef DONT_USE_INTERNAL_ROM FILE *f; - if (f = sim_fopen ("vmb.exe", "wb")) { + if ((f = sim_fopen ("vmb.exe", "wb"))) { printf ("Saving boot code to vmb.exe\n"); if (sim_log) fprintf (sim_log, "Saving boot code to vmb.exe\n"); - sim_fwrite (vax780_vmb_exe, sizeof(vax780_vmb_exe[0]), sizeof(vax780_vmb_exe)/sizeof(vax780_vmb_exe[0]), f); + sim_fwrite (vax_vmb_exe, sizeof(vax_vmb_exe[0]), sizeof(vax_vmb_exe)/sizeof(vax_vmb_exe[0]), f); fclose (f); printf ("Loading boot code from vmb.exe\n"); if (sim_log) @@ -652,11 +652,11 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ if (dptr->flags & DEV_NEXUS) { /* Nexus? */ - if (r = build_nexus_tab (dptr, dibp)) /* add to dispatch table */ + if ((r = build_nexus_tab (dptr, dibp))) /* add to dispatch table */ return r; } else { /* no, Unibus device */ - if (r = build_ubus_tab (dptr, dibp)) /* add to dispatch tab */ + if ((r = build_ubus_tab (dptr, dibp))) /* add to dispatch tab */ return r; } /* end else */ } /* end if enabled */ diff --git a/VAX/vax750_cmi.c b/VAX/vax750_cmi.c index 7b05f5dd..8fe72bd7 100644 --- a/VAX/vax750_cmi.c +++ b/VAX/vax750_cmi.c @@ -33,6 +33,10 @@ #include "vax_defs.h" +#ifndef DONT_USE_INTERNAL_ROM +#include "vax_vmb_exe.h" +#endif + /* 11/750 specific IPRs */ #define CMIERR_CRD 0x00000001 @@ -74,6 +78,9 @@ static struct boot_dev boot_tab[] = { { "HK", BOOT_HK, 0 }, { "RL", BOOT_RL, 0 }, { "RQ", BOOT_UDA, 1 << 24 }, + { "RQB", BOOT_UDA, 1 << 24 }, + { "RQC", BOOT_UDA, 1 << 24 }, + { "RQD", BOOT_UDA, 1 << 24 }, { "TQ", BOOT_TK, 1 << 24 }, { "TD", BOOT_TD, 0 }, { NULL } @@ -178,7 +185,7 @@ CTAB vax750_cmd[] = { reads a vector register that contains the Unibus vector for that IPL. -/* Find highest priority vectorable interrupt */ + Find highest priority vectorable interrupt */ int32 eval_int (void) { @@ -577,7 +584,7 @@ uint32 ba; t_stat r; regptr = get_glyph (ptr, gbuf, 0); /* get glyph */ -if (slptr = strchr (gbuf, '/')) { /* found slash? */ +if ((slptr = strchr (gbuf, '/'))) { /* found slash? */ regptr = strchr (ptr, '/'); /* locate orig */ *slptr = 0; /* zero in string */ } @@ -631,8 +638,26 @@ printf ("Loading boot code from vmb.exe\n"); if (sim_log) fprintf (sim_log, "Loading boot code from vmb.exe\n"); r = load_cmd (0, "-O vmb.exe 200"); -if (r != SCPE_OK) +if (r != SCPE_OK) { +#ifndef DONT_USE_INTERNAL_ROM + FILE *f; + + if ((f = sim_fopen ("vmb.exe", "wb"))) { + printf ("Saving boot code to vmb.exe\n"); + if (sim_log) + fprintf (sim_log, "Saving boot code to vmb.exe\n"); + sim_fwrite (vax_vmb_exe, sizeof(vax_vmb_exe[0]), sizeof(vax_vmb_exe)/sizeof(vax_vmb_exe[0]), f); + fclose (f); + printf ("Loading boot code from vmb.exe\n"); + if (sim_log) + fprintf (sim_log, "Loading boot code from vmb.exe\n"); + r = load_cmd (0, "-O vmb.exe 200"); + if (r == SCPE_OK) + SP = PC = 512; + } +#endif return r; + } SP = PC = 512; return SCPE_OK; } @@ -719,15 +744,15 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ if (dptr->flags & DEV_NEXUS) { /* Nexus? */ - if (r = build_nexus_tab (dptr, dibp)) /* add to dispatch table */ + if ((r = build_nexus_tab (dptr, dibp))) /* add to dispatch table */ return r; } else if (dptr->flags & DEV_MBUS) { /* Massbus? */ - if (r = build_mbus_tab (dptr, dibp)) + if ((r = build_mbus_tab (dptr, dibp))) return r; } else { /* no, Unibus device */ - if (r = build_ubus_tab (dptr, dibp)) /* add to dispatch tab */ + if ((r = build_ubus_tab (dptr, dibp))) /* add to dispatch tab */ return r; } /* end else */ } /* end if enabled */ diff --git a/VAX/vax750_stddev.c b/VAX/vax750_stddev.c index a98b7ce7..8b6e3a90 100644 --- a/VAX/vax750_stddev.c +++ b/VAX/vax750_stddev.c @@ -30,6 +30,31 @@ todr TODR clock tmr interval timer + 22-Oct-12 MP Generalized setting TODR for all OSes. + Unbound the TODR value from the 100hz clock tick + interrupt. TODR now behaves like the original + battery backed-up clock and runs with the wall + clock, not the simulated instruction clock. + Two operational modes are available: + - Default VMS mode, which is similar to the previous + behavior in that without initializing the TODR it + would default to the value VMS would set it to if + VMS knew the correct time. This would be correct + almost all the time unless a VMS disk hadn't been + booted from for more than a year. This mode + produces strange time results for non VMS OSes on + each system boot. + - OS Agnostic mode. This mode behaves precisely like + the VAX780 TODR and works correctly for all OSes. + This mode is enabled by attaching the TODR to a + battery backup state file for the TOY clock + (i.e. sim> attach TODR TOY_CLOCK). When operating + in OS Agnostic mode, the TODR will initially start + counting from 0 and be adjusted differently when an + OS specifically writes to the TODR. VMS will prompt + to set the time on each boot (if the TODR value is + less than about 1 month) unless the SYSGEN + parameter TIMEPROMPTWAIT is set to 0. 21-Oct-2012 MB First Version */ @@ -156,6 +181,11 @@ int32 clk_tps = 100; /* ticks/second */ int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ int32 todr_reg = 0; /* TODR register */ +struct todr_battery_info { + uint32 toy_gmtbase; /* GMT base of set value */ + uint32 toy_gmtbasemsec; /* The milliseconds of the set value */ + }; +typedef struct todr_battery_info TOY; int32 td_swait = 100; /* seek, per block */ int32 td_cwait = 150; /* command time */ @@ -183,6 +213,8 @@ t_stat tmr_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat clk_reset (DEVICE *dptr); +t_stat clk_attach (UNIT *uptr, char *cptr); +t_stat clk_detach (UNIT *uptr); t_stat tmr_reset (DEVICE *dptr); t_stat td_svc (UNIT *uptr); t_stat td_reset (DEVICE *dptr); @@ -267,20 +299,24 @@ DEVICE tto_dev = { /* TODR and TMR data structures */ -UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; /* 100Hz */ +UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */ REG clk_reg[] = { { DRDATA (TODR, todr_reg, 32), PV_LEFT }, { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (TPS, clk_tps, 8), REG_HIDDEN + REG_NZ + PV_LEFT }, +#if defined (SIM_ASYNCH_IO) + { DRDATA (LATENCY, sim_asynch_latency, 32), PV_LEFT }, + { DRDATA (INST_LATENCY, sim_asynch_inst_latency, 32), PV_LEFT }, +#endif { NULL } }; DEVICE clk_dev = { "TODR", &clk_unit, clk_reg, NULL, - 1, 0, 0, 0, 0, 0, + 1, 0, 8, 4, 0, 32, NULL, NULL, &clk_reset, - NULL, NULL, NULL, + NULL, &clk_attach, &clk_detach, NULL, 0 }; @@ -757,7 +793,7 @@ t_stat clk_svc (UNIT *uptr) tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate (&clk_unit, tmr_poll); /* reactivate unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ -todr_reg = todr_reg + 1; /* incr TODR */ +AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */ if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */ tmr_incr (TMR_INC); /* do timer service */ return SCPE_OK; @@ -830,9 +866,44 @@ t_stat clk_reset (DEVICE *dptr) tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */ sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ +if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */ + clk_unit.filebuf = calloc(sizeof(TOY), 1); + if (clk_unit.filebuf == NULL) + return SCPE_MEM; + todr_resync (); + } return SCPE_OK; } +/* CLK attach */ + +t_stat clk_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE); +memset (uptr->filebuf, 0, (size_t)uptr->capac); +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) + uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); +else + uptr->hwmark = (uint32) uptr->capac; +return r; +} + +/* CLK detach */ + +t_stat clk_detach (UNIT *uptr) +{ +t_stat r; + +r = detach_unit (uptr); +if ((uptr->flags & UNIT_ATT) == 0) + uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); +return r; +} + + /* Interval timer reset */ t_stat tmr_reset (DEVICE *dptr) @@ -851,32 +922,59 @@ return SCPE_OK; int32 todr_rd (void) { -return todr_reg; +TOY *toy = (TOY *)clk_unit.filebuf; +struct timespec base, now, val; + +clock_gettime(CLOCK_REALTIME, &now); /* get curr time */ +base.tv_sec = toy->toy_gmtbase; +base.tv_nsec = toy->toy_gmtbasemsec * 1000000; +sim_timespec_diff (&val, &now, &base); +return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */ } + void todr_wr (int32 data) { -todr_reg = data; -return; +TOY *toy = (TOY *)clk_unit.filebuf; +struct timespec now, val, base; + +/* Save the GMT time when set value was 0 to record the base for future + read operations in "battery backed-up" state */ + +if (-1 == clock_gettime(CLOCK_REALTIME, &now)) /* get curr time */ + return; /* error? */ +val.tv_sec = ((uint32)data) / 100; +val.tv_nsec = (((uint32)data) % 100) * 10000000; +sim_timespec_diff (&base, &now, &val); /* base = now - data */ +toy->toy_gmtbase = (uint32)base.tv_sec; +toy->toy_gmtbasemsec = base.tv_nsec/1000000; } t_stat todr_resync (void) { -uint32 base; -time_t curr; -struct tm *ctm; +TOY *toy = (TOY *)clk_unit.filebuf; -curr = time (NULL); /* get curr time */ -if (curr == (time_t) -1) /* error? */ - return SCPE_NOFNC; -ctm = localtime (&curr); /* decompose */ -if (ctm == NULL) /* error? */ - return SCPE_NOFNC; -base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ - ctm->tm_hour) * 60) + - ctm->tm_min) * 60) + - ctm->tm_sec; -todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */ +if (clk_unit.flags & UNIT_ATT) { /* Attached means behave like real VAX780 */ + if (!toy->toy_gmtbase) /* Never set? */ + todr_wr (0); /* Start ticking from 0 */ + } +else { /* Not-Attached means */ + uint32 base; /* behave like simh VMS default */ + time_t curr; + struct tm *ctm; + + curr = time (NULL); /* get curr time */ + if (curr == (time_t) -1) /* error? */ + return SCPE_NOFNC; + ctm = localtime (&curr); /* decompose */ + if (ctm == NULL) /* error? */ + return SCPE_NOFNC; + base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ + ctm->tm_hour) * 60) + + ctm->tm_min) * 60) + + ctm->tm_sec; + todr_wr ((base * 100) + 0x10000000); /* use VMS form */ + } return SCPE_OK; } @@ -994,7 +1092,7 @@ switch (td_state) { /* case on state */ if (td_txsize > 0) td_state = TD_WRITE1; else { /* check whole number of blocks written */ - if (td_olen = (512 - (td_offset % 512)) != 512) { + if ((td_olen = (512 - (td_offset % 512))) != 512) { for (i = 0; i < td_olen; i++) fbuf[da + i] = 0; /* zero fill */ da = da + td_olen; 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_defs.h b/VAX/vax780_defs.h index 274bce9f..c36a0b2d 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -287,6 +287,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 */ @@ -334,6 +336,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) @@ -345,6 +349,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) @@ -362,6 +368,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 */ @@ -382,6 +390,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_sbi.c b/VAX/vax780_sbi.c index a4ad4739..77a74464 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 */ @@ -37,7 +37,7 @@ #include "vax_defs.h" #ifndef DONT_USE_INTERNAL_ROM -#include "vax780_vmb_exe.h" +#include "vax_vmb_exe.h" #endif /* 11/780 specific IPRs */ @@ -224,7 +224,7 @@ CTAB vax780_cmd[] = { Instead, the interrupt handler for a given UBA IPL reads a vector register that contains the Unibus vector for that IPL. - +*/ /* Find highest priority vectorable interrupt */ int32 eval_int (void) @@ -646,7 +646,7 @@ DIB *dibp; t_stat r; regptr = get_glyph (ptr, gbuf, 0); /* get glyph */ -if (slptr = strchr (gbuf, '/')) { /* found slash? */ +if ((slptr = strchr (gbuf, '/'))) { /* found slash? */ regptr = strchr (ptr, '/'); /* locate orig */ *slptr = 0; /* zero in string */ } @@ -702,11 +702,11 @@ if (r != SCPE_OK) { #ifndef DONT_USE_INTERNAL_ROM FILE *f; - if (f = sim_fopen ("vmb.exe", "wb")) { + if ((f = sim_fopen ("vmb.exe", "wb"))) { printf ("Saving boot code to vmb.exe\n"); if (sim_log) fprintf (sim_log, "Saving boot code to vmb.exe\n"); - sim_fwrite (vax780_vmb_exe, sizeof(vax780_vmb_exe[0]), sizeof(vax780_vmb_exe)/sizeof(vax780_vmb_exe[0]), f); + sim_fwrite (vax_vmb_exe, sizeof(vax_vmb_exe[0]), sizeof(vax_vmb_exe)/sizeof(vax_vmb_exe[0]), f); fclose (f); printf ("Loading boot code from vmb.exe\n"); if (sim_log) @@ -810,15 +810,15 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ if (dptr->flags & DEV_NEXUS) { /* Nexus? */ - if (r = build_nexus_tab (dptr, dibp)) /* add to dispatch table */ + if ((r = build_nexus_tab (dptr, dibp))) /* add to dispatch table */ return r; } else if (dptr->flags & DEV_MBUS) { /* Massbus? */ - if (r = build_mbus_tab (dptr, dibp)) + if ((r = build_mbus_tab (dptr, dibp))) return r; } else { /* no, Unibus device */ - if (r = build_ubus_tab (dptr, dibp)) /* add to dispatch tab */ + if ((r = build_ubus_tab (dptr, dibp))) /* add to dispatch tab */ return r; } /* end else */ } /* end if enabled */ diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index 814a5f43..ec576050 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -1,6 +1,6 @@ /* vax780_stddev.c: VAX 11/780 standard I/O devices - 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"), @@ -29,6 +29,7 @@ todr TODR clock tmr interval timer + 18-Apr-12 RMS Revised to use clock coscheduling 28-Sep-11 MP Generalized setting TODR for all OSes. Unbound the TODR value from the 100hz clock tick interrupt. TODR now behaves like the original @@ -60,7 +61,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 @@ -461,7 +462,8 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, KBD_WAIT (uptr->wait, tmr_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmr_poll))); + /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; if (c & SCPE_BREAK) /* break? */ @@ -481,7 +483,7 @@ t_stat tti_reset (DEVICE *dptr) tti_buf = 0; tti_csr = 0; tti_int = 0; -sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); +sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); return SCPE_OK; } @@ -679,7 +681,7 @@ return (t? t - 1: wait); t_stat clk_reset (DEVICE *dptr) { tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */ -sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */ +sim_activate (&clk_unit, tmr_poll); /* activate 100Hz unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */ clk_unit.filebuf = calloc(sizeof(TOY), 1); diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index 71140c05..9025f616 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 @@ -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 */ @@ -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, diff --git a/VAX/vax780_uba.c b/VAX/vax780_uba.c index 16e2e910..bb6105fe 100644 --- a/VAX/vax780_uba.c +++ b/VAX/vax780_uba.c @@ -1,6 +1,6 @@ /* vax780_uba.c: VAX 11/780 Unibus adapter - Copyright (c) 2004-2008, Robert M Supnik + Copyright (c) 2004-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,9 +25,10 @@ uba DW780 Unibus adapter + 25-Mar-12 RMS Added parameter to int_ack prototype (Mark Pizzolata) 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" @@ -214,7 +215,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_cis.c b/VAX/vax_cis.c index e77680e4..3eec163e 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 @@ -331,7 +331,7 @@ switch (opc) { /* case on opcode */ R[3] = (R[3] + 1) & LMASK; /* next string char */ if (i >= sim_interval) { /* done with interval? */ sim_interval = 0; - if (r = sim_process_event ()) { /* presumably WRU */ + if ((r = sim_process_event ())) { /* presumably WRU */ PC = fault_PC; /* backup up PC */ ABORT (r); /* abort flushes IB */ } @@ -1225,8 +1225,8 @@ for (i = 0; i <= end; i++) { /* loop thru string */ } if ((i == end) && ((lnt & 1) == 0)) c = c & 0xF; -/* if (((c & 0xF0) > 0x90) || /* check hi digit */ -/* ((c & 0x0F) > 0x09)) /* check lo digit */ +/* if (((c & 0xF0) > 0x90) || *//* check hi digit */ +/* ((c & 0x0F) > 0x09)) *//* check lo digit */ /* RSVD_OPND_FAULT; */ src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8)); } /* end for */ @@ -1550,7 +1550,7 @@ uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin) { int32 i, s, nc; -if (s = sc * 4) { +if ((s = sc * 4)) { for (i = DSTRMAX; i >= 0; i--) { nc = (dsrc->val[i] << (32 - s)) & LMASK; dsrc->val[i] = ((dsrc->val[i] >> s) | @@ -1574,7 +1574,7 @@ uint32 NibbleLshift (DSTR *dsrc, int32 sc, uint32 cin) { int32 i, s, nc; -if (s = sc * 4) { +if ((s = sc * 4)) { for (i = 0; i < DSTRLNT; i++) { nc = dsrc->val[i] >> (32 - s); dsrc->val[i] = ((dsrc->val[i] << s) | diff --git a/VAX/vax_cmode.c b/VAX/vax_cmode.c index 8af75a03..dbf6d4cf 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 @@ -621,7 +621,7 @@ switch ((IR >> 12) & 017) { /* decode IR<15:12> */ else src2 = RdMemW (GeteaW (dstspec)); src2 = src2 & 077; src = RdRegW (srcspec); /* get src */ - if (sign = ((src & WSIGN)? 1: 0)) + if ((sign = ((src & WSIGN)? 1: 0))) src = src | ~WMASK; if (src2 == 0) { /* [0] */ dst = src; /* result */ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 9730cf0e..a2aa2bab 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -1,6 +1,6 @@ /* vax_cpu.c: VAX CPU - 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"), @@ -35,7 +35,9 @@ approach taken in the other BSD derived OSes. Determining a reasonable idle detection pattern does not seem possible for these versions. - 23-Mar-11 RMS Revised for new idle design (from Mark Pizzolato) + 13-Sep-11 RMS Fixed XFC, BPT to clear PSL before exception + (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 @@ -44,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 @@ -54,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 @@ -187,10 +188,6 @@ #define UNIT_CONH (1u << UNIT_V_CONH) #define UNIT_MSIZE (1u << UNIT_V_MSIZE) #define GET_CUR acc = ACC_MASK (PSL_GETCUR (PSL)) -#define VAX_IDLE_VMS 0x01 -#define VAX_IDLE_ULT 0x02 -#define VAX_IDLE_ULTOLD 0x04 -#define VAX_IDLE_QUAD 0x08 #define OPND_SIZE 16 #define INST_SIZE 52 @@ -500,7 +497,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; @@ -616,7 +613,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) @@ -634,7 +631,7 @@ for ( ;; ) { */ if (trpirq) { /* trap or interrupt? */ - if (temp = GET_TRAP (trpirq)) { /* trap? */ + if ((temp = GET_TRAP (trpirq))) { /* trap? */ cc = intexc (SCB_ARITH, cc, 0, IE_EXC); /* take, clear trap */ GET_CUR; /* set cur mode */ in_ie = 1; @@ -642,7 +639,7 @@ for ( ;; ) { SP = SP - 4; in_ie = 0; } - else if (temp = GET_IRQL (trpirq)) { /* interrupt? */ + else if ((temp = GET_IRQL (trpirq))) { /* interrupt? */ int32 vec; if (temp == IPL_HLTPIN) { /* console halt? */ hlt_pin = 0; /* clear intr */ @@ -1576,7 +1573,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? */ @@ -2544,12 +2541,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; @@ -3416,13 +3415,15 @@ struct os_idle { static struct os_idle os_tab[] = { { "VMS", VAX_IDLE_VMS }, - { "NETBSD", VAX_IDLE_ULTOLD }, + { "NETBSDOLD", VAX_IDLE_ULTOLD }, + { "NETBSD", VAX_IDLE_BSDNEW }, { "ULTRIX", VAX_IDLE_ULT }, { "ULTRIXOLD", VAX_IDLE_ULTOLD }, - { "OPENBSD", VAX_IDLE_QUAD }, + { "OPENBSDOLD", VAX_IDLE_QUAD }, + { "OPENBSD", VAX_IDLE_BSDNEW }, { "QUASIJARUS", VAX_IDLE_QUAD }, { "32V", VAX_IDLE_QUAD }, - { "ALL", VAX_IDLE_VMS|VAX_IDLE_ULTOLD|VAX_IDLE_ULT|VAX_IDLE_QUAD }, + { "ALL", VAX_IDLE_VMS|VAX_IDLE_ULTOLD|VAX_IDLE_ULT|VAX_IDLE_QUAD|VAX_IDLE_BSDNEW }, { NULL, 0 } }; @@ -3447,10 +3448,8 @@ return sim_set_idle (uptr, val, cptr, desc); t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc) { -if (sim_idle_enab && (cpu_idle_type != 0)) { +if (sim_idle_enab && (cpu_idle_type != 0)) fprintf (st, "idle=%s, ", os_tab[cpu_idle_type - 1].name); - sim_show_idle (st, uptr, val, desc); - } -else fprintf (st, "idle disabled"); +sim_show_idle (st, uptr, val, desc); return SCPE_OK; } diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index 8eeac8d9..d4e3ea32 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,13 +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 (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 @@ -37,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 @@ -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; @@ -1519,6 +1520,10 @@ switch (prn) { /* case on reg # */ case MT_IPL: /* IPL */ PSL = (PSL & ~PSL_IPL) | ((val & PSL_M_IPL) << PSL_V_IPL); + if ((VAX_IDLE_BSDNEW & cpu_idle_mask) && /* New NetBSD and OpenBSD */ + (0 != (PC & 0x80000000)) && /* System Space (Not BOOT ROM) */ + (val == 1)) /* IPL 1 */ + cpu_idle(); /* idle loop */ break; case MT_ASTLVL: /* ASTLVL */ diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index ba73fc4a..24392840 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 @@ -472,7 +473,7 @@ #define PR_PACV 2 /* pte ACV (780) */ #define PR_PLNV 3 /* pte len viol */ #define PR_TNV 4 /* TNV */ -/* #define PR_TB 5 /* impossible */ +/* #define PR_TB 5 *//* impossible */ #define PR_PTNV 6 /* pte TNV */ #define PR_OK 7 /* ok */ #define MM_PARAM(w,p) (((w)? 4: 0) | ((p) & 3)) /* fault param */ @@ -717,6 +718,14 @@ enum opcodes { else cc = 0; \ if (((uint32) s1) < ((uint32) s2)) cc = cc | CC_C +#define VAX_IDLE_VMS 0x01 +#define VAX_IDLE_ULT 0x02 +#define VAX_IDLE_ULTOLD 0x04 +#define VAX_IDLE_QUAD 0x08 +#define VAX_IDLE_BSDNEW 0x10 +extern uint32 cpu_idle_mask; /* idle mask */ +void cpu_idle (void); + /* Model dependent definitions */ #if defined (VAX_780) diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index 9a88bb57..1b15c179 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-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,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 + (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 @@ -34,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 @@ -103,7 +107,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 +351,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 +379,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 +392,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 +461,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 +650,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); @@ -896,7 +907,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; @@ -921,6 +932,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 +945,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 +1019,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 +1401,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 +1413,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 +1425,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 +1521,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 +1552,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 +1586,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_io.c b/VAX/vax_io.c index a52d93ea..95b46073 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -1,6 +1,6 @@ /* vax_io.c: VAX 3900 Qbus IO simulator - Copyright (c) 1998-2008, 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"), @@ -25,8 +25,9 @@ qba Qbus adapter + 25-Mar-12 RMS Added parameter to int_ack prototype (Mark Pizzolata) 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 +35,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 @@ -188,7 +189,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 */ @@ -791,7 +792,7 @@ init_ubus_tab (); /* init bus tables */ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ - if (r = build_ubus_tab (dptr, dibp)) /* add to bus tab */ + if ((r = build_ubus_tab (dptr, dibp))) /* add to bus tab */ return r; } /* end if enabled */ } /* end for */ diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index 1733d311..79175c41 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 @@ -536,7 +536,7 @@ return; void zap_tb (int stb) { -int32 i; +size_t i; for (i = 0; i < VA_TBSIZE; i++) { ptlb[i].tag = ptlb[i].pte = -1; @@ -577,7 +577,7 @@ return FALSE; t_stat tlb_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { int32 tlbn = uptr - tlb_unit; -int32 idx = (uint32) addr >> 1; +uint32 idx = (uint32) addr >> 1; if (idx >= VA_TBSIZE) return SCPE_NXM; @@ -592,7 +592,7 @@ return SCPE_OK; t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) { int32 tlbn = uptr - tlb_unit; -int32 idx = (uint32) addr >> 1; +uint32 idx = (uint32) addr >> 1; if (idx >= VA_TBSIZE) return SCPE_NXM; @@ -611,7 +611,7 @@ return SCPE_OK; t_stat tlb_reset (DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < VA_TBSIZE; i++) stlb[i].tag = ptlb[i].tag = stlb[i].pte = ptlb[i].pte = -1; diff --git a/VAX/vax_octa.c b/VAX/vax_octa.c index 5b0448da..c46b2718 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 + (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 @@ -37,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 */ @@ -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); @@ -184,7 +187,7 @@ switch (opc) { break; case MOVH: - if (r = op_tsth (opnd[0])) { /* test for 0 */ + if ((r = op_tsth (opnd[0]))) { /* test for 0 */ h_write_o (spec, va, opnd, acc); /* nz, write result */ CC_IIZP_FP (r); /* set cc's */ } @@ -195,7 +198,7 @@ switch (opc) { break; case MNEGH: - if (r = op_tsth (opnd[0])) { /* test for 0 */ + if ((r = op_tsth (opnd[0]))) { /* test for 0 */ opnd[0] = opnd[0] ^ FPSIGN; /* nz, invert sign */ h_write_o (spec, va, opnd, acc); /* write result */ CC_IIZZ_FP (opnd[0]); /* set cc's */ @@ -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_stddev.c b/VAX/vax_stddev.c index 204be3fe..2d98e3f7 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -1,6 +1,6 @@ /* vax_stddev.c: VAX 3900 standard I/O devices - Copyright (c) 1998-2008, 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"), @@ -27,6 +27,8 @@ tto terminal output clk 100Hz and TODR clock + 18-Apr-12 RMS Revised TTI to use clock coscheduling and + remove IORESET bug 13-Jan-12 MP Normalized the saved format of the TODR persistent file so that it may be moved around from one platform to another along with other simulator state files @@ -92,7 +94,7 @@ extern int32 int_req[IPL_HLVL]; extern int32 hlt_pin; -extern int32 sim_switches; +extern int32 sim_switches, sim_is_running; int32 tti_csr = 0; /* control/status */ int32 tto_csr = 0; /* control/status */ @@ -319,7 +321,8 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, KBD_WAIT (uptr->wait, tmr_poll)); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmr_poll))); + /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; if (c & SCPE_BREAK) { /* break? */ @@ -340,7 +343,7 @@ t_stat tti_reset (DEVICE *dptr) tti_unit.buf = 0; tti_csr = 0; CLR_INT (TTI); -sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); +sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); return SCPE_OK; } @@ -496,10 +499,12 @@ int32 t; clk_csr = 0; CLR_INT (CLK); -t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */ -sim_activate_abs (&clk_unit, t); /* activate unit */ -tmr_poll = t; /* set tmr poll */ -tmxr_poll = t * TMXR_MULT; /* set mux poll */ +if (!sim_is_running) { /* RESET (not IORESET)? */ + t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */ + sim_activate (&clk_unit, t); /* activate unit */ + tmr_poll = t; /* set tmr poll */ + tmxr_poll = t * TMXR_MULT; /* set mux poll */ + } if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */ clk_unit.filebuf = calloc(sizeof(TOY), 1); if (clk_unit.filebuf == NULL) diff --git a/VAX/vax_sys.c b/VAX/vax_sys.c index b9f2b95c..0cf2f482 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 @@ -115,518 +115,518 @@ const char *sim_stop_messages[] = { */ const uint16 drom[NUM_INST][MAX_SPEC + 1] = { -0, 0, 0, 0, 0, 0, 0, /* HALT */ -0, 0, 0, 0, 0, 0, 0, /* NOP */ -0, 0, 0, 0, 0, 0, 0, /* REI */ -0, 0, 0, 0, 0, 0, 0, /* BPT */ -0, 0, 0, 0, 0, 0, 0, /* RET */ -0, 0, 0, 0, 0, 0, 0, /* RSB */ -0, 0, 0, 0, 0, 0, 0, /* LDPCTX */ -0, 0, 0, 0, 0, 0, 0, /* SVPCTX */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* CVTPS */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* CVTSP */ -6, RL, RL, RL, RL, RL, WL, /* INDEX */ -4+DR_F, AB, RL, RW, AB, 0, 0, /* CRC */ -3, RB, RW, AB, 0, 0, 0, /* PROBER */ -3, RB, RW, AB, 0, 0, 0, /* PROBEW */ -2, AB, AB, 0, 0, 0, 0, /* INSQUE */ -2, AB, WL, 0, 0, 0, 0, /* REMQUE */ -1, BB, 0, 0, 0, 0, 0, /* BSBB */ -1, BB, 0, 0, 0, 0, 0, /* BRB */ -1, BB, 0, 0, 0, 0, 0, /* BNEQ */ -1, BB, 0, 0, 0, 0, 0, /* BEQL */ -1, BB, 0, 0, 0, 0, 0, /* BGTR */ -1, BB, 0, 0, 0, 0, 0, /* BLEQ */ -1, AB, 0, 0, 0, 0, 0, /* JSB */ -1, AB, 0, 0, 0, 0, 0, /* JMP */ -1, BB, 0, 0, 0, 0, 0, /* BGEQ */ -1, BB, 0, 0, 0, 0, 0, /* BLSS */ -1, BB, 0, 0, 0, 0, 0, /* BGTRU */ -1, BB, 0, 0, 0, 0, 0, /* BLEQU */ -1, BB, 0, 0, 0, 0, 0, /* BVC */ -1, BB, 0, 0, 0, 0, 0, /* BVS */ -1, BB, 0, 0, 0, 0, 0, /* BCC */ -1, BB, 0, 0, 0, 0, 0, /* BCS */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* ADDP4 */ -6+DR_F, RW, AB, RW, AB, RW, AB, /* ADDP6 */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* SUBP4 */ -6+DR_F, RW, AB, RW, AB, RW, AB, /* SUBP6 */ -5+DR_F, RW, AB, AB, RW, AB, 0, /* CVTPT */ -6+DR_F, RW, AB, RW, AB, RW, AB, /* MULP6 */ -5+DR_F, RW, AB, AB, RW, AB, 0, /* CVTTP */ -6+DR_F, RW, AB, RW, AB, RW, AB, /* DIVP6 */ -3+DR_F, RW, AB, AB, 0, 0, 0, /* MOVC3 */ -3+DR_F, RW, AB, AB, 0, 0, 0, /* CMPC3 */ -4+DR_F, RW, AB, AB, RB, 0, 0, /* SCANC */ -4+DR_F, RW, AB, AB, RB, 0, 0, /* SPANC */ -5+DR_F, RW, AB, RB, RW, AB, 0, /* MOVC5 */ -5+DR_F, RW, AB, RB, RW, AB, 0, /* CMPC5 */ -6+DR_F, RW, AB, RB, AB, RW, AB, /* MOVTC */ -6+DR_F, RW, AB, RB, AB, RW, AB, /* MOVTUC */ -1, BW, 0, 0, 0, 0, 0, /* BSBW */ -1, BW, 0, 0, 0, 0, 0, /* BRW */ -2, RW, WL, 0, 0, 0, 0, /* CVTWL */ -2, RW, WB, 0, 0, 0, 0, /* CVTWB */ -3+DR_F, RW, AB, AB, 0, 0, 0, /* MOVP */ -3+DR_F, RW, AB, AB, 0, 0, 0, /* CMPP3 */ -3+DR_F, RW, AB, WL, 0, 0, 0, /* CVTPL */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* CMPP4 */ -4+DR_F, RW, AB, AB, AB, 0, 0, /* EDITPC */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* MATCHC */ -3+DR_F, RB, RW, AB, 0, 0, 0, /* LOCC */ -3+DR_F, RB, RW, AB, 0, 0, 0, /* SKPC */ -2, RW, WL, 0, 0, 0, 0, /* MOVZWL */ -4, RW, RW, MW, BW, 0, 0, /* ACBW */ -2, AW, WL, 0, 0, 0, 0, /* MOVAW */ -1, AW, 0, 0, 0, 0, 0, /* PUSHAW */ -2, RF, ML, 0, 0, 0, 0, /* ADDF2 */ -3, RF, RF, WL, 0, 0, 0, /* ADDF3 */ -2, RF, ML, 0, 0, 0, 0, /* SUBF2 */ -3, RF, RF, WL, 0, 0, 0, /* SUBF3 */ -2, RF, ML, 0, 0, 0, 0, /* MULF2 */ -3, RF, RF, WL, 0, 0, 0, /* MULF3 */ -2, RF, ML, 0, 0, 0, 0, /* DIVF2 */ -3, RF, RF, WL, 0, 0, 0, /* DIVF3 */ -2, RF, WB, 0, 0, 0, 0, /* CVTFB */ -2, RF, WW, 0, 0, 0, 0, /* CVTFW */ -2, RF, WL, 0, 0, 0, 0, /* CVTFL */ -2, RF, WL, 0, 0, 0, 0, /* CVTRFL */ -2, RB, WL, 0, 0, 0, 0, /* CVTBF */ -2, RW, WL, 0, 0, 0, 0, /* CVTWF */ -2, RL, WL, 0, 0, 0, 0, /* CVTLF */ -4, RF, RF, ML, BW, 0, 0, /* ACBF */ -2, RF, WL, 0, 0, 0, 0, /* MOVF */ -2, RF, RF, 0, 0, 0, 0, /* CMPF */ -2, RF, WL, 0, 0, 0, 0, /* MNEGF */ -1, RF, 0, 0, 0, 0, 0, /* TSTF */ -5, RF, RB, RF, WL, WL, 0, /* EMODF */ -3, RF, RW, AB, 0, 0, 0, /* POLYF */ -2, RF, WQ, 0, 0, 0, 0, /* CVTFD */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -2, RW, WW, 0, 0, 0, 0, /* ADAWI */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -2, AB, AQ, 0, 0, 0, 0, /* INSQHI */ -2, AB, AQ, 0, 0, 0, 0, /* INSQTI */ -2, AQ, WL, 0, 0, 0, 0, /* REMQHI */ -2, AQ, WL, 0, 0, 0, 0, /* REMQTI */ -2, RD, MQ, 0, 0, 0, 0, /* ADDD2 */ -3, RD, RD, WQ, 0, 0, 0, /* ADDD3 */ -2, RD, MQ, 0, 0, 0, 0, /* SUBD2 */ -3, RD, RD, WQ, 0, 0, 0, /* SUBD3 */ -2, RD, MQ, 0, 0, 0, 0, /* MULD2 */ -3, RD, RD, WQ, 0, 0, 0, /* MULD3 */ -2, RD, MQ, 0, 0, 0, 0, /* DIVD2 */ -3, RD, RD, WQ, 0, 0, 0, /* DIVD3 */ -2, RD, WB, 0, 0, 0, 0, /* CVTDB */ -2, RD, WW, 0, 0, 0, 0, /* CVTDW */ -2, RD, WL, 0, 0, 0, 0, /* CVTDL */ -2, RD, WL, 0, 0, 0, 0, /* CVTRDL */ -2, RB, WQ, 0, 0, 0, 0, /* CVTBD */ -2, RW, WQ, 0, 0, 0, 0, /* CVTWD */ -2, RL, WQ, 0, 0, 0, 0, /* CVTLD */ -4, RD, RD, MQ, BW, 0, 0, /* ACBD */ -2, RD, WQ, 0, 0, 0, 0, /* MOVD */ -2, RD, RD, 0, 0, 0, 0, /* CMPD */ -2, RD, WQ, 0, 0, 0, 0, /* MNEGD */ -1, RD, 0, 0, 0, 0, 0, /* TSTD */ -5, RD, RB, RD, WL, WQ, 0, /* EMODD */ -3, RD, RW, AB, 0, 0, 0, /* POLYD */ -2, RD, WL, 0, 0, 0, 0, /* CVTDF */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -3, RB, RL, WL, 0, 0, 0, /* ASHL */ -3, RB, RQ, WQ, 0, 0, 0, /* ASHQ */ -4, RL, RL, RL, WQ, 0, 0, /* EMUL */ -4, RL, RQ, WL, WL, 0, 0, /* EDIV */ -1, WQ, 0, 0, 0, 0, 0, /* CLRQ */ -2, RQ, WQ, 0, 0, 0, 0, /* MOVQ */ -2, AQ, WL, 0, 0, 0, 0, /* MOVAQ */ -1, AQ, 0, 0, 0, 0, 0, /* PUSHAQ */ -2, RB, MB, 0, 0, 0, 0, /* ADDB2 */ -3, RB, RB, WB, 0, 0, 0, /* ADDB3 */ -2, RB, MB, 0, 0, 0, 0, /* SUBB2 */ -3, RB, RB, WB, 0, 0, 0, /* SUBB3 */ -2, RB, MB, 0, 0, 0, 0, /* MULB2 */ -3, RB, RB, WB, 0, 0, 0, /* MULB3 */ -2, RB, MB, 0, 0, 0, 0, /* DIVB2 */ -3, RB, RB, WB, 0, 0, 0, /* DIVB3 */ -2, RB, MB, 0, 0, 0, 0, /* BISB2 */ -3, RB, RB, WB, 0, 0, 0, /* BISB3 */ -2, RB, MB, 0, 0, 0, 0, /* BICB2 */ -3, RB, RB, WB, 0, 0, 0, /* BICB3 */ -2, RB, MB, 0, 0, 0, 0, /* XORB2 */ -3, RB, RB, WB, 0, 0, 0, /* XORB3 */ -2, RB, WB, 0, 0, 0, 0, /* MNEGB */ -3, RB, RB, RB, 0, 0, 0, /* CASEB */ -2, RB, WB, 0, 0, 0, 0, /* MOVB */ -2, RB, RB, 0, 0, 0, 0, /* CMPB */ -2, RB, WB, 0, 0, 0, 0, /* MCOMB */ -2, RB, RB, 0, 0, 0, 0, /* BITB */ -1, WB, 0, 0, 0, 0, 0, /* CLRB */ -1, RB, 0, 0, 0, 0, 0, /* TSTB */ -1, MB, 0, 0, 0, 0, 0, /* INCB */ -1, MB, 0, 0, 0, 0, 0, /* DECB */ -2, RB, WL, 0, 0, 0, 0, /* CVTBL */ -2, RB, WW, 0, 0, 0, 0, /* CVTBW */ -2, RB, WL, 0, 0, 0, 0, /* MOVZBL */ -2, RB, WW, 0, 0, 0, 0, /* MOVZBW */ -3, RB, RL, WL, 0, 0, 0, /* ROTL */ -4, RB, RB, MB, BW, 0, 0, /* ACBB */ -2, AB, WL, 0, 0, 0, 0, /* MOVAB */ -1, AB, 0, 0, 0, 0, 0, /* PUSHAB */ -2, RW, MW, 0, 0, 0, 0, /* ADDW2 */ -3, RW, RW, WW, 0, 0, 0, /* ADDW3 */ -2, RW, MW, 0, 0, 0, 0, /* SUBW2 */ -3, RW, RW, WW, 0, 0, 0, /* SUBW3 */ -2, RW, MW, 0, 0, 0, 0, /* MULW2 */ -3, RW, RW, WW, 0, 0, 0, /* MULW3 */ -2, RW, MW, 0, 0, 0, 0, /* DIVW2 */ -3, RW, RW, WW, 0, 0, 0, /* DIVW3 */ -2, RW, MW, 0, 0, 0, 0, /* BISW2 */ -3, RW, RW, WW, 0, 0, 0, /* BISW3 */ -2, RW, MW, 0, 0, 0, 0, /* BICW2 */ -3, RW, RW, WW, 0, 0, 0, /* BICW3 */ -2, RW, MW, 0, 0, 0, 0, /* XORW2 */ -3, RW, RW, WW, 0, 0, 0, /* XORW3 */ -2, RW, WW, 0, 0, 0, 0, /* MNEGW */ -3, RW, RW, RW, 0, 0, 0, /* CASEW */ -2, RW, WW, 0, 0, 0, 0, /* MOVW */ -2, RW, RW, 0, 0, 0, 0, /* CMPW */ -2, RW, WW, 0, 0, 0, 0, /* MCOMW */ -2, RW, RW, 0, 0, 0, 0, /* BITW */ -1, WW, 0, 0, 0, 0, 0, /* CLRW */ -1, RW, 0, 0, 0, 0, 0, /* TSTW */ -1, MW, 0, 0, 0, 0, 0, /* INCW */ -1, MW, 0, 0, 0, 0, 0, /* DECW */ -1, RW, 0, 0, 0, 0, 0, /* BISPSW */ -1, RW, 0, 0, 0, 0, 0, /* BICPSW */ -1, RW, 0, 0, 0, 0, 0, /* POPR */ -1, RW, 0, 0, 0, 0, 0, /* PUSHR */ -1, RW, 0, 0, 0, 0, 0, /* CHMK */ -1, RW, 0, 0, 0, 0, 0, /* CHME */ -1, RW, 0, 0, 0, 0, 0, /* CHMS */ -1, RW, 0, 0, 0, 0, 0, /* CHMU */ -2, RL, ML, 0, 0, 0, 0, /* ADDL2 */ -3, RL, RL, WL, 0, 0, 0, /* ADDL3 */ -2, RL, ML, 0, 0, 0, 0, /* SUBL2 */ -3, RL, RL, WL, 0, 0, 0, /* SUBL3 */ -2, RL, ML, 0, 0, 0, 0, /* MULL2 */ -3, RL, RL, WL, 0, 0, 0, /* MULL3 */ -2, RL, ML, 0, 0, 0, 0, /* DIVL2 */ -3, RL, RL, WL, 0, 0, 0, /* DIVL3 */ -2, RL, ML, 0, 0, 0, 0, /* BISL2 */ -3, RL, RL, WL, 0, 0, 0, /* BISL3 */ -2, RL, ML, 0, 0, 0, 0, /* BICL2 */ -3, RL, RL, WL, 0, 0, 0, /* BICL3 */ -2, RL, ML, 0, 0, 0, 0, /* XORL2 */ -3, RL, RL, WL, 0, 0, 0, /* XORL3 */ -2, RL, WL, 0, 0, 0, 0, /* MNEGL */ -3, RL, RL, RL, 0, 0, 0, /* CASEL */ -2, RL, WL, 0, 0, 0, 0, /* MOVL */ -2, RL, RL, 0, 0, 0, 0, /* CMPL */ -2, RL, WL, 0, 0, 0, 0, /* MCOML */ -2, RL, RL, 0, 0, 0, 0, /* BITL */ -1, WL, 0, 0, 0, 0, 0, /* CLRL */ -1, RL, 0, 0, 0, 0, 0, /* TSTL */ -1, ML, 0, 0, 0, 0, 0, /* INCL */ -1, ML, 0, 0, 0, 0, 0, /* DECL */ -2, RL, ML, 0, 0, 0, 0, /* ADWC */ -2, RL, ML, 0, 0, 0, 0, /* SBWC */ -2, RL, RL, 0, 0, 0, 0, /* MTPR */ -2, RL, WL, 0, 0, 0, 0, /* MFPR */ -1, WL, 0, 0, 0, 0, 0, /* MOVPSL */ -1, RL, 0, 0, 0, 0, 0, /* PUSHL */ -2, AL, WL, 0, 0, 0, 0, /* MOVAL */ -1, AL, 0, 0, 0, 0, 0, /* PUSHAL */ -3, RL, VB, BB, 0, 0, 0, /* BBS */ -3, RL, VB, BB, 0, 0, 0, /* BBC */ -3, RL, VB, BB, 0, 0, 0, /* BBSS */ -3, RL, VB, BB, 0, 0, 0, /* BBCS */ -3, RL, VB, BB, 0, 0, 0, /* BBSC */ -3, RL, VB, BB, 0, 0, 0, /* BBCC */ -3, RL, VB, BB, 0, 0, 0, /* BBSSI */ -3, RL, VB, BB, 0, 0, 0, /* BBCCI */ -2, RL, BB, 0, 0, 0, 0, /* BLBS */ -2, RL, BB, 0, 0, 0, 0, /* BLBC */ -4, RL, RB, VB, WL, 0, 0, /* FFS */ -4, RL, RB, VB, WL, 0, 0, /* FFC */ -4, RL, RB, VB, RL, 0, 0, /* CMPV */ -4, RL, RB, VB, RL, 0, 0, /* CMPZV */ -4, RL, RB, VB, WL, 0, 0, /* EXTV */ -4, RL, RB, VB, WL, 0, 0, /* EXTZV */ -4, RL, RL, RB, VB, 0, 0, /* INSV */ -4, RL, RL, ML, BW, 0, 0, /* ACBL */ -3, RL, ML, BB, 0, 0, 0, /* AOBLSS */ -3, RL, ML, BB, 0, 0, 0, /* AOBLEQ */ -2, ML, BB, 0, 0, 0, 0, /* SOBGEQ */ -2, ML, BB, 0, 0, 0, 0, /* SOBGTR */ -2, RL, WB, 0, 0, 0, 0, /* CVTLB */ -2, RL, WW, 0, 0, 0, 0, /* CVTLW */ -6+DR_F, RB, RW, AB, RB, RW, AB, /* ASHP */ -3+DR_F, RL, RW, AB, 0, 0, 0, /* CVTLP */ -2, AB, AB, 0, 0, 0, 0, /* CALLG */ -2, RL, AB, 0, 0, 0, 0, /* CALLS */ -0, 0, 0, 0, 0, 0, 0, /* XFC */ -0, 0, 0, 0, 0, 0, 0, /* 0FD */ -0, 0, 0, 0, 0, 0, 0, /* 0FE */ -0, 0, 0, 0, 0, 0, 0, /* 0FF */ -0, 0, 0, 0, 0, 0, 0, /* 100-10F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 110-11F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 120-12F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 130-13F */ -0, 0, 0, 0, 0, 0, 0, -ODC(2), RD, WO, 0, 0, 0, 0, /* CVTDH */ -2, RG, WL, 0, 0, 0, 0, /* CVTGF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -2, RG, MQ, 0, 0, 0, 0, /* ADDG2 */ -3, RG, RG, WQ, 0, 0, 0, /* ADDG3 */ -2, RG, MQ, 0, 0, 0, 0, /* SUBG2 */ -3, RG, RG, WQ, 0, 0, 0, /* SUBG3 */ -2, RG, MQ, 0, 0, 0, 0, /* MULG2 */ -3, RG, RG, WQ, 0, 0, 0, /* MULG3 */ -2, RG, MQ, 0, 0, 0, 0, /* DIVG2 */ -3, RG, RG, WQ, 0, 0, 0, /* DIVG3 */ -2, RG, WB, 0, 0, 0, 0, /* CVTGB */ -2, RG, WW, 0, 0, 0, 0, /* CVTGW */ -2, RG, WL, 0, 0, 0, 0, /* CVTGL */ -2, RG, WL, 0, 0, 0, 0, /* CVTRGL */ -2, RB, WQ, 0, 0, 0, 0, /* CVTBG */ -2, RW, WQ, 0, 0, 0, 0, /* CVTWG */ -2, RL, WQ, 0, 0, 0, 0, /* CVTLG */ -4, RG, RG, MQ, BW, 0, 0, /* ACBG */ -2, RG, WQ, 0, 0, 0, 0, /* MOVG */ -2, RG, RG, 0, 0, 0, 0, /* CMPG */ -2, RG, WQ, 0, 0, 0, 0, /* MNEGG */ -1, RG, 0, 0, 0, 0, 0, /* TSTG */ -5, RG, RW, RG, WL, WQ, 0, /* EMODG */ -3, RG, RW, AB, 0, 0, 0, /* POLYG */ -ODC(2), RG, WO, 0, 0, 0, 0, /* CVTGH */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -ODC(2), RH, MO, 0, 0, 0, 0, /* ADDH2 */ -ODC(3), RH, RH, WO, 0, 0, 0, /* ADDH3 */ -ODC(2), RH, MO, 0, 0, 0, 0, /* SUBH2 */ -ODC(3), RH, RH, WO, 0, 0, 0, /* SUBH3 */ -ODC(2), RH, MO, 0, 0, 0, 0, /* MULH2 */ -ODC(3), RH, RH, WO, 0, 0, 0, /* MULH3 */ -ODC(2), RH, MO, 0, 0, 0, 0, /* DIVH2 */ -ODC(3), RH, RH, WO, 0, 0, 0, /* DIVH3 */ -ODC(2), RH, WB, 0, 0, 0, 0, /* CVTHB */ -ODC(2), RH, WW, 0, 0, 0, 0, /* CVTHW */ -ODC(2), RH, WL, 0, 0, 0, 0, /* CVTHL */ -ODC(2), RH, WL, 0, 0, 0, 0, /* CVTRHL */ -ODC(2), RB, WO, 0, 0, 0, 0, /* CVTBH */ -ODC(2), RW, WO, 0, 0, 0, 0, /* CVTWH */ -ODC(2), RL, WO, 0, 0, 0, 0, /* CVTLH */ -ODC(4), RH, RH, MO, BW, 0, 0, /* ACBH */ -ODC(2), RH, RO, 0, 0, 0, 0, /* MOVH */ -ODC(2), RH, RH, 0, 0, 0, 0, /* CMPH */ -ODC(2), RH, WO, 0, 0, 0, 0, /* MNEGH */ -ODC(1), RH, 0, 0, 0, 0, 0, /* TSTH */ -ODC(5), RH, RW, RH, WL, WO, 0, /* EMODH */ -ODC(3), RH, RW, AB, 0, 0, 0, /* POLYH */ -ODC(2), RH, WQ, 0, 0, 0, 0, /* CVTHG */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -ODC(1), WO, 0, 0, 0, 0, 0, /* CLRO */ -ODC(2), RO, RO, 0, 0, 0, 0, /* MOVO */ -ODC(2), AO, WL, 0, 0, 0, 0, /* MOVAO*/ -ODC(1), AO, 0, 0, 0, 0, 0, /* PUSHAO*/ -0, 0, 0, 0, 0, 0, 0, /* 180-18F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 190-19F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -ODC(2), RF, WO, 0, 0, 0, 0, /* CVTFH */ -2, RF, WQ, 0, 0, 0, 0, /* CVTFG */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1A0-1AF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1B0-1BF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1C0-1CF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1D0-1DF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1E0-1EF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1F0-1FF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -ODC(2), RH, WL, 0, 0, 0, 0, /* CVTHF */ -ODC(2), RH, WQ, 0, 0, 0, 0, /* CVTHD */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0 +{0, 0, 0, 0, 0, 0, 0}, /* HALT */ +{0, 0, 0, 0, 0, 0, 0}, /* NOP */ +{0, 0, 0, 0, 0, 0, 0}, /* REI */ +{0, 0, 0, 0, 0, 0, 0}, /* BPT */ +{0, 0, 0, 0, 0, 0, 0}, /* RET */ +{0, 0, 0, 0, 0, 0, 0}, /* RSB */ +{0, 0, 0, 0, 0, 0, 0}, /* LDPCTX */ +{0, 0, 0, 0, 0, 0, 0}, /* SVPCTX */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* CVTPS */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* CVTSP */ +{6, RL, RL, RL, RL, RL, WL}, /* INDEX */ +{4+DR_F, AB, RL, RW, AB, 0, 0}, /* CRC */ +{3, RB, RW, AB, 0, 0, 0}, /* PROBER */ +{3, RB, RW, AB, 0, 0, 0}, /* PROBEW */ +{2, AB, AB, 0, 0, 0, 0}, /* INSQUE */ +{2, AB, WL, 0, 0, 0, 0}, /* REMQUE */ +{1, BB, 0, 0, 0, 0, 0}, /* BSBB */ +{1, BB, 0, 0, 0, 0, 0}, /* BRB */ +{1, BB, 0, 0, 0, 0, 0}, /* BNEQ */ +{1, BB, 0, 0, 0, 0, 0}, /* BEQL */ +{1, BB, 0, 0, 0, 0, 0}, /* BGTR */ +{1, BB, 0, 0, 0, 0, 0}, /* BLEQ */ +{1, AB, 0, 0, 0, 0, 0}, /* JSB */ +{1, AB, 0, 0, 0, 0, 0}, /* JMP */ +{1, BB, 0, 0, 0, 0, 0}, /* BGEQ */ +{1, BB, 0, 0, 0, 0, 0}, /* BLSS */ +{1, BB, 0, 0, 0, 0, 0}, /* BGTRU */ +{1, BB, 0, 0, 0, 0, 0}, /* BLEQU */ +{1, BB, 0, 0, 0, 0, 0}, /* BVC */ +{1, BB, 0, 0, 0, 0, 0}, /* BVS */ +{1, BB, 0, 0, 0, 0, 0}, /* BCC */ +{1, BB, 0, 0, 0, 0, 0}, /* BCS */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* ADDP4 */ +{6+DR_F, RW, AB, RW, AB, RW, AB}, /* ADDP6 */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* SUBP4 */ +{6+DR_F, RW, AB, RW, AB, RW, AB}, /* SUBP6 */ +{5+DR_F, RW, AB, AB, RW, AB, 0}, /* CVTPT */ +{6+DR_F, RW, AB, RW, AB, RW, AB}, /* MULP6 */ +{5+DR_F, RW, AB, AB, RW, AB, 0}, /* CVTTP */ +{6+DR_F, RW, AB, RW, AB, RW, AB}, /* DIVP6 */ +{3+DR_F, RW, AB, AB, 0, 0, 0}, /* MOVC3 */ +{3+DR_F, RW, AB, AB, 0, 0, 0}, /* CMPC3 */ +{4+DR_F, RW, AB, AB, RB, 0, 0}, /* SCANC */ +{4+DR_F, RW, AB, AB, RB, 0, 0}, /* SPANC */ +{5+DR_F, RW, AB, RB, RW, AB, 0}, /* MOVC5 */ +{5+DR_F, RW, AB, RB, RW, AB, 0}, /* CMPC5 */ +{6+DR_F, RW, AB, RB, AB, RW, AB}, /* MOVTC */ +{6+DR_F, RW, AB, RB, AB, RW, AB}, /* MOVTUC */ +{1, BW, 0, 0, 0, 0, 0}, /* BSBW */ +{1, BW, 0, 0, 0, 0, 0}, /* BRW */ +{2, RW, WL, 0, 0, 0, 0}, /* CVTWL */ +{2, RW, WB, 0, 0, 0, 0}, /* CVTWB */ +{3+DR_F, RW, AB, AB, 0, 0, 0}, /* MOVP */ +{3+DR_F, RW, AB, AB, 0, 0, 0}, /* CMPP3 */ +{3+DR_F, RW, AB, WL, 0, 0, 0}, /* CVTPL */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* CMPP4 */ +{4+DR_F, RW, AB, AB, AB, 0, 0}, /* EDITPC */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* MATCHC */ +{3+DR_F, RB, RW, AB, 0, 0, 0}, /* LOCC */ +{3+DR_F, RB, RW, AB, 0, 0, 0}, /* SKPC */ +{2, RW, WL, 0, 0, 0, 0}, /* MOVZWL */ +{4, RW, RW, MW, BW, 0, 0}, /* ACBW */ +{2, AW, WL, 0, 0, 0, 0}, /* MOVAW */ +{1, AW, 0, 0, 0, 0, 0}, /* PUSHAW */ +{2, RF, ML, 0, 0, 0, 0}, /* ADDF2 */ +{3, RF, RF, WL, 0, 0, 0}, /* ADDF3 */ +{2, RF, ML, 0, 0, 0, 0}, /* SUBF2 */ +{3, RF, RF, WL, 0, 0, 0}, /* SUBF3 */ +{2, RF, ML, 0, 0, 0, 0}, /* MULF2 */ +{3, RF, RF, WL, 0, 0, 0}, /* MULF3 */ +{2, RF, ML, 0, 0, 0, 0}, /* DIVF2 */ +{3, RF, RF, WL, 0, 0, 0}, /* DIVF3 */ +{2, RF, WB, 0, 0, 0, 0}, /* CVTFB */ +{2, RF, WW, 0, 0, 0, 0}, /* CVTFW */ +{2, RF, WL, 0, 0, 0, 0}, /* CVTFL */ +{2, RF, WL, 0, 0, 0, 0}, /* CVTRFL */ +{2, RB, WL, 0, 0, 0, 0}, /* CVTBF */ +{2, RW, WL, 0, 0, 0, 0}, /* CVTWF */ +{2, RL, WL, 0, 0, 0, 0}, /* CVTLF */ +{4, RF, RF, ML, BW, 0, 0}, /* ACBF */ +{2, RF, WL, 0, 0, 0, 0}, /* MOVF */ +{2, RF, RF, 0, 0, 0, 0}, /* CMPF */ +{2, RF, WL, 0, 0, 0, 0}, /* MNEGF */ +{1, RF, 0, 0, 0, 0, 0}, /* TSTF */ +{5, RF, RB, RF, WL, WL, 0}, /* EMODF */ +{3, RF, RW, AB, 0, 0, 0}, /* POLYF */ +{2, RF, WQ, 0, 0, 0, 0}, /* CVTFD */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{2, RW, WW, 0, 0, 0, 0}, /* ADAWI */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{2, AB, AQ, 0, 0, 0, 0}, /* INSQHI */ +{2, AB, AQ, 0, 0, 0, 0}, /* INSQTI */ +{2, AQ, WL, 0, 0, 0, 0}, /* REMQHI */ +{2, AQ, WL, 0, 0, 0, 0}, /* REMQTI */ +{2, RD, MQ, 0, 0, 0, 0}, /* ADDD2 */ +{3, RD, RD, WQ, 0, 0, 0}, /* ADDD3 */ +{2, RD, MQ, 0, 0, 0, 0}, /* SUBD2 */ +{3, RD, RD, WQ, 0, 0, 0}, /* SUBD3 */ +{2, RD, MQ, 0, 0, 0, 0}, /* MULD2 */ +{3, RD, RD, WQ, 0, 0, 0}, /* MULD3 */ +{2, RD, MQ, 0, 0, 0, 0}, /* DIVD2 */ +{3, RD, RD, WQ, 0, 0, 0}, /* DIVD3 */ +{2, RD, WB, 0, 0, 0, 0}, /* CVTDB */ +{2, RD, WW, 0, 0, 0, 0}, /* CVTDW */ +{2, RD, WL, 0, 0, 0, 0}, /* CVTDL */ +{2, RD, WL, 0, 0, 0, 0}, /* CVTRDL */ +{2, RB, WQ, 0, 0, 0, 0}, /* CVTBD */ +{2, RW, WQ, 0, 0, 0, 0}, /* CVTWD */ +{2, RL, WQ, 0, 0, 0, 0}, /* CVTLD */ +{4, RD, RD, MQ, BW, 0, 0}, /* ACBD */ +{2, RD, WQ, 0, 0, 0, 0}, /* MOVD */ +{2, RD, RD, 0, 0, 0, 0}, /* CMPD */ +{2, RD, WQ, 0, 0, 0, 0}, /* MNEGD */ +{1, RD, 0, 0, 0, 0, 0}, /* TSTD */ +{5, RD, RB, RD, WL, WQ, 0}, /* EMODD */ +{3, RD, RW, AB, 0, 0, 0}, /* POLYD */ +{2, RD, WL, 0, 0, 0, 0}, /* CVTDF */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{3, RB, RL, WL, 0, 0, 0}, /* ASHL */ +{3, RB, RQ, WQ, 0, 0, 0}, /* ASHQ */ +{4, RL, RL, RL, WQ, 0, 0}, /* EMUL */ +{4, RL, RQ, WL, WL, 0, 0}, /* EDIV */ +{1, WQ, 0, 0, 0, 0, 0}, /* CLRQ */ +{2, RQ, WQ, 0, 0, 0, 0}, /* MOVQ */ +{2, AQ, WL, 0, 0, 0, 0}, /* MOVAQ */ +{1, AQ, 0, 0, 0, 0, 0}, /* PUSHAQ */ +{2, RB, MB, 0, 0, 0, 0}, /* ADDB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* ADDB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* SUBB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* SUBB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* MULB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* MULB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* DIVB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* DIVB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* BISB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* BISB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* BICB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* BICB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* XORB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* XORB3 */ +{2, RB, WB, 0, 0, 0, 0}, /* MNEGB */ +{3, RB, RB, RB, 0, 0, 0}, /* CASEB */ +{2, RB, WB, 0, 0, 0, 0}, /* MOVB */ +{2, RB, RB, 0, 0, 0, 0}, /* CMPB */ +{2, RB, WB, 0, 0, 0, 0}, /* MCOMB */ +{2, RB, RB, 0, 0, 0, 0}, /* BITB */ +{1, WB, 0, 0, 0, 0, 0}, /* CLRB */ +{1, RB, 0, 0, 0, 0, 0}, /* TSTB */ +{1, MB, 0, 0, 0, 0, 0}, /* INCB */ +{1, MB, 0, 0, 0, 0, 0}, /* DECB */ +{2, RB, WL, 0, 0, 0, 0}, /* CVTBL */ +{2, RB, WW, 0, 0, 0, 0}, /* CVTBW */ +{2, RB, WL, 0, 0, 0, 0}, /* MOVZBL */ +{2, RB, WW, 0, 0, 0, 0}, /* MOVZBW */ +{3, RB, RL, WL, 0, 0, 0}, /* ROTL */ +{4, RB, RB, MB, BW, 0, 0}, /* ACBB */ +{2, AB, WL, 0, 0, 0, 0}, /* MOVAB */ +{1, AB, 0, 0, 0, 0, 0}, /* PUSHAB */ +{2, RW, MW, 0, 0, 0, 0}, /* ADDW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* ADDW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* SUBW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* SUBW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* MULW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* MULW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* DIVW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* DIVW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* BISW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* BISW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* BICW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* BICW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* XORW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* XORW3 */ +{2, RW, WW, 0, 0, 0, 0}, /* MNEGW */ +{3, RW, RW, RW, 0, 0, 0}, /* CASEW */ +{2, RW, WW, 0, 0, 0, 0}, /* MOVW */ +{2, RW, RW, 0, 0, 0, 0}, /* CMPW */ +{2, RW, WW, 0, 0, 0, 0}, /* MCOMW */ +{2, RW, RW, 0, 0, 0, 0}, /* BITW */ +{1, WW, 0, 0, 0, 0, 0}, /* CLRW */ +{1, RW, 0, 0, 0, 0, 0}, /* TSTW */ +{1, MW, 0, 0, 0, 0, 0}, /* INCW */ +{1, MW, 0, 0, 0, 0, 0}, /* DECW */ +{1, RW, 0, 0, 0, 0, 0}, /* BISPSW */ +{1, RW, 0, 0, 0, 0, 0}, /* BICPSW */ +{1, RW, 0, 0, 0, 0, 0}, /* POPR */ +{1, RW, 0, 0, 0, 0, 0}, /* PUSHR */ +{1, RW, 0, 0, 0, 0, 0}, /* CHMK */ +{1, RW, 0, 0, 0, 0, 0}, /* CHME */ +{1, RW, 0, 0, 0, 0, 0}, /* CHMS */ +{1, RW, 0, 0, 0, 0, 0}, /* CHMU */ +{2, RL, ML, 0, 0, 0, 0}, /* ADDL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* ADDL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* SUBL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* SUBL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* MULL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* MULL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* DIVL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* DIVL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* BISL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* BISL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* BICL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* BICL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* XORL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* XORL3 */ +{2, RL, WL, 0, 0, 0, 0}, /* MNEGL */ +{3, RL, RL, RL, 0, 0, 0}, /* CASEL */ +{2, RL, WL, 0, 0, 0, 0}, /* MOVL */ +{2, RL, RL, 0, 0, 0, 0}, /* CMPL */ +{2, RL, WL, 0, 0, 0, 0}, /* MCOML */ +{2, RL, RL, 0, 0, 0, 0}, /* BITL */ +{1, WL, 0, 0, 0, 0, 0}, /* CLRL */ +{1, RL, 0, 0, 0, 0, 0}, /* TSTL */ +{1, ML, 0, 0, 0, 0, 0}, /* INCL */ +{1, ML, 0, 0, 0, 0, 0}, /* DECL */ +{2, RL, ML, 0, 0, 0, 0}, /* ADWC */ +{2, RL, ML, 0, 0, 0, 0}, /* SBWC */ +{2, RL, RL, 0, 0, 0, 0}, /* MTPR */ +{2, RL, WL, 0, 0, 0, 0}, /* MFPR */ +{1, WL, 0, 0, 0, 0, 0}, /* MOVPSL */ +{1, RL, 0, 0, 0, 0, 0}, /* PUSHL */ +{2, AL, WL, 0, 0, 0, 0}, /* MOVAL */ +{1, AL, 0, 0, 0, 0, 0}, /* PUSHAL */ +{3, RL, VB, BB, 0, 0, 0}, /* BBS */ +{3, RL, VB, BB, 0, 0, 0}, /* BBC */ +{3, RL, VB, BB, 0, 0, 0}, /* BBSS */ +{3, RL, VB, BB, 0, 0, 0}, /* BBCS */ +{3, RL, VB, BB, 0, 0, 0}, /* BBSC */ +{3, RL, VB, BB, 0, 0, 0}, /* BBCC */ +{3, RL, VB, BB, 0, 0, 0}, /* BBSSI */ +{3, RL, VB, BB, 0, 0, 0}, /* BBCCI */ +{2, RL, BB, 0, 0, 0, 0}, /* BLBS */ +{2, RL, BB, 0, 0, 0, 0}, /* BLBC */ +{4, RL, RB, VB, WL, 0, 0}, /* FFS */ +{4, RL, RB, VB, WL, 0, 0}, /* FFC */ +{4, RL, RB, VB, RL, 0, 0}, /* CMPV */ +{4, RL, RB, VB, RL, 0, 0}, /* CMPZV */ +{4, RL, RB, VB, WL, 0, 0}, /* EXTV */ +{4, RL, RB, VB, WL, 0, 0}, /* EXTZV */ +{4, RL, RL, RB, VB, 0, 0}, /* INSV */ +{4, RL, RL, ML, BW, 0, 0}, /* ACBL */ +{3, RL, ML, BB, 0, 0, 0}, /* AOBLSS */ +{3, RL, ML, BB, 0, 0, 0}, /* AOBLEQ */ +{2, ML, BB, 0, 0, 0, 0}, /* SOBGEQ */ +{2, ML, BB, 0, 0, 0, 0}, /* SOBGTR */ +{2, RL, WB, 0, 0, 0, 0}, /* CVTLB */ +{2, RL, WW, 0, 0, 0, 0}, /* CVTLW */ +{6+DR_F, RB, RW, AB, RB, RW, AB}, /* ASHP */ +{3+DR_F, RL, RW, AB, 0, 0, 0}, /* CVTLP */ +{2, AB, AB, 0, 0, 0, 0}, /* CALLG */ +{2, RL, AB, 0, 0, 0, 0}, /* CALLS */ +{0, 0, 0, 0, 0, 0, 0}, /* XFC */ +{0, 0, 0, 0, 0, 0, 0}, /* 0FD */ +{0, 0, 0, 0, 0, 0, 0}, /* 0FE */ +{0, 0, 0, 0, 0, 0, 0}, /* 0FF */ +{0, 0, 0, 0, 0, 0, 0}, /* 100-10F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 110-11F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 120-12F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 130-13F */ +{0, 0, 0, 0, 0, 0, 0}, +{ODC(2), RD, WO, 0, 0, 0, 0}, /* CVTDH */ +{2, RG, WL, 0, 0, 0, 0}, /* CVTGF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{2, RG, MQ, 0, 0, 0, 0}, /* ADDG2 */ +{3, RG, RG, WQ, 0, 0, 0}, /* ADDG3 */ +{2, RG, MQ, 0, 0, 0, 0}, /* SUBG2 */ +{3, RG, RG, WQ, 0, 0, 0}, /* SUBG3 */ +{2, RG, MQ, 0, 0, 0, 0}, /* MULG2 */ +{3, RG, RG, WQ, 0, 0, 0}, /* MULG3 */ +{2, RG, MQ, 0, 0, 0, 0}, /* DIVG2 */ +{3, RG, RG, WQ, 0, 0, 0}, /* DIVG3 */ +{2, RG, WB, 0, 0, 0, 0}, /* CVTGB */ +{2, RG, WW, 0, 0, 0, 0}, /* CVTGW */ +{2, RG, WL, 0, 0, 0, 0}, /* CVTGL */ +{2, RG, WL, 0, 0, 0, 0}, /* CVTRGL */ +{2, RB, WQ, 0, 0, 0, 0}, /* CVTBG */ +{2, RW, WQ, 0, 0, 0, 0}, /* CVTWG */ +{2, RL, WQ, 0, 0, 0, 0}, /* CVTLG */ +{4, RG, RG, MQ, BW, 0, 0}, /* ACBG */ +{2, RG, WQ, 0, 0, 0, 0}, /* MOVG */ +{2, RG, RG, 0, 0, 0, 0}, /* CMPG */ +{2, RG, WQ, 0, 0, 0, 0}, /* MNEGG */ +{1, RG, 0, 0, 0, 0, 0}, /* TSTG */ +{5, RG, RW, RG, WL, WQ, 0}, /* EMODG */ +{3, RG, RW, AB, 0, 0, 0}, /* POLYG */ +{ODC(2), RG, WO, 0, 0, 0, 0}, /* CVTGH */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{ODC(2), RH, MO, 0, 0, 0, 0}, /* ADDH2 */ +{ODC(3), RH, RH, WO, 0, 0, 0}, /* ADDH3 */ +{ODC(2), RH, MO, 0, 0, 0, 0}, /* SUBH2 */ +{ODC(3), RH, RH, WO, 0, 0, 0}, /* SUBH3 */ +{ODC(2), RH, MO, 0, 0, 0, 0}, /* MULH2 */ +{ODC(3), RH, RH, WO, 0, 0, 0}, /* MULH3 */ +{ODC(2), RH, MO, 0, 0, 0, 0}, /* DIVH2 */ +{ODC(3), RH, RH, WO, 0, 0, 0}, /* DIVH3 */ +{ODC(2), RH, WB, 0, 0, 0, 0}, /* CVTHB */ +{ODC(2), RH, WW, 0, 0, 0, 0}, /* CVTHW */ +{ODC(2), RH, WL, 0, 0, 0, 0}, /* CVTHL */ +{ODC(2), RH, WL, 0, 0, 0, 0}, /* CVTRHL */ +{ODC(2), RB, WO, 0, 0, 0, 0}, /* CVTBH */ +{ODC(2), RW, WO, 0, 0, 0, 0}, /* CVTWH */ +{ODC(2), RL, WO, 0, 0, 0, 0}, /* CVTLH */ +{ODC(4), RH, RH, MO, BW, 0, 0}, /* ACBH */ +{ODC(2), RH, RO, 0, 0, 0, 0}, /* MOVH */ +{ODC(2), RH, RH, 0, 0, 0, 0}, /* CMPH */ +{ODC(2), RH, WO, 0, 0, 0, 0}, /* MNEGH */ +{ODC(1), RH, 0, 0, 0, 0, 0}, /* TSTH */ +{ODC(5), RH, RW, RH, WL, WO, 0}, /* EMODH */ +{ODC(3), RH, RW, AB, 0, 0, 0}, /* POLYH */ +{ODC(2), RH, WQ, 0, 0, 0, 0}, /* CVTHG */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{ODC(1), WO, 0, 0, 0, 0, 0}, /* CLRO */ +{ODC(2), RO, RO, 0, 0, 0, 0}, /* MOVO */ +{ODC(2), AO, WL, 0, 0, 0, 0}, /* MOVAO*/ +{ODC(1), AO, 0, 0, 0, 0, 0}, /* PUSHAO*/ +{0, 0, 0, 0, 0, 0, 0}, /* 180-18F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 190-19F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{ODC(2), RF, WO, 0, 0, 0, 0}, /* CVTFH */ +{2, RF, WQ, 0, 0, 0, 0}, /* CVTFG */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1A0-1AF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1B0-1BF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1C0-1CF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1D0-1DF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1E0-1EF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1F0-1FF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{ODC(2), RH, WL, 0, 0, 0, 0}, /* CVTHF */ +{ODC(2), RH, WQ, 0, 0, 0, 0}, /* CVTHD */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0} }; /* Opcode mnemonics table */ @@ -1173,7 +1173,7 @@ const char *force[] = { "S^", "I^", "B^", "W^", "L^", NULL }; *r = SCPE_OK; /* assume ok */ M1C ('@', SP_IND); /* look for @ */ -if (tptr = parse_rnum (cptr, &rn)) { /* look for Rn */ +if ((tptr = parse_rnum (cptr, &rn))) { /* look for Rn */ if (*cptr == '[') { /* look for [Rx] */ cptr = parse_rnum (++cptr, &index); if ((cptr == NULL) || (*cptr++ != ']')) @@ -1425,6 +1425,7 @@ int32 i, lnt; t_value regnum; char *tptr; +*rn = 0; for (i = 15; i >= 0; i--) { /* chk named reg */ lnt = strlen (regname[i]); if (strncmp (cptr, regname[i], lnt) == 0) { diff --git a/VAX/vax_syscm.c b/VAX/vax_syscm.c index edc17edf..46225523 100644 --- a/VAX/vax_syscm.c +++ b/VAX/vax_syscm.c @@ -1,6 +1,6 @@ /* vax_syscm.c: PDP-11 compatibility mode symbolic decode and parse - 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,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. + 29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato) 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 */ @@ -610,7 +611,7 @@ switch (j) { /* case on class */ return SCPE_ARG; if ((pflag & A_REL) == 0) disp = (disp - ad32) & 0177777; - if ((disp & 1) || (disp > 0400) && (disp < 0177402)) + if ((disp & 1) || ((disp > 0400) && (disp < 0177402))) return SCPE_ARG; val[0] = val[0] | (((disp - 2) >> 1) & 0377); break; diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index 7121d109..03c62937 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" @@ -409,8 +409,8 @@ DEVICE cso_dev = { */ DIB sysd_dib[] = { - 0, 0, NULL, NULL, - 2, IVCL (TMR0), 0, { &tmr0_inta, &tmr1_inta } + {0, 0, NULL, NULL, + 2, IVCL (TMR0), 0, { &tmr0_inta, &tmr1_inta } } }; UNIT sysd_unit[] = { @@ -481,16 +481,17 @@ return ((val << 24) & 0xff000000) | (( val << 8) & 0xff0000) | ((val >> 8) & 0xff00) | ((val >> 24) & 0xff); } +volatile int32 rom_loopval = 0; + int32 rom_read_delay (int32 val) { uint32 i, l = rom_delay; -int32 loopval = 0; if (rom_unit.flags & UNIT_NODELAY) return val; /* Calibrate the loop delay factor when first used. - Do this 4 times to and use the largest value computed. */ + Do this 4 times and use the largest value computed. */ if (rom_delay == 0) { uint32 ts, te, c = 10000, samples = 0; @@ -503,15 +504,15 @@ if (rom_delay == 0) { away by a good compiler. loopval always is zero. To avoid smart compilers, the loopval variable is referenced in the function arguments so that the function expression is not loop invariant. It also must be referenced - by subsequent code or to avoid the whole computation being eliminated. */ + by subsequent code to avoid the whole computation being eliminated. */ for (i = 0; i < c; i++) - loopval |= (loopval + ts) ^ rom_swapb (rom_swapb (loopval + ts)); + rom_loopval |= (rom_loopval + ts) ^ rom_swapb (rom_swapb (rom_loopval + ts)); te = sim_os_msec (); if ((te - ts) < 50) /* sample big enough? */ continue; - if (rom_delay < (loopval + (c / (te - ts) / 1000) + 1)) - rom_delay = loopval + (c / (te - ts) / 1000) + 1; + if (rom_delay < (rom_loopval + (c / (te - ts) / 1000) + 1)) + rom_delay = rom_loopval + (c / (te - ts) / 1000) + 1; if (++samples >= 4) break; c = c / 2; @@ -521,8 +522,8 @@ if (rom_delay == 0) { } for (i = 0; i < l; i++) - loopval |= (loopval + val) ^ rom_swapb (rom_swapb (loopval + val)); -return val + loopval; + rom_loopval |= (rom_loopval + val) ^ rom_swapb (rom_swapb (rom_loopval + val)); +return val + rom_loopval; } int32 rom_rd (int32 pa) @@ -1563,7 +1564,7 @@ if (*rom == 0) { /* no boot? */ #ifndef DONT_USE_INTERNAL_ROM FILE *f; - if (f = sim_fopen ("ka655x.bin", "wb")) { + if ((f = sim_fopen ("ka655x.bin", "wb"))) { printf ("Saving boot code to ka655x.bin\n"); if (sim_log) fprintf (sim_log, "Saving boot code to ka655x.bin\n"); diff --git a/VAX/vax_syslist.c b/VAX/vax_syslist.c index f2e4eefe..054c5e43 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 @@ -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/VAX/vax780_vmb_exe.h b/VAX/vax_vmb_exe.h similarity index 98% rename from VAX/vax780_vmb_exe.h rename to VAX/vax_vmb_exe.h index 6b6af820..45d0bae6 100644 --- a/VAX/vax780_vmb_exe.h +++ b/VAX/vax_vmb_exe.h @@ -1,11 +1,12 @@ -#ifndef ROM_vax780_vmb_exe_H -#define ROM_vax780_vmb_exe_H 0 +#ifndef ROM_vax_vmb_exe_H +#define ROM_vax_vmb_exe_H 0 /* - VAX/vax780_vmb_exe.h produced at Sun Feb 26 12:32:44 2012 - from VAX/vmb.exe which was last modified at Sat Feb 18 00:01:12 2012 + VAX/vax_vmb_exe.h produced at Mon Oct 22 06:06:02 2012 + from VAX/vmb.exe which was last modified at Sun Oct 21 18:12:55 2012 file size: 44544 (0xAE00) - checksum: 0xFFC014CC + This file is a generated file and should NOT be edited or changed by hand. */ -unsigned char vax780_vmb_exe[] = { +unsigned char vax_vmb_exe[] = { 0xD4,0xEF,0x34,0x61,0x00,0x00,0x17,0xEF,0xB8,0x5D,0x00,0x00,0xC1,0xAB,0x38,0xAB, 0x34,0x57,0xC0,0x8F,0x00,0x02,0x00,0x00,0x57,0xCA,0x8F,0xFF,0x01,0x00,0x00,0x57, 0x95,0xCF,0x18,0x03,0x13,0x08,0xD4,0x50,0x7D,0xAB,0x44,0x52,0x11,0x24,0x7D,0xAB, @@ -2790,4 +2791,4 @@ unsigned char vax780_vmb_exe[] = { 0x4C,0x52,0x45,0x41,0x44,0x3A,0x58,0x2D,0x32,0x20,0x20,0x43,0x4F,0x4E,0x49,0x4F, 0x3A,0x58,0x2D,0x33,0x20,0x20,0x2A,0x45,0x6E,0x64,0x20,0x6F,0x66,0x20,0x49,0x64, 0x65,0x6E,0x74,0x20,0x6C,0x69,0x73,0x74,0x73,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,}; -#endif /* ROM_vax780_vmb_exe_H */ +#endif /* ROM_vax_vmb_exe_H */ diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index e0c06198..9bd1832d 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -187,7 +187,7 @@ /* CMCTL registers */ -/* #define CMCTLSIZE (18 << 2) /* 18 registers */ +/* #define CMCTLSIZE (18 << 2) *//* 18 registers */ #define CMCTLSIZE (19 << 2) /* KA655X extra reg */ #define CMCTLBASE (REGBASE + 0x100) /* CMCTL addr base */ diff --git a/Visual Studio Projects/0ReadMe_Projects.txt b/Visual Studio Projects/0ReadMe_Projects.txt index 8b90b547..4640df79 100644 --- a/Visual Studio Projects/0ReadMe_Projects.txt +++ b/Visual Studio Projects/0ReadMe_Projects.txt @@ -21,7 +21,7 @@ For Example, the directory structure should look like: The contents of the windows-build directory can be downloaded from: - https://github.com/downloads/markpizz/simh/windows-build.zip + https://github.com/downloads/simh/simh/windows-build.zip Network devices are capable of using pthreads to enhance their performance. 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/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/Visual Studio Projects/PDP11.vcproj b/Visual Studio Projects/PDP11.vcproj index fc4f4b67..ef31b431 100644 --- a/Visual Studio Projects/PDP11.vcproj +++ b/Visual Studio Projects/PDP11.vcproj @@ -396,10 +396,6 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc" > - - diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln index fc14324e..42709754 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}" @@ -61,7 +59,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lgp", "lgp.vcproj", "{927C3 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "I7094", "I7094.vcproj", "{927C3BD9-BD0C-4A23-99F9-DEAD402BEEF9}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SWTP", "SWTP.vcproj", "{0ABAF350-853E-4A8F-8435-B583E29FB78C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swtp6800mp-a", "swtp6800mp-a.vcproj", "{0ABAF350-853E-4A8F-8435-B583E29FB78C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swtp6800mp-a2", "swtp6800mp-a2.vcproj", "{A0BAF350-853E-4A8F-8435-B583E29FFACE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BuildROMs", "BuildROMs.vcproj", "{D40F3AF1-EEE7-4432-9807-2AD287B490F8}" EndProject @@ -153,10 +153,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 @@ -193,6 +189,10 @@ Global {0ABAF350-853E-4A8F-8435-B583E29FB78C}.Debug|Win32.Build.0 = Debug|Win32 {0ABAF350-853E-4A8F-8435-B583E29FB78C}.Release|Win32.ActiveCfg = Release|Win32 {0ABAF350-853E-4A8F-8435-B583E29FB78C}.Release|Win32.Build.0 = Release|Win32 + {A0BAF350-853E-4A8F-8435-B583E29FFACE}.Debug|Win32.ActiveCfg = Debug|Win32 + {A0BAF350-853E-4A8F-8435-B583E29FFACE}.Debug|Win32.Build.0 = Debug|Win32 + {A0BAF350-853E-4A8F-8435-B583E29FFACE}.Release|Win32.ActiveCfg = Release|Win32 + {A0BAF350-853E-4A8F-8435-B583E29FFACE}.Release|Win32.Build.0 = Release|Win32 {D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Debug|Win32.ActiveCfg = Debug|Win32 {D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Debug|Win32.Build.0 = Debug|Win32 {D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/Visual Studio Projects/VAX.vcproj b/Visual Studio Projects/VAX.vcproj index 13136d28..4e30884e 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 @@ > @@ -357,10 +361,6 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc" > - - diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj index 09051630..2044067c 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" @@ -250,6 +253,10 @@ RelativePath="..\PDP11\pdp11_tu.c" > + + @@ -270,6 +277,7 @@ > @@ -379,10 +387,6 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc" > - - diff --git a/Visual Studio Projects/SWTP.vcproj b/Visual Studio Projects/swtp6800mp-a.vcproj similarity index 78% rename from Visual Studio Projects/SWTP.vcproj rename to Visual Studio Projects/swtp6800mp-a.vcproj index e573d26e..bf86be0d 100644 --- a/Visual Studio Projects/SWTP.vcproj +++ b/Visual Studio Projects/swtp6800mp-a.vcproj @@ -2,9 +2,9 @@ @@ -19,7 +19,7 @@ + + + + + + + + + + + + + + + + + + @@ -217,22 +253,6 @@ RelativePath="..\sim_tmxr.c" > - - - - - - - - diff --git a/Visual Studio Projects/PDP18B.vcproj b/Visual Studio Projects/swtp6800mp-a2.vcproj similarity index 78% rename from Visual Studio Projects/PDP18B.vcproj rename to Visual Studio Projects/swtp6800mp-a2.vcproj index 236714c9..b3230803 100644 --- a/Visual Studio Projects/PDP18B.vcproj +++ b/Visual Studio Projects/swtp6800mp-a2.vcproj @@ -2,9 +2,9 @@ @@ -19,7 +19,7 @@ - - - - - - @@ -314,6 +302,10 @@ RelativePath="..\sim_tmxr.h" > + + 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/descrip.mms b/descrip.mms index d93a7de3..6c53d6d8 100644 --- a/descrip.mms +++ b/descrip.mms @@ -39,7 +39,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. # VAX730 Just Build The DEC VAX730. # VAX750 Just Build The DEC VAX750. @@ -88,8 +89,8 @@ CC_DEBUG = /DEBUG .IFDEF DEBUG -LINK_DEBUG = /DEBUG/TRACEBACK CC_OPTIMIZE = /NOOPTIMIZE +NEST_DEBUG = ,DEBUG=1 .IFDEF MMSALPHA ALPHA_OR_IA64 = 1 @@ -97,27 +98,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 @@ -126,9 +137,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 @@ -137,8 +150,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 @@ -146,10 +166,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) @@ -163,30 +185,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. # @@ -234,6 +232,67 @@ 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 + @ 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$ERROR NLA0: + @ DEFINE/USER SYS$OUTPUT CC_VERSION.DAT + @ CC/DECC/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" + @ 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."")) + @ 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) + @ 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$(NEST_DEBUG)) + + # MITS Altair Simulator Definitions. # ALTAIR_DIR = SYS$DISK:[.ALTAIR] @@ -253,7 +312,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,\ @@ -337,7 +396,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") @@ -491,8 +552,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)) @@ -517,13 +577,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. @@ -632,7 +707,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") @@ -661,7 +736,7 @@ I7094_OPTIONS = /INCL=($(SIMH_DIR),$(I7094_DIR))/DEF=($(CC_DEFS)) ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 \ ID32 NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 \ VAX VAX730 VAX750 VAX780 \ - SDS I7094 SWTP + SDS I7094 SWTP6800MP-A SWTP6800MP-A2 $! No further actions necessary .ELSE # @@ -669,7 +744,7 @@ ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 \ # ALL : ALTAIR ALTAIRZ80 GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 \ - VAX VAX730 VAX750 VAX780 SDS SWTP + VAX VAX730 VAX750 VAX780 SDS SWTP6800MP-A SWTP6800MP-A2 $! No further actions necessary .ENDIF @@ -702,8 +777,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. @@ -1042,11 +1116,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) @@ -1057,6 +1142,7 @@ $(VAX_LIB1) : $(VAX_SOURCE1) $! $! Building The $(VAX_LIB1) Library. $! + $ 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 - @@ -1079,6 +1165,7 @@ $(VAX730_LIB1) : $(VAX730_SOURCE1) $! $! Building The $(VAX730_LIB1) Library. $! + $ RUN/NODEBUG $(BIN_DIR)BuildROMs-$(ARCH).EXE $ $(CC)$(VAX730_OPTIONS)/OBJ=$(VAX730_DIR) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - @@ -1101,6 +1188,7 @@ $(VAX750_LIB1) : $(VAX750_SOURCE1) $! $! Building The $(VAX750_LIB1) Library. $! + $ RUN/NODEBUG $(BIN_DIR)BuildROMs-$(ARCH).EXE $ $(CC)$(VAX750_OPTIONS)/OBJ=$(VAX750_DIR) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - @@ -1123,6 +1211,7 @@ $(VAX780_LIB1) : $(VAX780_SOURCE1) $! $! Building The $(VAX780_LIB1) Library. $! + $ 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 - @@ -1483,16 +1572,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/doc/gri_doc.doc b/doc/gri_doc.doc new file mode 100644 index 00000000..a9832a60 Binary files /dev/null and b/doc/gri_doc.doc differ diff --git a/doc/h316_doc.doc b/doc/h316_doc.doc new file mode 100644 index 00000000..d39be690 Binary files /dev/null and b/doc/h316_doc.doc differ diff --git a/doc/hp2100_doc.doc b/doc/hp2100_doc.doc new file mode 100644 index 00000000..5a1ee522 Binary files /dev/null and b/doc/hp2100_doc.doc differ diff --git a/doc/i1401_doc.doc b/doc/i1401_doc.doc new file mode 100644 index 00000000..a081da8b Binary files /dev/null and b/doc/i1401_doc.doc differ diff --git a/doc/i1620_doc.doc b/doc/i1620_doc.doc new file mode 100644 index 00000000..bdb40704 Binary files /dev/null and b/doc/i1620_doc.doc differ diff --git a/doc/i7094_doc.doc b/doc/i7094_doc.doc new file mode 100644 index 00000000..5ef7d0c3 Binary files /dev/null and b/doc/i7094_doc.doc differ diff --git a/doc/id_doc.doc b/doc/id_doc.doc new file mode 100644 index 00000000..27eabd6c Binary files /dev/null and b/doc/id_doc.doc differ diff --git a/doc/lgp_doc.doc b/doc/lgp_doc.doc new file mode 100644 index 00000000..9eebced8 Binary files /dev/null and b/doc/lgp_doc.doc differ diff --git a/doc/nova_doc.doc b/doc/nova_doc.doc new file mode 100644 index 00000000..5b0785e5 Binary files /dev/null and b/doc/nova_doc.doc differ diff --git a/doc/pdp10_doc.doc b/doc/pdp10_doc.doc new file mode 100644 index 00000000..baddd5ff Binary files /dev/null and b/doc/pdp10_doc.doc differ diff --git a/doc/pdp11_doc.doc b/doc/pdp11_doc.doc new file mode 100644 index 00000000..8169ee7f Binary files /dev/null and b/doc/pdp11_doc.doc differ diff --git a/doc/pdp18b_doc.doc b/doc/pdp18b_doc.doc new file mode 100644 index 00000000..1fb4b54c Binary files /dev/null and b/doc/pdp18b_doc.doc differ diff --git a/doc/pdp1_doc.doc b/doc/pdp1_doc.doc new file mode 100644 index 00000000..3d475e94 Binary files /dev/null and b/doc/pdp1_doc.doc differ diff --git a/doc/pdp8_doc.doc b/doc/pdp8_doc.doc new file mode 100644 index 00000000..2a5cb19e Binary files /dev/null and b/doc/pdp8_doc.doc differ diff --git a/doc/sds_doc.doc b/doc/sds_doc.doc new file mode 100644 index 00000000..6e694c44 Binary files /dev/null and b/doc/sds_doc.doc differ diff --git a/doc/simh_doc.doc b/doc/simh_doc.doc new file mode 100644 index 00000000..2d69a511 Binary files /dev/null and b/doc/simh_doc.doc differ diff --git a/doc/simh_faq.doc b/doc/simh_faq.doc new file mode 100644 index 00000000..09e08c9f Binary files /dev/null and b/doc/simh_faq.doc differ diff --git a/doc/simh_swre.doc b/doc/simh_swre.doc new file mode 100644 index 00000000..6a344112 Binary files /dev/null and b/doc/simh_swre.doc differ diff --git a/doc/vax780_doc.doc b/doc/vax780_doc.doc new file mode 100644 index 00000000..07b7f872 Binary files /dev/null and b/doc/vax780_doc.doc differ diff --git a/doc/vax_doc.doc b/doc/vax_doc.doc new file mode 100644 index 00000000..19a70329 Binary files /dev/null and b/doc/vax_doc.doc differ diff --git a/makefile b/makefile index 6064cbf1..ea7c0240 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,39 +12,98 @@ # 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. # +# 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. +# +# OSX and other environments may have the LLVM (clang) compiler +# installed. If you want to build with the clang compiler, invoke +# make with GCC=clang. +# # 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. +# +# For linting (or other code analyzers) make may be invoked similar to: +# +# make GCC=cppcheck CC_OUTSPEC= LDFLAGS= CFLAGS_G="--enable=all --template=gcc" CC_STD=--std=c99 +# # 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 + endif +else + ifeq ($(MAKECMDGOALS),) + # default target is all + NETWORK_USEFUL = true + BUILD_MULTIPLE = s + BUILD_SINGLE := all $(BUILD_SINGLE) + endif +endif ifeq ($(WIN32),) #*nix Environments (&& cygwin) ifeq ($(GCC),) 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 + ifeq (,$(shell $(GCC) -v /dev/null 2>&1 | grep 'clang version')) + GCC_VERSION = $(shell $(GCC) -v /dev/null 2>&1 | grep 'gcc version' | awk '{ print $$3 }') + COMPILER_NAME = GCC Version: $(GCC_VERSION) + else + COMPILER_NAME = $(shell $(GCC) -v /dev/null 2>&1 | grep 'clang version' | awk '{ print $$1 " " $$2 " " $$3 }') + CLANG_VERSION = $(word 3,$(COMPILER_NAME)) + ifeq (,$(findstring .,$(CLANG_VERSION))) + COMPILER_NAME = $(shell $(GCC) -v /dev/null 2>&1 | grep 'clang version' | awk '{ print $$1 " " $$2 " " $$3 " " $$4 }') + CLANG_VERSION = $(word 4,$(COMPILER_NAME)) + endif + endif + LTO_EXCLUDE_VERSIONS = + PCAPLIB = pcap ifeq (agcc,$(findstring agcc,$(GCC))) # Android target build? - OS_CCDEFS = -D_GNU_SOURCE -DSIM_ASYNCH_IO - OS_LDFLAGS = -lm + OS_CCDEFS = -D_GNU_SOURCE + ifeq (,$(NOASYNCH)) + OS_CCDEFS += -DSIM_ASYNCH_IO + endif + OS_LDFLAGS = -lm else # Non-Android Builds 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 + # OSX's XCode gcc doesn't support LTO, but gcc built to explicitly enable it will work + ifneq (,$(GCC_VERSION)) + ifeq (,$(shell $(GCC) -v /dev/null 2>&1 | grep '\-\-enable-lto')) + LTO_EXCLUDE_VERSIONS += $(GCC_VERSION) + endif + endif else ifeq (Linux,$(OSTYPE)) LIBPATH := $(sort $(foreach lib,$(shell /sbin/ldconfig -p | grep ' => /' | sed 's/^.* => //'),$(dir $(lib)))) @@ -64,27 +123,32 @@ 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 - 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)) @@ -92,13 +156,16 @@ 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 += -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 endif @@ -114,57 +181,59 @@ 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 - else - ifeq ($(MAKECMDGOALS),) - # default target is all - NETWORK_USEFUL = true - endif - 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)) + NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components 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)) + NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components endif - $(info *** Simulator(s) being built with networking support using) - $(info *** $(OSTYPE) provided libpcap components) else - NETWORK_CCDEFS = -DUSE_SHARED + 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 *** Simulator(s) being built with networking support using) - $(info *** $(OSTYPE) provided libpcap components) 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 *** Simulator(s) 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) + 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.) + $(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 + 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 @@ -188,45 +257,55 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP endif else + NETWORK_FEATURES = - WITHOUT networking support $(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) + $(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) 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) 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 + 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)) + 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)) PCAP_CCDEFS = -I../windows-build/winpcap/Wpdpack/include -I$(GCC_Path)..\include\ddk -DUSE_SHARED - NETWORK_LDFLAGS = + 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 = + 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 -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)) @@ -236,15 +315,88 @@ else NETWORK_OPT = -DUSE_SHARED endif endif +ifneq ($(DEBUG),) + CFLAGS_G = -g -ggdb -g3 + CFLAGS_O = -O0 + BUILD_FEATURES = - debugging support +else + ifneq (clang,$(findstring clang,$(COMPILER_NAME))) + CFLAGS_O = -O2 + else + ifeq (Darwin,$(OSTYPE)) + CFLAGS_O += -O4 -fno-strict-overflow -flto -fwhole-program + else + CFLAGS_O := -O2 -fno-strict-overflow + endif + endif + LDFLAGS_O = + GCC_MAJOR_VERSION = $(firstword $(subst ., ,$(GCC_VERSION))) + ifneq (3,$(GCC_MAJOR_VERSION)) + 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 -finline-functions,$(GCC_OPTIMIZERS))) + CFLAGS_O += -finline-functions + endif + ifneq (,$(findstring -fgcse-after-reload,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fgcse-after-reload + endif + ifneq (,$(findstring -fpredictive-commoning,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fpredictive-commoning + endif + ifneq (,$(findstring -fipa-cp-clone,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fipa-cp-clone + endif + ifneq (,$(findstring -funsafe-loop-optimizations,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fno-unsafe-loop-optimizations + endif + ifneq (,$(findstring -fstrict-overflow,$(GCC_OPTIMIZERS))) + CFLAGS_O += -fno-strict-overflow + endif + ifeq (,$(NO_LTO)) + ifneq (,$(findstring -flto,$(GCC_OPTIMIZERS))) + CFLAGS_O += -flto -fwhole-program + LDFLAGS_O += -flto -fwhole-program + endif + endif + BUILD_FEATURES = - compiler optimizations and no debugging support +endif +ifneq (3,$(GCC_MAJOR_VERSION)) + 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 +ifneq (clean,$(MAKECMDGOALS)) + BUILD_FEATURES := $(BUILD_FEATURES). $(COMPILER_NAME) + $(info ***) + $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with:) + $(info *** $(BUILD_FEATURES).) + ifneq (,$(NETWORK_FEATURES)) + $(info *** $(NETWORK_FEATURES).) + endif + $(info ***) +endif ifneq ($(DONT_USE_ROMS),) ROMS_OPT = -DDONT_USE_INTERNAL_ROM 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) +CC_STD = -std=c99 +CC_OUTSPEC = -o $@ +CC = $(GCC) $(CC_STD) -U__STRICT_ANSI__ $(CFLAGS_G) $(CFLAGS_O) -I . $(OS_CCDEFS) $(ROMS_OPT) +LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) $(LDFLAGS_O) # # Common Libraries @@ -355,7 +507,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} @@ -364,9 +516,9 @@ PDP10 = ${PDP10D}/pdp10_fe.c ${PDP11D}/pdp11_dz.c ${PDP10D}/pdp10_cpu.c \ ${PDP10D}/pdp10_ksio.c ${PDP10D}/pdp10_lp20.c ${PDP10D}/pdp10_mdfp.c \ ${PDP10D}/pdp10_pag.c ${PDP10D}/pdp10_rp.c ${PDP10D}/pdp10_sys.c \ ${PDP10D}/pdp10_tim.c ${PDP10D}/pdp10_tu.c ${PDP10D}/pdp10_xtnd.c \ - ${PDP11D}/pdp11_pt.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_xu.c \ + ${PDP11D}/pdp11_pt.c ${PDP11D}/pdp11_ry.c \ ${PDP11D}/pdp11_cr.c -PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} ${NETWORK_OPT} +PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} @@ -396,7 +548,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} @@ -468,7 +621,7 @@ ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_cpu_nommu.c \ ${ALTAIRZ80D}/altairz80_hdsk.c ${ALTAIRZ80D}/altairz80_net.c \ ${ALTAIRZ80D}/flashwriter2.c ${ALTAIRZ80D}/i86_decode.c \ ${ALTAIRZ80D}/i86_ops.c ${ALTAIRZ80D}/i86_prim_ops.c \ - ${ALTAIRZ80D}/i8272.c ${ALTAIRZ80D}/insnsa.c ${ALTAIRZ80D}/insnsd.c \ + ${ALTAIRZ80D}/i8272.c ${ALTAIRZ80D}/insnsd.c \ ${ALTAIRZ80D}/mfdc.c ${ALTAIRZ80D}/n8vem.c ${ALTAIRZ80D}/vfdhd.c \ ${ALTAIRZ80D}/s100_disk1a.c ${ALTAIRZ80D}/s100_disk2.c ${ALTAIRZ80D}/s100_disk3.c\ ${ALTAIRZ80D}/s100_fif.c ${ALTAIRZ80D}/s100_mdriveh.c \ @@ -496,10 +649,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} # @@ -508,7 +666,7 @@ SWTP_OPT = -I ${SWTPD} ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ vax vax730 vax750 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} @@ -520,16 +678,19 @@ 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 $@ + gcc $(wordlist 2,1000,${CC}) sim_BuildROMs.c $(CC_OUTSPEC) else - ${CC} sim_BuildROMs.c -o $@ + ${CC} sim_BuildROMs.c $(CC_OUTSPEC) endif ifeq ($(WIN32),) $@ ${RM} $@ + ifeq (Darwin,$(OSTYPE)) # remove Xcode's debugging symbols folder too + ${RM} -rf $@.dSYM + endif else $(@D)\$(@F) del $(@D)\$(@F) @@ -542,55 +703,55 @@ pdp1 : ${BIN}pdp1${EXE} ${BIN}pdp1${EXE} : ${PDP1} ${SIM} ${MKDIRBIN} - ${CC} ${PDP1} ${SIM} ${PDP1_OPT} -o $@ ${LDFLAGS} + ${CC} ${PDP1} ${SIM} ${PDP1_OPT} $(CC_OUTSPEC) ${LDFLAGS} pdp4 : ${BIN}pdp4${EXE} ${BIN}pdp4${EXE} : ${PDP18B} ${SIM} ${MKDIRBIN} - ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} -o $@ ${LDFLAGS} + ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} $(CC_OUTSPEC) ${LDFLAGS} pdp7 : ${BIN}pdp7${EXE} ${BIN}pdp7${EXE} : ${PDP18B} ${SIM} ${MKDIRBIN} - ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} -o $@ ${LDFLAGS} + ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} $(CC_OUTSPEC) ${LDFLAGS} pdp8 : ${BIN}pdp8${EXE} ${BIN}pdp8${EXE} : ${PDP8} ${SIM} ${MKDIRBIN} - ${CC} ${PDP8} ${SIM} ${PDP8_OPT} -o $@ ${LDFLAGS} + ${CC} ${PDP8} ${SIM} ${PDP8_OPT} $(CC_OUTSPEC) ${LDFLAGS} pdp9 : ${BIN}pdp9${EXE} ${BIN}pdp9${EXE} : ${PDP18B} ${SIM} ${MKDIRBIN} - ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} -o $@ ${LDFLAGS} + ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} $(CC_OUTSPEC) ${LDFLAGS} pdp15 : ${BIN}pdp15${EXE} ${BIN}pdp15${EXE} : ${PDP18B} ${SIM} ${MKDIRBIN} - ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} -o $@ ${LDFLAGS} + ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} $(CC_OUTSPEC) ${LDFLAGS} pdp10 : ${BIN}pdp10${EXE} ${BIN}pdp10${EXE} : ${PDP10} ${SIM} ${MKDIRBIN} - ${CC} ${PDP10} ${SIM} ${PDP10_OPT} -o $@ ${LDFLAGS} + ${CC} ${PDP10} ${SIM} ${PDP10_OPT} $(CC_OUTSPEC) ${LDFLAGS} pdp11 : ${BIN}pdp11${EXE} ${BIN}pdp11${EXE} : ${PDP11} ${SIM} ${MKDIRBIN} - ${CC} ${PDP11} ${SIM} ${PDP11_OPT} -o $@ ${LDFLAGS} + ${CC} ${PDP11} ${SIM} ${PDP11_OPT} $(CC_OUTSPEC) ${LDFLAGS} vax : ${BIN}vax${EXE} ${BIN}vax${EXE} : ${VAX} ${SIM} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX} ${SIM} ${VAX_OPT} $(CC_OUTSPEC) ${LDFLAGS} vax730 : ${BIN}vax730${EXE} @@ -608,106 +769,113 @@ vax780 : ${BIN}vax780${EXE} ${BIN}vax780${EXE} : ${VAX780} ${SIM} ${BUILD_ROMS} ${MKDIRBIN} - ${CC} ${VAX780} ${SIM} ${VAX780_OPT} -o $@ ${LDFLAGS} + ${CC} ${VAX780} ${SIM} ${VAX780_OPT} $(CC_OUTSPEC) ${LDFLAGS} nova : ${BIN}nova${EXE} ${BIN}nova${EXE} : ${NOVA} ${SIM} ${MKDIRBIN} - ${CC} ${NOVA} ${SIM} ${NOVA_OPT} -o $@ ${LDFLAGS} + ${CC} ${NOVA} ${SIM} ${NOVA_OPT} $(CC_OUTSPEC) ${LDFLAGS} eclipse : ${BIN}eclipse${EXE} ${BIN}eclipse${EXE} : ${ECLIPSE} ${SIM} ${MKDIRBIN} - ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} -o $@ ${LDFLAGS} + ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} $(CC_OUTSPEC) ${LDFLAGS} h316 : ${BIN}h316${EXE} ${BIN}h316${EXE} : ${H316} ${SIM} ${MKDIRBIN} - ${CC} ${H316} ${SIM} ${H316_OPT} -o $@ ${LDFLAGS} + ${CC} ${H316} ${SIM} ${H316_OPT} $(CC_OUTSPEC) ${LDFLAGS} hp2100 : ${BIN}hp2100${EXE} ${BIN}hp2100${EXE} : ${HP2100} ${SIM} ${MKDIRBIN} - ${CC} ${HP2100} ${SIM} ${HP2100_OPT} -o $@ ${LDFLAGS} + ${CC} ${HP2100} ${SIM} ${HP2100_OPT} $(CC_OUTSPEC) ${LDFLAGS} i1401 : ${BIN}i1401${EXE} ${BIN}i1401${EXE} : ${I1401} ${SIM} ${MKDIRBIN} - ${CC} ${I1401} ${SIM} ${I1401_OPT} -o $@ ${LDFLAGS} + ${CC} ${I1401} ${SIM} ${I1401_OPT} $(CC_OUTSPEC) ${LDFLAGS} i1620 : ${BIN}i1620${EXE} ${BIN}i1620${EXE} : ${I1620} ${SIM} ${MKDIRBIN} - ${CC} ${I1620} ${SIM} ${I1620_OPT} -o $@ ${LDFLAGS} + ${CC} ${I1620} ${SIM} ${I1620_OPT} $(CC_OUTSPEC) ${LDFLAGS} i7094 : ${BIN}i7094${EXE} ${BIN}i7094${EXE} : ${I7094} ${SIM} ${MKDIRBIN} - ${CC} ${I7094} ${SIM} ${I7094_OPT} -o $@ ${LDFLAGS} + ${CC} ${I7094} ${SIM} ${I7094_OPT} $(CC_OUTSPEC) ${LDFLAGS} ibm1130 : ${BIN}ibm1130${EXE} ${BIN}ibm1130${EXE} : ${IBM1130} ${MKDIRBIN} - ${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} -o $@ ${LDFLAGS} + ${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} $(CC_OUTSPEC) ${LDFLAGS} s3 : ${BIN}s3${EXE} ${BIN}s3${EXE} : ${S3} ${SIM} ${MKDIRBIN} - ${CC} ${S3} ${SIM} ${S3_OPT} -o $@ ${LDFLAGS} + ${CC} ${S3} ${SIM} ${S3_OPT} $(CC_OUTSPEC) ${LDFLAGS} altair : ${BIN}altair${EXE} ${BIN}altair${EXE} : ${ALTAIR} ${SIM} ${MKDIRBIN} - ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ ${LDFLAGS} + ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} $(CC_OUTSPEC) ${LDFLAGS} altairz80 : ${BIN}altairz80${EXE} -${BIN}altairz80${EXE} : ${ALTAIRZ80} ${SIM} +${BIN}altairz80${EXE} : ${ALTAIRZ80} ${SIM} ${MKDIRBIN} - ${CC} ${ALTAIRZ80} ${SIM} ${ALTAIRZ80_OPT} -o $@ ${LDFLAGS} + ${CC} ${ALTAIRZ80} ${SIM} ${ALTAIRZ80_OPT} $(CC_OUTSPEC) ${LDFLAGS} gri : ${BIN}gri${EXE} ${BIN}gri${EXE} : ${GRI} ${SIM} ${MKDIRBIN} - ${CC} ${GRI} ${SIM} ${GRI_OPT} -o $@ ${LDFLAGS} + ${CC} ${GRI} ${SIM} ${GRI_OPT} $(CC_OUTSPEC) ${LDFLAGS} lgp : ${BIN}lgp${EXE} ${BIN}lgp${EXE} : ${LGP} ${SIM} ${MKDIRBIN} - ${CC} ${LGP} ${SIM} ${LGP_OPT} -o $@ ${LDFLAGS} + ${CC} ${LGP} ${SIM} ${LGP_OPT} $(CC_OUTSPEC) ${LDFLAGS} id16 : ${BIN}id16${EXE} ${BIN}id16${EXE} : ${ID16} ${SIM} ${MKDIRBIN} - ${CC} ${ID16} ${SIM} ${ID16_OPT} -o $@ ${LDFLAGS} + ${CC} ${ID16} ${SIM} ${ID16_OPT} $(CC_OUTSPEC) ${LDFLAGS} id32 : ${BIN}id32${EXE} ${BIN}id32${EXE} : ${ID32} ${SIM} ${MKDIRBIN} - ${CC} ${ID32} ${SIM} ${ID32_OPT} -o $@ ${LDFLAGS} + ${CC} ${ID32} ${SIM} ${ID32_OPT} $(CC_OUTSPEC) ${LDFLAGS} sds : ${BIN}sds${EXE} ${BIN}sds${EXE} : ${SDS} ${SIM} ${MKDIRBIN} - ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ ${LDFLAGS} + ${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} -o $@ ${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/scp.c b/scp.c index 2d7b5deb..3cdc678a 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,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. + 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 asynchronously by the new scp command SET ASYNCH and @@ -59,6 +61,7 @@ 17-Aug-08 RMS Revert RUN/BOOT to standard, rather than powerup, reset 25-Jul-08 JDB DO cmd missing params now default to null string 29-Jun-08 JDB DO cmd sub_args now allows "\\" to specify literal backslash + 04-Jun-08 JDB label the patch delta more clearly 31-Mar-08 RMS Fixed bug in local/global register search (Mark Pizzolato) Fixed bug in restore of RO units (Mark Pizzolato) 06-Feb-08 RMS Added SET/SHO/NO BR with default argument @@ -70,6 +73,7 @@ 30-Jan-07 RMS Fixed bugs in get_ipaddr 17-Oct-06 RMS Added idle support 04-Oct-06 JDB DO cmd failure now echoes cmd unless -q + 30-Aug-06 JDB detach_unit returns SCPE_UNATT if not attached 14-Jul-06 RMS Added sim_activate_abs 02-Jun-06 JDB Fixed do_cmd to exit nested files on assertion failure Added -E switch to do_cmd to exit on any error @@ -86,6 +90,7 @@ 22-Mar-05 JDB Modified DO command to allow ten-level nesting 18-Mar-05 RMS Moved DETACH tests into detach_unit (Dave Bryan) Revised interface to fprint_sym, fparse_sym + 13-Mar-05 JDB ASSERT now requires a conditional operator 07-Feb-05 RMS Added ASSERT command (Dave Bryan) 02-Feb-05 RMS Fixed bug in global register search 26-Dec-04 RMS Qualified SAVE examine, RESTORE deposit with SIM_SW_REST @@ -97,6 +102,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) @@ -209,9 +215,15 @@ #include "sim_defs.h" #include "sim_rev.h" +#include "sim_ether.h" #include #include #include +#if defined(_WIN32) +#include +#else +#include +#endif #include #if defined(HAVE_DLOPEN) /* Dynamic Readline support */ @@ -236,7 +248,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 @@ -321,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); @@ -334,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); @@ -398,9 +412,15 @@ 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_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); +void run_cmd_message (const char *unechod_cmdline, t_stat r); /* Global data */ @@ -436,11 +456,16 @@ 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[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_do_depth = 0; +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 char *sim_do_label[MAX_DO_NEST_LVL+1]; static t_stat sim_last_cmd_stat; /* Command Status */ @@ -561,15 +586,15 @@ static CTAB cmd_table[] = { { "EVALUATE", &eval_cmd, 0, "ev{aluate} evaluate symbolic expression\n" }, { "RUN", &run_cmd, RU_RUN, - "ru{n} {new PC} reset and start simulation\n" }, + "ru{n} {new PC} reset and start simulation\n", &run_cmd_message }, { "GO", &run_cmd, RU_GO, - "go {new PC} start simulation\n" }, + "go {new PC} start simulation\n", &run_cmd_message }, { "STEP", &run_cmd, RU_STEP, - "s{tep} {n} simulate n instructions\n" }, + "s{tep} {n} simulate n instructions\n", &run_cmd_message }, { "CONT", &run_cmd, RU_CONT, - "c{ont} continue simulation\n" }, + "c{ont} continue simulation\n", &run_cmd_message }, { "BOOT", &run_cmd, RU_BOOT, - "b{oot} bootstrap unit\n" }, + "b{oot} bootstrap unit\n", &run_cmd_message }, { "BREAK", &brk_cmd, SSH_ST, "br{eak} set breakpoints\n" }, { "NOBREAK", &brk_cmd, SSH_CL, @@ -602,7 +627,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" @@ -611,10 +638,20 @@ 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 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" + "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" @@ -623,6 +660,18 @@ 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 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" @@ -632,8 +681,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" @@ -648,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" @@ -655,17 +703,28 @@ static CTAB cmd_table[] = { "sh{ow} SHOW show device SHOW commands\n" "sh{ow} {arg,...} show device parameters\n" "sh{ow} {arg,...} show unit parameters\n" + "sh{ow} ethernet show ethernet devices\n" "sh{ow} on show on condition actions\n" }, { "DO", &do_cmd, 1, - "do {arg,arg...} process command file\n" }, + "do {-V} {-O} {-E} {-Q} {arg,arg...}\b" + " process command file\n" }, { "GOTO", &goto_cmd, 1, "goto