首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

組合語言實戰:串口 UART 類型檢測程序 (SERTYPE.ASM) 詳解

     編輯:組合語言

程序功能

SERTYPE 掃描系統 BIOS 數據區 (0040h:0000h) 中的 COM 端口基址 (最多 4 個),對每個存在的端口通過 I/O 端口操作識別 UART 型號:

  • Type 0: NS 8250 (無 FIFO)
  • Type 1: NS 8250A/16450/16550 (無 FIFO)
  • Type 2: NS 16550A / Intel 82510 (有 FIFO)
  • Type 3: IBM Type 3 (FIFO + DMA)

檢測結果直接輸出到屏幕,無參數交互。

核心檢測邏輯 (uartdet 子程序)

  1. 保存現場:PUSH BX, CX,BX 保存基址。
  2. 禁用中斷:讀取 Modem Control Register (基址+4),清 bit2 (OUT2),寫回,防止檢測過程產生中斷。
  3. Scratch Register 測試 (基址+7):
    • 寫 0x55,讀回比較;寫 0xAA,讀回比較。
    • 均通過 → 至少是 16450/16550 (Type ≥ 1),CH=1。
    • 失敗 → 8250 (Type 0),跳轉 endudet。
  4. FIFO Control Register 測試 (基址+2, 實為 IIR/FCR 共用):
    • 寫 0x07 (啟用 FIFO),讀回 IIR 高兩位 (bit6-7)。
    • 高兩位為 0 → 16450/16550 無 FIFO (Type 1)。
    • 高兩位非 0 → 有 FIFO (Type ≥ 2),CH=2。
  5. Enhanced Register 測試 (基址+0x8003, 僅 Type 3 支持):
    • 讀取 Enhanced Register 1,置 bit6 (DMA 發送使能),寫回。
    • 再次讀取 FCR 高兩位,若為 0x40 → 支持 DMA (Type 3),CH=3。
  6. 恢復現場:恢復 Modem Control Register,返回 AL=CH (0-3)。

關鍵 I/O 端口映射 (以 COM1 0x3F8 為例)

偏移讀/寫功能
+0R/WRBR/THR/DLL (接收/發送緩衝/除數鑰低位)
+1R/WIER/DLM (中斷使能/除數鑰高位)
+2RIIR (中斷識別)
+2WFCR (FIFO 控制)
+3R/WLCR (線路控制)
+4R/WMCR (Modem 控制)
+5RLSR (線路狀態)
+6RMSR (Modem 狀態)
+7R/WSCR (Scratch 暫存)

完整源碼 (SERTYPE.ASM)

comment *
 SERTYPE.ASM
 Purpose: Determines the type of UART in each serial port
 Author: Douglas Boling, in PcMag. With some modifications by Yousuf Khan.
*
dosseg
bdseg segment at 40h
 com1 dw ?
 com2 dw ?
 com3 dw ?
 com4 dw ?
 ends
_data segment para 'data'
 uart1 db 0
 uart2 db 0
 uart3 db 0
 uart4 db 0
 portmsg db "COMx: $"
 x8250 db "NS 8250 (non-FIFO)",13,10,"$"
 x16450 db "NS 8250A/16450/16550 (non-FIFO)",13,10,"$"
 xfifo db "NS 16550A/Intel 82510 (FIFO)",13,10,"$"
 xdma db "IBM type 3 (FIFO/DMA)",13,10,"$"
 pas_de_ports db "No serial ports detected",13,10,"$"
 ends
_stack segment para stack 'stack'
 db 200h dup (?)
 ends
cseg segment para 'code'
 mov ax, bdseg
 mov es, ax
 mov ax, _data
 mov ds, ax
 assume cs:cseg, ds:_data, es:bdseg, ss:_stack
 xor al, al
 mov dx, [com1]
 cmp dx, 0
 je eoproc
 inc al
 push ax
 call uartdet
 mov [uart1], al
 pop ax
 mov dx, [com2]
 cmp dx, 0
 je eoproc
 inc al
 push ax
 call uartdet
 mov [uart2], al
 pop ax
 mov dx, [com3]
 cmp dx, 0
 je eoproc
 inc al
 push ax
 call uartdet
 mov [uart3], al
 pop ax
 mov dx, [com4]
 cmp dx, 0
 je eoproc
 inc al
 push ax
 call uartdet
 mov [uart4], al
 pop ax
eoproc:
 call disp
 mov ah, 4ch
 int 21h
delay macro
 jmp $+2
 endm
uartdet proc near
 push bx
 push cx
 mov bx, dx
 add dx, 4
 in al, dx
 push ax
 and al, 11111011b
 out dx, al
 mov ch, 0
 mov dx, bx
 add dx, 7
 mov al, 55h
 cli
 out dx, al
 delay
 in al, dx
 cmp al, 55h
 jne endudet
 mov al, 0AAh
 out dx, al
 delay
 in al, dx
 sti
 cmp al, 0AAh
 jne endudet
 inc ch
 mov dx, bx
 add dx, 2
 mov al, 7
 cli
 out dx, al
 delay
 in al, dx
 sti
 and al, 0c0h
 jz endudet
 inc ch
 mov dx, bx
 add dx, 8003h
 cli
 in al, dx
 push ax
 or al, 01000000b
 out dx, al
 push dx
 mov dx, bx
 add dx, 2
 in al, dx
 mov cl, al
 pop dx
 pop ax
 out dx, al
 sti
 and cl, 0c0h
 cmp cl, 40h
 jne endudet
 inc ch
endudet:
 pop ax
 mov dx, bx
 add dx, 4
 out dx, al
 xor ax, ax
 mov al, ch
 mov dx, bx
 pop cx
 pop bx
 ret
uartdet endp
disp proc near
 push ax
 cmp al, 0
 je noports
 mov bx, offset ds:[uart1]
 mov di, offset ds:[portmsg][3]
 mov cx, 0
 mov cl, al
@l1:
 mov dl, 4
 sub dl, cl
 add dl, 30h
 mov [di], dl
 lea dx, portmsg
 mov ah, 9
 int 21h
 mov dl, [bx]
 cmp dl, 0
 jne @t2
 lea dx, x8250
 mov ah, 9
 int 21h
 jmp @eot
@t2: cmp dl, 1
 jne @t3
 lea dx, x16450
 mov ah, 9
 int 21h
 jmp @eot
@t3: cmp dl, 2
 jne @t4
 lea dx, xfifo
 mov ah, 9
 int 21h
 jmp @eot
@t4: lea dx, xdma
 mov ah, 9
 int 21h
@eot: inc bx
 loop @l1
 jmp eoproc2
noports:
 lea dx, pas_de_ports
 mov ah, 9
 int 21h
eoproc2:
 pop ax
 ret
disp endp
 ends
 end

技術亮點總結

  • 直接操作 BIOS 數據區獲取端口基址,無需枚舉 PCI/ISA 總線。
  • 利用 Scratch Register 存在性區分 8250 與 16450+。
  • 利用 FCR 寫入後 IIR 高兩位回讀區分是否有 FIFO (16550A 特徵)。
  • 嘗試訪問 Enhanced Register (0x8003) 並啟用 DMA 位識別 IBM Type 3。
  • delay macro (JMP $+2) 提供極短 I/O 恢復延遲,兼容慢速總線。
  • 代碼結構清晰:主循環枚舉端口 → 調用檢測 → 存儲類型 → 統一顯示。

現代視角

現代系統串口多為 PCIe/USB 虛擬 UART,BIOS 數據區可能不再準確反映硬件。但該檢測邏輯在嵌入式開發、舊硬件維護、引導加載器早期串口初始化中仍具參考價值。理解 8250/16450/16550/16550A/16750/16950 等 UART 演進歷史,有助於編寫健壯的串口驅動。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved