NOW SpinRite 6.1 – Fast and useful for spinning and solid state mass storage!
SBC6120 PDP-8SBC6120 PDP-8
“Lights Out” for the SBC6120/FP6120

A front panel puzzle toy for Bob Armstrong's beautiful PDP-8 recreation.

You may download this MP4 video for local playback with this link: "Deep Thought Show & Tell"
LightsOut Source Code

The top half (low memory) puzzle interaction portion of this program's source code should be largely understandable, and the synthesis of an XOR through “carryless addition” is interesting. However, the puzzle setup code beginning at 0200 is rather dense and may be difficult to reverse engineer without the aid of clear descriptions of the algorithms used. Though the code is clearly commented, it wasn't clear how much real interest there would be in understanding the algorithms, so they have not been documented in great detail.

Since most SBC6120/FP6120 owner interest will likely be in equipping systems with this puzzle, you can skip the source and jump down to the "Installing LightsOut into your SCB6120/FP6120" section...

PDP-8 / SBC6120/FP6120 “LightsOut” Source Code

/ "Lights Out" - A simple switch-register puzzle to turn OUT all of the lights
/ During puzzle play, each switch-register switch *changes* the illumination of
/ exactly two lights and each light is changed by *exactly* two of the switches.
/   Operation:  1. With the program loaded, start at location 0026 or 0200.
/                  (0026 is the starting location required by the boot loader.)
/               2. Set display knob to anything other than MD (memory data).
/                  (This is required for software to control the data lights.)
/               3. Move any switch-register switch to begin new puzzle.
/                  (Upon moving any switch, the randomization stops.)
/               4. Now find the combination that turns ALL lights OFF.
/               5. If you give up and/or are stumped, press the EXAMine switch.
/               6. To begin another puzzle, press the CLEAR switch to start
/                  randomizing then move any data switch to begin a new puzzle.
/     Hint #1:  If you want to give yourself only a hint, cover up some of the
/               display lights with one hand when you press EXAMine to see the
/               correct answer. Then set those switches as shown, leaving them
/               undisturbed as you solve for the positions of the others.
/     Hint #2:  Try making a chart of which lights are controlled by each switch.
/  Too Simple?  The value at location 0060 (Difficulty) specifies the number of
/               lights that are controlled by each switch. '1' is trivial to
/               solve ... but '6' will extinguish *YOUR* lights permanently!
/               (And difficulty level '11' (octal 13) is simple to solve in
/               a very different way if you have a pencil and paper to make
/               a chart of which ONE light is NOT changed by each switch.)
/  Final Note:  At "difficulty" level '2', there are *two* (very different)
/               solutions to each puzzle. So don't be alarmed if the solution
/               you achieve is different from what the EXAM switch shows.
/ Requirements: The program will run in 4K and needs no EAE or other add-on.
/     Have fun with the front panel of your lovely classic PDP-8 computer!
/                 Contemporary PDP-8 FREEWARE written and placed
/                  into the PUBLIC DOMAIN by Steve Gibson, 2009

/ Implementation notes - The code below uses two SBC6120/FP6120-specific features
/ which will not work on a regular PDP-8:  As explained below, it takes over the
/ display of the data lights.  This is done because the 30hz sampling of the AC
/ sometimes catches the AC at a bad time causing the display to flicker annoyingly.
/ This would NOT be a problem on a real PDP-8, since its AC display is not being
/ sampled and held. Also, since we're able to read the other front panel function
/ switches (CLEAR, EXAMine, etc.) we use these in the program (see below).  On a
/ regular PDP-8, the puzzle's solution would be kept in the "MQ" register so the
/ user could get the result or a hint by briefly displaying the MQ register data.

CALLBIOS=6206           / Call SBC6120 BIOS function, function code follows call
LIGHTS=12               / BIOS function to take over the display of data lights
SETLEDS=6246            / write data LEDs (when ROTSW != MD)    
                        / Note that for some reason the SBC system doesn't like
                        / to have its "set lights" function (12) called over and
                        / over to perform that function.  So the solution, which
                        / works perfectly, is to call that function exactly ONCE
                        / at the start of the program to stop the automatic 30hz
                        / refresh of the data lights from the user-mode machine
                        / state. Then we subsequently write the data we want
                        / displayed directly to the hardware.

RFNS=6434               / read function switches (BOOT, EXAM, DEP, ROTSW, etc)
/      Bit definitions for the private Read Function Switches (RFNS) IOT       |
/   0       1      2  |   3       4      5  |  6      7     8 |  9   10    11  |

SAC=7340                / Set AC to all 1's and clear the link - microprogrammed
                        / custom "operate" opcode we use to good purpose below.
ShowResult,     CLA
                TAD     Result
SetLights,      SETLEDS                 / we write directly to the hardware
                                        / after declaring our intent only once
                RFNS                    / read the various function switches
                AND     ExamSW          / check for the EXAM switch active
                JMP     CheckForClear   / no EXAM switch, keep checking...
                CLA                     / we DO have EXAM, so put the puzzle's
                TAD     PuzzleAnswer    / answer into the data display
                JMP     SetLights
CheckForClear,  RFNS                    / read the various function switches
                AND     ClearSW         / check for the CLEAR switch active
                SZA                     / not CLEAR either, show current answer
                JMP  I  RestartLoc      / restart the app to run another puzzle

                / the following code is the way we perform an XOR (exclusive OR)
                / when the system doesn't have one available. Since an XOR is
                / also a "carryless add", we perform an ADD, then subtract the
                / carrys that resulted (where both bits were 1's) that works!
                / -(SwitchMask AND PuzzleAnswer) + SwitchMask + PuzzleAnswer

                CLA OSR                 / get the user's current puzzle guess
                DCA     SwitchMask      / save the new switch register
                TAD     SwitchMask      / and get the new switch reg back
                AND     PuzzleAnswer    / find the common bits
                CLL RAL                 / double the value of common bits
                CIA                     / to subtract them from the sum
                TAD     SwitchMask      / add into this one of the terms
                SKP                     / skip over 0026, our startup entry. Our
                                        / funky SBC6120 OS/8 boot requires this
                JMP  I  StartupLoc      / fixed 0026 entrypoint, but it's easily
                                        / accommodated with a SKP instruction
                TAD     PuzzleAnswer    / and add in the second of the terms
                DCA     SwitchMask      / and update/save new XOR result

                DCA     Result          / initialize our XOR accumulator to ZERO
                TAD     BitMasksLoc     / point to our first BitMask
                DCA     TargetPtr       / setup to process XORing of them

XorOneSwitch,   CLL                     / make sure LINK is clear before rotate
                TAD     SwitchMask      / get the current (remaining) switchmask
                SNA                     / if there are still 1 bits, let's go...
                JMP     ShowResult      / we're all done, so setup to wait
                RAR                     / rotate low-bit into the LINK
                DCA     SwitchMask      / save the updated SwitchMask for next
                SNL                     / if that bit was NOT zero, perform XOR
                JMP     NextBit         / link=0 if it WAS zero, setup for next
                TAD     Result          / link=1 get the current cumulative result
                AND  I  TargetPtr       / and find the common bits
                CLL RAL                 / double the value of common bits
                CIA                     / to subtract them from the sum
                TAD     Result          / add into this one of the terms
                TAD  I  TargetPtr       / and add in the second of the terms
                DCA     Result          / and update/save new XOR result

NextBit,        ISZ     TargetPtr       / bump to the next possible XOR target
                JMP     XorOneSwitch    / and go back to check for more work

/------------------------ Initialized Constant Values -------------------------

StartupLoc,     Start                   / used for our startup cross-page JMP
RestartLoc,     NewPuzzle               / used for our restart cross-page JMP
C7764,          7764                    / (-12)
Difficulty,     2                       / 1-11 puzzle complexity (bits per switch)
ClearSW,        0400                    / front panel Clear switch bit
ExamSW,         0100                    / front panel Exam switch bit
CRandAdd,       541                     / 353 base 10
BitMasksLoc,    Masks                   / pointer to our 12 word Mask array

/-------------------------- Uninitialized Variables ----------------------------

Masks,          ZBLOCK  14              / our array of 12 bitmask words
BitsUsed,       0                       / the bits we've reset so far
TargetPtr,      0                       / indirect reference to bitmask array
TargetCtr,      0                       / counter for 12 bitmask
CandidateBit,   0                       / index pointer into our arrays
BitsToSet,      0                       / counter of bits we're setting
LoopCtr,        0                       / generic short-term use counter
PriorBits,      0                       / used to see whether we changed anything
LastRand,       0                       / our previous random value
PuzzleAnswer,   0                       / this is what the user is seeking
Result,         0                       / cumulative XORing result
SwitchMask,     0                       / switch register shifting mask

/ Uninitialized software multiplier temporaries used by our unsigned multiply

Multiplier,     0                       / used to shift and conditionally sum
PhaseCount,     0                       / used to down-count 12 shift/adds
AccumLow,       0                       / low 12 bits of multiplication accum
AccumHigh,      0                       / high 12 bits of mult accumulation
/---------------------------- Start at location 0200 ---------------------------

Start,          CALLBIOS                / call SBC6120 BIOS to declare that from
                LIGHTS                  / now on, WE will control the data lights
                1                       / by writing directly to the hardware...

NewPuzzle,      CLA OSR                 / we grab the switches at start
                DCA     SwitchMask      / and save them to find the first change

Randomize,      JMS     GetRand         / start spinning the PRNG to randomize
                LIGHTS                  / show that we're in our "randomize" mode
                CLA OSR                 / get the switches again
                CIA                     / negate them
                TAD     SwitchMask      / add the original switchreg state
                SNA                     / skip if they have been changed
                JMP     Randomize       / no change, so keep randomizing...
/--------------------------- Initialize a New Puzzle ---------------------------
/ Our overall goal is to create a set of twelve "bitmap" words, one for each
/ switch register switch, each containing some number (typically 2) of '0' bits
/ occupying pseudo-random bit locations in each word.  Each of the '0' bits in
/ the bitmap specifies the lights to be inverted by its respective switch reg sw.
/ The other goal is to evenly distribute the '0' bits across the lights so that,
/ for example, we don't wind up with many switches all toggling the same few
/ lights. This could happen if we didn't globally track the used and unused bits.
/ We accomplish this by keeping a master mask (BitsUsed) of bits we have set so
/ far, and only choosing from those remaining unset as we choose bits for the
/ individual words. Once "BitsUsed" is all 0's, meaning no bits-to-set remaining,
/ we reset it to all 1's and continue setting bits into the 12 individual bitmaps.
                JMS     GetRand         / pickup a random puzzle answer
                DCA     PuzzleAnswer    / save it for this puzzle

                / Setup the twelve bitmask words with N randomly chosen bits.

                TAD     BitMasksLoc     / point to our first BitMask
                DCA     TargetPtr       / setup to fill from there
                TAD     C7764           / AC <- (-12)
                DCA     TargetCtr       / setup to fill twelve bitmask words

                CMA                     / init BitsUsed to all 1's
                DCA     BitsUsed        / show NO bits used so far

FillOneWord,    SAC                     / set AC to 7777 and clear link
                DCA  I  TargetPtr       / initialize the target to all bits on
                TAD     Difficulty      / get the puzzle complexity (bits/switch)
                CIA                     / setup our set bit counter
                DCA     BitsToSet       / set the bit set counter
ClearOneBit,    JMS     GetRnd0to11     / AC <- RND(0..11)
                CMA                     / AC <- Rand(-1 to -12)
                DCA     LoopCtr         / set our bit rotator for random bit
                TAD  I  TargetPtr       / get the current bitmask
                DCA     PriorBits       / save current for comparison
                SAC                     / turn all AC bits on and LINK *OFF* (!)
SpinBits,       RAL                     / rotate zero link into the AC
                ISZ     LoopCtr         / bump our loop counter
                JMP     SpinBits        / and do it until we're done
                DCA     CandidateBit    / save the bit we're considering
                TAD     CandidateBit    / get it back for initial testing       
                AND  I  TargetPtr       / turn OFF all other already OFF bits
                DCA  I  TargetPtr       / save the result back to our target
                TAD  I  TargetPtr       / get the new bitmask back
                CLL CIA                 / form its negative
                TAD     PriorBits       / add our prior bit mask to detect change
                SNA                     / if result is nonzero, we did change something
                JMP     ClearOneBit     / we already had that bit reset, so choose another
                TAD     CandidateBit    / now check our new candidate against
                AND     BitsUsed        / see whether we have already used this bit
                TAD     BitsUsed        / AC = 0 if bits used WAS NOT changed
                SZA                     / not changed, so that bit was not available
                JMP     KeepBit         / it was changed, so we can keep it...
                TAD     PriorBits       / that bit was not available
                DCA  I  TargetPtr       / return to the previous bitmap
                JMP     ClearOneBit     / and get another candidate
KeepBit,        CLA                     / we need to update UsedBits
                TAD     CandidateBit    / get the bit we've chosen
                AND     BitsUsed        / turn off the bit
                SNA                     / skip if we still have bits to use
                CMA                     / we ran out, so reset to all available
                DCA     BitsUsed        / save the updated BitsUsed mask
                ISZ     BitsToSet       / count this bit and check for more
                JMP     ClearOneBit     / we're not done yet, so set another

                TAD  I  TargetPtr       / finally ... invert the bits
                CMA                     / flip the few 0's into a few 1's
                DCA  I  TargetPtr       / and save'em back
                ISZ     TargetPtr       / bump to the next target bitmask word
                ISZ     TargetCtr       / see whether we might be done?
                JMP     FillOneWord     / we're not done... so do another!
/ The one problem with the approach we took to assigning bits to bitmap masks,
/ is that the Bits Used are assigned to linearly successive switches, filling
/ all bits then resetting and refilling. This can render many puzzles trivial
/ to solve. So we now breakup the local association grouping by performing 12
/ swaps between pseudo-randomly chosen pairs of the twelve bitmap masks...
                TAD     C7764           / AC <- (-12)
                DCA     TargetCtr       / setup to fill twelve bitmask words

SwapRndMasks,   JMS     GetRnd0to11     / pickup the first index to swap
                TAD     BitMasksLoc     / form an index
                DCA     TargetPtr       / save the first target pointer
                JMS     GetRnd0to11     / pickup the second index to swap
                TAD     BitMasksLoc     / form an index
                DCA     BitsToSet       / save the second target pointer
                TAD  I  TargetPtr       / get the first one
                DCA     BitsUsed
                TAD  I  BitsToSet       / get the second one
                DCA  I  TargetPtr       / save into the first one
                TAD     BitsUsed        / get back the first one
                DCA  I  BitsToSet       / save back into the second
                ISZ     TargetCtr       / see whether we've done 12
                JMP     SwapRndMasks    / let perform another random swap               
                JMP     ShowResult      / the puzzle is ready for solving...
/ GetRand ----------------------------------------------------------------------
/               This is the simplest way I know of to generate highly random
/               looking 12-bit values.  It's a Linear Congruential Pseudo Random
/               Number Generator (LCPRNG).  Each time it's called, it evaluates
/               the expression:  NextRand = LastRand * 5545 + 541 (all octal)
/      GetRnd:  returns PRNG (0-4095),
/ GetRnd0to11:  returns (0-11)

GetRand,        0                       / subroutine return
                TAD     LastRand        / get the last PRNG value
                JMS     MUY             / multiply by the following constant:
                5545                    / 2917 base 10 - LCPRNG multiplicand
                TAD     CRandAdd        / sum in our LCPRNG addend
                DCA     LastRand        / save this for next time
                TAD     LastRand        / and return it to our caller
                JMP  I  GetRand         / return the AC to the caller

GetRnd0to11,    0                       / (subroutine return)
                JMS     GetRand         / get a number (0-7777)
                JMS     MUY             / treat it as (0 to .9999999)
                14                      / and multiply by 12 to generate
                CLA                     / a range from 0 to 11
                TAD     AccumHigh       / return our 0-11 value
                JMP  I  GetRnd0to11     / return with AC <-- RND (0..11)
/ MUY --------------------------------------------------------------------------
/               This is a full 12x12 multiply, needed because the HD6120 PDP-8
/               emulation chip used by the SBC6120 inexplicably lacks the EAE
/               "Extended Arithmetic Element" multiplier.  Annoying as this is,
/               it does mean that these "ToggleToys" will be usable on ALL real
/               PDP-8 systems, including those without EAE's.
/  On Entry:    AC contains Multiplier & the word after the call has Multiplicand
/    Return:    least significant 12-bits in AC, most significant in AccumHigh.

MUY,            0                       / subroutine return
                DCA     Multiplier      / save the multiplier for shifting              
                TAD     C7764           / setup our -12 loop counter
                DCA     PhaseCount
                DCA     AccumLow        / clear our 24-bit results accumulator
                DCA     AccumHigh       

MuyShift,       TAD     Multiplier      / get a bit from the multiplier
                CLL RAL                 / move the high-bit into LINK
                DCA     Multiplier      / put the updated multiplier back
                SNL                     / we do need to add-in the multiplicand
                JMP     Iterate         / no multiplicand add-in
                TAD  I  MUY             / add the multiplicand into accumulator
                TAD     AccumLow        / this *may* overflow, clearing the LINK
                DCA     AccumLow        / either way, put the updated low 12 back
                SNL                     / if LINK is still '1', no overflow
                ISZ     AccumHigh       / bump the high-half if we carried out
Iterate,        ISZ     PhaseCount      / see whether we've done all 12 bits
                JMP     Shift24         / not done, so shift and iterate again

                CLL CLA                 / return the lower 12-bits in AC
                TAD     AccumLow
                ISZ     MUY             / return to the instruction after multiplier
                JMP  I  MUY
Shift24,        TAD     AccumLow        / get the lower 12-bit half
                CLL RAL                 / shift it left, high bit into LINK
                DCA     AccumLow        / put back the new low half
                TAD     AccumHigh       / get the upper 12-bit half
                RAL                     / shift it left, LINK into low bit
                DCA     AccumHigh       / put back the new high half
                JMP     MuyShift

The assembled listing for this source code, LightsOut.lst, is also available.

Due to the size of the OS/8 operating system, and the fact that three hours of 9600 baud transfer is required to move it in hex ASCII format from a PC to the SBC6120, I wrote the OS/8 Windows utilities to make that process instantaneous by allowing the SBC6120's IDE drive to be attached through any means available to a Windows system, and to then perform a raw physical transfer of the OS/8 partition data to the SBC's drive.

However, the “DeepThought” and “LightsOut” toggle toys, the custom boot sector, and the sector read/write utilities are all short enough to be feasibly entered through a terminal console. This also means that there is no need for a Windows-centric approach, so Apple Mac and Linux/Unix users will not be disadvantaged.

Installing LightsOut into your SCB6120/FP6120

The following instructions will allow you to deposit the “LightsOut” program in RAM, then write it to any one or more IDE drive partitions of your choosing. Then the modified multi-boot sector will allow you to load and run the program any time you wish using only the front panel switches. This code was developed on SBC6120's having an attached eight gigabyte drive, yielding more than 4300 (octal) partitions. So, for ease of switch register use, the toggle toys were written to partitions 4000 and 4001 (octal). Before proceeding, you should determine where — into which partition(s) — you wish to write these toggle toys. (You should probably have already installed the custom multi-boot sector before installing the “DeepThought” and “LightsOut” toggle toys since their subsequent loading and running requires the multi-boot sector.)

If the SBC6120 is currently running (the front panel RUN light is illuminated), briefly lower and raise the front panel HALT switch to return control to the BIOS and console. Establish communication with the BIOS so that pressing “Enter” on your terminal or terminal emulator returns the BIOS '>' prompt.

Begin by either resetting the SBC6120 or performing a master reset (mr) command to bring the SBC6120 into a known state:

Then clear all of memory. This will take a few seconds, during which the front panel's address register will count all the way up to 77777 as zeroes are being written into the PDP-8's RAM:
You can verify that memory has been cleared by displaying the first sector's-worth of RAM with the examine memory (e) command. You'll receive a nice block display of zeroes, not shown here:
>e 0-377
Now we need to deposit the LightsOut program into RAM. The commands to do this are a series of deposit (d) commands shown below. You can enter each line manually, but terminal emulation programs often understand “copy & paste” semantics which make copying the commands from this page and pasting them into the terminal for sending to the SBC6120 much quicker, easier, and less error prone.

If you are a Windows user, the free, open source, and very nice “Tera Term” terminal emulator can be used. With Tera Term, the keystroke combination “Alt-V” will paste the Windows' clipboard into the terminal window while simultaneously sending it to the SBC6120, exactly as if it had been manually entered. (Here is a locally archived copy in case the file's home site ever disappears:

The following series of SBC6120 deposit (d) commands will place the LightsOut program into SBC RAM:
>d 00000 7200,1112,6246,6434,0062,7450,5012,7200
>d 00010 1111,5002,6434,0061,7440,5456,7604,3113
>d 00020 1113,0111,7104,7041,1113,7410,5455,1111
>d 00030 3113,3112,1064,3102,7100,1113,7450,5000
>d 00040 7010,3113,7420,5053,1112,0502,7104,7041
>d 00050 1112,1502,3112,2102,5034,0200,0203,7764
>d 00060 0002,0400,0100,0541,0065

>d 00200 6206,0012,0001,7604,3113,4324,6246,7604
>d 00210 7041,1113,7450,5205,4324,3111,1064,3102
>d 00220 1057,3103,7040,3101,7340,3502,1060,7041
>d 00230 3105,4334,7040,3106,1502,3107,7340,7004
>d 00240 2106,5237,3104,1104,0502,3502,1502,7141
>d 00250 1107,7450,5231,7200,1104,0101,7041,1101
>d 00260 7440,5265,1107,3502,5231,7200,1104,0101
>d 00270 7450,7040,3101,2105,5231,1502,7040,3502
>d 00300 2102,2103,5224,1057,3103,4334,1064,3102
>d 00310 4334,1064,3105,1502,3101,1505,3502,1101
>d 00320 3505,2103,5305,5000,0000,1110,4343,5545
>d 00330 1063,3110,1110,5724,0000,4324,4343,0014
>d 00340 7200,1117,5734,0000,3114,1057,3115,3116
>d 00350 3117,1114,7104,3114,7420,5363,1743,1116
>d 00360 3116,7420,2117,2115,5371,7300,1116,2343
>d 00370 5743,1116,7104,3116,1117,7004,3117,5351
Verify the accuracy of the data you just entered by asking the BIOS to compute the checksum (ck command) of the first two PDP-8 pages of RAM, locations 00000 through 00377:
>ck 0-377
You should receive the reply:
Checksum = 7343
Next, we need to write these first two pages of PDP-8 RAM to non-volatile storage so that we can reload and run it at any time with just a few flips of our front panel switches. The partition writer (PartWrite) code given below is quite short. Its source code and documentation can be found on the custom OS/8 boot sector page. So, as before, deposit the partition writer into RAM (starting at location 00400) using the following sequence of SBC6120 BIOS deposit (d) commands:
>d 00400 7604,7450,7402,3223,6206,0010,0000,0423
>d 00410 4000,0027,0001,6206,0004,4207,0000,0000
>d 00420 7430,7402,7402
With the partition writer code in RAM at location 00400, we're ready to write LightsOut to its own partition. FIRST set the front panel data switches to the address of the target partition. If you have a very large drive, you might use something like 4001, but 0007 or 0010—or whatever—would be fine too). Verify that the front panel's “HALT” switch is UP (not enforcing a halt), then, with the front panel switches set to the target partition, start the partition writer with the BIOS start (st) command:
>st 0400
Note that to prevent any chance of inadvertently overwriting partition zero, where most users will have installed the OS/8 operating system, the little partition writer will not write to partition zero. So if the switches were inadvertently set to 0000, you will receive:
?Halted at 00403
PC>0403 PS>1000 AC>0000 MQ>0000 SP1>0000 SP2>0000

(That's NOT what you want.)

With a non-zero partition number set into the switches, you should receive:
?Halted at 00423
PC>0423 PS>1000 AC>0000 MQ>0000 SP1>0000 SP2>0000
You can (and should) verify that the two-page sector was written to the IDE drive by dumping the target partition's first sector with the following command, where <partition> is replaced with the number of the partition where the sector was written:
>dd <partition> 0 1
So, for example, assuming that “LightsOut” had been saved into partition 4001, you would give the following command and receive the following dump:
>dd 4001 0 1
0000.000/ 7200 1112 6246 6434 0062 7450 5012 7200
0000.010/ 1111 5002 6434 0061 7440 5456 7604 3113
0000.020/ 1113 0111 7104 7041 1113 7410 5455 1111
0000.030/ 3113 3112 1064 3102 7100 1113 7450 5000
0000.040/ 7010 3113 7420 5053 1112 0502 7104 7041
0000.050/ 1112 1502 3112 2102 5034 0200 0203 7764
0000.060/ 0002 0400 0100 0541 0065 0000 0000 0000
0000.070/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.100/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.110/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.120/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.130/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.140/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.150/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.160/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.170/ 0000 0000 0000 0000 0000 0000 0000 0000
0000.200/ 6206 0012 0001 7604 3113 4324 6246 7604
0000.210/ 7041 1113 7450 5205 4324 3111 1064 3102
0000.220/ 1057 3103 7040 3101 7340 3502 1060 7041
0000.230/ 3105 4334 7040 3106 1502 3107 7340 7004
0000.240/ 2106 5237 3104 1104 0502 3502 1502 7141
0000.250/ 1107 7450 5231 7200 1104 0101 7041 1101
0000.260/ 7440 5265 1107 3502 5231 7200 1104 0101
0000.270/ 7450 7040 3101 2105 5231 1502 7040 3502
0000.300/ 2102 2103 5224 1057 3103 4334 1064 3102
0000.310/ 4334 1064 3105 1502 3101 1505 3502 1101
0000.320/ 3505 2103 5305 5000 0000 1110 4343 5545
0000.330/ 1063 3110 1110 5724 0000 4324 4343 0014
0000.340/ 7200 1117 5734 0000 3114 1057 3115 3116
0000.350/ 3117 1114 7104 3114 7420 5363 1743 1116
0000.360/ 3116 7420 2117 2115 5371 7300 1116 2343
0000.370/ 5743 1116 7104 3116 1117 7004 3117 5351
The “4573” at the end is a checksum of the block just dumped, and it (and everything else) should match what's shown above.

You're all done!
You now have the “LightsOut” program safely written, and verified, to an IDE drive partition of your choosing. If you have already installed the modified FlexBoot sector, you can fire up the “LightsOut” toggle toy by setting the target partition into the switch register then depressing the front panel “BOOT” switch twice in succession.

Good luck turning all of the lights out!

Oh!... and if it's too tame and easy for you . . . the program DOES support the toggling of ANY NUMBER of lights with each switch! As mentioned in the comments at the top of the source code, location '0060' will normally contain '0002' (you can see it in the block of octal above). So you can halt the program, change location '0060' to, say, '0004' and really give yourself a headache. You could even write a succession of programs to successive partitions, each with a different difficulty level. Then you could use the switches to select the difficulty by which version is loaded and started.

This ZIP file (352kb) contains all of the recently-written bits and pieces of
SBC6120 & FP6120 PDP-8 code for DeepThought, LightsOut, the custom OS/8
boot sector, and other PDP-8 code snippet utilities I created for this project.

GRC's PDP-8 Pages:
CLICK HERE to learn how YOU can acquire & build
one of these complete PDP-8 systems for yourself !!!

Jump to top of page
Gibson Research Corporation is owned and operated by Steve Gibson.  The contents
of this page are Copyright (c) 2024 Gibson Research Corporation. SpinRite, ShieldsUP,
NanoProbe, and any other indicated trademarks are registered trademarks of Gibson
Research Corporation, Laguna Hills, CA, USA. GRC's web and customer privacy policy.
Jump to top of page

Last Edit: Jan 27, 2016 at 18:11 (3,034.56 days ago)Viewed 4 times per day