Enter email address here to subscribe to B5500 blog posts...

Sunday, November 20, 2016

Emulator Release 1.04

Nigel and I are pleased to announce that version 1.04 of the retro-B5500 emulator was released on 4 September 2016. All changes have been posted to the repository for our GitHub project. The hosting site has also been updated with this release, and for those of you running your own web server, a zip file of the release can be downloaded from Google Drive.

This is a minor release containing a number of enhancements and corrections for issues we have discovered since version 1.03 was released a little over a year ago.

Enhancements in Release 1.04

This release of the emulator supports the following enhancements.

New Single-Precision Add/Subtract Implementation

The B5500 uses a unified numeric format, which means that it does not have the typical distinction between integer and floating-point numbers that most computer architectures do. Integers are simply values that have been normalized so that their exponent is zero. For exaple, octal 0000000000000001 (the integer representation of 1) and 1141000000000000 (the normalized floating-point representation of 1.0, i.e., octal 1000000000000 × 8-12) are the same value as far as the B5500 numeric operators are concerned.

There is a document informally referred to as "The Flows," which contains a schematic representation of the logic equations for each operator syllable. Alas, we did not have access to this document when initially developing the emulator, and had to rely on its companion, the Processor Training Manual, which is a good, but not-quite-complete narrative guide to The Flows. As a result, the first implementation of single-precision arithmetic was something of a best-guess effort, and as reported previously in this blog, some of my early numeric benchmarks were producing results that had at best one significant digit of agreement with results from a real B5500.

After much frustrating research, that problem turned out to be improper rounding in single-precision Add and Subtract, which are implemented as the same instruction with some small differences in the treatment of signs. I finally fixed the problem empirically by generating results from 64 "interesting" numeric values and comparing the octal results to those from a modern Unisys MCP system, which uses the same numeric word format. That revealed many cases where rounding was being done improperly -- mostly during scaling of the smaller operand to make exponents equal. Fixing those cases allowed the benchmarks to agree with the results from a real B5500.

By the time I got around to implementing the double-precision arithmetic operators about a year later, The Flows had become available on bitsavers.org, and I followed them closely in implementing the double-precision operators. That gave me the idea that at some point I should go back and redo single-precision Add/Subtract with more rigorous attention to implementing them the way The Flows said they worked.

Earlier this year, I had a lengthly and very interesting exchange of correspondence with Reinhard Meyer in Germany, who was contemplating design of a B5500 emulator of his own and perhaps eventually producing an FPGA implementation of the machine. That exchange finally galvanized me to go back and re-implement single-precision Add/Subtract according to The Flows.

Rigorously following The Flows turned out to be considerably more of a challenge than I had originally anticipated. Digital logic tends to work in parallel, with many states changing at each clock pulse. Most of that translates fairly easily to the sequentially-executed code of a traditional programming language, but some of it does not, and you continuously need to be on guard that states set during one clock cycle do not become effective until the start of the next one.

The most frustrating problem that arose during this effort was one where subtracting two numbers of equal value generated a result that was not completely zero. The mantissa would be zero, but the sign or exponent would not. There is explicit logic in The Flows to test for this condition in the J05L block under the secondary control of Q04F/ (see index 1.01.1 page 2 of 2 in the document) and exit the operator early if the sign or exponent do not need to be cleared to zero. That test is based on the logic term W03L, which is defined as "A[39->37] = B[39->37]", meaning the high-order octade of the A-register mantissa (bits 39 through 37) equals the high-order octade of the B-register mantissa. The corresponding narrative in the Processor Training Manual (page 3.17-11) states, "If the 13th octade of the A and B registers do not equal each other (W03L/) it is not possible for the resultant sum of the complement addition to equal all zeros and the operator is terminated."

I implemented the code exactly that way. It didn't work. After staring at that portion of the logic for days, it finally occurred to me that neither the definition of W03L nor the statement in the Training Manual made sense -- it's entirely possible for the two high-order octades to be unequal and still sum to zero -- 7+1 (ignoring the carry), for example. That made me begin to wonder whether "equal" and "not equal" meant what I thought they did. To answer that question, I had to look at the document upon which The Flows are based, the Processor Equation Book, where on page 422.00, I found the term W03L/ to be defined as:

A39F*B39F + A39F/*B39F/ + A38F*B38F + A38F/*B38F/ + A37F*B37F + A37F/*B37F/

This is somewhat simplified from the notation in the Equation Book, which appears to refer to physical circuit elements. For the uninitiated, "*" means logical-AND, "+" means logical-OR, and "/" used as a suffix means logical-NOT. Operator precedence is NOT-AND-OR, highest to lowest. The numbers refer to bits in the registers, with 48 being high-order and 01 being low-order. A suffix of "F" means flip-flop.

That equation clearly does not determine inequality of the high-order A and B octades -- it determines the logical equivalence of the three pairs of bits in the octades and ORs those equivalences together. Logical equivalence is the complement of exclusive-OR. In other words, W03L/ is true if any of the three pairs of bits match. Equivalently, W03L is true if none of the three pairs of bits match. After making that change in the code, results with zero mantissas finally generated words of all zeroes.

After all the hard work to re-implement single-precision Add/Subtract from The Flows, it produced very little improvement over the results of the previous, empirically-corrected implementation. There were a few differences in the way that results are normalized, and a rounding difference if one of the values is octal 0161000000000000 and the other value is one of 0004444444444444, 0005555555555555, 0006666666666666, or 0007777777777777. On that basis, the effort invested in the new implementation was not worth the very slight improvement in results. On the other hand, it was a very interesting experience, and I learned a lot about digital logic and how the B5500 worked at the electronic level.

There is one other significant difference -- the new implementation runs noticeably slower, in terms of emulated clock time, than the prior one. For one heavily numeric benchmark that runs about ten minutes, the new implementation increases the emulated run time by 48 seconds -- a little over 8%.

Card Reader Enhancement

The implementation of the B129 card reader in the emulator allows you to load one or more text files into the reader as if they are card decks. Each line in a text file is treated as an 80-column card image. Thus, in order to read cards, you first must have a text file on your local system to hold the necessary card images.

This has proven to be a little inconvenient. If you have a file of source code you wish to compile, for example, you either need to modify that file and add the necessary B5500 control cards, or create a copy of the file and add the control cards to that.

Starting with this release, the user interface for the card reader now supports the ability to enter card images directly into the reader from your keyboard without creating a text file first. Card images entered this way can be interspersed with card images from text files. This allows you, among other things, to "wrap" existing files with control cards, compiler $-option cards, or anything else you need but don't have (or don't want) in a text file on disk.

The card reader's panel has a new button in the upper right-hand corner labeled KEY IN DECK. This button is disabled unless the reader is in a not-ready state. Clicking the button opens a sub-window that allows you to enter card images directly into the reader's buffer:

While the key-in window is open, the reader's START button is disabled.

The bulk of this window is occupied by a standard text area. You can enter text into this area from your keyboard or copy/paste text from another source. You can edit the text using the normal controls of your operating system. Clicking the Insert button at the bottom of the window appends the contents of the text area to the card reader's buffer and closes the window. Clicking the Cancel button simply closes the window without affecting the reader's buffer. Once text is inserted into the buffer, it cannot be modified or deleted, just as with inserting a text file into the buffer.

There are three white buttons along the bottom of the window with commonly-used control card images. Clicking one of these simply inserts the respective card image into the text area at the current cursor position. From there it can be appended to the reader's buffer by clicking the Insert button.

Miscellaneous Improvements

1. The size of the terminal adapter buffer in B5500DatacomUnit has been reduced from 112 to 56 characters to accommodate the requirements of the R/C interactive editor. Users of the Timesharing MCP (TSMCP) and CANDE will need to update their SYSTEM/DISK file with the new buffer size, e.g.,
2. We have discovered that the emulator now works with Apple Macintosh OS X using Safari versions 8 and above. Nothing has changed in the emulator to support this -- the issue was waiting for Safari to implement the IndexedDB API used by the emulated disk subsystem.

We continue to be unable to get the emulator to run in either Microsoft Windows Explorer or Edge. If anyone has tried the emulator in Opera or any other GUI browser, please let us know how that works. 

3. Despite a statement in the project wiki that the emulator must be loaded over HTTP from a web server, it appears to run just fine when loaded directly from your local file system, e.g., using a URL like this:
The wiki has been corrected.

4. The alternate B5500SyllableDebugger user interface for the emulator has been enhanced with an Execute Single button. This executes the instruction currently in the T register, but differs from the Step button in that it does not advance the C and L instruction counter registers. This makes Execute Single a better choice than Step for testing and debugging a specific operator.

5. The default height of the SPO and line printer windows has been reduced to about a third of the screen height.

6. The tools/B5500DeleteStorageDB.html script can be used to remove the IndexedDB database for an emulated disk subsystem. Previously, this script could only remove the default data base, named B5500DiskUnit. The script now takes a "?db=" query string parameter with the name of the data base to remove.

7. The Algol Glyphs option for the card punch (CPA) has been set to false by default. Some text editors were corrupting the Unicode characters produced in Cold- and Cool-start decks when this option was set to true, making the decks useless for loading under CARD LOAD SELECT.

8. The exponential moving average computations for Delay Delta and Processor Slack in the Processor object have been adjusted slightly.


1. Rounding in Integer Store operators has been corrected to produce a word of all zeroes if the mantissa is zero. Previously, non-zero sign and exponent fields could have been present when mantissa was scaled to zero.

2. BCL translation for alpha-mode (even parity) tape files has been corrected. Previously, the translation was being done twice -- once by the I/O Control Unit and once again by the tape drive. It is now handled entirely within the tape drive.

3. Both EOF and parity error are now reported by the tape units for any attempt to read beyond the end of a tape image.

4. The way that "green-bar" formatting was being done on the line printer was causing a blank line to be inserted every third line when copying text directly from the "paper" area of the printer's window. A different method is now used that does not result in extraneous lines in the copied text.

5. When the emulator was powered on, the browser windows for the individual peripheral devices were being created twice. This behavior was intentional, but dated from very early in the emulator's development when crashes and aborts were a frequent occurrence. The act of opening a window, closing it, and then reopening it served to close any windows left open by a crashed emulator instance. We are long past the need for that now, so the screwy open/close behavior has been removed. As part of this effort, de-registration of event handlers for the various windows has been implemented.

6. After almost five years, we are still finding errors in the transcription of the Mark XVI Algol compiler listing. Most of the errors that have come to light in the past few years have been in comments, but a few months ago we found a serious error in line 06073850 -- a plus sign had been transcribed as a minus. I doubt we are ever going to get all of the errors out of this transcription -- or of any other large transcription like this.

The B5500 Source Code Archive

We are starting to amass a significant amount of source code for the B5500. Most of this has been recovered by transcribing it from listings. Up to this point, we have been including the transcriptions we've done or received from others in the emulator project's repository. Rich Cornwell in North Carolina (US) and Jim Fehlinger in New Jersey (US) have been especially prolific in turning scanned listings into text files.

There are now multiple B5500 emulators, however, either in existence or under development. In addition to Sid McHarg's C++ emulator and this project, Rich Cornwell completed an emulator earlier this year that runs in the SimH framework, and Mark Lloyd in the UK continues to work on his Lazarus/Pascal version.

With multiple emulator projects and multiple sources of recovered source code, it has becoming less and less appropriate for that code to be embedded in a specific project. I have been thinking about this for a while, and a few months ago decided to set up a separate project on GitHub to serve as a common repository for all B5500 emulators:
Rather than set this up under someone's personal account, I've created a GitHub "organization" to be the owner. This will make it easier to share and ultimately transfer responsibility for the archive, and also to create additional repositories in the future to maintain recovered source code for other systems. Initially, Nigel and I are the administrators of this organization and the B5500 archive, but hopefully that can be expanded in the future.

To seed this new repository, I have exported the source code transcriptions, and their history, from the retro-b5500 project and made that the initial contribution to the B5500-software project. In the process, I rearranged the directory structure into something that hopefully will be more maintainable over time. The source code in the retro-b5500 project will probably be deleted at some point down the road.

In a future blog post, I will propose some standards and procedures for maintaining the archive, but will be happy to receive comments and recommendations on this from others. I will also be happy to receive new contributions and will consider pull requests for updates. Each transcription should be accompanied by some text that describes it provenance and who did the transcription. See the README.txt files in the repository for examples of what I'd like to have in this regard.

I would like for all of the transcriptions to be faithful to their original sources, so please include sequence numbers if they are present in the original, and please do not correct spelling in comments, or even bugs in the code. Any original errors can be corrected in separate projects or branches from the transcriptions of the originals.

Monday, August 24, 2015

Emulator Release 1.03 and Browser Disk Space Usage

Nigel and I are pleased to announce that version 1.03 of the retro-B5500 emulator was released on 22 August 2015. All changes have been posted to the repository for our GitHub project. The hosting site has also been updated with this release, and for those of you running your own web server, a zip file of the release can be downloaded from Google Drive.

This is a minor release containing corrections for a few issues we have discovered since version 1.02 was released in June. The most significant correction addresses excessive disk storage usage for emulated B5500 disk units.

Excessive Browser Disk Usage Fixed

The emulator uses an HTML5 API known as IndexedDB to provide persistent storage for B5500 disk devices. IndexedDB is a non-relational (NoSQL) database mechanism. It stores Javascript objects, indexed either by an external key value, or by possibly multiple data items internal to the object being stored. Instead of tables, IndexedDB has "object stores," which serve much the same purpose.

The emulator creates a small IndexedDB database named "retro-B5500-Config" to store system configuration data. It creates one additional IndexedDB database for each emulated disk system created by the configuration interface. Each of these subsystem databases contains a "CONFIG" store for its internal configuration, plus an "EUn" store for each disk Electronics Unit in the subsystem. Within an EU store, each disk sector is represented as an object, indexed by its zero-relative sector number. An SU is modeled simply as the range of sector numbers it represents.

The Problem

One of the puzzling (and quite disappointing) things several of us have noticed about the emulator is the very large amount of physical disk space it uses to store B5500 disk sector data. The amount of physical disk space required for the IndexedDB database is typically at least 30 times the size of the data being stored.

Each browser manages IndexedDB data internally in its own proprietary way, and nether of the two browsers that are known to support the emulator, Mozilla Firefox and Google Chrome, make it easy to see from the outside what's there or how it's stored. Firefox implements IndexedDB on top of SQLite. It is easy to see the EU structures in the SQLite database, but the objects themselves are very opaque, probably because they are compressed. Chrome implements IndexedDB using LevelDB, an open-source database manager developed by Google and based on its BigTable technology. Its internal structures are opaque from the outside, also due to compression.

In the past few months, several of us who have larger disk subsystems have been having increasing problems with Firefox accessing those subsystems. The first symptoms were that B5500 operations would simply grind to a halt in the middle of running ordinary work. The MCP was still active, but one of the Disk File Control Units (DFCU, i.e., DKA or DKB) would be hung, along with one of the I/O Units. A halt/load would bring the system back up, but often the system would lock up again fairly quickly. If you had multiple disk subsystems, deleting one of them would usually bring the system back to normal operation. This behavior was seen only with Firefox, not with Chrome.

After a couple of weekends of very frustrating investigation, I finally discovered that (a) Firefox was aborting a disk I/O due to a "Quota Exceeded" error, and (b) aborts are not reported to the IndexedDB onerror event, but rather to its onabort event, and the emulator was not catching the onabort event. The aborted I/O resulted in that I/O never being reported as complete, so the IO Unit stayed busy, and the MCP considered the I/O to still be in progress. Additional I/Os for that DCHA or EU queued up behind the aborted I/O, and eventually everything in the system went idle waiting for I/Os to complete. Not detecting the onabort event in the disk driver was a design error on my part.

The quota error reports that the emulator's "source" (web site) is using more local disk storage than it is allowed. I have not been able to find out exactly what that storage limit is in Firefox, plus, either the limit or the way it is enforced has been changing over the last few Firefox releases. Based on what a few of us have observed, the limit appears to be somewhere in the range of 500MB to 1GB of disk usage. With a 30X inflation factor, that relates to 30-60MB of B5500 data, which means that just loading the SYSTEM, SYMBOL1, and SYMBOL2 tape images would put you in range of the limit.

Knowing we were hitting a quota error and approximately where that error is triggered was useful, but it did not help in knowing what to do about it. My working assumption was that the method we were using to represent sector data was responsible for the 30X inflation factor, and was starting to think about different representations in order to reduce that factor.

The situation came to a head about two weeks ago when Firefox 40.0 was released. It refused to open most of my disk subsystems. I couldn't even halt/load the MCP in order to dump the files to tape. Fortunately, I had held off upgrading to FF 40 on my main development system until I found out about this problem, so was able to dump its disk subsystem while still on FF 39.

At this point something obviously had to be done about the way the emulator was storing disk sectors, so last weekend I started to build a testbed to evaluate different ways of representing sector data. As reported in more detail in this post on the forum, I used the old B5500ColdLoader script as a basis for my testbed, and decided to start by creating a disk subsystem using the current sector representation to obtain a baseline disk space usage.

To generate that baseline, I simply loaded the entire SYSTEM tape image, which is 12.4MB in size. When I checked the size of the resulting IndexedDB database to determine its inflation factor, I found -- surprise, surprise -- it wasn't inflated at all! In fact, it was only 10MB -- 80% the size of the raw data.

That result made me start looking very carefully at the way the ColdLoader and the emulator's disk driver stored data to IndexedDB. I had thought they were the same, but found there was one of those differences that you wouldn't believe could cause a problem until the evidence pushes the realization in your face.

The short story is that each IO Unit has an internal 16KB buffer it uses to convert between the 6-bit character codes in B5500 memory and the 8-bit ASCII codes used by the device drivers. The buffer is an HTML5 Uint8Array, which is a form of TypedArray object. The IO Unit passes this buffer during calls to the drivers, along with a length that indicates how much of the buffer is valid.

Since each disk sector is modeled as a separate object in IndexedDB, each sector must be stored to IndexedDB separately. Therefore, the disk driver must extract each sector of a multi-sector write from the IO Unit buffer and store it with a separate IndexedDB put() call. It implemented that extract using the subarray() method of Uint8Array:
eu.put(buffer.subarray(bx, bx+240), segAddr);
Alas, the resulting object that gets passed to put() is not a 240-byte Uint8Array, but rather an object that consists of the underlying array plus the starting and ending index values, as if it were something like this:
{data: buffer, start: bx, end: bx+240}
Thus, what got stored in the EU object store for that sector was not 240 bytes as I had assumed, but a copy of the entire 16KB IO Unit buffer, plus the two index values. No wonder we were seeing at least a 30X inflation factor in the data stored.

Firefox obviously does some compression on this object, but the degree of compression depends largely on what is in the IO Unit buffer. That buffer initially contains all zero bytes, and is simply overwritten by the data for each I/O. Thus, while the end of the buffer could be expected still to contain zeroes, the extent to which the front of the buffer had been overwritten by non-zero data, and therefore how much it could be compressed, would depend on the length of previous I/Os.

While storing these inflated sector objects had thus far only caused a problem in Firefox, they had the same effect in Chrome, and the sizes of Chrome's LevelDB databases were comparable to that of Firefox's SQLite databases. Chrome computes its quota threshold differently, however, based on the workstation's total available disk space. Apparently no one running the emulator has yet hit the Chrome quota limit.

The Solution

The solution to this problem is quite simple -- stop dragging that 16KB buffer around and storing it as part of every sector object. I did that by declaring a 240-byte Uint8Array object local to the disk driver, extracting sector data from the IO Unit buffer into that local object, and doing the IndexedDB put() on that local object, thus:
var sectorBuf = new Uint8Array(240);

while (segAddr <= endAddr) {
    for (x=0; x<240; ++x) {
        sectorBuf[x] = buffer[bx++];
    eu.put(sectorBuf, segAddr);
where bx is the current offset into the IO Unit buffer, segAddr is the current disk sector address, endAddr is the ending sector address for the I/O, and x is just a local index variable.

This approach introduces a little extra overhead to copy the bytes of each sector from the IO Unit buffer to the local buffer, but that overhead should be more than offset by the elimination of the 16KB IO Unit buffer in the stored object, the need to compress that buffer, and the extra I/O overhead to read and write an inflated sector object.

The nice thing about this solution is that it can be used with existing disk subsystems. Sector objects already present in the subsystem will be big and fat, but will still work. When a sector is written, it will stored in the new, more space-efficient format. Rewriting a sector will release some space to the underlying database's available pool, but it will not reduce the total amount of disk space used by the subsystem database. To do that, some sort of compaction process needs to take place, such as the vacuum command for SQLite. LevelDB will apparently compact its databases gradually over time automatically.

Experience to date with this solution indicates that my initial testbed experience is holding up. By completely dumping a disk subsystem to tape images, deleting and recreating it (to get an empty subsystem database), and reloading the dump, I am seeing reductions in disk space usage of 30-60X. In Firefox, the physical size of the reloaded databases continues to be about 80% of the size of the tape images used to load the databases. To cite one concrete example, the disk subsystem I use for most of my emulator development and testing went from 1.9GB down to 48MB, a reduction of almost 40X.  The dump tapes used to reload the subsystem totaled 58.7MB.

Even though this solution was easy to implement, works with existing disk subsystems, and adequately resolves the problems we have been having with recent versions of Firefox, I have not entirely given up on the idea of a new representation for sector data. There is a lot of overhead in the IO Unit involved in translating between 6- and 8-bit characters, packing and unpacking words, etc., and it may be that another approach will yield both better space and better processing efficiency.


Since the fix for IndexedDB disk space usage in 1.03 is compatible with existing disk subsystems, there is nothing you need to do in preparation for moving to this release. If you are already having trouble with Firefox quotas, or have large disk subsystems and want to avoid having problems in the future, then you should consider dumping and reloading your disk subsystems. This section describes how to do that.

If you have already upgraded to Firefox 40 and cannot access your disk subsystems at all, then dumping the data is going to be problematic. See the next section for some ideas on things you can try and some background on where IndexedDB data is stored.

Assuming you can halt/load from your disk subsystem, however, then here are the steps to shrink the amount of disk space that subsystem is using.
  1. Dump the B5500 disk data: 
    1. Mount a blank tape in one of your tape drives. Make sure it is write-enabled (it will be by default) and the drive is in REMOTE status. 
    2. On the SPO, enter the following command: "?DUMP TO MYDUMP =/=; END". You may substitute any other tape name for MYDUMP, up to seven characters long.
    3. After the drive rewinds, click LOCAL and UNLOAD on the drive, then indicate you want to save the tape image.
    4. You can either save the page directly in Firefox (make sure you save it as type Text, not HTML), or copy/paste the text of the image to a text editor and save it from there. Make sure your editor is set not to trim trailing spaces from lines in the file or to replace spaces with tabs.
    5. If Library/Maintenance is not finished, mount another blank tape and repeat steps 3 and 4 above as necessary.
  2. Start the emulator, but do not power it on.
  3. Delete and recreate the disk subsystem:
    1. Enter the System Configuration tool by clicking the B5500 logo on the Operator Console panel.
    2. Select the appropriate system configuration, then click the EDIT button next to the Storage name for that configuration.
    3. In the Disk Storage Configuration window that opens, click the yellow DELETE button. Click through the "are you sure you want to do this" prompts. The Disk Storage Configuration window should close.
    4. Back on the System Configuration window, click the NEW button next to the Storage name field. The name of the subsystem just deleted will probably still display in the pull-down list. Enter the name of the disk subsystem you just deleted in the pop-up dialog that displays.
    5. Configure the new disk subsystem as desired in the resulting Disk Storage Configuration window. Click SAVE on that window when finished, then click SAVE on the System Configuration window.
  4. Cold-start the new disk subsystem. See the instructions for doing this in the Getting Started wiki page. You can either use the standard SYSTEM tape image to do this, or the first tape of the dump you just created. In that latter case, you will need to modify the cold-start deck to use the tape name of the dump.
  5. Once the system has halt/loaded, enter on the SPO, "?LOAD FROM MYDUMP =/=; END". Library/Maintenance will refuse to overwrite a few system files, such as the running MCP. Do not forget to CI the Intrinsics file once it has been reloaded.
This may read like a lot of work, but it usually goes quickly. You should repeat this process for each of your disk subsystems.

Recovering from Quota Exceeded Problems

If Firefox considers your disk storage already to have exceeded the quota limit, then you may not be able to run the emulator in order to dump the data. There are a couple of things you can try, however.
  • If you have multiple disk subsystems, try moving all but one of them out of the folder where Firefox maintains IndexedDB databases. That may reduce the disk space usage below the quota threshold, and allow you to halt/load from the remaining disk subsystem and dump it to tape. You may then be able to swap in the remaining disk subsystems one at a time and dump them as well.
  • If some disk subsystems are too large for the first suggestion to work, you can try downgrading temporarily to an earlier version of Firefox, and see if you can halt/load and dump the subsystem using that version. You can download older Firefox releases from https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/.
On Windows 7, Firefox stores its IndexedDB data in the following location:
\Users\<user>\AppData\Roaming\Mozilla\Firefox\Profiles\<profile ID>\storage\default\<source>\idb\
where <user> is your Windows user name, <profile ID> is the profile name Firefox assigns (e.g., 0qus6gtz.default), and source is the host name of the web site from which you have loaded the emulator, e.g.,
Within the idb\ folder, each IndexedDB database is represented by a directory and an SQLite file. The names of these files are derived from the disk subsystem name as follows:

  • The first part of the name is a 10-digit number, probably derived from a numeric hash of the name.
  • The second part of the name is the disk subsystem name, but with the letters rearranged. This part consists of the characters from the first half of the name, with the remaining characters inserted between them in reverse order. For example, B5500DiskUnit is converted to 1182897429Bt5i5n0U0kDsi.
  • The directory name has the extension ".files" and the SQLite file has the extension ".sqlite".
If the database is presently open and being updated, there may be additional SQLite files with the same name but different extensions. 

I have found that you can move the file and directory for a database into and out of the idb\ folder, and Firefox will adapt to that, but it is best to do this when Firefox is completely shut down.

For Ubuntu Linux, the IndexedDB data is stored in this path under your home directory. Most Linux distributions will probably be similar:
~/.mozilla/firefox/<profile ID>/storage/default/<source>/idb/
For Apple Macintosh OS X, the IndexedDB data is stored in this path under your home directory:
~/Library/Application Support/Firefox/Profiles/<profile ID>/storage/default/<source>/idb/
Prior to Firefox 38, IndexedDB data was stored in the .../storage/persistent/ folder instead of .../storage/default/ for all host systems, and the directory for the database did not have the ".files" extension.

Other Corrections in Release 1.03

In addition to the disk space usage fix described above, this release has the following:

  1. Added onabort traps in B5500DiskUnit to catch QuotaExceeded errors. These are reported to the MCP as unit not-ready conditions, which will cause an error message to be printed on the SPO.
  2. Modified the delay-deviation adjustment mechanism in B5500SetCallback to avoid oscillating between positive and negative cumulative deviations. This should improve the responsiveness of the emulator's internal timing and multi-threading.
  3. Corrected tape reel angular motion in B5500MagTapeDrive, especially during reverse tape movement.
  4. Fixed a bug with reporting memory parity error during tape I/O (should that error ever occur, which at present it won't, as the emulator does not generate memory parity errors).
  5. Reset the Algol Glyphs option for card punch CPA in the default system configuration template. Newly-created configurations will no longer have this option set by default.
  6. Fixed tools/B5500LibMaintDecoder to examine an entire .bcd tape image file instead of just the first 64KB.
  7. Added USE SAVEPBT to the default cold-start options in tools/COLDSTART-XIII.card. This will cause printer-backup tapes to be marked as saved when they are released and not printed automatically.
  8. Eliminated the extraneous "schema update successful" alert when altering a disk subsystem configuration. This means there is one less dialog box you must click through when changing that configuration.
  9. Commited minor corrections supplied by Richard Fehlinger to source/B65ESPOL/SOURCE.alg_m.