|
GE-115 Emulator
An Emulator of the General Electrics GE-115 computer
|
A modern operator's guide to the GE-120 front panel and to the three consoles shipped with gemu (the headless CLI, the ncurses --tui client, and the in-browser WebAssembly panel).
Every control, lamp and procedure below is drawn from the original GE documentation. Sources are cited inline as CPU[n] <section> fo.<folio> where CPU[n] is the descriptive-manual volume and fo. is the drawing/folio number; confidence and OCR caveats are noted where the scan is unreliable.
Primary sources
CPU/GE 120 CENTRAL PROCESSOR [4].pdf§3 Operator Panel, §4 Maintenance Panel — drawing 30004122, fo.30–37.CPU/GE 120 CENTRAL PROCESSOR [1].pdf— diagnostic organisation / loading.- Reproduced and regression-tested in gemu:
tests/cpu.c(cpu_isolation.test_k,cpu_isolation.oper_call_by_register_forcing).
The GE-120 console is physically two panels (CPU[4] dwg 30004122, fo.30–34):
| Panel | Audience | Purpose |
|---|---|---|
| Operator panel | normal operation | load + run programs, observe HALT / OPER CALL, set the two program-readable switches |
| Maintenance panel | field engineering | force and display every internal register and memory, single-step the microsequencer, stop on jump conditions, inhibit error stops |
The maintenance panel only comes alive when one of its switches is inserted or the LAMPS switch is at ON/DIAG (CPU[4] §4.3, fo.37). In DIAG the unit is put in diagnostic mode and MAINT ON is lit.
**MAINT ON — observed on the restored machine, 2026-07-29.** The lamp says the maintenance panel has the machine, and it is lit when
The nine maintenance switches are the ones in §4.3 — PAPA, PATE, RICI, ACOV, ACON, INAR, STOC, INCE, SITE — and the sixteen AM forcing toggles, which are switches on that panel too: setting one up is the engineer preparing a value to force. The operator panel's SWITCH 1 / SWITCH 2 are not part of it: those are program-readable (JS1/JS2) and belong to the running program, not to the engineer. Turning the rotary off NORM is enough on its own — that is what arms the forcing cycle START would perform (§4.2), which is exactly when an operator wants telling. A running machine keeps the lamp dark whatever the panel is doing.
Modelled in console.c (ge_fill_console_data); test console_fidelity.maint_on_lamp.
| Lamp | Colour | Meaning | gemu field |
|---|---|---|---|
| HALT | white | machine stopped — by HLT, by STEP-BY-STEP, or from the maintenance panel | ALTO |
| OPER CALL | — | operator-call request raised by the program (ALAM, set by the ALAM/LON path → CI87) | ALAM |
| SWITCH 1 / SWITCH 2 | white | position of the two program-readable switches; lit when the switch reads logic 1 (the value that makes JS1/JS2 jump) | JS1 / JS2 |
| I | — | interrupt enabled | INTE |
| C1 / C2 / C3 | — | channel-busy / peripheral-connector status | PUC1/2/3 |
| OF / NZ / IM / JE | — | condition flags (overflow, non-zero, …) and jump-enable | FA bits / JE |
| LOAD 1 / LOAD 2 | white (double) | which of the two install-time load units is selected | ALOI |
Bit lamps mirror internal registers directly:
| Lamps | Register |
|---|---|
R000–R008 | RO |
S000–S007 | SO (microsequencer state) |
FA00–FA03 | low 4 bits of FA |
UR | the URPE flip-flop |
B1–B4 | selection of the four connectors |
SA00–SA07 | SA (next-state latch) |
The BO bus drives the rotary-selected register onto the display while the machine is stopped (see §5). gemu surfaces it as ADD_reg (ge->rBO), OP_reg (ge->rFO) and RO.
A panel bulb is a filament with thermal inertia, and at 500,000 elementary cycles a second most of what the register lamps do is far faster than that filament can follow. It does not flicker: it sits at whatever temperature the duty cycle holds it at. On the machine you read the difference straight off the row — a bit that is steadily set burns bright orange, a bit that is toggling glows dull red, and a bit that is clear is dark glass.
A panel repainted at 60 Hz cannot see that by sampling once a frame: it would catch one arbitrary cycle in eight thousand and blink nonsense. So the emulator measures the duty cycle — sampling the lamps as it turns, at a prime stride so nothing beats with a periodic bit — and integrates it into a per-lamp filament temperature with a first-order lag (heating quicker than cooling, as in a bulb: the filament is driven up and radiates down). What crosses into the page is that temperature, 0..255; the page owns what a filament at that temperature looks like, and hands the holder styling a face colour and a glow through the --lamp-face / --lamp-glow / --lamp-heat custom properties.
Measured on funktionalcpu.cap mid-run, the SO row reads 62 115 103 33 21 206 255 148 — one bit hard on, one nearly dark, the rest sitting where their duty cycles hold them. console/wasm/main.c.
A momentary key that lights every console lamp for a bulb test (CPU[4] §3.2). It must not be pressed during machine operation. On the panel it shares a button with the MAINT ON lamp — MAINT.ON above, LAMPS CHECK below — so pressing that button lights the whole console for as long as it is held.
Modelled as ge->lamps_test: ge_fill_console_data overwrites every lamp while it is set, so the ncurses panel and the browser panel test the same lamps from the same place, and nothing in the CPU is disturbed. Test console_fidelity.lamps_check_lights_everything.
| Control | Type | Behaviour (CPU[4] §3.3, fo.31–33) |
|---|---|---|
| CLEAR | key | Stops everything in the subsystem, clears all error conditions, presets CPU + peripherals to a defined state. Required after MEM CHECK and after power-on. No lamp. In gemu: AINI/ALAM/PODI/ADIR, ALTO set, RC00-RC03, the reader's command/mode latches and LUREN, the fault latches MEM CHECK and INV ADD, the FI/FA condition flip-flops, the channel end/error latches (RIG1, RACI, RECE, …), the working registers V1-V4 / L1-L3 / FO / RO / BO, **PO**, and the sequencer, preset to the display state (§4.2). Not core. Resuming a halted program is START on its own, which touches none of that; CLEAR is how you say start over. |
| LOAD 1 / LOAD 2 | switch | Selects one of two peripheral units enabled at install time for program loading (Conn.2/3, Conn.4/3, or Conn.2/4 — CPU[4] fo.43). |
| LOAD | key | Arms the bootstrap and does nothing else: it sets the AINI flip-flop. No card moves, no lamp lights. The next START is what reads. |
| START (HALT) | key | Starts operation. The white HALT lamp shows the machine is stopped. First START after CLEAR: runs the program if no other switch is set; runs the load if LOAD was pressed. |
| STEP-BY-STEP | switch | Executes one instruction per START. Mid-run, it makes the program stop at the end of the current instruction. **INS inhibits it; ENS, CLEAR, or the maintenance-panel STOC switch re-enable it.** White lamp = inserted. This is the operator panel's own switch, signal ASIN, and it is not the maintenance panel's PAPA — see the note below. |
| SWITCH 1 / SWITCH 2 | switch | Two general-purpose switches the program reads via the JS1 / JS2 instructions. |
Loading sequence (CPU[4] §3.3 / §5.3):
CLEAR→ select unit (LOAD1/LOAD2) →LOAD→START.What
STARTactually reads: one card. The80 → c8 → … → e3walk issues a single "read unchanged" order withL1 = 0x80toV1 = 0x0000, and the channel packs two presented nibbles per byte — so 80 columns become 40 bytes at address 0, and the machine executes them. It does not read a deck. The card does:software/loader.txtis the original bootstrap listing and it is exactly 40 bytes (0x0000-0x0027) of twoPERreads and aJU 0x0028. Verified on the bench, July 2026.
STEP-BY-STEP and PAPA are two separate circuits. They have the same apparent effect — the machine stops and each
STARTadvances it — but they are independent, and only one of them has a lamp. From theALTOset conditions (CPU[4] fo.115):
signal path stops after program can inhibit? lamp STEP-BY-STEP (operator panel) ASINCI891atE2/E3of alpha — the commandHLTitself useseach instruction yes: INSsetsADIR,ENS/CLEARclear it,STOCoverridesyes PAPA (maintenance panel) AMICBALS71at the end of a CPU work cycleeach microsequence no no Because
ASINgoes throughCI891, the stop lands after the function code is read with the program addresser still on the OP code of the instruction just read (CPU[4] §5.1 b).PAPAsteps the microsequences "without interfering with the transfers from peripheral unit" (CPU[4] §2.4); the sameALS71term also stops the machine whenever the rotary is offNORMand off position 8.gemu modelled the two as one thing until 2026-07-29, with the lamp following
PAPAand theINSinhibit wrongly applied to it — so any program that had issuedINScould silently ignore an insertedPAPA. They are now separate:ge.hASIN,msl-states.c state_E2_E3_TO80_CI89,ge.c fsn_last_clock. Testsconsole_fidelity.step_by_step_and_papa_are_separateandconsole_fidelity.step_by_step_stops_earlier_than_the_program_end.
Sixteen toggles AM00–AM15 that load (force) or display configurations on the main registers (CPU[4] §4.2, fo.34). In rotary positions 8, 12, 13 and 14 only AM00–AM07 are used.
With the machine stopped each position routes a register onto BO for display — possible because the Logic Sequence Matrix is still clocked by the free- running delay line. Pressing START instead runs a forcing cycle, writing the AM switches into the selected register (CPU[4] §4.2, fo.35–37).
| Pos | gemu RS_* | Display | START forces |
|---|---|---|---|
| 1 | RS_V4 | V4 | AM → V4 |
| 2 | RS_L3 | L3 | AM → L3 |
| 3 | RS_V3 | V3 | AM → V3 |
| 4 | RS_R1_L2 | RI-L2 | AM → RI-L2 |
| 5 | RS_V2 | V2 | AM → V2 |
| 6 | RS_L1 | L1 | AM → L1 |
| 7 | RS_V1 | V1 | AM → V1 |
| 8 | RS_V1_SCR | V1 | AM → storage from address V1 onward (memory key-in) — see the note below: this one does not stop after a cycle |
| 9 | RS_V1_LETT | mem[V1] on RO | reads memory at V1 and steps V1 by 1; the lamps show the byte at V1 for as long as the position is selected |
| 10 | RS_NORM | PO | *(normal operating position — no forcing)* |
| 11 | RS_PO | PO | AM → PO |
| 12 | RS_FI_UR | *(none)* | AM → FI register and URPE |
| 13 | RS_SO | *(none)* | AM → SO, SI |
| 14 | RS_FO | *(none)* | AM → FO |
In position 8, AM08 forces the memory check bit (even if incorrect) when the INCE switch is inserted.
The storage key-in does not stop, and that is not a bug. fo.98's end-of-cycle stop (
ALSOA=0) exempts position 8 along withNORM, so with neitherPAPAnor a step switch inserted aSTARTat position 8 keys theAMswitches into address after address, straight through core, until the addresser walks off the installed memory and INV ADD stops the machine. That is what the machine at Electric Dreams does. InsertPAPAand eachSTARTstores one byte, leaving V1 advanced for the next.The stop is the point: a memory fault does not merely light a lamp, it stops the subsystem — which is why
CLEARis required afterMEM CHECK(§3.3) and whyINARexists to inhibit it. gemu raises the lamp either way and setsALTOunlessINARis inserted (pulse.c mem_fault). Testconsole_fidelity.storage_key_in_runs_until_the_error_stop.The fault lamps are conditions, not latches. Each reports the memory cycle it belongs to, and a good cycle puts it out again — which you only see with the stop inhibited. Nothing loaded,
INARin,START: the machine walks zeroes up through core and INV ADD comes on as the addresser passes the installed 32K, then goes out as it wraps to0x0000, blinking once per lap (~0.1 s each way on this 2 µs machine). WithINARout the machine stops ON the faulting cycle, so the lamp stands there lit untilCLEAR— the same behaviour seen from the other side. Observed on the restored machine, 2026-07-31; testconsole_fidelity.inv_add_follows_the_cycle_it_reports.MEM CHECK stands on throughout that same run on the iron, and does not by default in gemu. The difference is what "core it has not written" means: core retains, so on a machine in service every cell holds something with the check bit its last write left, and reads clean — which is the default, and what lets a deck read scratch it has not filled yet. A machine powered up over core that has never been written has no valid check bit anywhere, and running it through blank core stands MEM CHECK on. Set
ge->mem_check_blankfor that machine. It is a property of the iron in front of you, not a rule: with it set,funktionalcpu.capstops at cycle 57660 on a MEM CHECK at0x00E8, a scratch cell the deck reads before writing.Position 9 is the read-out.
ROis cleared atTO20of every cycle (fo.142), so anything on those lamps is put there by the cycle you are looking at: with the rotary atV1-LETTthe display sequence fetchesmem[V1]and the byte stands on theROlamps for as long as the position is selected; eachSTARTsteps V1 to the next byte. (gemu's display chart gained that read, andCI33— which would otherwise reloadROwith the low half of the address — is excluded for this position;msl-states.cstate_00. Whether the iron instead freezes the byte just read is the one part of this that wants a bench check.)
Keying a start address into PO (position 11) is the ordinary way to run a program that is already in core, and it has to survive the return to
NORM:CLEAR -> rotary PO -> AM = address, INAR in -> START (forcing cycle) -> rotary NORM, INAR out -> START (runs from it)Note the order: the address is keyed after the
CLEAR, becauseCLEARzeroesPOalong with the rest of the preset state (§3).gemu got this wrong in two places until 2026-07-31, and the symptom was the plain one — the machine ran from somewhere else. First, a
HLTparks the sequencer mid-phase with the halted instruction still inFO, andge_cleardid not preset it: the nextSTARTfinished the OLD instruction and ate the forced address as its operand.CLEARnow presets the sequencer to the display state (00), which is where a stopped machine sits and which walks00 -> 80 -> alpha, i.e. straight into a fetch atPO. Second, the display sequence's ownCI15row (NO <- L1) was firing for every rotary position and overwriting thePOthatTO10had just routed into the knot; Initialisation'sCO00(PO <- NI) then wrote that back into the program addresser, so the machine started from the last program'sL1. ConditioningCI15on theL1position — which is whatCI33's own exclusion list says — leaves the address positions alone. Testconsole_fidelity.po_can_be_forced_and_run_from.
| Switch | gemu flag | Behaviour |
|---|---|---|
| PAPA | PAPA | Step-by-step execution of the microsequences (stops after each), without disturbing peripheral transfers. START runs one step. *(This is the panel STEP-BY-STEP.)* |
| PATE | PATE | Stops the timing after every delay-line cycle; START runs one cycle. Finer than PAPA. |
| RICI | RICI | Disables loading of the next status — repeats execution of the current Status. |
| ACOV | ACOV | Stops the machine when a jump condition is verified at the end of reading a jump instruction. |
| ACON | ACON | Stops the machine when a jump condition is not verified. |
| STOC | STOC | Lets STEP-BY-STEP stop the CPU even if the program inhibited step-by-step (via INS). |
| INAR | INAR | Inhibits the error stop on a memory check error or on addressing a non-existent address — the lamp still lights, the machine does not stop (pulse.c mem_fault). Without it, a fault sets ALTO: that is what ends a runaway storage key-in, and what makes CLEAR "required after MEM CHECK". |
| INCE | INCE | Inhibits check-bit correction for characters from external units. During a console storage forcing it stores AM08 as the (possibly wrong) odd-parity bit, suppressing parity generation for AM07–AM00. |
| SITE | SITE | The CPU no longer waits for availability / triggers from external units — the program evolves as if peripherals are always ready. |
| LAMPS | — | 3-position: OFF (all maintenance lamps off) / ON (lamps powered) / DIAG (lamps + diagnostic mode + MAINT ON). |
gemu drives the same internal model through three consoles. The C API (console.h) is the common substrate:
| Front-end | How to start | Notes |
|---|---|---|
| CLI (headless) | ./ge deck.cap (--deck is an alias) | Drives CLEAR→LOAD1→LOAD→START for you and runs to HLT; --trace for logs. A .cap deck is the only input it takes. |
| ncurses TUI | ./ge --tui | Implies --console; spawns console/curses/console.py against the /tmp/gemu.console socket. |
| WebAssembly | make wasm && make wasm-run | Browser panel; exports press_clear/press_load/press_start, press_power_off, set_switches(flags, am), set_register_selector(s), set_switch_1_2(s1, s2) (the program-readable switches → JS1/JS2), set_load_unit(load1) (LOAD1/LOAD2 selector), set_speed(mult) (run-speed multiplier), mount_deck (deck loader) with deck_cards/deck_cards_left (what is in the hopper), refresh_lamps (after LAMPS CHECK). The page's only input is a .cap deck chosen from the operator's disk — picking the file mounts it, exactly as the CLI mounts a positional .cap; nothing is vendored beside the page and there is no second format. The run loop is requestAnimationFrame-driven and paces the cycle count to nominal GE-120 wall-clock time, taking the elementary-cycle period from the machine's own straps — ge_cycle_period_ns, the E03 row of cp06 ch.002 TAB.1: 2/4/6 µs for a UCE 468/467/466. This machine is a 468, so real time is 500 cycles/ms; the panel used to assume 4 µs and ran everything at half the iron's speed. A simulator-toolbar selector scales it (default real time). For instruction-level inspection use PAPA single-step instead. A live gdb-style disassembly window (shared disasm.c, driven from opcodes.h) tracks the program counter — AAAA: <bytes> MNEM ops, current instruction highlighted. |
The WebAssembly set_switches packs the maintenance switches into a flags word:
A real GE-120 has no file dialog — a program enters through a deck of cards physically loaded into the reader. The browser panel keeps that distinction visible with a small simulator gadget, drawn deliberately apart from the authentic console (dashed border, monospace) so it never reads as a real control. The gadget does exactly one thing, and it is the one thing a browser cannot do for you: it carries cards to the hopper.
There is no staging path and no image path. LOAD sets AINI and nothing else; START runs the 80 → c8 → … → e3 bootstrap, which reads one card, packs its 80 columns into 40 bytes at 0x0000 and executes them. Every card after that is pulled by a PER read the loaded program issues itself.
The operator's window between LOAD and START is still there and still useful: the rotary register dials can force values into memory (e.g. the diagnostic test-select byte at 0x0E00 — dial V1 ← 0x0E00, V1 SCR ← 0x40) and they survive into the run.
A rail down the left of the browser panel switches between three ways of looking at the same machine. Only the first is a control surface; the other two are the iron, drawn from the card-layout Atlas (drawing 14026 136, cabinet section 2A) and reachable at #front and #back.
CPU front is the card cage as you see it with the boards in: nine tiers of forty positions, blue board faces, position 40 at the left and 1 at the right. A board normally spans both backplane rows of its tier — one part number appears against A and again against B — so it is drawn full height; where the two rows carry different cards (rows I and L do this) each is drawn at half height, because that is what the layout says is in there. 373 boards are fitted, 246 of them across two rows. Scroll to zoom, drag to pan; the part number and slot label appear once the zoom makes them legible. No controls — looking only.
The card names come from the part number, not from the layout drawing. atlas/cp09_verified.json is the circuit-card catalogue read by hand off cp09 — 74 entries keyed by the part number's first seven digits, each with the card's real name and the page its entry starts on. The Atlas CSVs are OCR of the layout drawing and mangle the names badly, so where the catalogue covers a code it decides the name and the Atlas type is only a fallback. That renames 208 positions: AND02A→ANDO2A, 1NVE2A→INVE2A, L1R12A→LIRI2A, LOG12C→CISP2C, and so on. The catalogue's page number is used for the board sheet's Card catalogue tab too, in place of the page found by searching the OCR text.
The catalogue is itself a careful reading of a poor scan, so it is not the last word either. Corrections the machine's owner makes with the manual open override it, in OWNER_NAME: 0610025 is **FILT2B** not FILI2B (it is a filter, which is what the position is for), 0610002 is **AMPL2A** not AMFL2A (the card carries the amplifiers and is named for them), and 0610045 is **LOSE2H** not LOSE2G — that H is real, which is the best argument yet for having dropped the blanket H→M table, since it would have broken this one.
The catalogue's page column drifts through the middle of the volume: it puts 0610045 on 143 where the card is printed on 158. So the page comes from where the scan's text layer finds the part number, past the index, and only where that keeps the catalogue in code order without jumping — the volume is bound in code order, so a page that goes backwards or leaps is the number appearing in a cross-reference rather than on its own entry. Both pages checked against the manual came out on the text layer's side.
No verified name contains a 0 or a 1 — across all 74 the only digits are the 2 in 2A and one 8 — so a digit like that in a type is the scan reading O or I, and it is folded back. That only matters for the seven codes the catalogue does not cover; everywhere else the verified name replaces the type outright.
There used to be an H→M correction table here as well, on the reasoning that the 1968 typeface confuses the two. cp09 settled four of its five entries and two were wrong:
AHPL2AisAMFL2A, notAMPL2A, andLOSE2HisLOSE2G, notLOSE2M. The corroboration had looked good and was not —hardware-options.mdwas following the same bad reading, andLOSE2Mdoes exist, at a different code. The inference is gone; an uncovered type now reads as the scan has it, disagreements and all.
The proportions are measured off the photographs rather than guessed: the board handles repeat about every 13.7 px across a cage that steps about 110 px per tier, so a card position is roughly one to eight — thin and tall.
Which card is in each position comes from the restoration workbook, sheet SCHEDE CPU — the layout as checked against the real machine. It is organised by tier (one cell per AB, CD, … ST per column), which is itself the statement that a board spans two rows, and it holds the part number's last three characters. console/wasm/import-sheet.py exports it to atlas/tier_layout.tsv alongside the Atlas CSVs; the generator reads that. Where the two sources meet they agree at 481 positions and the workbook overrides 36, and it fills 29 the Atlas left blank. Most of the overrides are OCR slips in the scan of the factory drawing — E17 read 0610016G and F17 read 06100160, the same card under the O↔0 confusion, which is why that position used to draw as two half-height boards instead of the one dual-slot board it is.
The two core stores stand in the cage, not under it, in rows Q to T, spanning slots 39–32 and 9–2 — eight positions each, per the machine's owner. (The workbook's own fill runs a slot wider at each outer end, 40–32 and 10–2, because it marks the bay rather than the box; the fill is used only to find which rows are memory rows.)
The CO1N2x connector cards the layout drawing puts at the four positions bracketing the boxes — 39/32 and 9/2 — are the core store's own, inside its housing, so the box covers them and they are not drawn as cards standing in the cage. The board sheet says as much for those positions.
The box is drawn as the photographs show it: a glass cover that throws the wire mass behind it out of focus, with two round ports, one near each end, through which the same wires read sharp — the brass-ringed one at the top and the dark red one at the foot. Light metal clamps with their screws sit across the top and a rail runs under it. Q+R 30 and 31 and I+L 32 carry a dark olive-brown face rather than the usual blue; that is observed, not derived, and recorded against the position in console.html. Q+R 21 is the rotary switch card — MAME2A, 0610051X, which the layout sheet calls rotary SW 51X: blue at the bottom like any other board, grey up top, with a black thumbwheel mounted along the card and the selected digit showing in white. On the machine it is set by hand; gemu does not read it, so it is drawn at its resting 0.
The odd faces are per position and not per card type — Q/R 30–31 are 0610002J and I+L 32 is 0610055Y, and the other 0610055Y in the machine (I+L 16) is ordinary blue. With 40 at the left on the front view, that puts one near the left edge and the other over towards the right, flanking the boards between them — the arrangement in the photographs. Each is a dark red core mat behind a perspex cover between light metal brackets, spanning both the Q+R and S+T tiers. They are not card positions and are not in the Atlas, so they are drawn over the run rather than as boards. The pair is what straps this machine to 32K (PONT 2N/2P, cp06 ch.001).
CPU back is the wire-wrap side, so the columns mirror: position 1 at the left, 40 at the right. Every position presents its seventeen pins, the nine odd ones down the left and the eight even ones down the right, offset half a pitch the way the connector body is moulded, pin 01 top-left and pin 17 bottom-left. Contacts are gold where the layout reads a net and dark where it does not. Click one and the read-out names it, gives the schematic chapter and — where a trace in docs/signals/traces/ has it — the gate equation that drives it. A position or a contact can be linked to directly: #back/P32 centres on that connector, #back/P32-01 picks the pin.
12,240 contacts is more than a browser wants as live SVG, so the pins for a position are built only when it is both on screen and big enough to aim at. Panning rebuilds just what came into view; everything else stays a block.
Double-click a board on the front view and everything else goes behind a modal sheet for that one card (Esc, the ×, or a click outside closes it; the rack is inert while it is up). #front/EF12 opens it directly.
The left column is what the layout knows: which rows and position, the card mnemonic and part number, any OCR caveats the Atlas recorded for that cell, and both connectors' seventeen pins with the net at each and its chapter. Clicking a pin closes the sheet and lands on that contact on the back view.
The right column is the manual. Which pages are offered is derived, not configured:
Chapter pages come from three places, and the sheet says which. 27 are stated outright in docs/signals/traces/ ("Chapter 052 (cp06 p129)") and are trusted as read. 109 are recovered from cp06's own OCR text layer by taking pages that name exactly one chapter and keeping the longest run whose chapter number rises with the page — the gate sheets are bound in order, so a number that goes backwards is a misread; where these and the hand-read pages overlap they never disagree. The remaining 150 are interpolated between anchors, across stretches where the chapter gap and the page gap agree and the sheets are therefore running one page per chapter. Interpolation stops at any page whose own text names a different chapter, and never overwrites a page somebody read.
Interpolated pages are shown as cp06 ~p201, with a tooltip saying so, because they are a good place to start and not a citation: held out against the hand-read anchors the method predicts 24 of 25 exactly, and the miss (chapter 158) lands four pages off. 286 chapters are located in total; one with no page still says so rather than guessing.
Clicking a contact isolates its net. The rest of the rack goes dark and only the contacts wired to the same signal stay lit, so a wire reads as a shape rather than as a list of positions; the read-out names the other ends and links to them, and the coarse layer outlines the positions carrying it so the far end is findable from zoomed out. Members are gathered on a canonical spelling — the schematics' name where the index knows it, otherwise the reading with O/0 and I/1 folded together — because the same wire can be read two ways at two pins. Clicking off a contact lets the net go.
Pin 17 is the zero rail on every board. The layout leaves it blank at 613 of the 619 populated positions because it is not a signal anyone routes; at the six where the scan did read something it says ZERO0, the same rail. It is drawn in a cooler tint and reported as GND everywhere, and picking one lights pin 17 across the rack rather than outlining all 619 positions.
Double-clicking a position — anywhere on it but a contact — opens the board plugged in on the other side, the same sheet the front view gives. It works at any zoom, including fitted, where no contacts are drawn at all.
The option sockets are drawn as what is in them. Columns 3, 4 and 5 of rows E and F are the OPTION sockets — the Atlas prints their type as ****** (OPZIONE) and gives them the two or three strap signals the ch.001/ch.002 tables read. What card sits in each is a property of this machine rather than of the layout, so it comes from ge_init in ge.c, which is where the emulator already keeps it: E03/F03 and E05/F05 hold PONT bridge cards, and column 4 is empty — itself a setting, since the tables read the absent bridges as the other variant. A PONT sits in the same blue handle as any other card, so it is drawn as an ordinary single-row board — its face carries PONT2N or PONT2P in place of a part number, which is the one thing about it worth reading. The two positions ge.c calls empty get a dashed outline.
The other twenty option sockets — Q28–31, R28–31, S26–31, T26–31 — are in the memory rows, which are laid out for the largest build and marked OPZIONE below it. Whether they are populated is therefore a function of the capacity strap, not of the layout, and this machine straps the 32K row, so they are filled.
Which card is in each comes from the workbook, which names them where the Atlas CSVs are blank: 0610002J ×8 across Q/R 28–31, 0610029W ×8 at S/T 26–29 and 0610030U ×4 at S/T 30–31. All three are dual-slot, so the fitted pairs span their tier like their neighbours. (The generator can also recover a socket's card from its pin shape — the signal names with the digits masked, matched against the named positions in its own row — which reaches the same answer independently and stands in wherever the workbook is silent.)
Every board sitting in an option socket — the PONT straps included — carries EXP on the green label at its foot, so the cards that are there because of the build rather than always are readable off the cage. Fourteen boards are marked: E3/E5 and F3/F5, Q+R 28–31, and S+T 26–31.
A socket that is neither strapped nor confidently named would be drawn in neutral slate — neither board nor empty — but on this machine there are none.
Their sheet points at the strap documentation instead of a part number they do not have: cp06 p78 (TAB.1, memory capacity — the {PONT2N, PONT2P} row that makes this machine 32K), cp06 p79 (version, cycle period, interruptions, loading) and cp10F p253, the PONT card's own catalogue drawing. All three are located rather than hardcoded — p78 by being the only cp06 page printing VAMC2, p79 through the chapter index at ch.002, and p253 by the drawing number 015 433 91 that ge.c cites.
The filter boards are naked too, and single. FILT2A/FILT2B/FILT2C and their kin sit one per row — never a pair spanning a tier — with no blue handle and a screw holding them top and bottom. Eighteen of them: slot 1 across the AB/CD/EF/QR/ST tiers, slot 5 across GH/IL/MN, slot 7 across OP. The scans read I as 1, so the same card is typed FILT2B at one position and F1LT2B at the next; the test folds the digit back, without which G5 and H5 — one card either side of a tier — render as two different things. The workbook writes either CONN or FILTRI over these positions and both mean a filter, so the label is accepted as well as the type.
The COCA positions stay as the Atlas has them even though the workbook is silent there: the looms were unplugged when the machine was surveyed, which is why that survey has nothing to record.
Both cables leave the middle of the board face — they are the board's own conductors carrying on, not something plugged into its top — and run to the side of the machine. The frame is drawn — broad uprights either side, the cross-bars that run under rows D, H, N and P, a thinner bar closing the top of the cage, and above that the cabinet's own cover: a deep dark blue band, the console front's #5a7bb3 taken down to what the top of the machine reads as, with the light catching its leading edge. It overhangs the cage on both sides because it is the width of the whole machine, and the side panels that would fill that width are not in this view. That last one breaks the rhythm: the bars would otherwise fall every two tiers, but P sits one tier lower down the run because the core stores stand in the rows beneath it and the bar has to clear them. With the frame in place the difference between the two cables is visible: the COCA loom, a heavy multi-way cable, passes behind the upright and carries on out of sight, while the filter's thin lead ends there, on the 5V / 20V / 12V rails the frame hides, with a lug where it lands. (One photograph shows a COCA loom hanging out in front of the cage, but that is a bench arrangement, not how it sits.)
The row letters are inked on. They are not printed anywhere on the machine — somebody went down the right-hand upright with a dark blue marker and wrote them — so they are drawn as that. Setting them as text would put whatever face the browser happens to have on a hand-lettered panel (and headless has no script font at all), so each letter is stroked instead: single-stroke letterforms in a 10×14 box, laid down with a round nib, each at its own slight tilt and offset, with the bleed the felt leaves in the metal around it.
A position is free when nothing is wired to it, whatever the type cell says. The scans drop junk in that cell now and then — I22 reads HUH and is annotated FREE slot — so the test is what is actually there: no part number, and not a wire on any pin. It changes exactly one position and flips no other.
COCA positions are drawn naked. Thirty positions along the edges of rows G to N carry no part number on any layout page, and neither catalogue lists them: a COCA is not a circuit card but the connector the cable loom lands on, drawn on cp06's connector sheets (p80–84). The front view gives them a bare board with no blue handle, running straight into thick cables that bend away to the nearer side of the panel, and their sheet offers the connector sheets in place of a catalogue entry. A COCA is one card per row and never a pair spanning a tier, even where both rows of a column carry one — so each gets its own cable.
What is framed is the scan, not the explorer. ge120.xyz renders its PDFs client-side and routes on #/<volume>/<page>, but it does not apply that route inside a frame — it comes up on "pick a manual" however the src is set, which is reproducible headless with and without virtual time. The PDFs themselves are served plainly and honour byte ranges, so the sheet frames manuals/<file>#page=N and the browser's own viewer opens the one page. The "open in the manual explorer ↗" link still goes to the explorer, which is the better place to navigate on to contents, thumbnails and search.
The data is baked by console/wasm/gen-backplane.py into backplane.js, which is committed because the Atlas CSVs live outside this repo. The generator reads two independent sources and says so when they differ: the Atlas names the signal at a position, and the Backplane columns and traces in docs/signals/ place signals at positions. They agree at 760 of the 766 pins both describe; where they do not, the read-out flags it rather than picking a winner.
Each procedure is taken from the original manuals and is reproduced verbatim in gemu's tests. Confidence is high where a regression test passes.
Source: CPU[4] §3.3 / §5.3 (fo.31–32, fo.43). Confidence: high.
In gemu this is exactly what ./ge --deck funktionalcpu.cap does (main.c:192): ge_load_1 → ge_load → attach the deck to the reader on connector 2 → run. The natural 00 → 80 → c8 → alpha bootstrap leaves the entry address as the machine defines it.
Source: CPU[4] §3.3 (STEP-BY-STEP) + §4 (PAPA). Confidence: high.
During step-by-step the address (PO) and function code (FO) of the next instruction are displayed (CPU[4] §3.3).
Source: CPU[4] §4.2 rotary pos 8 / pos 9; reproduced as cpu_isolation.test_k ("diag fo.82"). Confidence: high.
INAR is inserted so writing into never-before-written memory does not raise MEM CHECK / INV ADD.
Source: CPU[4] §4 "Maintenance Panel", dwg 30004122 fo.35–37; reproduced as cpu_isolation.oper_call_by_register_forcing. Confidence: high (validated on gemu against the real-machine procedure).
This keys a 2-character LON instruction (opcode 0x02, second char 0x80) straight into the CPU registers and single-steps it through every fetch phase until it executes and raises OPER CALL.
Key fidelity point (gemu ge.c:fsn_last_clock): a forcing cycle preserves the program sequencer SO — only forcing SO itself (pos 13) changes it. Without this, each register-force would clobber the sequencer and the phase walk could never complete. This was the bug fixed in commit *"preserve the program sequencer
during console forcing (CPU[4] fo.35-37)"*.
Source: CPU[4] §4.2 (fo.36). Confidence: medium (display path verified; "non-disturbing" guarantee relies on the delay line still clocking the LSM).
Because the rotary only forces on START, simply turning it to a register and reading the lamps is non-destructive.
| Behaviour | gemu status |
|---|---|
| CLEAR / LOAD / START / LOAD1-2 bootstrap | implemented (§6.1) |
| PAPA step-by-step + STEP_BY_STEP lamp | implemented (§6.2) |
| Rotary force/display, SO-preserving forcing | implemented (§6.3, §6.4) |
OPER CALL via keyed LON | implemented + regression-tested (§6.4) |
INAR inhibits the error stop during forcing | exercised by test_k; full stop-on-fault model partial |
**STEP-BY-STEP (ASIN) and PAPA are independent circuits** | implemented — only ASIN lights the lamp and only ASIN is inhibitable by INS; tests console_fidelity.step_by_step_and_papa_are_separate, …_stops_earlier_than_the_program_end (§3) |
**INS inhibits step-by-step; ENS/STOC re-enable** | implemented — state_E2_E3_TO80_CI89 gates ASIN by STOC \|\| !ADIR (CI77/CI78) |
SWITCH 1 / SWITCH 2 lamps ← JS1/JS2 | implemented — console.c; test console_fidelity.switch_lamps |
| PATE (single delay-line-cycle step) | implemented — fsn_last_clock halts after every delay-line cycle; test console_fidelity.pate_single_cycle |
ACOV / ACON jump-condition stop | implemented in CI38 (AVER && ACOV, !AVER && ACON); verified by inspection |
**INCE parity forcing (AM08 as check bit)** | implemented — pulse.c stores AM08 as the parity bit during V1-SCR forcing; test console_fidelity.ince_forces_check_bit |
SITE (ignore peripheral availability) | partial — open |
| Keys reach the machine over the console socket | implemented — console_socket.c parses the client frame and dispatches CLEAR / LOAD1-2 / LOAD / START edge-triggered; tests console_socket.*. Before this the ncurses client's key presses were received and discarded. |
**LOAD arms only; START reads one card** | implemented and regression-tested — bootstrap.card0_loads_to_alpha compares all 40 bytes against the deck's own loader card |
The one remaining open item, SITE (don't wait for peripheral availability), reaches into the peripheral handshaking rather than the console proper, and is the next target.