35

On x86 the first four general-purpose registers are named AX, CX, DX, BX. It would be quite intuitive if their indices (those used in instruction encoding) were in alphabetical order, but instead of ABCD we actually have ACDB. E.g. mov bl, 1 is encoded as B3 01 while mov cl, 1 is B1 01.

Is there any reason why they weren't enumerated in alphabetical order?

  • 19
    You bring as Exhibit A the x86 architecture, and you're asking why it lacks in consistency in mapping between register mnenomics and opcode binary values? :-) Remember, at that time, a new CPU was allowed to be much more of a clean break with the past than what we might expect today. Just look at the interaction between the 80286's real and protected modes (which Intel did fix in the 386 especially by introducing V86 mode). – a CVn Dec 1 '17 at 15:19
  • 6
    The AX/CX/DX/BX order also makes an appearance in PUSHA, which suggests it might correspond to the internal register file implementation... – Stephen Kitt Dec 1 '17 at 15:31
  • 24
    i always learned these registers as accumulate, count, data, and base. They weren't ordered alphabetically so much as ordered by usage, ax for most arithmetic operations, cx for loop counters, dx for either left over arithmetic (think of the remainder or carry for div/mul) or i/o data, and bx for a base pointer to memory. Roughly, the ACDB is the order of importance for your average use case – Steve Cox Dec 1 '17 at 18:54
  • 3
    @SteveCox actually in the time we're talking about guys writing the instruction set would prioritize minimal number of gates and then minimal gate depth/delay over just about everything else, I would think. So I wonder if there's an explanation in considering the (non-microcoded) instruction decode logic w.r.t. the special purposes of each "general" register. – davidbak Dec 1 '17 at 23:36
  • 5
    Consider looking at 8080 and 8086 opcodes since those are the ancestors of x86. – Thorbjørn Ravn Andersen Dec 2 '17 at 23:53
43

There are no technical reasons, as any order would work and result in the same amount of gates. More likely it originated in the process by which the 8086 was developed. A main goal was to allow easy conversion of 8080 programs, so the development of the 8086 structure started out from a 8080 programming model. 8080 registers were ordered as 16 bit pairs in the sequence of PSW/A, B/C, D/E, H/L (SPand PC) with HL being the general base or memory pointer and DE being a backup (*1). So assigning them in the same order with similar functionality will result in

  • PSW/A becomes AX, and AL is also the general purpose 8 bit accumulator,
  • B/C becomes CX, as these were the general purpose, usually counter registers
  • D/E becomes DX, as general purpose 16 bit pair, and finally
  • H/L becomes BX, as the primary pointer register.

I wouldn't be much surprised if early documents reveal 8080-like names used during development.

Remember, while 8086 registers are more adapted for general use than in the 8080, they had dedicated functions like BX in addressing, and/or optimized coding for certain applications - like AL/AX as primary accumulator. This provided a way for more compact coding when the registers were used in the specialized way, thus faster execution of programs acknowledging these differences.

More important it also gave programs rewritten by automated translation utilities (like Digital Research's XLT86) from 8080 assembler sources to 8086 assembler, an encoding comparably compact to 8080 code. An important argument toward early adopters, as memory requirements where still a major cost factor back then, and asking them to buy a CPU that needs bigger ((E)P)ROMs just for holding the (translated) existing one didn't come over well.


*1 - The physical 8080 model is different, as PSW and A were not part of the register file, which in addition featured a W/Z pair for internal operation (like buffering memory access, or addresses during 16 bit operations)

  • 5
    There is also a slightly mnemonic quality to some of the register names: Accumulator, Branch control (B as used in the Z80 instruction DJNZ), Count as in the CX register used by the x86 LOOP instruction and REP modifiers, and a general-purpose Data register. I would assume the naming of H:L is simply based on "high" and "low". – njuffa Dec 2 '17 at 15:58
  • @njuffa: So BX / "base" may have been named just to fit into the alphabetic pattern. Other letters could have been chosen, like "P" for pointer or T for table, but weren't. Similar to how the new segment regs in 386 were named FS and GS (meaningless letters), mostly to follow 8086's SS (stack) / CS (code) / DS (data), ES (extra? used implicitly only for string / rep-string insns). – Peter Cordes Dec 3 '17 at 4:25
  • 1
    @PeterCordes x86 has SP (stack pointer) and BP (base pointer) registers, so the 'P' for pointers is there in some sense. I agree that BX as an indexing base, to be used in conjunction with the SI (source index) and DI (destination index) registers is also mnemonic. – njuffa Dec 3 '17 at 5:01
  • @njuffa: Funny to imagine if we'd had PX and PA / PH, and then later EPX / RPX. Then 386 setcc would have given us instructions like setp ah and seta ph. >.< And 8086 already had PF (as a bit in FLAGS). I'm glad they (or Stephen Morse specifically) chose B for base :) – Peter Cordes Dec 3 '17 at 5:22
  • 1
    Side comment: I'd never heard of Morse, so I looked him up. I was amused to note he considered a PDP-11 to be 'a mainframe'. I guess it is, if you're designing the 8086. – another-dave May 12 at 22:04
10

@davidbak suggests a possible physical implementation motivation for the design choice:

In the time we're talking guys writing the instruction set would prioritize minimal number of gates and then minimal gate depth/delay over just about everything else, I would think.

BX is the only one of ACDB that can be used in a 16-bit addressing mode:
[ (BX|BP) + (DI|SI) + (0 | disp8 | disp16) ], where any of the 3 components are optional.

BX is also the only 16-bit-addressing-mode register that has a low/high half. So maybe in 8086 it was physically on the boundary between the split low/high registers and the address-capable registers that the AGU had to read.

Or maybe not: 8086 ModR/M and opcode encodings were designed before the hardware by Stephen Morse, primarily a software guy. We can't know whether he considered a HW layout benefit, or thought of this as a logical reason, or whether it just worked out well for the HW design, or maybe I'm way off base and it isn't even helpful for the HW implementation.

(off topic re: low-8 of other registers) In x86-64, a REX prefix changes the meaning from AH/CH/DH/BH to SPL/BPL/SIL/DIL, in that order (Intel manual vol.2, Appendix B.1.4.2, Table B-5). In 16/32 bit modes, 16-bit operand size was the smallest for SP/ESP and the other non-X registers. (Making registers more uniform helps compilers, except that compilers sometimes end up wasting a REX prefix by picking a register that needs one to access the low 8 component.)


The pusha/popa ordering matches too, and while that's interesting, the internal implementation probably uses a counter and goes through the same fetch-by-index logic as explicit register operands. So it doesn't add new information that pusha goes in order of the encodings.

It makes sense that the physical layout of the register file would match the register-number encodings, though, to keep the decoding logic simple. I had a look at the addressing-mode encodings, to see if there was a similar pattern there. (I haven't looked at 8086 gate diagrams, but maybe the AGU fetches directly from the last 4 registers in the register file without going through the full indexing that can select any of the 8.)

It's complicated by the fact that 16-bit doesn't have a SIB byte, so base and base+index modes share the same 3 bit R/M field in the ModR/M byte.

Intel x86 manual vol.2, 2.1.5 Addressing-Mode Encoding of ModR/M and SIB Bytes, Table 2-1. 16-Bit Addressing Forms with the ModR/M Byte

 Effective Address |  R/M field          | (added): /r encoding
[BX+SI]               000
[BX+DI]               001
[BP+SI]               010
[BP+DI]               011
[SI]                  100                | SI=110
[DI]                  101                | DI=111
disp16 (no base)      110                | (BP=101)
[BX]                  111                | BX=011

So BX alone is at the opposite end from BX+SI and BX+DI, but it's one wrap-around away from being adjacent to the other two codes that involve BX. When SI and DI are involved, bit0=0 means SI, bit0=1 means DI.

When there are both base and index registers (bit2=0), then bit1=0 means BX, bit1=1 means BP. So that's maybe consistent with BX being earlier in the physical layout of the register file (lower numbers to access it). But R/M fields clearly need significant decoding before they turn into register fetches.

Still, I think it's plausible that the AGU in 8086 has a "back door" into the register file that can only select from the last 4 registers (in /r field and pusha encoding order). Note that 8086 uses the adder in its regular ALU for address calculations, but the addressing-mode decoding hardware might use different paths to fetch inputs for the ALU's address calculations. (Totally guessing; certainly possible it just decodes those addressing modes to the usual 3-bit register codes and drives the normal ALU through regular register-fetch paths.)


In 32/64-bit addressing modes, the encoding matches the usual register encoding, so presumably (in CPUs without out-of-order / register renaming, like 80386) the AGU can access the register file with the same 3-bit address as the ALU.

(fun fact, 32/64-bit shares the same pattern of [e/rbp] being the escape code for disp32 with no base (or RIP relative), which is why EBP always needs at least a disp8 = 0. This is why disassembly looks like [ebp+0] vs. [edx].) Same for r13 in x86-64 mode, because it has the same code as rbp (except for the extra bit in the REX prefix).

  • 3
    well done finding patterns in the ModR/M byte! – davidbak Dec 2 '17 at 6:12
  • 4
    Nice work, just it begins with a little flaw: Stephen Morse, who was the lead architect and single handed wrote most specs, was a software guy. He did 'invent' the modr/m byte as well as seting the opcodes to be used, before any hardware at such a detail level needed for above reasoning was defined, even less designed. Reading his 1980 book '8086 Primer' gives some insight in the way he saw the CPU. It also describes part the reasoning for the reg field the OP asked about. Last but not least, when looking at other modr/m encodings, above theory would result in more gates. – Raffzahn Dec 2 '17 at 14:03
  • 4
    The 8086 Primer is BTW a very important book for anyone who wants to understand the 8086. The same way Stephen Morese development of the 8086 is special, as he is not a hardware guy, and wasn't involved in any CPU project before or after the 8086 (not even the 8088), the book is special, as the description of the 8086 he gives differ in structure and wording quite from all Intel material. The way it's written reveals a lot about his view when designing and what parts he emphased on. – Raffzahn Dec 2 '17 at 14:20
  • @Raffzahn: More gates for the AGU to have a back door into the register file? Yeah, I wondered about that; fetching through the regular indexing logic would presumably be fewer gates. Maybe more total gates on chip, but fewer gate-delays in some of the critical paths? Thanks for the info that the ModR/M encodings were set before HW design by a software guy. I'm a software guy, too, though, and I thought of this, so perhaps he did consider BX as on the boundary between data and pointer. – Peter Cordes Dec 2 '17 at 14:28
  • 2
    I wonder how the cost of the 8x88's approach compared with the cost of something like the 6809's approach which could IIRC use some bits of an extension byte as part of an offset and others for register/segment selection. In many programs, the fraction of instructions that would need an ES: prefix is much higher than the fraction of instructions that would need a displacement of +/-32..127, or beyond +/-16384, so adding an extra byte to instructions needing a longer displacement would be a small price to pay for having some addressing modes imply ES: [the way BP implies SS:]. – supercat Dec 5 '17 at 21:30
3

A related question was asked on StackOverflow after this question was asked.

Background

In the other question, it was assumed that the register names are simply taken from the alphabet, so an extension to the x86 registers (as it has been done with the x86-64) would lead to the following register names: AX-BX-CX-DX-EX-FX-GX-...

However, this assumption is wrong. In nearly all early CPUs (8080, 6502, 6800 ...) CPU register names were named by their (intended) function, not by any systematic naming scheme (such as taking the letters from the alphabet or using numbers).

The x86 registers are also named by the function the registers were intended for:

R0 = AX = Accumulator
R1 = CX = Counter
R2 = DX = Data (maybe also Double)
R3 = BX = Base
R4 = SI = Source Index
R5 = DI = Destination Index
R6 = BP = Base Pointer
R7 = SP = Stack Pointer

The actual answer

It is pure incident that the words "Accumulator", "Base", "Counter" and "Data" start with the first four letters of the alphabet (A, B, C, D).

The developer could have decided to use the word "Pointer" instead of "Base"; in this case the register names would be AX-CX-DX-PX instead of AX-CX-DX-BX.

I doubt that the developers of Intel even noticed that the register names follow the first four letters of the alphabet so they could be sorted alphabetically.

Explanation of the register names

  • Accumulator: In early CPUs, there were only one register that could perform arithmetic operations: The accumulator. I'm not sure about x86-64, but in the 8086 the AX register still was the only one that could be used for multiplication and division.
  • Counter: The rep and loop instructions are using this register for counting.
  • Double: The DX register is used to hold the high 16 bits of a 32-bit ("double word") value.
  • Base: Before the 80386, BX was the only GPR that could be used for memory addressing. (Example[BX+5]) (Note: Because SI, DI and BP were intended for storing addresses only, I think that they were originally considered not to be "GPRs".)
  • Source Index: Registers whose only purpose was to point to an address were often called "index registers". SI is the index register holding the address lods and movs are reading data from.
  • Destination Index: DI is the index register holding the address stos and movs are writing data to.
  • Base Pointer: This register points to the base address of the stack frame.
  • 1
    "Before the 80386, BX was the only GPR that could be used for memory addressing" — wrong: SI, DI, BP can also be used in 16-bit mode to address memory with an offset. – Ruslan May 11 at 13:05
  • @Ruslan I updated the description of the "Base". – Martin Rosenau May 11 at 14:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.