48

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?

10
  • 27
    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).
    – user
    Dec 1, 2017 at 15:19
  • 11
    The AX/CX/DX/BX order also makes an appearance in PUSHA, which suggests it might correspond to the internal register file implementation... Dec 1, 2017 at 15:31
  • 42
    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, 2017 at 18:54
  • 6
    @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, 2017 at 23:36
  • 13
    Consider looking at 8080 and 8086 opcodes since those are the ancestors of x86. Dec 2, 2017 at 23:53

4 Answers 4

57

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)

12
  • 15
    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, 2017 at 15:58
  • 2
    @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). Dec 3, 2017 at 4:25
  • 3
    @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, 2017 at 5:01
  • 2
    @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 :) Dec 3, 2017 at 5:22
  • 3
    Well, not all his wished came thru, as for example he called what later became Convert Byte to Word in his papers Signe EXtend
    – Raffzahn
    Dec 3, 2017 at 13:18
18

@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).

9
  • 4
    well done finding patterns in the ModR/M byte!
    – davidbak
    Dec 2, 2017 at 6:12
  • 6
    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, 2017 at 14:03
  • 7
    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, 2017 at 14:20
  • 1
    @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. Dec 2, 2017 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, 2017 at 21:30
10

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 register not explicitly intended for storing addresses that could also be used for memory addressing. (Example[BX+5])
  • 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.

EDIT

I removed the term "GPR" from the description of BX.

This is because the word "GPR" implies that a register does not have any intended purpose. However, the names of the registers already imply a certain purpose of each register.

8
  • 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, 2019 at 13:05
  • 3
    I disagree with your definition of General Purpose as excluding SI / DI / BP. As long as you can use them for general ALU instructions like add ax,si or mul si, they're GPRs. Would you disqualify CX because it's "intended" for counts (with instructions like loop and shl reg,cl to support it)? See Why are rbp and rsp called general purpose registers?. The argument for SP is better; you need to disable interrupts (or be in user-space so interrupts will use a different stack) to actually use it for anything but a stack pointer. Jul 23, 2020 at 8:11
  • 2
    But in common computer-architecture terminology, even SP is a GPR, because it's part of the same "address" space encoded with 3-bit register numbers in machine code. OTOH, keil.com/support/man/docs/armasm/armasm_dom1359731128950.htm describes ARM as having 13 GPRs (r0..r12), considering PC (R15) as non-GRP which makes sense even though it's addressable like a GPR, SP (R13) as non-GPR which is debatable, and LR (R14) as non-GPR which seems totally weird to me. But then they go on to point out that LR can be used as a GPR, and (in ARM state) so can SP. Jul 23, 2020 at 8:16
  • 1
    Sure, I'd agree with that address vs. data terminology, but address registers are also GPRs. Even moreso than 68000, when you don't happen to need that many addresses in regs, you can very much use them for other kinds of data. BTW, I wondered whether there was agreement that 68k's GPRs included the address regs, and found disagreement on it's wikipedia talk page: en.wikipedia.org/wiki/… Jul 23, 2020 at 10:36
  • 3
    Gah, sometimes I hate loose ill-defined terminology like "GPR", or "16-bit CPU" or "word size". It just leads to a lot of wasted time discussing what label to stick on something that everyone involved understands the actual details of. English en.wikipedia.org/wiki/Processor_register#Types makes the distinction that a GPR is one that can hold an address or data, which would rule out AX, CX, and DX. So I don't like that definition either. Fortunately, Wikipedia is not an authoritative source on terminology so we're free to disregard it. Jul 23, 2020 at 12:47
6

Agreeing with existing answers but being too long to shove into a comment, per a recent post on Ken Shirriff’s blog that traced the instruction set from the Datapoint 2200 through the 8008, 8080 and 8085 and into the 8086:

The 8086 extended its registers to 16 bits and added several new registers. An Intel patent (below) shows that the 8086's registers were originally called A, B, C, D, E, H, and L, matching the Datapoint 2200. The A register was extended to the 16-bit XA register, while the BC, DE, and HL registers were used unchanged. When the 8086 was released, these registers were renamed to AX, CX, DX, and BX respectively.18


  1. This renaming is why the instruction set has the registers in the order AX, CX, DX, BX, rather than in alphabetical order as you might expect. The other factor is that Intel decided that AX, BX, CX, and DX corresponded to Accumulator, Base, Count, and Data, so they couldn't assign the names arbitrarily.

So the alphabetical naming was likely a late-stage renaming, explaining why it had no effect upon encoding.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .