univac.1004
Operator's Manual · Plate I

UNIVAC 1004 · programmed by wiring.

The 1004 has no software, no instruction set, and no memory in which to hold either. To program it, you wire it. This manual is a complete guide to the emulator's plug-board, its primitives, and the half-dozen idioms that 1962-vintage operators used to make a machine without code add up a column, count a deck, multiply by repeated addition, and print a header report.

Manual no.
I · 1st ed.
For emulator
UNIVAC 1004 · plug-board reconstruction
Reading time
~30 minutes end-to-end
Audience
Operators new to plug-board programming
§ I

The machine.

The UNIVAC 1004 was introduced by Sperry-Rand in 1962 and stayed in service through the early 1970s. It is sometimes described as a small computer, but that is not quite right. The 1004 has no addressable memory, no opcodes, no program counter, and nothing resembling a CPU register file. What it has is an electromechanical card path, a 132-column drum printer, four BCD counters, four selector flip-flops, and a removable plug-board: a panel of perhaps four hundred patch-cord jacks at which the operator physically wires together the machine's data paths.

A program for the 1004 was a particular pattern of patch cords. To install a program was to remove one plug-board and slot in another. A library of programs was a library of physical objects — payroll on Tuesday's board, billing on Wednesday's, inventory on Thursday's. Programmers were called wiremen.

The 1004 has no software. It has wiring. The two are not the same thing.

Despite this, the 1004 was an industrial workhorse. Through most of the 1960s it computed payroll for the United States Army, processed inventory for Westinghouse, and printed insurance statements for Mutual of Omaha. What it could not do — multiply two numbers directly, sort more than the deck the operator had pre-sorted, branch on arbitrary conditions — it accomplished by clever wiring of the four counters, four selectors, and thirty-one program steps that the plug-board makes available.

The emulator preserves this conceptual model deliberately. There is no source-code editor, because there was no source code. There is no instruction trace, because there were no instructions. There is, instead, a thirty-one-row table representing the plug-board, a field-definition table representing the named-bus assignments, and a live overlay that draws the active patch cord on every machine cycle in a glowing curve so that you can see what your wiring actually does.

§ II

The card cycle.

Everything the 1004 does happens inside a card cycle. A card cycle begins when a fresh card is read from the hopper into the read buffer, runs the program steps top to bottom (one by one, fast), and ends when one of the steps fires a NEW-CARD sequence action. At that point the print buffer is ejected as a printed line, the punch buffer (if used) is punched as an output card, and the next card is read in. The step counter resets to step 1 and the cycle begins again.

A program is therefore a recipe for one card cycle, run repeatedly. There is no outer loop and no main function. The repetition is built into the machine.

READ CARD into card buffer RUN STEPS 1 — 31 in order, top-to-bottom, until NEW-CARD or HALT EJECT print buffer → printed line punch buffer (opt.) EOF? if hopper empty, latch EOF if not EOF — repeat with next card ONE CARD CYCLE
Fig. 1 The card cycle. Each cycle reads a card, runs program steps, ejects buffers, and (if the hopper still has cards) repeats.

Fields are named buses

The 1004 reads cards as raw 80-column strings of 6-bit BCD characters. To do anything useful with that data you have to tell the machine which columns mean what. That is the job of the field-definition table: it lets you declare up to eight named fields (FLD-A through FLD-H) by their column ranges on the card, the print drum, and the punch deck.

A field definition has five slots:

SlotMeaning
LengthNumber of card columns the field occupies, 1 to 60-something. Required.
Card ColFirst card column to read. 1-based. Set to 0 if the field is not sourced from the card (a counter-display field, for instance).
Print ColFirst print column to write to when the field is used as a print destination (Print A, etc.). 1-based.
Punch ColFirst punch column to write to when the field is used as a punch destination (Pu A, etc.). 1-based.
Literal TextA constant string. If Card Col is 0 and this is non-empty, the field's source reads this literal — useful for printable labels like TOTAL = .

A field is a name for a piece of data, plus instructions for where on the printer or punch its contents should land. Field A might be a 3-character HOURS field that reads card columns 1–3 and prints at print column 5. Field B might be a 5-character TOTAL field that doesn't read from the card (Card Col = 0) but writes to print column 35 with the literal text TOTAL = . The same field name may be used as both a source and a destination in different program steps.

§ III

The program step.

The plug-board has thirty-one program steps. Each step is a single row of the program table. A step has seven slots, and they answer seven questions in order:

07 no EOF FLD-A ADD CTR-1 NEXT STEP COND SOURCE OP DEST SEL SEQ ARG Read as: "On step 7, while there's a card in the hopper, add Field A to Counter 1, then advance to step 8."
Fig. 2 The seven slots of a single program step. Each step is one full row of the plug-board table.

Reading a step is a left-to-right exercise in answering questions. Cond: when should this step fire? Src: what data hub do we read from? Op: what do we do with that data? Dst: where do we send the result? Sel: (only for compares) which selector should I set? Seq: what happens after this step finishes? Arg: the argument to the sequence action — the target step number for a JUMP, ignored otherwise.

The condition gates the whole step

If the step's condition is false, the entire step is skipped — no transfer, no sequence action — and execution falls through to the next step. This is important: a row whose sequence is NEW-CARD but whose condition is false will not fire the new-card action. The condition gates everything.

The default sequence is NEXT, which simply advances to the following step. Most rows in a typical program use NEXT. The interesting sequences are the ones that change the flow: JUMP, NEW-CARD, PRT-LINE, HALT.

Convention The literature reads steps as imperative sentences. A step with cond=NEOF, src=Field A, op=MOV, dst=Print A, seq=PRT-LINE reads as: "While there's a card in the hopper, copy Field A to its print column, then eject the line." Get used to this voice; it's how the rest of this manual writes them.
§ IV

Reference tables.

These five tables enumerate every primitive available in the emulator. Bookmark this section. You will scroll back to it constantly while writing your first few patch-boards.

Sources — what a step reads from

CodeNameProvides
OFFNo sourceUse when the step exists only for its sequence action (e.g. an unconditional JUMP or a trailer HALT). No data is transferred.
FA – FHField A — HThe field's contents. If the field has a non-zero Card Col, the data comes from that range of columns of the current card. If Card Col = 0 and the field has Literal Text, the literal is provided. Otherwise, blanks of the field's length.
C1 – C4Counter 1 — 4The current 5-digit BCD value of the counter, sign and all.
ZEROZerosThe 5-character string "00000". Useful for resetting a counter (with MOV) or zero-padding a print field.
BLANKBlanksFive spaces. Useful for blanking a region of the print buffer between lines.
E1 – E9Digit emitterA 5-digit BCD constant equal to the digit suffix: E1 emits "00001", E5 emits "00005", and so on. The standard idiom for incrementing a counter by one is src=E1, op=ADD, dst=Cn.

Operations — what a step does

CodeNameBehavior
MOVMoveCopy the source bytes into the destination, replacing whatever was there. The classic way to load a counter, write a print field, or copy data between fields.
ADDAddBCD-add the source value to the destination's current value. Only meaningful when the destination is a counter; using it on a print field treats the print buffer as a numeric region, which is rarely what you want.
SUBSubtractBCD-subtract the source from the destination. Underflow wraps without flagging an error.
CMPCompareCompare the source value to the destination's current value (the destination is read, not written). Sets the EQ / LT / GT flags so that subsequent rows can branch on them. If the Sel slot is set to S1S4, also latches that selector. Does not modify the destination.

Destinations — where the result goes

CodeNameEffect
OFFNo destinationUse for sequence-only rows or for compares that don't need a particular destination. The transfer is a no-op.
PA – PHPrint A — HWrite to the print buffer beginning at the field's Print Col. The print buffer is 132 columns wide and is ejected by a PRT-LINE or implicitly by NEW-CARD.
PuA – PuHPunch A — HWrite to the punch buffer beginning at the field's Punch Col. The punch buffer is ejected by PCH-CARD.
C1 – C4Counter 1 — 4Target the corresponding 5-digit BCD counter. MOV sets it; ADD/SUB accumulate into it; CMP reads it.

Conditions — when a step fires

CodeTests
AlwaysStep always fires.
S1 ON / S1 OFF
… S4 ON / S4 OFF
Tests the corresponding selector flip-flop (set by a previous CMP or by an explicit selector set).
EQ / NEThe most recent CMP resulted in equality (or did not).
LT / GTThe most recent CMP resulted in source < destination (or >).
EOFA read past the last card has occurred — we are now on the trailer cycle.
no EOFA card was successfully read for this cycle.
C1 = 0 … C4 = 0The counter currently holds zero.
C1 ≠ 0 … C4 ≠ 0The counter currently holds a non-zero value.

Sequences — what happens after the step

CodeNameEffect
NEXTNext stepAdvance to step n + 1. The default for any row that doesn't say otherwise.
JUMP nJumpJump to step n in the same card cycle. The Arg column holds the target step number. Cycles can contain many jumps; the cycle ends only on NEW-CARD or HALT.
PRT-LINEPrint lineEject the current print buffer as one printed line, then advance to the next step. The print buffer is cleared after ejection.
PCH-CARDPunch cardPunch one card from the current punch buffer, then advance. The punch buffer is cleared.
NEW-CARDNext cardEject any pending print buffer, punch any pending punch buffer, read the next card from the hopper, and restart at step 1. If the hopper is empty, latch EOF and run the trailer cycle.
HALTStopStop the processor. The COMPLETE light comes on. There is no "go again" — to run the program a second time you reload the hopper and press RUN.
§ V

Counters & selectors.

The 1004 has eight pieces of stateful hardware that programs can read and write: four counters and four selectors. Everything else — the card buffer, the print buffer, the punch buffer, the EOF latch, the comparison flags — is either transient or driven by the machine itself. The counters and selectors are the entire user-accessible state of a 1004 program.

Counters

A counter is a 5-digit signed BCD register. There are four of them, addressed C1 through C4. They are initialized to +00000 when the program starts and are not cleared between card cycles. Anything you accumulate into them stays there.

Operations on a counter are exactly what you would expect: MOV ZERO → C1 resets it. MOV C1 → Print A places the counter's current value into the print buffer at field A's print column. ADD FA → C1 adds field A's value to the counter — this is the standard accumulator pattern. SUB E1 → C1 decrements the counter by one. CMP C1 → C2 compares two counters and sets the comparison flags.

The most useful conditions on a counter are C1 = 0 and C1 ≠ 0. These let you implement loops without setting up a comparison every iteration. The repeated-add multiplication pattern (§ VI) uses a counter as its loop variable: load HOURS into C2, then loop while C2 ≠ 0, adding RATE to C1 and subtracting E1 from C2 on each pass.

Selectors

A selector is a single-bit latching flip-flop. There are four of them, named S1 through S4. Each is either ON or OFF. They start OFF. Selectors are latching: once set, they keep their value until something explicitly changes them.

Selectors are set by the Sel slot of a CMP step. The slot chooses which selector to set, and the comparison result determines whether to set it ON or OFF, by these conventions:

SelSets ON when
S1source < destination ("low")
S2source = destination ("equal")
S3source > destination ("high")
S4source ≠ destination ("unequal")

Subsequent rows test selectors via the Cond slot: S1 ON, S2 OFF, and so on. The classic use is a group break: compare the current group code (a card field) to the saved one (a counter holding the previous cycle's group code). Set S2 on equal. On the next row, run the detail-print logic only if S2 ON; otherwise run the subtotal-line logic and reset.

Selectors are also used for once-only logic — a header line printed only on the first card, for instance. The trick is to use a counter as a poor man's flag: a C3 = 0 condition gates the header rows on the first cycle, and at the end of the header you bump C3 with E1 ADD C3. From the second cycle onward, C3 is non-zero and the header rows are silently skipped. This idiom appears in the FORMAT sample (§ VII).

§ VI

Common patterns.

Six idioms cover most of what 1004 operators wrote. Internalize these and the rest of plug-board programming is composition.

The accumulator

Sum a numeric field across all cards into a counter. After EOF, print the total.

ACCUMULATORPATTERN-1
  ROW  COND   SRC   OP   DST    SEQ           NOTES
    1  NEOF   FA    ADD  C1     NEXT          accumulate the field
    2  NEOF   FA    MOV  PA     PRT-LINE      echo the detail line
    3  NEOF   —     —    —      NEW-CARD      advance
    4  EOF    C1    MOV  PB     PRT-LINE      print total at field B
    5  EOF    —     —    —      HALT

The counter

Count the number of cards processed using a digit emitter as the increment.

CARD COUNTPATTERN-2
  ROW  COND   SRC   OP   DST    SEQ
    1  NEOF   E1    ADD  C2     NEXT          count++
    2  NEOF   —     —    —      NEW-CARD
    3  EOF    C2    MOV  PA     PRT-LINE      print count
    4  EOF    —     —    —      HALT

Multiplication via repeated add

The 1004 has no MUL instruction. To multiply HOURS × RATE, initialize a result counter to zero, load HOURS into a loop counter, then loop: add RATE to the result, decrement the loop counter, and exit when the loop counter reaches zero.

HOURS × RATE = GROSSPATTERN-3
  ROW  COND   SRC   OP   DST    SEQ      ARG  NOTES
    1  NEOF   ZERO  MOV  C1     NEXT          gross = 0
    2  NEOF   FA    MOV  C2     NEXT          loop = HOURS
    3  C2=0   —     —    —      JUMP     7    exit when done
    4  Always FB    ADD  C1     NEXT          gross += RATE
    5  Always E1    SUB  C2     NEXT          loop--
    6  Always —     —    —      JUMP     3    retest
    7  NEOF   C1    MOV  PC     PRT-LINE      print gross
    8  NEOF   —     —    —      NEW-CARD

This is the canonical 1962 form. Operators were paid by the hour and the 1004 paid them one addition at a time.

Once-only logic (the header trick)

Print a header line only on the first card. Use a counter as a flag: gate the header rows on C3 = 0, then bump C3 at the end of the header.

HEADER ONCEPATTERN-4
  ROW  COND   SRC   OP   DST    SEQ           NOTES
    1  C3=0   FH    MOV  PH     PRT-LINE      FH = literal "REPORT"
    2  C3=0   E1    ADD  C3     NEXT          mark header-printed
    3  NEOF   FA    MOV  PA     NEXT          detail line begins
    ...

Group break (control break)

When a sorted deck contains group codes, you often want a subtotal line each time the group changes. Save the previous group's code in a counter, compare each new card's group code against it, and use a selector to detect change.

GROUP BREAKPATTERN-5
  ROW  COND     SRC   OP   DST   SEL  SEQ      ARG  NOTES
    1  NEOF     FA    CMP  C4    S2   NEXT          S2 = (group == prev)
    2  S2 OFF   C1    MOV  PE    —    PRT-LINE      break: print subtotal
    3  S2 OFF   ZERO  MOV  C1    —    NEXT          reset subtotal
    4  NEOF     FA    MOV  C4    —    NEXT          save current group
    5  NEOF     FB    ADD  C1    —    NEXT          accumulate detail
    ...

The trailer (post-EOF processing)

The trailer is whatever runs after the last card has been read. The EOF latch is set just before the trailer cycle, so any rows with cond = EOF become the trailer routine. Always finish with an EOF-conditioned HALT; otherwise the program may loop on the trailer indefinitely.

§ VII

Worked examples.

Six sample plug-boards ship with the emulator. Each is short enough to read in full and each demonstrates one or two patterns from § VI. Load any of them with the Load Sample dropdown.

ECHO — print every card

The minimal program. Defines one 60-character field, prints it, advances. Three rows total. The "hello world" of plug-board programming.

ECHOSAMPLE-1
  Field A: len=60, cardCol=1, prtCol=5

  ROW  COND   SRC   OP   DST   SEQ
    1  NEOF   FA    MOV  PA    PRT-LINE
    2  NEOF   —     —    —     NEW-CARD
    3  EOF    —     —    —     HALT

TOTAL — sum a numeric column

Reads a 5-digit amount from cols 1–5, prints each detail, accumulates a grand total into C1, and prints TOTAL = nnnnn after EOF using a literal-text field for the label. With the shipped card data (125, 250, 75, 1000, 500) the trailer reads TOTAL = 01950.

MULTI — multi-field invoice listing

Three fields per card: a 4-character ID, a 20-character NAME, and a 5-digit AMOUNT. Each detail line prints all three. The trailer prints a grand total. Demonstrates the common case where one card produces one printed line.

GROUPS — card count and grand total

Each card has a 2-digit GROUP code and a 5-digit AMOUNT. Counts cards into C2 using E1 ADD C2, accumulates totals into C1, and prints CARDS = nnnnn and TOTAL = nnnnn in the trailer. The simplest use of the digit-emitter primitive — E1 as a +1 source is the canonical way to count.

PAYROLL — multiplication via repeated add

The headline sample. For each card, multiplies HOURS × RATE by repeated addition (Pattern 3) and prints NAME   GROSS = nnnnn. With the shipped cards (40 × $25, 35 × $30, 20 × $15) the gross-pay column reads 01000, 01050, 00300. This is real 1962 math: forty additions to compute one multiplication.

FORMAT — header, detail, trailer

The most elaborate sample. Demonstrates Pattern 4 (header-once via C3 = 0), a card count via E1 ADD C2, a grand total via FB ADD C1, and a two-line trailer that prints both COUNT = nnnnn and TOTAL = nnnnn from literal-text fields. Six fields, fourteen program steps, and produces a recognizable 1968-style report.

§ VIII

Limits & gotchas.

A few things to know before they bite you.

The 31-step limit is real

A real 1004 plug-board has thirty-one program steps and there is no software upgrade that will give you a thirty-second. If a program won't fit, you must factor it: write the deck out via PCH-CARD with intermediate results punched in unused columns, then re-run the deck through a second plug-board that completes the work. This is how the 1962 operator got around the limit, and it's also why card-handling speed mattered as much as logic speed.

BCD decimal, not binary

All arithmetic is BCD on 5-digit signed quantities. There is no binary, no floating-point, and no bit-manipulation. Counter overflow at ±99999 wraps silently. You cannot store a flag in a counter as bit 0 — counters are decimal-coded five characters wide.

One source, one destination, one operation per step

Each row of the plug-board is a single transfer. You cannot, in one step, simultaneously add field A to counter 1 and field B to counter 2. That requires two rows. This sounds obvious but the temptation to write a "fat" row is real, especially when you're tight on the 31-step budget.

Conditions gate the entire step

A row whose condition is false skips both its data transfer and its sequence action. This is different from the historical machine, where the sequence wires fired regardless of the condition wires. The emulator chooses the more conventional flow because it makes loops and trailers easier to reason about. If a step needs to fire its sequence unconditionally, set its condition to Always and use a no-op OFF → OFF transfer.

The trailer must HALT

The card cycle does not naturally stop after EOF. If your trailer rows do not end with a row that fires HALT under cond = EOF, the program will continue running the EOF cycle forever. (The emulator caps it at a reasonable instruction count to avoid hangs, but the right discipline is always to provide an explicit halt.)

Differences from the historical machine

The emulator simplifies a few things that the real 1004 did differently. The historical plug-board had hundreds of named hubs, not eight fields; there were dedicated digit emitters at every counter input, not a generic E1–E9 source pool; and the real machine could read, compute, print, and punch in parallel within one cycle. The emulator's logic is sequential within a card cycle, which is a fair simplification given that most 1004 programs never relied on the parallelism. The conceptual model — fields, sources, destinations, conditions, sequences, counters, selectors — is faithful.

A historical note The 1004 stayed in service well into the era of stored-program computing because of the physical robustness of plug-boards: a working program could not be corrupted by a memory fault, could not be lost in a head crash, and could be carried under one arm. When you install a 1004 plug-board, the program is the wiring. There is no software layer between the operator and the machine.