SIMH Investigations =================== COMPLETED INVESTIGATIONS ------------------------ The following investigations have been completed with patches prepared: PENDING INVESTIGATIONS ---------------------- These investigations have been characterized by observation, but no patches have been prepared: xxx. PROBLEM: A device can trap unit disables but not unit enables. VERSION: 3.12-0 OBSERVATION: A device may wish to determine when a unit is disabled or enabled. For example, a device might send every command to all enabled units. This may occur with such frequency that cycling through all units to check for UNIT_DIS on each command would be prohibitive. Or a device may wish to notify the CPU when a new unit is added to a device bus by enabling the unit. To maintain a list of enabled units, a device would want to trap and record SET ENABLED and SET DISABLED commands. Attempting to do this by including extended MTAB entries for "ENABLED" and "DISABLED" reveals that the validation routine is only called for the "DISABLED" command. Entering a SET ENABLED command for a disabled unit prints "Unit disabled" and does not call the routine. CAUSE: There is a check in the "set_cmd" routine (scp.c) that returns SCPE_UDIS in lieu of calling the validation routine if the MTAB_VUN and UNIT_DIS flags are set. This prohibits an enable command for a disabled unit from being seen by the device. Note that extended MTAB entries for "ENABLED" and "DISABLED" can be used to trap device enable and disable commands. So currently a device can record SET ENABLED, SET DISABLED, and SET DISABLED commands, but not SET ENABLED. RESOLUTION: Add a new MTAB flag that overrides the disabled unit check. STATUS: Reported; Bob agrees in an e-mail on 2021-07-17. xxx. PROBLEM: Cannot continue from an "Indirect address loop" error. VERSION: 3.10-0 OBSERVATION: The HP 2100 simulator traps a code sequence such as: JMP *+1,I DEF *,I ...by the "cpu_resolve_indirects" routine, which returns STOP_INDIR after the indirect limit is reached. The limit is set by the "SET CPU INDIR=" command and allows values from 0 to 32767. The above sequence, however, will never resolve, regardless of the value. In hardware, interrupts are checked while resolution is ongoing, so a user program containing the above sequence running under an operating system can be aborted, typically with an "OFF" command entered at the system console. If interrupts are off, the sequence may still be stopped by halting the CPU. Under simulation, only the latter option is available. Regardless of the indirect limit setting, resuming after STOP_INDIR will stop again after an imperceptible delay, so the user running an operating system has no opportunity to abort the program. The only recourse is to deposit a halt instruction at the location containing the offending instruction and rely on the resulting memory-protect violation after resuming execution to abort the program and allow the OS to continue. CAUSE: The "cpu_resolve_indirects" routine always terminates if the indirect limit is reached. While it checks for a pending interrupt on entry and will service it after three indirect levels, no further check is made at deeper levels. Nor is the "sim_interval" updated, so no interrupts will occur during indirect resolution. If the indirect limit were never reached, and if no interrupt were pending on entry, then the routine would loop forever and hang the simulator. RESOLUTION: //None.// Modify "cpu_resolve_indirects" (hp2100_cpu.c) to recognize the "-B" (bypass) switch on resumption and temporarily set an unlimited indirect depth. Update "sim_interval" during resolution, check for new interrupts, and if one is pending, exit with NOTE_INDINT status to abort the instruction and service the interrupt. NOTE: Some callers do not handle being interrupted properly. These instructions must be fixed before this will work!!! STATUS: Unreported. xxx. PROBLEM: Telnet negotiation handling doesn't really work properly. VERSION: 3.8-0 OBSERVATION: Telnet negotiation is supposed to reach a mutual agreement between client and host on the protocol to use. But actually, SIMH simply sends a bunch of commands and pays no attention to the responses (except for binary mode request). A patch was created by Richard Cornwell in August 2007 to support Kermit, but it leads to a negotiation loop with QCTerm. Loop avoidance involves ensuring that a denied request is not repeated. We really need proper negotiation. CAUSE: Expediency? RESOLUTION: None. STATUS: Unreported. xxx. PROBLEM: The free HP 700/92 terminal emulator, QCTERM from AICS, does not work with SIMH. VERSION: 3.7-0 OBSERVATION: Attempting to run QCTERM as a Telnet client with SIMH seems to lose characters. In particular, the first character typed after a CR is lost. CAUSE: QCTERM does not appear to follow the Telnet protocol as described in RFC 854, "Telnet Protocol Specification." Specifically, QCTERM sends a "bare" carriage-return character to SIMH in non-binary mode. RFC 854 says, in part: ...The sequence "CR LF" must be treated as a single "new line" character and used whenever their combined action is intended; the sequence "CR NUL" must be used where a carriage return alone is actually desired; and the CR character must be avoided in other contexts. [...] ...The protocol requires that a NUL be inserted following a CR not followed by a LF in the data stream. However, QCTERM does not follow CR with LF or NUL; it sends nothing after the CR. SIMH presumes that CR will always be followed by one or the other, so it simply drops the next character. For QCTERM, this is the first character of the subsequent transmission. To negotiate a binary connection, a server sends WILL BIN and DO BIN to the client. An accepting client will respond with WILL BIN and DO BIN; a rejecting client will respond with WONT BIN and DONT BIN. SIMH sends WILL BIN and DO BIN. If the client does not respond with WONT BIN, a binary connection is assumed, and "bare" CRs will be accepted. If the client responds with WONT BIN, then binary mode is rejected; CR LF is required to transmit a CR, and CR NUL LF is required to transmit a CR LF. QCTERM sends DO ECHO, DO SUPPRESS LOCAL ECHO, and WONT BIN upon connection. The WONT BIN indicates to SIMH that "bare" CRs will not occur, so the character following the CR is unconditionally discarded. As a point of reference, these Telnet clients send the following negotiations to SIMH upon connection: Telnet client Negotiation ==================== ================================================== Microsoft Telnet DONT LINEMODE, DO SGA, DO ECHO, DO BIN, WILL BIN Microsoft Hyperterm DONT LINEMODE, DO SGA, DO ECHO, DO BIN, WILL BIN Attachmate Crosstalk DONT LINEMODE, DO SGA, DO ECHO, DO BIN AICS QCTERM DO ECHO, DO SUPPRESS LOCAL ECHO, WONT BIN ...and transmit these characters for end-of-line: Telnet client "Normal" mode "Auto LF" mode ==================== ============= ============== Microsoft Telnet CR CR LF Microsoft Hyperterm CR CR LF Attachmate Crosstalk CR CR LF AICS QCTERM CR CR NUL LF WORKAROUND: Modify the TNS_SKIP case in "tmxr_poll_rx" (sim_tmxr.c) to skip only LF or NUL following CR. Any other character is processed as is. STATUS: Patch created 2007-04-11 and submitted 2008-04-10. xxx. PROBLEM: The "real time" settings for, e.g., the 7970 drive only work with a given CPU. VERSION: 3.7-0 OBSERVATION: Devices that implement REALTIME timing (7970, 2767, and 277x) pass their diagnostics only when the CPU matches the hard-coded timing, typically the 1000-E. Devices calculate "real time" responses in terms of instructions. However, the hardware responds in terms of time. So they set a certain number of instructions to represent the desired time, but a given "real time" value is accurate only for one CPU. Running a diagnostic that times responses on a different CPU results in failures. CAUSE: "Real time" instruction counts must change with CPU type. It would be best if these changed with SET CPU rather than SET REALTIME, as doing the latter and then the former would screw up the timing. Add a table of instruction timings (based on the diagnostic configurator timer) to "hp2100_defs.c". Add a field to the DIB structure to indicate a device-specific routine that must be called when the CPU type changes. Modify the 7970, 2767, and 277x simulators to express REALTIME values in microseconds and to update a corresponding table of instruction counts when the CPU type changes or when switching from FASTTIME to REALTIME. These routines could query the CPU speed via a function in hp2100_cpu.c ("cpu_instrs_per_msec", perhaps) to scale their interpretations of real time response. RESOLUTION: None. STATUS: Unreported. xxx. PROBLEM: FMGR "list spacing" control requests (e.g., :CN,1,11B,5) produce text files that cannot be read by Windows Notepad. This problem affects FMGR directory listings and anything that might use a control request. VERSION: 3.6-1 OBSERVATION: Directory listings end with CR-LF-LF, which is displayed as three square boxes in Notepad. CAUSE: DVR00 is outputting "bare" LFs for line spacing control requests. Windows wants to see CR-LFs for null lines. RESOLUTION: Unresolved. Might want to modify TTY to add CR if "bare" LF is output. STATUS: Unreported. xxx. PROBLEM: The various parts of the DMS status are not kept consistent. VERSION: 3.2-1 OBSERVATION: DMS status is exposed in several pseudo-registers: DMSENB (DMS enabled), DMSCUR (DMS user map is current), and DMSSR (DMS base-page fence). During simulator break, changes to the first two are not reflected in the third. When simulation is restarted, the states of the first two override the state set in the third. CAUSE: ? RESOLUTION: Modify "hp2100_cpu.c" to remove the visible DMSENB and DMSCUR pseudo-registers and to change all conditionals on "dms_enb" and "dms_cur" to use the appropriate bits in "dms_sr" instead. STATUS: Unimplemented. xxx. PROBLEM: The current BOOT implementation is flawed, as it depends on some bits (but not all) being set in the S register before issuing the command. VERSION: 3.2-1 OBSERVATION: Bootstrapping the simulator works by executing an internal "ROM loader" routine to read and configure the appropriate ROM bootstrap loader, setting the S register appropriately, and then executing the bootstrap. At version 3.2-1, the action of the BOOT command was altered to merge in some bits from the current value of the S register, rather than using predefined values. This was done to support system-specific requirements (e.g., RTE I/O reconfiguration). However, the specific bits merged are device-specific, so in some cases S must be set, while in others it is irrelevant. As such, BOOT is more difficult to use than before. The HP cold load procedure is to set the S register (to specify the desired boot ROM, the device select code, and any other ROM-specific bits, e.g., desired disc head), then press IBL (to load the ROM bootstrap into memory, configure it, and preset the P register to the proper starting address), and then press RUN (to initiate the bootstrap). The features needed to simulate this process already exist and would be available to the user if an IBL command was created to expose the internal IBL routine. Currently, BOOT has been overloaded to provide both a simplified bootstrap mechanism, wherein parts of the S register are preset, and a general mechanism that requires S register bits to be set by the user. In effect, this implies that S must always be set by the user before booting, obviating the simplified mechanism. In addition, conflicting settings between the S register and the BOOT command are resolved arbitrarily by the individual device routines. What is needed are really two bootstrap commands: a command ("BOOT") that provides defaults that are appropriate in most circumstances, and a command ("IBL") that provides full user control over the bootstrap sequence. BOOT should revert to the simplified mechanism of versions 3.2-0 and earlier. "BOOT [switches] dev" should derive the proper ROM and device select code from the device name and otherwise default the optional S-register bits in the absence of any device-provided switches. BOOT would not depend on any prior setting of the S register. An IBL command should be added that loads the ROM specified by the S-register bits 15-14, configures it according to S-register bits 5-0, and presets the P register to the start of the bootstrap code. The S-register would be set before executing IBL. Splitting the bootstrap functions allows "BOOT" to be used in most cases without the version-3.2-1 behavior of requiring that S be set beforehand but provides IBL for when specific bits must be set before booting. Possible flow would be: IBL command -- calls "ibl_copy" based on S register contents; ROM assigned via SET CPU ROM0 PTR (e.g.); result reflected in registers. BOOT command -- uses default S register values unless "-s" specified; uses ROM associated with boot device; calls "ibl_copy"; reports error if OVFL, else runs. CAUSE: ? RESOLUTION: Unknown. STATUS: Unimplemented. xxx. PROBLEM: The execution time reported by the DOS-III :EJ command is zero. VERSION: 3.2-1 OBSERVATION: Running a program that loops for several seconds and then ending the job shows "EXEC=0000 MIN. 00.0 SEC.". The wall clock time report in the end-of-job listing appears to be about correct. Execution time appears to increment only if the program is started with the :RUN command and not with the :PROG command. This may be correct, as only :RUN may specify a job execution time limit. CAUSE: ? RESOLUTION: This may be working as designed. STATUS: Unreported. UNCHARACTERIZED INVESTIGATIONS ------------------------------ These brief notes pertain to investigations yet to be characterized by observation and testing: -- Add a CONDTOF register (default = 1) that controls whether a TOF is executed when the location is already at TOF. We seem to get lots of leading blank pages. The printer does print-and-space, so we'd suppress motion only if the buffer is empty, the line number is 1, and a TOF request is made. Q: Does the printer do conditional TOFs, or will two consecutive TOF requests produce two blank pages? -- To accomodate the ICA driver for the Tally 2000 printer, the "slew_count" is set to 0 instead of 1 when the "format_byte" is "FORMAT_SUPPRESS" because the paper does not advance after printing with this driver (even though the printer is not capable of overprinting). This is really a driver problem, in that a "*" as a carriage-control character is interpreted as "don't print" rather than as "overprint." -- For MAC discs, Request Status returns Status-2 showing Not Ready if the unit number of the prior command was > 7. Otherwise, it returns Status-2 for the unit number in the Request Status command. Controller microcode bug. -- idling doesn't seem to work for SIO (SFS sc / JMP *-1). Idle is detected properly, but timing is wonky. Make this a local patch until resolved. -- "sim_del_char" isn't tested in every "sim_os_poll_char" (only 3 of 6) shouldn't char testing be os-independent (and abstracted)? wouldn't we want DEL, etc. to be mapped when console is on telnet? -- should sim_time be uint64 instead of double if possible? Better performance or worse? -- Is mag tape status properly mapped between SIMH and RTE? Does ":LI,8" at EOT provide proper response? Does ":LI,8" after intermediate EOF provide proper response? -- Commands taking string parameters have parsing limitations. For instance, filenames cannot have spaces because "get_glyph_nc" only returns up to the first space, e.g., SET CONSOLE LOG= (LOAD filename, etc., has same problem). CLOSED INVESTIGATIONS --------------------- These investigations turned out to be user error or software bugs in the simulated operating system: 1. PROBLEM: RTE-6/VM FMGR is not outputting leader and trailer for the paper tape punch. Instead, punched data has a LF appended. VERSION: 3.6-1 OBSERVATION: Doing ":DU,%FILE,4" to punch a relocatable file produces a punch image without leader and with a LF appended to the end of the binary data. This causes the image to be unreadable by the paper tape reader. CAUSE: FMGR routine FM.CM, which opens the destination LU by creating a type 0 DCB, is not setting the "leader" EOF code for the punch. In fact, FM.CM detects only DVR types >17 to set the code to EOF, and everything else gets a TOF. DVR00 is interpreting the TOF as a call for a LF. It appears that RTE-6 is using the RTE-A version of FM.CM, and A-Series systems do not support paper tape. So no special handling is performed for DVR02. RESOLUTION: This is a bug in RTE-6/VM. Workaround is to create a type 0 file for LU 4 and specify the control subfunction as "LE". This produces trailer but no leader, so a "CN,PTP,LE" is necessary before starting to punch. STATUS: Closed 2006-09-04. 2. PROBLEM: A device without units will not allow examination or alteration of its state. VERSION: 3.8-0 OBSERVATION: "Writing a Simulator for the SIMH System" says in Section 4.1, "sim_device Structure:" units pointer to array of sim_unit structures, or NULL if none. However, if NULL is supplied, the EXAMINE and DEPOSIT commands will not work: sim> ex var Invalid argument sim> dep var 1 Invalid argument CAUSE: The "get_sim_opt" routine exits if the unit pointer is NULL. RESOLUTION: The assumption that a device will have at least one unit is pervasive in the code. Reclassified as a documentation bug. Section 4.1 will be revised to say that the "units" pointer cannot be NULL. STATUS: Closed 2008-09-12. 3. PROBLEM: The sim_close_sock() routine does not appear to clean up completely. VERSION: 3.8-0 OBSERVATION: Detaching a terminal multiplexer socket after a Telnet client connection has been established leaves an open transaction on the client that remains until the client is terminated. Attempting to reattach the simulator to the same port without terminating the client first gives "Bind error 10048" (WSAEADDRINUSE). CAUSE: Unknown. The LISTENING transaction remains after the simulator ends, even though the two line sockets close properly. qcterm can even "connect" to the listening port! on attach: - tmxr_attach calls tmxr_open_master - tmxr_open_master calls sim_master_sock to create master socket - sim_master_sock calls sim_create_sock, bind, sim_setnonblock, and listen - sim_create_sock calls socket (AF_INET, SOCK_STREAM, 0) sim_setnonblock calls ioctlsocket (sock, FIONBIO, &non_block) on detach: - tmxr_detach calls tmxr_close_master - tmxr_close_master calls tmxr_reset_ln and then sim_close_sock - sim_close_sock calls closesocket Everything seems to be proper. It's just that winsock doesn't release the port until qcterm exits too. Doing a "hard" closure doesn't help. RESOLUTION: This is not a bug. QCterm is being started after the ATTACH, so it inherits the socket, just as it inherits the file handles and environment. Everything works fine if QCTerm is started just before the ATTACH. STATUS: Closed 2008-09-12. ——————————————————————————————————————————————————————————————————————————————— xxx. PROBLEM: VERSION: 3.12-0 OBSERVATION: CAUSE: RESOLUTION: None. STATUS: Unreported.