4

Note: I hope this question is on topic. I'm not sure where else to put it.

There are several tutorials available online for writing emulators/simulators. Unfortunately they all seem to focus on microprocessors, often with the intention of playing video games. The problem is that these guides are not too useful if you are interested in emulating/simulating computers from before the '70s.

In particular, there is never any discussion about punched cards (reading and writing), paper or magnetic tape, or line printers. (I'm not at all criticizing the tutorials for this; the omission is entirely sensible.) The core functionality of early computers can be emulated/simulated without too much effort, but any large, interesting program is going to have some sort of interface. The manuals for the devices can't tell you how best to reconcile the differences between modern and old IO conventions. Should card decks be stored as binary files with the bit patterns corresponding to actual punched-card encoding? Or should they simply be text files whose characters get converted just before being processed? What if the machine supports an extended character set?

Examples of computers that aren't too complicated in essence but have troubling IO conventions are the IBM 7090 and the LGP-30.

Are there any good resources for dealing with early computer IO?

9
  • 1
    It is on-topic ... kind of, as I would read it about the need for information about I/O. Having said that, I do not think you will find a lot of easy to swallow tutorials. Especially since the underlaying principles are quite easy and well documented within the manuals of such peripherals
    – Raffzahn
    Dec 27 '20 at 12:03
  • 1
    You could browse the source of SIMH, which I did in the past. Also 'A simulator for digital circuits' (mitpress.mit.edu/sites/default/files/sicp/full-text/book/…) of 'Structure and Interpretation of Computer Programs" might help you learn the fundamentals of hardware simulation (off the top of my head, there might be better books YMMV)
    – chthon
    Dec 27 '20 at 12:18
  • 1
    The convention for storing media seems to be of practical importance but not of compelling interest. Since you'll be writing the emulated device, you can use whatever format seems useful. For cards used primarily as input, for example, you'll need a way to prepare that input, and that will surely help your design decision. Dec 27 '20 at 14:11
  • 1
    Unfortunately, there seems to be no convenient way to represent overprinting in line printer output -- sometimes used to represent missing characters by combining existing ones, or to print grayscale images -- amenable for adequate display in modern browsers.
    – Leo B.
    Dec 28 '20 at 19:26
  • 1
    On the other hand, many characters previously rendered as composites by overprinting are now available as single characters. An intelligent line-reconstruction algorithm should be able to replace < backspace _ (or the equivalent with line-printer overprinting) by a single . This is what compiler lexers had to do for input streams. Dec 28 '20 at 20:21
11

You can have a look at how simh, which emulates quite a few computer systems that had punch cards, paper tape, magnetic tape, harddisks, floppy disks, printer and terminals, handle it.

Basically most kind of storage mediums (including paper tape) are mapped to a file. The printer is also mapped to file. Terminals are mapped to some kind of interface you can connect a terminal emulator like xterm to, for example via a telnet server.

Conventions as to how to map words that are not multiples of 8 bits, different endian, and different character sets, are mostly ad-hoc.

For a pure storage medium, it doesn't really matter (though you need conversion programs to create copies from real media). For different charsets, external programs like iconv are useful.

5

Not too sure about resources, actually. But, I can walk you through the logic I used when I wrote an (unpublished) emulator for BESK, a machine that had paper tape for input, either in "5-bit teletype code" mode or "4-bit binary number" (using one channel as a "there's data" indicator) and for output had a printer (well, an electric typewriter) or a paper tape punch. It also had a built-in "plot screen" that I guess technically counts s an output device.

What I did for that was to "encode" the input as the 5-bit teletype/baudot code, left-shifted 3 bits (or "multiplied by 8), to mostly make it easily readable. It did mean I ended up with some non-displayable characters (an "all-bits set" ends up as DEL, and a "no bits set" ends up as a NUL) and it is probably possible to find other encodings that are less messy while still making things easily readable.

The other option I was entertaining was simply to use the lower 5 bits to encode the data, but in the end I went for the slightly more complicated scheme. However, I really canät tell you why, at this point, this was well over a decade ago.

5

Peter Onion's Elliott 803 emulator tries to replicate the experience of using an 803 in a 3D, almost VR, setting. Virtual paper tapes are used to load programs and data.

Doug W. Jones's Punched Cards pages have more on how punched cards were used than almost anywhere else. The simh emulator uses Doug's punched card library for managing card inputs for multiple machines.

There are a lot of aspects of old media that you can't or might not want to emulate: the faint aroma of light machine oil and slightly warm motors around teletypes, card readers and paper punches; the heft of a box of punched cards or even the “wieldiness” of a single 9-track spool; the constant air-conditioning whine in the computer room almost drowning out the fan noise from a tape loader vacuum or the spin-up of a big disk pack; the surprising sharpness of card or paper tape chad bin (leading to the urban myth of the punch girl's wedding party ending up in the eye hospital when someone threw chad instead of confetti); the staccato start-stop of the big tape drives on a data processing run; the machine-gunning of a big line printer; the incredible patience required to deal with real (and slow) old media … Later media really only provided small sounds, usually warnings: the distinctive seek-read-fail-retry clunking from a floppy drive that came before a Bdos Err On A, or the much later Iomega Click of Death

2
  • 2
    "the incredible patience required to deal with real (and slow) old media". The media themselves were not what slowed things down. I remember watching a punched card reader consume a deck at a rate comparable to a banknote counter. I was also given a guided tour of the machine room when my tape was read. Long lengths were sucked into chambers on each side, and then the 9-track read my file in a fraction of a second, when the operator loaded the tape half an hour after I submitted my batch job :)
    – Badger
    Dec 29 '20 at 1:54
  • 2
    even the fastest card readers were slower than dialup, and "high speed" paper tape readers were around 300 cps. But the CPUs were slower than anything we can imagine now
    – scruss
    Dec 29 '20 at 2:55
2

Speaking of punched cards, there are several conventions used to encode arbitrary combinations of punches, usually akin to Base64, so that 80 columns are encoded into 160 printable ASCII characters. Thus, if a line is no more than 80 characters long, it represents a text card, converted into the appropriate encoding, otherwise if it is exactly 160 characters long and consists of the Base64 ASCII subset, it represents a binary image, each two characters encoding a column, the first — rows 9-4, the second — rows 3-12.

For my simulator, I use Unicode Braille which is less compact but it provides a passable visual representation of the cards; for example, below is a punched form of an object module. The quality depends on the font, though: in my Linux terminal window the columns are properly aligned, not so much in the browser.

enter image description here

⠀⠆⢠⠀⠀⢠⠀⡤⠤⡀⠀⠀⡠⠤⢄⠀⢀⠤⢄⠀⢠⠤⠤⢄⠀⠤⢤⠤⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠌⠄
⡀⡃⠀⢣⢠⠃⠀⡇⠀⠈⡆⠀⠑⠒⢢⠀⡇⢀⡀⡇⢸⠤⢤⠜⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣺⡃
⠂⠀⠀⠀⠃⠀⠀⠓⠒⠊⠀⠈⠒⠒⠊⠀⠈⠒⠊⠂⠘⠀⠀⠑⠀⠀⠘⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣥⡄

⠈⡀⠌⠄⠀⠀⠀⠀⠁⠀⠃⠀⠀⠀⠀⠀⠀⠃⠀⠁⠀⠘⠀⠘⠀⠀⠀⠀⠀⢁⢉⢪⠀⠠⣾⠡⢽⠂⠌⠄
⡀⡅⣺⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠂⠂⠂⠀⠐⢠⢐⢡⠀⣺⡃
⠂⠁⣥⡄⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⢈⢨⣰⢨⡀⣥⡄

⠐⡀⠬⡀⣖⡃⢠⡢⢽⠁⠀⠜⡟⠬⡗⢀⢰⣷⡢⠁⡅⠋⣆⣞⢨⠀⢀⠀⡅⠀⠀⠀⠀⢀⠀⢀⠀⠀⠌⠄
⡀⡆⡊⠀⠙⠀⢘⢐⢡⢈⠀⡊⡄⡊⡄⠀⠈⠋⢎⠁⠀⠀⠱⠙⠀⠀⠀⠐⠀⡄⡁⠀⠀⠀⠀⠠⠀⠀⣺⡃
⠂⡃⡂⡂⠀⠀⠀⢰⢨⡀⠀⡆⣅⡆⣅⢐⠀⠀⠀⠀⠀⡂⠀⠀⢸⢀⢸⠀⠀⡅⠀⡅⠀⠀⠀⢀⠀⠀⣥⡄

⠘⡊⠌⠄⠠⠀⠀⠅⠀⠆⠀⣺⠄⡢⠄⢐⠥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠌⠄
⡀⡃⣺⡃⠀⡄⠀⢠⠀⢠⠀⠐⡂⢸⡂⠀⢗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣺⡃
⠂⡆⣥⡄⢀⡄⠀⣠⠀⣠⠀⣙⠂⣡⠂⢈⡓⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣥⡄


2

I don't know of any online resources that will teach you how to handle emulation of I/O devices, aside from looking at the source code of emulators that do this. There aren't any hard and fast rules about how an emulated I/O device should be mapped to 'real' I/O -- just do it however it's convenient for you and your users. Some mappings are natural, such as using a TCP network connection to simulate a serial port, or a file on disk to simulate a disk drive or a paper tape. Some mappings will require you to develop your own convention or reuse an already established one, such as the format SIMH uses for magnetic tape images.

Once you are past the mapping/file format problem (which is often the easy part), generally there are two basic approaches for implementation. First, you can treat I/O as incidental to your CPU emulation, which means it doesn't need to be an accurate emulation itself, it only needs to work well enough to meet the needs of the CPU emulator. Emulated I/O devices of this type will often take shortcuts such as assuming that I/O operations will execute instantaneously. Such shortcuts are convenient because your I/O can be triggered by having your CPU emulator recognize (and act on) I/O instructions. If I/O instructions complete as soon as they are executed, you don't need to worry about keeping track of the status of slower operations that might take many cycles to complete, which makes things simpler.

The second approach is to attempt a more accurate emulation of the I/O device, which may include simulating delays waiting for I/O operations to complete. For example you might delay writing a sector to disk for a few tens or hundreds of milliseconds for no reason except that real hardware would have taken that long. This approach is a bit more complicated because now you have essentially two emulators running in parallel -- one emulating the CPU, and another emulating the I/O device -- which means you either need a way to pass messages between the two emulators (if they are running independently), or you need a way to 'time-slice' the emulators so they run in lockstep (if they are sharing a common clock).

During development, it may work well to start with the first approach just to get something basically functional, then switch to the second approach as your needs get more sophisticated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.