Before 1955, the control logic for central processing units was designed by ad hoc methods. One of the simplest was to use rings of flip-flops to sequence the computer's control logic.
In 1955 Maurice Wilkes had a fundamental insight. He realized that if one takes the control signals for a computer, one could understand them as being played much like a player piano roll. That is, they are controlled by a sequence of very wide words constructed of bits.
A microprogram provides the bits to control these. The fundamental advance is that CPU control becomes a specialized form of a computer program. It thus transforms a complex electronic design challenge (the control of a CPU) into a less-complex programming challenge.
To take advantage of this, computers were divided into several parts:
A microsequencer picked the next word of the control store. A sequencer is mostly a counter, but usually also has some way to jump to a different part of the control store depending on some data, usually data from the instruction register and always some part of the control store. The simplest sequencer is just a register loaded from a few bits of the control store.
A register set is a fast memory containing the data of the central processing unit. It may include the program counter, stack pointer, and other numbers that are not easily accessible to the application programmer. Often the register set is triple-ported, that is, two registers can be read, and a third written at the same time.
An arithmetic and logic unit performs calculations, usually addition, logical negation, a right shift, and logical AND. It often performs other functions, as well.
Together, these elements form an "execution unit." Most modern CPUs have several execution units. Even simple computers usually have one unit to read and write memory, and another to execute user code.
The parts of the execution units, and the execution units themselves are interconnected by a bundle of wires called a bus.
Programmers develop microprograms. The basic tools are software: A microassembler allows a programmmer to define the table of bits symbolically. A simulator program executes the bits in the same way as the electronics (hopefully), and allows much more freedom to debug the microprogram.
A typical micromachine's control word has a field, a range of bits, to control each piece of electronics in the CPU. For example, one simple arrangement might be:
| register source A | register source B | destination register | arithmetic and logic unit operation | type of jump | jump address |
For this type of micromachine to implement a jump instruction with the address following the jump op-code, the microassembly would look something like:
# Any line starting with a number-sign is a comment # This is just a label, the ordinary way assemblers symbolically represent a # memory address. InstructionJUMP: # To prepare for the next instruction, the instruction-decode microcode has already # moved the program counter to the memory address register. This instruction fetches # the target address of the jump instruction from the memory word following the # jump opcode, by copying from the memory data register to the memory address register. # This gives the memory system two clock ticks to fetch the next # instruction to the memory data register for use by the instruction decode. # The sequencer instruction "next" means just add 1 to the control word address. MDR, NONE, MAR, COPY, NEXT, NONE # This places the address of the next instruction into the PC. # This gives the memory system a clock tick to finish the fetch started on the # previous microinstruction. # The sequencer instruction is to jump to the start of the instruction decode. MAR, 1, PC, ADD, JMP, InstructionDecode # The instruction decode is not shown, because it's usually a mess, very particular # to the exact processor being emulated. Even this example is simplified. # Many CPUs have several ways to calculate the address, rather than just fetching # it from the word following the op-code. Therefore, rather than just one # jump instruction, those CPUs have a family of related jump instructions.
The above is an example of "horizontal" microcode. This is microcode that sets all the bits of the CPU's controls on each tick of the clock that drives the sequencer.
Note how many of the bits in horizontal microcode contain fields to do nothing. Some CPUs use a completely different design called "vertical" microcode to reduce cost. Some vertical microcodes are just the assembly language of a simple conventional computer that is emulating a more complex computer. This technique was popular in the time of the PDP-8. Another form of vertical microcode has two fields:
| field select | field value |
The "field select" selects which part of the CPU will be controlled by this word of the control store. The "field value" actually controls that part of the CPU. With this type of microcode, a designer explicitly chooses to make a slower CPU to save money by reducing the unused bits in the control store; however, the reduced complexity may increase the CPU's clock frequency, which lessens the effect of an increased number of cycles per instruction.
Because transistors are becoming cheaper, horizontal microcode is coming to dominate the design of hardware control units. As of the early 2000s, CPUs no longer use vertical microcode except perhaps in emulator software designed to run on a standard computer.
After the microprogram is finalized, and extensively tested, it is sometimes used as the input to a computer program that constructs logic to produce the same data. This program is similar to those used to optimize a programmable logic array. No known computer program can produce optimal logic, but even pretty good logic can vastly reduce the number of transistors from the number required for a ROM control store. This reduces the cost and power used by a CPU.