velxio/test/test_intel/autosearch/15_8086_authoritative_spec.md

11 KiB

8086 Authoritative Spec (for Velxio Emulator)

Primary source: Intel, The 8086 Family User's Manual, October 1979 (order 9800722-03), located at pdfs/iapx_86_88_users_manual.pdf in this folder. All page citations use the PDF page index in parentheses followed by the manual section number that appears on the page (Intel uses chapter-relative numbering like "2-25", "4-2"). Where the manual is silent or ambiguous, the iAPX 86,88 User's Manual, 1981 edition (a superset) is consulted by reference; no disagreements were found in the parts that overlap.


1. Pin Contract — 40-pin DIP, Minimum Mode (MN/MX = Vcc)

From figure 4-1 (PDF p.240, manual p.4-2). All 40 pins of the 8086 are listed.

Common pins (both modes)

Pin Name Type Function
2-16, 39 AD15-AD0 Bidirectional, 3-state Time-multiplexed address (T1) / data (T2-T4)
35-38 A19/S6 - A16/S3 Output, 3-state Upper address bits in T1; status thereafter
34 BHE/S7 Output, 3-state Bus High Enable in T1 (low = upper byte valid)
33 MN/MX Input Strap: Vcc = minimum mode, GND = maximum
32 RD Output, 3-state Read strobe (active low)
23 TEST Input WAIT instruction polls this (active low)
22 READY Input Wait-state insertion (sampled in T3)
21 RESET Input Active high; min 4 CLK cycles (50 µs at power-up)
17 NMI Input Rising edge, vector 2
18 INTR Input Level, maskable by IF
19 CLK Input 33% duty, 5/8/10 MHz
40 Vcc / 1, 20 GND Power

Min-mode-only pins (24-31) — Table 4-1 (PDF p.249, manual p.4-11):

Pin Min Mode Maximum-mode alias
31 HOLD RQ/GT0
30 HLDA RQ/GT1
29 WR LOCK
28 M/IO S2
27 DT/R S1
26 DEN S0
25 ALE QS0
24 INTA QS1

ALE pulses high once per bus cycle, valid trailing edge in T1 (PDF p.245, manual p.4-7). DEN gates the bidirectional bus transceiver; DT/R selects direction (1 = transmit/write, 0 = receive/read). M/IO is high for memory, low for I/O on the 8086 (the 8088 inverts this signal as IO/M, PDF p.249).


2. Reset State

From "System Reset" (PDF p.51, manual p.2-29) and Table 2-4 referenced there. RESET must be held high for ≥ 4 CLK cycles (≥ 50 µs at power-up). When RESET goes low, the CPU initializes:

Component Value at reset
Flags clear (0x0000; reserved bits per Fig 2-9 are 1, see §5)
IP 0x0000
CS 0xFFFF
DS 0x0000
SS 0x0000
ES 0x0000
Instruction queue empty

First fetched physical address = CS:IP = FFFF:0000 → physical 0xFFFF0 (PDF p.51 / manual p.2-29). Typical ROM holds an inter-segment JMP there. NMI/INTR/HOLD are ignored while RESET is active. HOLD is honored immediately after RESET deasserts if asserted (PDF p.252, manual p.4-14).


3. Bus Cycle T1-T4 (Minimum Mode)

From "Bus Operation" (PDF pp.244-247, manual pp.4-6 to 4-9), figures 4-7 through 4-10. One bus cycle = 4 CLK states T1, T2, T3, T4. Wait states Tw are inserted between T3 and T4 when READY is sampled low in T3 (PDF p.244).

State AD15-AD0 A19/S6-A16/S3 ALE RD/WR DT/R DEN M/IO
T1 20-bit address out (with BHE) address out high pulse inactive set early inactive valid
T2 float (read) or write data out status S3-S6 low RD or WR active stable active held
T3 data sampled (read) or held (write) status low active stable active held
Tw bus held; READY polled status low active stable active held
T4 bus released status low inactive inactive inactive

Status lines S3-S4 indicate which segment was used (Table 2-7, PDF p.52): 00 = ES, 01 = SS, 10 = CS or none, 11 = DS. S5 mirrors IF, S6 = 0 (8086).

S2-S0 in maximum mode encode the cycle type (Table 2-6, PDF p.52 / Table 4-2, PDF p.250): 000 = INTA, 001 = I/O read, 010 = I/O write, 011 = HALT, 100 = code fetch, 101 = mem read, 110 = mem write, 111 = passive.


4. 20-Bit Address Arithmetic

From "Physical Address Generation" (PDF pp.34-35, manual pp.2-12 to 2-13), figure 2-18:

physical = (segment << 4) + offset    (modulo 0x100000 — wraps at 1 MB)

The segment is shifted left 4 bits (multiplied by 16), then the 16-bit offset is added. Carry out of bit 19 wraps. Inside a single 64 KB segment, the offset arithmetic itself is modulo 0x10000 (PDF p.34, manual p.2-12: "addresses wrap around from the end of a segment to the beginning of the same segment").


5. Default Segments and Override Prefixes

From Table 2-2 "Logical Address Sources" (PDF p.35, manual p.2-13):

Reference type Default seg Offset Allowed overrides
Instruction fetch CS IP none
Stack push/pop, call/ret SS SP none
BP used as base reg SS EA CS, DS, ES
Data variable (other) DS EA CS, ES, SS
String source (SI) DS SI CS, ES, SS
String destination (DI) ES DI none

Override prefixes (one byte, applies to next instruction): 0x26 = ES:, 0x2E = CS:, 0x36 = SS:, 0x3E = DS: (manual p.2-13 and encoding table 4-12, PDF p.260+). The general SR encoding is 00=ES, 01=CS, 10=SS, 11=DS (Table 4-11, PDF p.259).


6. ModR/M Decode (Tables 4-8, 4-9, 4-10; PDF p.258, manual p.4-20)

The instruction's second byte is mod (2) | reg (3) | r/m (3).

MOD field (Table 4-8):

00 = memory mode, no displacement       (special: r/m=110 → 16-bit disp16 direct)
01 = memory mode, sign-extended 8-bit displacement
10 = memory mode, 16-bit displacement
11 = register mode (r/m selects the register)

REG field (Table 4-9) — w-bit selects byte vs word register:

REG w=0 w=1
000 AL AX
001 CL CX
010 DL DX
011 BL BX
100 AH SP
101 CH BP
110 DH SI
111 BH DI

R/M effective-address table (Table 4-10, manual p.4-20). When MOD ≠ 11:

R/M Effective address
000 (BX)+(SI)+disp
001 (BX)+(DI)+disp
010 (BP)+(SI)+disp (default seg = SS)
011 (BP)+(DI)+disp (default seg = SS)
100 (SI)+disp
101 (DI)+disp
110 (BP)+disp (default SS; if MOD=00 → disp16 absolute, default DS )
111 (BX)+disp

Default segment for any addressing mode that uses BP as a base is SS; all others default to DS. Segment-override prefix overrides this.


7. Flag Register Layout

From "Flags" (manual pp.2-7 to 2-8) and figure 2-9 (referenced PDF p.30, manual p.2-8). The 16-bit flag register is laid out as:

bit 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0
     -  -  -  -  OF DF IF TF SF ZF -  AF -  PF -  CF

Bits 1, 3, 5, 12-15 are reserved; bit 1 reads as 1 on real hardware (the 1979 manual is silent on the reserved-bit encoding — a known disagreement: 8086tiny treats them as 0, MartyPC and the 8088 V2 SingleStepTests canonicalize bit 1 = 1, bits 12-15 = 1 on reset. Both agree all other bits clear at reset.)

Per-flag rules (PDF pp.57-58, manual pp.2-35 to 2-36):

  • CF: carry-out of MSB on add; borrow into MSB on sub. Used by ADC/SBB.
  • AF: carry-out of bit 3 on add; borrow into bit 3 on sub. Used only by decimal-adjust instructions.
  • SF: copy of bit 7/15 of result.
  • ZF: 1 if result == 0.
  • PF: even parity over the low 8 bits of the result.
  • OF: signed overflow (XOR of carry-into-MSB and carry-out-of-MSB).
  • DF: 0 = string ops auto-increment SI/DI; 1 = decrement.
  • IF: 1 = INTR enabled.
  • TF: 1 = single-step (INT 1 after each instruction).

8. Variable-Length Instruction Format

From manual §4.2, "Machine Instruction Encoding" (PDF p.258+). Up to 6 bytes, in this order:

[ prefix ]*  opcode (1-2 bytes)  [ ModR/M ]  [ disp lo,hi ]  [ imm lo,hi ]

Prefix bytes: segment override (0x26/2E/36/3E), LOCK (0xF0), REP/REPE (0xF3), REPNE (0xF2). Multiple prefixes are allowed but the CPU "remembers" only one per category (PDF p.64, manual p.2-42); on interrupted REP+segov the segment override is dropped on resume.

Displacement encoding (Table 4-11 key, PDF p.259): little-endian; an 8-bit displacement is sign-extended to 16 bits before EA addition. Immediates likewise little-endian, with sign-extension controlled by the s bit in arithmetic encodings.


9. Decimal-Adjust and ASCII-Adjust Flag Rules

From PDF pp.57-58 (manual pp.2-35 to 2-37) and the instruction reference table 2-21 (PDF p.73, manual p.2-51) which gives the canonical "flags affected" mask ODITSZAPC (each letter = 1 flag) per instruction.

Insn Flags OF SF ZF AF PF CF
AAA OSZP undefined; AF, CF defined U U U X U X
AAS OSZP undefined; AF, CF defined U U U X U X
AAM OAC undefined; SZP defined U X X U X U
AAD OAC undefined; SZP defined U X X U X U
DAA OF undefined; AF/CF/PF/SF/ZF defined U X X X X X
DAS OF undefined; AF/CF/PF/SF/ZF defined U X X X X X
MUL SF/ZF/AF/PF undefined; OF=CF=(AH≠0) for byte, (DX≠0) for word X U U U U X
IMUL SF/ZF/AF/PF undefined; OF=CF=(sign-extend mismatch) X U U U U X
DIV all six arithmetic flags undefined U U U U U U
IDIV all six arithmetic flags undefined U U U U U U

DAA pseudocode (manual p.2-36, PDF p.58):

old_AL = AL;  old_CF = CF
if (AL & 0x0F) > 9 OR AF=1 :  AL += 6;  AF=1;  CF |= (AL overflowed)
if old_AL > 0x99 OR old_CF=1 : AL += 0x60;  CF=1

DAS is the symmetric subtract form. Adrian Cable's 8086tiny and Daniel Balsom's MartyPC both implement this exact pseudocode; they disagree only on flag-after-DAA OF (manual says undefined; tinyemus typically leave it unchanged).


10. String-Op + REP Flag/Counter Rules

From "String Instructions" (manual pp.2-41 to 2-43, PDF pp.63-65).

Each iteration:

  1. If CX = 0, fall through immediately (no flag/index changes).
  2. Execute one MOVS / CMPS / SCAS / LODS / STOS.
  3. Decrement CX by 1 (no flag effect from this decrement).
  4. Adjust SI/DI by ±1 (byte) or ±2 (word); sign = -1 if DF=1 else +1.
  5. For CMPS/SCAS only: check ZF — REPE/REPZ exits when ZF=0; REPNE/REPNZ exits when ZF=1.
  6. For MOVS/STOS/LODS: no ZF check; exit only when CX = 0.

Interruptibility: the CPU samples INTR between iterations (manual p.2-42); on interrupt, IP is rolled back to the prefix byte so the REP resumes after IRET, but only the last-seen prefix among LOCK/segov/REP survives — a known erratum quoted on PDF p.64.


Sources & Disagreements Flagged

  1. Reserved-flag-bit encoding: 1979 iAPX manual silent; SingleStepTests 8088 V2 suite canonicalizes bit 1 = 1.
  2. DAA effect on OF: manual says undefined; 8086tiny leaves OF unchanged, MartyPC follows the manual literally and writes a random value.
  3. POP CS (opcode 0x0F) is not documented in the 1979 manual but is a known real-hardware behavior on 8086 only (8088 ignores it differently). See 16_8086_reference_implementations.md §"Cross-checked edge cases".