x86 Real-Mode Segmentation & the 8086 Memory Interface

Real-mode x86 forms a twenty-bit address from a sixteen-bit segment and offset, so many logical addresses alias the same byte. The original 8086 then maps bytes onto two eight-bit memory banks selected by A0 and BHE#, making alignment visible as bus cycles.

The 8086 has 16-bit offsets but a 20-bit external address bus. Segmentation bridges that mismatch: a logical address names a segment and an offset; the bus interface converts them into the physical byte address used by memory. The same arithmetic survives in current x86 real-address mode, while the original pin-level bank selection belongs specifically to the 8086 bus.

Segment plus offset #

1 · Form the physical byte address segment S 16 bits offset O 16 bits (S ≪ 4) + O 20-bit bus address on the 8086 paragraph base Aliasing example 1234:0010 1235:0000 12350h different logical pairs, same physical byte 2 · Select byte lane(s) for the transfer low bank · D7…D0 even byte addresses selected when A0 = 0 high bank · D15…D8 odd byte addresses selected when BHE# = 0 address + transfer width aligned word: both banks once · odd-address word: two bus cycles
Logical addressing and physical byte-lane selection are two consecutive mechanisms: first form an address, then select the required bank or banks.

For the original 8086, the address calculation is

Aphysical=(S≪4)+OA_{physical} = (S \ll 4) + O

where SS is the unsigned 16-bit segment value and OO is the unsigned 16-bit offset. Shifting by four makes segment bases start on 16-byte paragraph boundaries. Each segment can address 64 KiB of offsets, and adjacent segment windows overlap heavily.

The overlap lets software relocate a 64 KiB view cheaply, but it also creates aliases: different segment:offset pairs can name identical storage. Aliasing complicates pointer comparison, serialization, debugging, and reasoning about ownership.

Which segment is selected #

Reference Offset source Default segment
instruction fetch IP CS
stack push/pop/call/return SP SS
effective address using BP BP plus permitted index/displacement SS
most other data references BX, SI, DI, or displacement combinations DS
string source SI DS (override permitted)
string destination DI ES on the 8086

A segment-override prefix changes the default for an eligible memory operand in the following instruction. It does not rewrite a segment register and it does not turn IP, SP, or arbitrary general registers into legal 8086 addressing components.

The effective address calculation and segment calculation are distinct:

  1. the EU calculates a 16-bit effective offset from allowed registers and displacement;
  2. the BIU selects a segment register, shifts it by four, adds the offset, and initiates the bus cycle.

That distinction is why LEA returns an effective offset without reading memory or adding a segment base.

The one-megabyte boundary and A20 #

The original device presents only twenty address bits. A sum that produces bit 20 cannot appear on its pins, so the bus address wraps modulo 2202^{20}. This made addresses near FFFF:0010 alias low memory.

Later processors had more address lines and would naturally expose bit 20. The IBM PC/AT added control of the A20 line to preserve software that depended on the old wraparound. Modern systems normally enable A20 early; emulators and firmware still need a defined policy when reproducing legacy real-mode behavior.

Two byte banks on a sixteen-bit bus #

Memory is byte-addressed, but the 8086 transfers up to sixteen data bits per bus cycle. Board designs therefore arrange two eight-bit banks:

  • the low bank carries the byte at an even address and is selected with A0=0;
  • the high bank carries the byte at an odd address and is selected with active-low BHE#=0;
  • an aligned word at an even address selects both banks in one transfer;
  • an unaligned word beginning at an odd address spans two aligned words and requires two bus cycles.
Transfer A0 BHE# Active byte lanes
byte at even address 0 1 low bank
byte at odd address 1 0 high bank
word at even address 0 0 both banks
word at odd address two cycles two cycles high byte of one word, low byte of the next

This is not a general law that every unaligned x86 access takes exactly two external cycles. It is the direct consequence of the original 8086's 16-bit bus and bank-select signals. Current cores use caches, wider internal transfers, and split-access rules at several boundaries.

Memory and I/O are separate spaces #

The 8086 exposes a one-megabyte memory address space and a separate 16-bit port address space. Memory operands use ordinary instruction addressing and segmentation. IN and OUT address ports either with an immediate eight-bit port number or the value in DX; the accumulator is the data operand.

The separation affects board decoding and instruction choice. A numeric port address is not a memory pointer, even if the same numeric value exists in both spaces.

Worked address trace #

Assume:

text
DS = 2000h
BX = 0101h
SI = 0002h
instruction operand = word [BX + SI + 3]

The effective offset is 0101h + 0002h + 0003h = 0106h. Because no BP participates, the default segment is DS. The physical address is 2000h × 10h + 0106h = 20106h. It is even, so the word can select both byte banks in one original-8086 bus transfer.

Change only BX to 0102h; the physical address becomes 20107h, and the same word is now unaligned and crosses two bus cycles. Address arithmetic and transfer cost meet at the final physical byte address.

Diagnose the layer that failed #

Observation Likely layer
correct offset, wrong 64 KiB region default/override segment selection
two logical pointers disagree but memory changes together segment aliasing
byte accesses pass, odd-address words fail bank selection or split-cycle handling
code works below 1 MiB but fails near the boundary A20 policy or wrap assumption
IN/OUT reaches nothing while memory reads work port-space decode, not segmentation

Always write the logical address, effective offset, physical address, transfer width, and active lanes separately. Collapsing them into “the address” hides the fault.

Sources

  1. docsThe 8086 Family User's Manualpdfnotes
  2. docsIntel 64 and IA-32 Architectures Software Developer's Manualpdf

Searches titles, aliases, headings, summaries, and full text.↑↓ move ↵ open esc close