Assembler (Intel 8086)
The 16-bit assembly language Intel defined for the 8086 in 1978 — ASM86, a deliberately strongly typed assembler with segmented addressing, PTR overrides and user-definable codemacros — and the source-level bridge that carried 8080 programs into the x86 era.
Created by Intel Corporation; instruction set architecture by Stephen P. Morse
Assembler (Intel 8086) is the assembly language Intel defined in 1978 for its first 16-bit microprocessor. Intel called it ASM86 and documented it in the MCS-86 Assembly Language Reference Manual, order number 9800640, which carries a 1978 copyright. It is the point at which the 8-bit Intel line — 8008, 8080, 8085 — turned into the x86 architecture that still runs most desktops and servers. Almost everything a modern x86 programmer recognises is already present in the 1978 manual: MOV, PUSH, JMP, the AX/BX/CX/DX register file, the REP-prefixed string instructions, segment registers, the PTR override. What is not present is the flat address space; that arrived with the 386 seven years later, and much of what distinguishes 8086 assembly from later x86 assembly is the machinery for living without it.
History and Origins
A stopgap that outlived everything around it
The 8086 project started in May 1976. Intel’s flagship effort at the time was the iAPX 432, an ambitious 32-bit object-oriented processor that was running badly late, and the 8086 was commissioned as a temporary answer to the 16-bit parts that Motorola, Zilog and National Semiconductor were about to ship. Stephen P. Morse, the architect, later recalled that this was precisely what gave him room to work: “Because nobody expected the design to live long, no barriers were placed in my way, and I was free to do what I wanted.” He also described the methodological shift that made the result unusual for its era — “For the first time, we were going to look at processor features from a software perspective,” asking what features would make software more efficient rather than what would fit in the available die area.
The chip was released on 8 June 1978. It was built in nMOS at roughly 3 μm with on the order of 29,000 transistor sites (about 20,000 of them active logic, the rest ROM and PLA), packaged in a 40-pin DIP, and initially specified at 5 MHz; later HMOS parts reached 8 and 10 MHz. The iAPX 432 went nowhere. The stopgap became the architecture.
The compatibility constraint that shaped the language
Intel’s management set a condition on the design: software written for the 8080 had to be able to move forward. The 8086 is not binary compatible with the 8080 — no 8080 object code runs on it — but it was deliberately made source compatible in a mechanical sense, and Intel shipped the tool to prove it. CONV86, documented in manual 9800642 (copyright 1979), reads an error-free 8080/8085 assembly source file and writes an 8086 assembly source file. Its register mapping is the clearest surviving fingerprint of that constraint:
| 8080/8085 | 8086 |
|---|---|
| A | AL |
| B, C | CH, CL |
| D, E | DH, DL |
| H, L | BH, BL |
That is why the 8086’s byte registers are addressable as halves of the word registers at all, and why BX — not AX — is the register the 8086 will use as a memory pointer: BX is where HL landed.
Intel was honest about the limits of the exercise. The converter manual devotes a section to what conversion does not preserve, including program execution time and software timing delays, and CONV86 emits “caution messages” flagging constructs that need manual editing. Intel’s own manual even asks, in a section heading, “What Advantage Is There in Rewriting Programs in 8086 Assembly Language Rather Than Converting?”
The Language
An assembler that type-checks
The most distinctive feature of ASM86 as Intel defined it is not an instruction. It is the claim the 1978 manual makes in its first chapter:
The 8086 assembly language is “strongly typed”. This means it performs extensive checks on your variables and labels… The assembler makes sure that each use of a symbol in later instructions conforms to the usage defined for that symbol when it was declared.
A variable declared with DB has type byte, one declared with DW has type word, one declared with DD has type doubleword, and the assembler refuses instructions that use them inconsistently. This is why PTR exists: MOV BYTE PTR [BX], 0 is not decoration but the override that tells a type-checking assembler you meant it. The companion operators SEG, TYPE, OFFSET, THIS, LENGTH, SIZE and WIDTH all exist to interrogate or construct those attributes at assembly time. Intel’s stated rationale was defensive: the checks are “an extra safeguard against unintended or meaningless code arising from errors of omission or inconsistency.”
The register model
| Register | Written as | Role |
|---|---|---|
| AX | AX / AH, AL | Accumulator; implicit in MUL, DIV, IN, OUT, the string and BCD instructions |
| BX | BX / BH, BL | Base register — the only general register besides BP, SI and DI usable in [...] addressing |
| CX | CX / CH, CL | Count for REP-prefixed strings, LOOP and variable shifts (via CL) |
| DX | DX / DH, DL | High half of MUL/DIV operands; indirect I/O port number |
| SI, DI | SI, DI | Source and destination indexes; the implicit operands of the string instructions |
| BP, SP | BP, SP | Frame pointer and stack pointer, both defaulting to the stack segment |
| CS, DS, SS, ES | CS, DS, SS, ES | Code, data, stack and extra segment bases |
| IP, FLAGS | — | Instruction pointer and status flags, not directly addressable as operands |
Sixteen-bit arithmetic that the 8080 had to synthesise from carry chains became a single ALU operation, and MUL, IMUL, DIV and IDIV exist in hardware for the first time in the family — though they are microcoded and slow, quoted in Intel’s timing tables at roughly 70-160 clocks for multiply and 80-190 for divide depending on operand size and data, versus 2-4 clocks for a register-to-register MOV or ALU operation. Those are the manufacturer’s published instruction timings for the original part, not measured benchmark figures, and they are best-case numbers that ignore prefetch state and instruction alignment.
Segments, and the 20-bit address
The 8086 has 16-bit registers but a 20-bit address bus. A physical address is formed by shifting a segment register left four bits and adding a 16-bit offset, giving a 1 MB space carved into overlapping 64 KB windows. Every memory reference therefore carries an implicit segment: instruction fetches go through CS, stack operations and anything based on BP through SS, most data through DS, and string destinations through ES.
The language is built around making that implicit choice explicit and checkable. SEGMENT/ENDS declare a segment with an alignment (BYTE, WORD, PARA, PAGE, INPAGE) and a combination type (PUBLIC, COMMON, STACK, MEMORY, AT). GROUP collects segments that will share a base. And ASSUME — the directive with no counterpart in flat-model assembly — tells the assembler which segment register it may presume points at which segment, so that it can decide for itself whether a reference needs a segment-override prefix byte. ASSUME NOTHING withdraws that presumption. Get ASSUME wrong and the assembler will silently compute addresses against a segment register that does not hold what you think it holds; this is the classic 8086 assembly bug, and it has no analogue on a 386 in flat mode.
Directives and expressions
Beyond the segment machinery, the 1978 language provides DB/DW/DD with the DUP replication facility and ? for uninitialised storage, RECORD for bit-field definitions, PROC/ENDP with NEAR and FAR distance attributes, LABEL, EQU, PURGE, ORG, and the module-linkage set NAME, PUBLIC, EXTRN and END. Assembly-time expressions have a full operator hierarchy: additive operators, the variable-manipulation operators above, SHORT, the logical AND/OR/XOR/NOT, the relational EQ/NE/LT/LE/GT/GE, multiplicative and shift operators, and the byte-isolation HIGH and LOW inherited from the 8080 assembler.
Codemacros
One genuinely unusual feature of Intel’s assembler is that the instruction set is not hard-wired into it. Chapter 7 of the 1978 manual documents codemacros: definitions that specify how a mnemonic, given operands matching certain specifiers, is to be encoded into bytes. The primitives are things like SEGFIX and NOSEGFIX (emit or suppress a segment-override prefix), MODRM (build the addressing-mode byte), RELB/RELW (emit a relative displacement) and DB/DW/DD. Appendix A of the manual prints the codemacros for the entire 8086 instruction set — the assembler’s own instruction definitions, written in the user-accessible notation. A programmer could extend the mnemonic set the same way, which is how coprocessor instructions could be bolted on.
| |
Beyond Intel’s Assembler
Intel’s ASM86 ran on Intellec development systems under ISIS-II, which put it out of reach of most people who ended up writing 8086 code. The language spread through other implementations of the same mnemonics:
- 86-DOS. Tim Paterson wrote what became MS-DOS in 8086 assembly starting in April 1980, using his own assembler; the operating system and the tools to build it grew up together.
- MASM. Microsoft’s Macro Assembler appeared in 1981, sold both directly and as IBM’s OEM-branded IBM Macro Assembler (December 1981). According to the commonly cited MASM version list, successive releases tracked the hardware — 8087 support in 1.10 (1982), 8087 emulation in 1.25 (1983), 186/286/287 instructions in 2.00 (1984), 286 protected-mode instructions in 3.00 (1984) and 386 support in 5.00 (August 1987), the release that also introduced the simplified segment directives. Other secondary accounts place 286 support a version later, at 4.0 (October 1985), so the intermediate version-to-feature mapping should be treated as approximate. MASM’s
.MODEL/.CODE/.DATAdirectives and itsASSUMEbehaviour are recognisably descended from Intel’s design. - Borland’s Turbo Assembler (TASM), released in the late 1980s, offered a MASM-compatible mode alongside its own
IDEALsyntax, which tightened exactly the type and segment rules that MASM had loosened. - NASM, first released as version 0.90 in October 1996 by Simon Tatham and Julian Hall, is free, portable, and deliberately more regular in its treatment of operand sizes and memory references. It remains one of the most widely used ways to assemble 16-bit 8086 code today.
These are all the same language in the sense that matters — the same mnemonics against the same instruction encodings — but they differ substantially in directives, macro facilities, and how much type checking they impose. Code written for one rarely assembles unmodified under another without attention to the segment and size directives.
Evolution
The 8086 language was extended rather than replaced. The 8088 (1979) is the identical programming model over a narrower bus. The 8087 (announced 1980) added an 80-bit floating-point stack machine whose instructions ride in the 8086’s ESC opcode space, so FADD and FMUL became part of the same assembly source files. The 80186 added a handful of convenience instructions — PUSHA, POPA, ENTER, LEAVE, immediate-form IMUL, block I/O — and the 80286 added protected mode and its supervisory instructions. None of this invalidated an 8086 program; the family’s compatibility discipline has been maintained ever since, which is why a correctly written 1978 MOV/ADD/JNZ sequence still assembles and still executes on hardware nearly five decades later.
The one discontinuity is the address space. The 386 of 1985 widened the registers to 32 bits and introduced a flat model that made segmentation largely vestigial, and 64-bit long mode removed most of what remained. ASSUME, GROUP, NEAR/FAR and the segment-override prefix are the parts of 8086 assembly that a modern x86 programmer will never have used.
Current Relevance
Nobody starts new commercial projects in 16-bit 8086 assembly, which is why the encyclopedia lists the language as historical. But it remains unusually present for a language of its age:
- Every x86 processor still boots into it. An x86 CPU begins execution in real-address mode, with 8086 semantics and segmented 20-bit addressing, and the firmware executes 8086-compatible instructions before switching to protected or long mode. No shipping x86 processor has removed that mode.
- It is a standard teaching vehicle. Undergraduate computer-architecture and microprocessor courses still use 8086 assembly, usually under an emulator, because the register model is small enough to hold in your head and the segmentation is pedagogically instructive.
- Retrocomputing and DOS preservation. The DOS software base is 8086-family machine code, and disassembling, patching and reimplementing it is a large and active hobby. NASM, and emulators for the original hardware, keep the toolchain alive.
- The documentation survives intact. Intel’s 1978 and 1985 manuals, the CONV86 converter manual and the full instruction reference are scanned and freely readable at bitsavers and the Internet Archive, which is more than can be said for many languages fifty years younger.
Why It Matters
The 8086 assembly language is where a particular set of accidents became permanent. The register naming, the byte/word register aliasing, the choice of BX as the pointer register, the accumulator’s privileged role in multiply and I/O, the string instructions with their direction flag and REP prefix — all of these were shaped by the requirement that 8080 assembly source convert mechanically, a constraint imposed on a chip nobody at Intel expected to last. Every one of them is still visible in the instruction set that runs the majority of the world’s servers.
It is also a reminder that assemblers can be opinionated. Intel’s ASM86 type-checks variables, tracks segment attributes across ASSUME declarations, and defines its own instruction encodings in a user-visible macro notation. That is a considerably more elaborate design than “one mnemonic, one opcode”, and it was a deliberate response to a machine whose addressing model was easy to get quietly wrong. The PTR keyword that x86 programmers still type every day is a surviving piece of a 1978 argument about whether an assembler should be allowed to tell you that you are wrong.
Timeline
Notable Uses & Legacy
86-DOS and MS-DOS (Seattle Computer Products / Microsoft, 1980-)
Tim Paterson wrote 86-DOS entirely in 8086 assembly language, starting in April 1980 and reaching version 0.10 by that July. Microsoft bought a non-exclusive licence in December 1980 (the signed agreement is dated January 1981), and the assembly-language lineage ran on through PC DOS and MS-DOS, including the practice of writing whole utilities and the kernel itself in ASM.
IBM PC and its software ecosystem (1981-)
The IBM PC of 12 August 1981 used the 8088, which programs in the identical assembly language. The IBM Macro Assembler (December 1981) and Microsoft MASM 1.00 made 8086 assembly the lingua franca for BIOS code, device drivers, terminate-and-stay-resident utilities and the performance-critical inner loops of early PC applications.
IBM PS/2 Models 25 and 30 (1987)
IBM's entry-level PS/2 machines, announced 2 April and 4 August 1987, both ran a genuine 8086 at 8 MHz rather than the 8088 of the original PC. They put the 1978 part — and hand-written 8086 assembly in their ROM and drivers — into offices and schools well into the 1990s.
Portable and embedded systems built on the CMOS 80C86
The fully static CMOS 80C86 was adopted for battery-powered machines where the nMOS original could not go, including the Toshiba T1200, the HP 110 and the GRiDPad. Low-power 8086-compatible parts in CMOS remained in embedded use long after the desktop market had moved on.
Intel development systems and CONV86 migrations (1978-1980s)
Intel's own Intellec/ISIS-II systems hosted ASM86 alongside PL/M-86, and CONV86 gave 8080 and 8085 shops a mechanical path forward. Intel was candid that conversion was not free: converted code preserves function, not timing, and the converter emitted caution messages wherever hand-editing was required.
Lunar Prospector (NASA, 1998-1999)
The Lunar Prospector orbiter is reported to have used an 80C86 in its flight computer, placing the CMOS descendant of the 1978 design in lunar orbit twenty years after the chip's introduction. The attribution is widely repeated but rests on secondary sources rather than a mission document we could verify directly.