One-bit Computing at 60 Hertz

LE logo

This page describes a tiny computer made from an EPROM and a few logic chips. Although its specifications are ridiculously modest, the machine readily satisfied application requirements.
  • Clock Rate: 60 Hertz
  • Instruction Repertoire: 1
  • Registers: 1 (a one-bit status Flag Bit)
  • I/O-mapped memory (not memory-mapped I/O) — 2 bits
This is a design I came up with in response to a customer's request to add some new automated functions to a printing press. The new behavior might reasonably have been achieved using hardwired counters, gates and flip-flops, but I wanted to use programmable logic instead. (Later, when additional presses were modified, I switched to using a microcontroller.)

schematic of one-bit computer
click to enlarge

This is not a Motorola MC14500 computer, but it was the MC14500 that introduced me to the idea of one-bit computing. Exploring ways to reduce the chip count, a series of pencil & paper designs revealed the MC14500 itself could be omitted! Its tiny complement of 16 instructions was actually overkill.

In contrast to the 14500's 4-bit op-code, my design uses no op-code at all. That's because there's only one instruction and it executes endlessly. That instruction includes two functions. One is an Input Test whose result controls a two-way branch, and the other is an Output operation that writes 1 or 0 to any of the bits in the output port (a 4099 addressable latch). For the printing press application the inputs were driven by mechanical switches and by a pair of logic signals from the original press wiring. The outputs drove Solid State Relays which, in turn, activated solenoids.

instruction format

There's an unvarying, two-phase cycle. Each phase fetches a byte from the EPROM.

  • The byte fetched in Phase One has several fields. There's a 1-bit and a 3-bit field which together control the Output operation, and a 3-bit field that controls the Input Test. Bit7 is unused.

  • The byte fetched in Phase Two has only a single, 8-bit field. This field specifies one of 256 Jump (branch) Destinations.

There's a wrinkle, and it's that each of the 256 destinations is organized to hold four bytes, not two. This is evident on the schematic. The Jump Destination Register drives eight EPROM address inputs, the lowest of these being A2. But A1 of the EPROM is driven by Phase Two, and A0 is driven by the so-called Flag Bit (which contains the result of the Input Test that occurs on every instruction). When the Flag Bit is true, "true" instruction bytes will be fetched (ie; with EPROM A0 =1). When the Flag Bit is false, EPROM A0 will =0 and "false" instruction bytes will be fetched.

That is the basis of the two-way branch mentioned earlier. The Input Test during Phase One selects one of the eight inputs to the 4051 mux, and that input's value is clocked into the Flag Bit at the start of Phase Two. During Phase Two, the Jump Destination is fetched, and the fetch will occur either with EPROM A0 =1 or =0, depending on the state of the 4051 input that was tested. Thus two different jump destinations can result.

The machine always jumps from one instruction to the next. It doesn't know how to "fall through" to the "next" address because it has no program counter and no ability to count (compute an increment). Thus you won't reduce execution time or program size if you choose to arrange conditional branches in the usual way;   ie, "branch, else fall through to the instruction at address+1."   Computers that have a program counter can use Address+1 as an implicit default. But nothing is implict with this machine — there are always two explicit jump addresses, one for each outcome of the condition test. It's possible to write some really nutty code! That said, instructions generally do tend to get stored in sequential order, and, as a matter of coding style, conditional branches very often do specify address+1 as one of the outcomes. The assembler makes it easy to use the familiar branch, else fall through to the instruction at address+1 arrangement.

As mentioned, every instruction includes both an Input/branch operation and an Output operation. That can be powerful, but the programmer mustn't be forced to do both every time. When only one operation is required there needs to be a way to omit or neutralize the other.

An unwanted Input/branch operation is neutralized by testing any input (it doesn't matter which) and making both branch destinations the same. Only the Output portion of the instruction will have any meaningful effect.

As for neutralizing an Output operation, one bit (Q7) of the 4099 addressable latch is left unconnected for this exact purpose. It is reserved as a Write-Only-Memory! In other words, when you want the Output operation to be a NOP, you code it to write to Q7. It doesn't matter whether you write a 1 or a 0. Q7 goes nowhere, leaving only the Input/branch portion of the instruction with any meaningful effect.

This computer has no RAM as such, making it awkward if you need to store a bit of information. One approach is to simply branch the program into two paths, based on the status of the bit you need to remember. But, for long-term storage, a better approach is to write the bit to one of the dedicated 4099 outputs which connect back to 4051 inputs. This allows the stored information to be read back when needed. (The schematic shows two such I/O-mapped memory bits.)

In the printing press application, one of the memory bits is used to guide subroutine returns. There are two main parts to the program, and they share a few subroutines. At the exit of each subroutine, a memory bit (previously prepared by the caller) is tested to see which of two return addresses to jump to.

Also notable on the schematic are an RC filter to de-glitch the input line, and a Reset circuit that forces the EPROM to select a shadow array filled entirely with unconditional "Jump to Start" instructions.

The clock oscillator can easily be replaced by a square wave derived from the AC power line. Of course this computer is capable of running a lot faster than 60 Hz, but 60 Hz is plenty fast enough for this application. I chose the low operating frequency merely because it simplified implementation of a software time delay.

Two sections are unused on the lower 74C374 register. This means a 74C174 could replace the '374, reducing space requirements. Alternatively, one of the 374's unused sections could capture the unused bit from the EPROM, providing an extra address line to double the machine's Input or Output space via an additional 4051 or 4099.

Servicing the Unserviceable
extra (main index)   — for registerheads only
copyright notice (Jeff Laughton)