Retrochallenge 2016/10:
Ironic Computer Space Simulator (ICSS)

Episode 12: Wrap-Up

October is over and so is Retrochallenge 2016/10.
Time to wrap up the project, to draw any conclusions, and to see what we may have learned from it.

Computer Space and Ironic Computer Space Simulator for the PDP-1 (2016)

Computer Space — a space age family portrait (edited image, N.L. 2016).
(Sources: DEC PDP-1 during restoration, here imagined to be running ICSS: the CHM PDP-1 Restoration Team, 2005;
Computer Space: Dennis Scimeca via The Daily Dot; Girl from original Computer Space flyer art via pinrepair.com.)

Let's wrap this project up. First of all, we succeeded. The program worked out even better than we dared to hope. And we may flatter ourselves to have been October's most productive PDP-1 programmer. Big deal, since we were, at all odds, the only active one.

Seriously, I'm content with the result. Especially, since this isn't only my first complete program for the PDP-1, it's also my first assembler program since when the 6502/6510 wasn't retro. My knowledge of the PDP-1 as a programming platform originates entirely from digging around in Spacewar! code and a few other programming resources that have survived the course of time and are now available again thanks to institutions like the Computer History Museum and bitsavers.org. — First, I was just interested in digigging up some versions of the program that seemed to be lost, then, I found it interesting to have a look at how things were approached for the very first time. Also, we've have a unique chance of peeking over the shoulders of such ingenious programmers as Steve Russell, who had previously made LISP a real programming language, Dan Edwards and his JIT solution, or Peter Samson, who may be dubbed the father of all hackers, not only for his TMRC Dictionary (first edition 1959), which eventually became the base for the Jargon File. — Provided, I had a good start thanks to these outstanding examples.

Expectations

From what I already knew of the PDP-1, I started with some anticipations into the project:

As it Was — Things to Write Home About

  • The overall experience was great. The directness in programming while owning the entire machine is outstanding. Everything being based on absolute addresses (no relative offsets and so on) adds to it. "Riding the bare machine" is a cosy and centered state of mind. (It's long since I've been such annoyed by some update popup notices by new-fangled software than while being on this project. So, please, UX, …)

    In fact, the experience was that pleasing that I realized at some point, I had entirely given up using macros (but "random"). Stepping up to any higher levels turned out to be more of an irritation than a convenience.

    Another cause for the generally rather direct approaches, I chose, was found in the very subject, simulating a 74xx-logic device in software. As the example device consists of directly wired gates, there was no real use case for indirect approaches, pointers, or any object oriented solutions. Some values are mangled by some routines, some of them serve the input for others, and so on. Just the same, the assembler was for me all about symbolic labels and named locations as provided by assembler variables.

  • While I did have an eye on the runtime very early on, taking care of any single instruction cycle, this proved of no greater importance while advancing in the project. As illustrated by a quite stable frame rate of about 60 frames per second!

  • Some of this is owed to the specific instruction set of the machine. No penalty whatsoever for any instruction, aside the extra cycle for any memory access. Especially the variable shift and rotate instructions poved to be very versatile. (Unlike with many other machine, there's no difference for a shift by 9 bit positions as compared to a shift by a single one.)

  • The speed gained from this is quite important for the aesthetics of the resulting game, as the granularity of any motions on the display is clearly documented by the CRT's long sustain. The aesthetics of this time preserving display technology (its a 3D display, X, Y, and delta t!) posed also some challenges on the algorithmic level, like smoothing any paths of the onscreen objects.

  • dacs and daps and other rather homonymous mnemonics didn't pose any challenges. In fact, I erred about three times. Speaking of errors, the lack of debugging tools wasn't much of a hassle. Most of the errors (typos) were identified by the assembler, and a quick glance at the code revealed the culprit almoust every time. On the other hand, this wouldn't have been possible without modern on-screen editing tools and frequent retries. I still can't imagine how this would have worked out with offline repunchs only.

    The single time, I was in need of any debugging tools, was the incident with the static unit offsets for the character outline compiler. While this proved to be not related to the compiler code, still, I probably wouldn't have found out about it without any facility to inspect the object code generated by the routine in memory.

  • By the way, Im still wondering, how difficult could this be, really?

    octset calculator to octal mode
    4004001 << 8 (256) one screen location
    ××times
    55offset 5
    =2400screen offset (×1)
    ++add
    24002400same
    =5000sum (×2)
    =7400again (×3)
    =12000again (×4)

    "Calculators for Dummies" proudly presented by mass:werk.

    However…

  • Speaking of dacs and daps, symbol names being limited to up to 3 characters only (and just a single name space for op-codes and asigned symbols and labels) proved to be a rather unsuspected restriction. Some naming conventions help, but become confusing on the other hand, when followed too strictly. (E.g. prefixing anything related to a longer routine by the same two characters doesn't help in memorization. And, if there are also some related opcodes, you may run out of meaningful permuations soon.)

  • As for self modifying code, this feels totally natural with regard to the machine and its instruction set. There's no irritation at all. Yes, we could do without it (with some severe penalties in runtime), as illustrated below. We could step up to even higher and higher levels of abstraction, even building a basic OS and a simple programming language from simple macros. (Mind that there are some common macros allready providing basic building blocks.) But there's not much meaning in this on a bare machine of 4K of memory. Really.

  • / PDP-1 macros to emulate a cpu stack (nl, 2016)
    
    / init the stack pointer
    define	stkinit
    	lac (777700		/ stack grows up towards 0777777
    	dac \tos		/ top of stack
    	terminate
    
    / push a return address and continue at address A
    /  18 cycles (90 microseconds)
    define	jpsr A
    	dac \act		/ backup ac
    	lap			/ transfer contents of program counter (pc) into ac
    	dac i \tos		/ store it (indirect) as return address
    	idx i \tos		/ increment it to point to next memory location
    	idx \tos		/ increment tos
    	law A			/ load target address (absolute)
    	dac \jpv		/ set it up in a temporary jump vector
    	lac \act		/ restore AC
    	jmp i \jpv		/ jump (indirect) to subroutine
    	terminate
    
    / pull a return address and continue there
    /  16 cyles (80 microseconds)
    define	return
    	dac \act		/ backup ac
    	law i 1			/ decrement tos (tos = -1 + tos)
    	add \tos
    	dac \tos
    	lac i \tos		/ fetch (indirect) the return address
    	dac \jpv		/ set up a jump vector
    	lac \act		/ restore ac
    	jmp i \jpv		/ jump (indirect) to return
    	terminate
    
    
    / usage example (neither economical nor reasonable)
    
    ex1,	stkinit
    	lac val
    	jpsr by2
    	dac res
    	hlt
    
    by2,	sal 1s
    	return
    
    val,	3
    res,	0
    

    Heck, we could make this even relocatable code:

    / jump to subroutine, relocatable code, forward only
    define	rjsf A
    	B=A-R			/ offset to insertion point
    	dac \act		/ backup ac
    	lap			/ transfer contents of program counter (pc) into ac
    	dac i \tos		/ store it (indirect)
    	law B			/ compute offset + current loc
    	add i \tos
    	dac \jpv		/ store it as jump vector
    	idx i \tos		/ increment contents at tos, now return address
    	idx \tos		/ increment tos
    	lac \act		/ restore AC
    	jmp i \jpv		/ jump (indirect) to subroutine
    	terminate
    
    / backwards ...
    define	rjsb A
    	B=R-A
    	dac \act
    	lap
    	dac i \tos
    	law i B			/ load (absolute) as a negative value
    	add i \tos
    	dac \jpv
    	idx i \tos
    	idx \tos
    	lac \act
    	jmp i \jpv
    	terminate
    

    But by this, we would lose al the fun. Nothing compares to the directness conveyed by the architecture of the PDP-1. Even such simple stack-oriented instructions as jsr, rts, pha, or pla (6502) alienate you somewhat from a machine. Make it 48-bit words (and, maybe, IO a second accumulator) and the PDP-1 is a programmer's dream machine.

  • Memory restrictions weren't of any concern. Even with runtime generated object code of the size of the program itself we still have ample space left in the 4K 18-bit memory. That is, at the very end I was thinking of a message to be rendered at the bottom of the screen during attract mode and added the original character interpreter ("codeword display") found in the assorted subroutines from 1961. At this time, I actually ran out of memory. So, we're doing great without this message, even more, as there isn't any in the original Computer Space.

    Results

    In the end, all worked out gracefully and beautifully. Some approaches were already lined out by Spacewar! and its code, and I don't know how I would have done without knowledge of it. But there's no way of finding out, because I'm already heavily contaminated. So, I'm resigned to gratefulness.

    Did I mention the fantastic runtime speed of ~ 60 FPS already? — A testament to the realtime capabilities of the PDP-1. Not that puny, this little machine…

    *****

    If we're allowed to rephrase Elon Musk's argument of the chance of us not living in a computer simulation being one in billions, provided the progress of visual representation and computing powers in video games from Pong to now and its extra­polation into the future, we may put it this way:

    Considering the decline in video game graphics and the computing power required in just a single decade, from Spacewar! to Pong, and extrapolating this into the future, we may heavily doubt that there will be electricity at all, 40 years from now.

    *****

    The source code can be downloaded from the related links section of the emulation page and is public domain as long as a note regarding the original author (me) and the date of the program (2016, as opposed to 1962) are preserved.

    Live

    Ironic Computer Space Simulator for the PDP-1 (2016)

    The Ironic Computer Space Simulator running on the emulated PDP-1.

    Experience the program live, running in an in-browser emulation of the DEC PDP-1 and its Type 30 CRT display:

    www.masswerk.at/icss/.

    Usage note: Chrome may not be able to keep up with the frame rate of the emulated program and may lag and skip frames. Please try Safari (on Mac) or Firefox.

    Hopes & Outlook

    Ironic Computer Space Simulator for the PDP-1, edited image.

    Are we allowed to dream? (edited image, N.L. 2016).
    (Source: DEC PDP-1 at the CHM, the PDP-1 Restoration Team, 2013.)

    If dreams come true and there's also some footage of it thanks to modern dream capturing technologies, as digital video provides, we'll return on the purpose. Otherwise …

    Update:

    Ironic Computer Space Simulator on the DEC PDP-1 at the CHM, Dec. 2016 (youtube.com)

     

     — finis — 

    … oh, we have another one

     

    Next:   Addendum: All New Pyrotechnics

    Previous:   Episode 11: It Lives!

    Back to the index.

    — This series is part of Retrochallenge 2016/10. —