在 8086 到 486 時代,CPU 指令集與數學協處理器 (8087/287/387) 的有無直接決定了軟體能否使用浮點指令、32 位元指令、特定優化路徑。CHIPS (由 Pat Shea 撰寫,1987-88) 提供一個標準 C 可呼叫的 FAR 函式 int chips(void),回傳編碼後的 CPU 型號與 NDP 型號,供執行期動態選擇最佳程式碼路徑。程式碼模組化 (cpu_type + ndp_type)、註解詳盡、相容 MASM 5.0,是系統程式庫設計的教科書級範例。
AX = CPU_Code * 10 + NDP_Code (實際為 CPU_Code + NDP_Code,CPU_Code 為 80/180/280/380/200,NDP_Code 為 0/1/2/3):
採決策樹,依序排除:
PUSHF/POP/AND/PUSH/POPF/POP 測試 → 可清零則 ≥286 (回傳 2),否則進入 dig。7000h。PUSH/POPF/PUSHF/POP/AND 檢查是否保留 → 保留則 386+ (回傳 4),否則 286 (回傳 2)。MOV AX,0FFFFH / MOV CL,33 / SHL AX,CL。8088/86 僅取 CL 低 5 位 (33→1),結果非零;186/188 取完整 CL,33 位移清零。非零 → 186/188 (回傳 180)。XOR AL,AL / MOV AL,40H / MUL AL。NEC V20/V30 不影響 ZF (結果 0);8088/86 設定 ZF。ZF=1 → NEC (回傳 200),否則 8088/86 (回傳 80)。採用 Ted Forgeron (PC Tech Journal, 1987) 經典演算法:
03h (預設控制字高位元組) → 有 NDP,否則無 (回傳 0)。FDISI / FSTCW 檢查 IEM 是否置位。8087 支援 FDISI/FENI;287/387 不支援 (忽略)。置位 → 8087 (回傳 1)。FINIT / FLD1 / FLDZ / FDIV / FLD ST / FCHS / FCOMPP / FSTSW 產生 +∞ 和 -∞ 比較。8087/287 的無限大比較行為不同:8087 視為無序 (C3=1),287 視為不相等 (C3=0)。SAHF / JNZ 區分 → 287 (回傳 2)。_chips PROC
control dw 0
push BP
mov BP,SP
push DI
push SI
push CX
call cpu_type ; DX = CPU code
call ndp_type ; AX = NDP code
add AX,DX ; 合併回傳\n /> pop CX
pop SI
pop DI
pop BP
ret\n />_chips ENDP\n />cpu_type PROC\n /> pushf\n /> xor DX,DX\n /> xor AX,AX\n /> push AX\n /> popf\n /> pushf\n /> pop AX\n /> and AX, 0F000h\n /> cmp AX, 0F000h\n /> jz dig\n /> mov AX, 7000h\n /> push AX\n /> popf\n /> pushf\n /> pop AX\n /> and AX, 7000h\n /> jnz got386\n /> mov DX, 280\n /> jmp SHORT CPUbye\n />got386: mov DX, 380\n /> jmp SHORT CPUbye\n />dig: mov AX, 0FFFFh\n /> mov CL, 33\n /> shl AX, CL\n /> jz digmor\n /> mov DX, 180\n /> jmp SHORT CPUbye\n />digmor: xor AL,AL\n /> mov AL, 40h\n /> mul AL\n /> jz gotNEC\n /> mov DX, 80\n /> jmp SHORT CPUbye\n />gotNEC: mov DX, 200\n />CPUbye: popf\n /> ret\n />cpu_type ENDP\n />ndp_type PROC\n />do_we: fninit\n /> mov byte ptr control+1, 0\n /> fnstcw control\n /> mov AH, byte ptr control+1\n /> cmp AH, 03h\n /> je chk_87\n /> xor AX,AX\n /> jmp SHORT NDPbye\n />chk_87: and control, NOT 0080h\n /> fldcw control\n /> fdisi\n /> fstcw control\n /> test control, 0080h\n /> jz chk287\n /> mov AX, 1\n /> jmp SHORT NDPbye\n />chk287: finit\n /> fld1\n /> fldz\n /> fdiv\n /> fld st\n /> fchs\n /> fcompp\n /> fstsw control\n /> fwait\n /> mov AX, control\n /> sahf\n /> jnz got387\n /> mov AX, 2\n /> jmp SHORT NDPbye\n />got387: mov AX, 3\n />NDPbye: ret\n />ndp_type ENDP
cpu_type、ndp_type 獨立 PROC,單一職責,易維護擴展。cpu_type 開頭 PUSHF、結尾 POPF,確保不干擾呼叫端旗標。/R 選項即可組譯協處理器指令 (內建支援)。cpu = ret/10; ndp = ret%10 類邏輯)。現代 x86 以 CPUID (EAX=1 → ECX/EDX 特徵旗標) 統一偵測 CPU 特性 (SSE/AVX/HT/VMX 等) 與 FPU 內建 (所有現代 CPU 含 x87)。但 CHIPS 的設計哲學依然適用:
chips()),上層應用無需知悉細節。CHIPS 以不到 200 行組合語言,解決了當時跨硬體平台部署的核心難題,其「偵測 → 抽象 → 適配」三階段模式,正是現代硬體抽象層 (HAL)、JIT 編譯器特性探測、WebAssembly SIMD 特性檢測的遠古雛形。