This is Paul Kimpel with another guest post on Tom's 205 and 220 blog. Version 1.01 consists of bug fixes, internal enhancements, and a few new features that are externally visible. This post will describe those changes.
New Features
Power-Off Behavior
The thing that everyone who uses the retro-205 emulator needs to know about this release is that the way you "power off" and shut down the emulator has changed. Previously, a single click of the red OFF button on the Supervisory Panel would terminate the emulator and close all of its windows, leaving only the original browser window with the home page open on your screen.
Now, the OFF button requires a double-click to shut down the emulator. If you hover over the button with your cursor, a tool-tip will pop up to remind you. This behavior has been adopted from the retro-220 emulator, where the power-off and system-clear buttons are close together. I was frequently clicking power-off when I intended to click the clear button, so added the double-click as a safety measure. It seems reasonable to make this behavior consistent between the two emulators.
Memory Dump Generation
The emulator now supports a memory-dump capability. On the Supervisory Panel, below the D register, is a section labeled TEST SYSTEM. The controls in this section have been non-functional in the emulator, as they affected the 205 electronics at a level below which the emulator operates.
Supervisory Panel TEST SYSTEM section |
Now, however, clicking the SINGLE PULSE button in the upper-right corner of this section will cause the emulator to open a sub-window and format the current processor state and memory contents to that window. You can generate this dump at any time, even while the emulator is running a program. It will show an instantaneous snapshot of the system state at that point in time.
SINGLE-PULSE Button Memory Dump |
From this window, you can copy, save, or print the dump using the standard facilities in your browser for doing so. You can click the button multiple times to generate multiple dumps, each in its own window. When you are finished with a dump, simply close its window.
Apple Safari Pop-up Restrictions
This next item could be qualified as a bug fix, but it's really a new feature. The emulator had been operating quite well in the three major modern workstation browsers -- Google Chrome, Mozilla Firefox, and Apple Safari. I recently updated my MacBook Air to macOS 10.13 (High Sierra), and with that update came Safari 11.0.
Trying to run the retro-220 emulator in Safari after this update resulted in the emulator crashing after opening its first pop-up window. I quickly discovered that the retro-b5500 and retro-205 emulators suffered the same problem. I had Safari configured to allow pop-ups, so what gives?
Some research revealed that this new version of Safari places additional restrictions on pop-up windows. Specifically, it would always allow the first pop-up, but if subsequent pop-ups were opened before some amount of time had passed, Safari would inhibit the pop-up. Reports varied on the amount of time that had to elapse between opens, ranging upward from 500ms.
The emulator opens pop-ups for the Supervisory Panel, Control Console, and each of its peripheral devices. All of these elements are implemented as Javascript objects, and as part of their instantiation, each one opens, sizes, and positions its own pop-up window. Trying to insert appropriate delays in the initialization process that instantiates these objects was going to be difficult, so I decided instead to centralize the mechanism for opening pop-ups.
Now, each object calls a common "open pop-up" function in the D205Util.js module, passing parameters necessary to open and configure the window. In addition, each object passes a reference to its "onload" event handler that should be called once the browser opens the window and loads its initial content. These parameters are bundled into a data structure, and that structure is inserted into a queue of pop-up open requests. If the queue was previously empty, the open function calls another function to dequeue and process the first (and in this case, only) entry in the queue. If the queue was not previously empty, then processing of the queue is known to be on-going, and the open function simply exits.
The dequeue function plucks the first entry from the queue and uses the parameter values from the entry to perform a Javascript window open call. If that call fails (i.e., returns a null result), the dequeue function reinserts the failed entry back into the head of the queue, increments a timeout value, and using that updated timeout value, schedules itself for later execution using the Javascript setTimeout() function. When the timeout expires and calls the dequeue function, that function again tries to process the first entry in the queue. This process repeats, incrementing the timeout value at each iteration, until the window open is successful.
Once the dequeue function obtains a successful window-open result, it attaches the original caller's onload event handler to the window. After the browser finishes loading the window, it will call this handler, which will complete the initialization of the console or peripheral device object. Finally, and unless the queue is now empty, the dequeue function reschedules itself using the current timeout period to process the next entry in the queue.
This new mechanism works extremely well. It automatically adjusts the delay between opens based on the individual browser's behavior. The initial timeout value is 500ms and increments by 250ms on each iteration of a failed open. My tests indicate that Safari 11.0 starts making nice when the timeout reaches 1000ms. Chrome and Firefox both cruise through pop-up opens, because their open attempts do not fail; thus nothing ever gets queued, so the opens proceed without any delay.
Bug Fixes
The following problems have been corrected in the emulator:
- Floating-point addition/subtraction was producing the wrong result if the mantissa of either operand was zero. Thanks to Tom Sawyer for finding and reporting this problem.
- During floating-point divide, the quotient mantissa was not being normalized properly.
- If a magnetic tape operation was initiated against a not-ready unit, the Processor's internal performance throttling mechanism could become corrupted, causing the emulator to run erratically.
- The Designated Unit lamps on Cardatron devices were not always being illuminated properly.
- Changes to the Format Select control on Cardatron input devices (card readers), an emulator feature that allows the band-select column on cards to be overridden, were not being detected properly. This usually rendered that control non-functional.
- Format-Lockout for Cardatron input devices was not working when there was a simulated 8-punch in the band selection column of the card. See the Cardatron wiki page for details on how simulated 8-punch coding is implemented in this emulator.
- Skip-to-channel carriage control on Cardatron printer devices did not always work properly, depending on the carriage control being applied on the next write to the device.
- Several 205 devices display output from the system in windows or frames, and allow you to save or print the data using standard browser controls. The common document used for these windows and frames contained extraneous white-space, which resulted in blank lines before and after the actual output. This extraneous white-space has been eliminated.
Internal Enhancements
Every release contains a number of minor tweaks and optimizations to improve the performance, reliability, or maintainability of the emulator. Sometimes there are new Javascript or DOM features that are mature enough to replace custom coding in the emulator that was doing the same or a similar thing. Many of these changes are too minor or obscure to mention, but all are visible in the source file "deltas" available on the project's repository site.
The following summarizes the most important of these internal enhancements for version 1.01:
- Binding an object context to a function is a common feature of Javascript object-oriented programming. The traditional way of doing this has been to wrap the subject function with another function that captures the context in a closure and then calls the subject function with the Function.apply() method. Recent versions of Javascript can now do this internally using the Function.bind() method. The emulator's custom bindMethod() utility functions have been replaced with this intrinsic capability.
- A common operation in web programming is to manipulate the list of CSS class names in a DOM element's className property. Traditionally this has been done using simple regular expressions, but the modern DOM treats the className property as a classList object, which has intrinsic methods to add, remove, and test for the presence of specific class names. These classList methods are now used in the emulator.
- Data transfers between memory and card devices are controlled by format band programming in the Cardatron. Because of this, the Cardatron controls how much data is transferred. Thus it must signal the Processor when the transfer is complete so that the Processor can terminate that I/O instruction and continue execution. The way this signal was being passed to the Processor during card-read operations was not particularly reliable, and has been improved.
- The setCallback() function used to manage asynchronous functions in the emulator seems to be forever undergoing refinement. Some additional tuning changes were made in this release.