The page was updated on 1996-05-20.
Revision history:
1996-05-20 - 8086/8 vs. 80C86/8 added
1996-02-26 -initial version finished
This part of article describes the routines for recognizing 8086/88, V20/V30, 80186/188 and 80286 CPUs. Finally the test for 386 or better CPU is presented.
8086 was the first CPU in 80x86 family. Shortly it was followed by 8088, which had 8-bit data bus and slightly changed Bus Interface Unit.
80C86 and 80C88 are CMOS versions of 8086 and 8088. They have some bugs fixed.
80186 and 80188 have enhanced execution unit, capable of executing several new instruction for HLL support. The CPU is faster than 8086/88. There are also some peripheral devices on chip: DMA, interrupt controller and system controller.
NEC V-20 (8-bit bus) and V-30 (16-bit bus) are very smart chips: they can replace 8088 or 8086 CPU (have the same pinout). They execute all the instructions of 80186/188, but in some instruction details resemble rather 8086/88. They also introduce several new instructions (no practical use, since their opcodes overlap the opcodes for 80286 and above). They also have some other interesting property: they can execute 8080 binary code in so-called emulation mode.
80286 is the first CPU in x86 family providing OS support (protection etc.).
80186 and newer CPUs mask the shift/rotate amount with 1f hex to ensure that it is not greater than 32. This masking does not occur on 8086/8, V20 and V30. The test is simple: load any non-zero value to AX, load 32 to CL and shift AX by CL. The result will be zero on old CPUs, the original value on 80186 and newer chips.
V20 and V30 execute all the 80186 instructions. We can test the PUSHA (push all registers) instruction. This is single byte instruction on V20/V30, but 8086/88 executes it as two-byte NOP. The right sequence is PUSHA followed by NOP. After executing it we can check if SP value has changed. If so - we have V20/V30 and we shall execute POPA. Otherwise we have 8086/88.
CMOS vesions do not loose multiple prefixes during interrupt service. Practically the only situation in which it is important is MOVS prefixed with REP and segment override (segment override changes source segment and does not affect ES as destination segment). If the instruction is coded as REP + ES: + MOVS, REP prefix will be lost when the instruction is interrupted. On a PC, try to perform long block move (32KB or more) several times in a row, checking the value of CX after each pass. If CX != 0, REP was lost, and we have NMOS version.
The useful quirk is the behavior of PUSH SP instruction. On 186 and earlier machines SP value pushed on stack is the value after PUSH (decremented). On 286 and above, value PUSHed is the original value of SP. If we PUSH SP, then POP it to another register and compare the value against SP, they will be equal on 286+, different on earlier chips.
16-bit chips differ from their 8-bit bus versions in their Bus Interface Unit design. The instruction queue on 16-bit chips is 6 bytes long, while on 8-bit versions it is 4-bytes long. To test the length of instruction queue, we shall write a routine that modifies the instruction 5 bytes away from the current one (the one that actually modifies another one). The modified instruction can be NOP and it can be changed to INC register. If the instruction was executed as NOP, we have 6-byte queue (16-bit chip). If it was executed as INC, we have 4-bye queue (8-bit chip). Interrupts must be disabled while performing the test.
We can distinguish 286 from 32-bit chips by observing the behavior of CPU while trying to set bits 12..14 of FLAGS register. We do so by loading the value 7000 hex into FLAGS using PUSH and POPF instructions. Then we PUSHFlags, POP the value and check if bits 14..12 are all ones. If so, we have 32-bit CPU. Otherwise we have 286.