Lessons from the Alpha ISA: Clean 64-bit RISC Design

Alpha was designed around 1990 by engineers who had watched a decade of RISC architectures accumulate awkward compromises, and who deliberately set out to build something that would still make sense after twenty-five years of implementations. Looking back from 2026, many of their choices read like a checklist that later architects quietly adopted.

The design brief: plan for a thousandfold

Digital's architects framed Alpha as a long-lived architecture, and the often-repeated goal was to allow roughly a thousandfold performance increase over its lifetime: some from clock speed, some from issuing multiple instructions per cycle, and some from multiple processors. Every feature was judged against that goal. Anything that made a fast single-issue pipeline easy but a wide, out-of-order, multiprocessor implementation hard was a candidate for removal.

The result was a strictly 64-bit load/store architecture with fixed 32-bit instructions, 32 integer and 32 floating-point registers, and a register (R31 and F31) hardwired to zero. That much was already conventional for RISC. The interesting part is what Alpha left out.

No condition codes

Most architectures of the era, RISC and CISC alike, had a flags register that arithmetic instructions updated as a side effect. Flags are cheap in a simple pipeline and a headache in a wide one: every instruction that might set them creates an implicit dependency on a single shared piece of state, which must be renamed, tracked and ordered.

Alpha simply did not have one. Comparisons wrote their result to an ordinary register, and branches tested a register against zero:

cmplt   $1, $2, $3     # $3 = ($1 < $2) ? 1 : 0
bne     $3, target     # branch if $3 != 0
cmoveq  $4, $5, $6     # if $4 == 0 then $6 = $5

Conditional move instructions (CMOVxx) gave the compiler a branch-free way to handle short if-then-else patterns, without the complexity of full predication. For an out-of-order core like the 21264, this meant every dependency was an explicit register dependency, visible to the renamer like any other.

No branch delay slots

MIPS and SPARC exposed their original pipeline in the ISA: the instruction after a branch always executed, because on the first implementations it was already in flight. It was a neat trick for a five-stage pipeline and a permanent tax on every design afterward, since deeper and wider machines had to emulate a behaviour that no longer matched their hardware.

Alpha refused to bake any pipeline detail into the architecture. Branches took effect immediately. Instead, the ISA provided hints: branch displacement direction as a static prediction convention, and hint bits in jump instructions to help predict return addresses. Hints can be ignored by a future implementation; delay slots cannot.

A deliberately weak memory model

Alpha's memory ordering rules were among the weakest ever shipped in a commercial architecture. Without explicit barriers, a processor could observe another processor's loads and stores in almost any order. Software used MB (memory barrier) and WMB (write memory barrier) to impose ordering where it mattered, and load-locked/store-conditional pairs (LDL_L/STL_C, LDQ_L/STQ_C) for atomic updates.

The most famous consequence is that Alpha permitted even data-dependent loads to appear reordered: reading a pointer and then the data it pointed to could, on some multiprocessor implementations with banked caches, return stale data for the second load. Linux carried a special barrier primitive for years largely because of Alpha. It was a real burden on kernel developers, and a good argument that Alpha went a step too far.

PALcode: a programmable layer below the OS

Alpha kept the architected privileged state extremely small. Operations such as TLB miss handling, interrupt entry and exit, context switching and some atomic sequences were implemented in PALcode (Privileged Architecture Library), ordinary Alpha instructions running in a special mode with access to implementation-specific registers.

This had two big payoffs. First, each operating system could have its own PALcode: OpenVMS, Digital UNIX/Tru64 and Windows NT each defined different page table formats and privilege models, all on the same silicon. Second, chip designers could change internal hardware between generations without breaking operating systems, because PALcode absorbed the difference. The modern echo is the machine-mode firmware layer in RISC-V, which serves a similar role.

What Alpha left out, then had to add

Not every omission survived contact with real software. The original Alpha had no byte or 16-bit word loads and stores. The argument was that byte access complicates the memory system and that sequences of 64-bit loads, extracts, inserts and masks would suffice. For numeric code they did. For string handling, device drivers and code ported from x86 they were a visible cost.

The BWX (byte/word extension) arrived with the 21164A around 1996, adding LDBU, LDWU, STB, STW and sign-extension instructions. Later extensions followed a similar pattern:

ExtensionFirst implementation (approx.)Adds
BWX21164A (EV56), c. 1996Byte and 16-bit word loads/stores, sign extension
MVI21164PC (PCA56), c. 1997Small set of multimedia/pixel instructions
FIX21264 (EV6), c. 1998Square root, moves between integer and FP registers
CIX21264A (EV67), c. 1999Count leading/trailing zeros, population count

Other omissions stayed: Alpha never had an integer divide instruction, relying on software routines, and floating-point exceptions were imprecise by default, with a TRAPB barrier for software that needed exact trap reporting. The 21264A product page on this archive shows the implementation where most of these extensions came together.

Influence on RISC-V and ARM64 thinking

Direct lineage is hard to prove and easy to overstate; architects read widely and draw on many predecessors. Still, the overlap with later designs is striking:

  • RISC-V has no condition codes, no branch delay slots, a hardwired zero register, fixed-width base instructions, load-reserved/store-conditional atomics and a weak memory model with explicit fences. It also chose to include byte and halfword access from day one, a lesson Alpha learned the hard way.
  • ARM64 broke sharply with 32-bit ARM by dropping near-universal predication, adding a zero register in most contexts, and adopting a weak, barrier-based memory model. Contrarian note: it kept condition flags, and its conditional select instructions work well in wide out-of-order cores. Flags turned out to be manageable with modern renaming, so Alpha's purism here was arguably more than necessary.
  • Both architectures isolate firmware and hypervisor layers in ways that resemble PALcode's separation of concerns, though with much more architected state.

The broader lesson is the one Alpha's designers set out to prove: an ISA should describe what software needs, not how the first chip happened to be built. The implementations that followed, from the 21064 to the 21364, show how far that approach could be pushed, and why the 21264 still matters is largely a story about an ISA that stayed out of the way.

Further reading on this archive

← Back to the archive