Skip to content

端口

端口的概念

CPU 可以直接读写的地址空间:

  • 内存地址空间:连接内存芯片
  • 端口地址空间:连接各种接口芯片(键盘控制器、磁盘控制器、CMOS RAM 等)

接口芯片内部有寄存器,CPU 通过端口地址读写这些寄存器,间接控制外设。

端口地址范围:0~65535(共 64KB 个端口)

类比:端口 ≈ 设备的"寄存器窗口",CPU 通过 I/O 地址总线访问,与内存总线分离。

in 和 out 指令

端口读写只能用专用指令,不能用 mov

从端口读数据

asm
; 端口号 ≤ 255:直接写端口号
in al, 60h      ; 从 60h 端口读 1 字节到 al

; 端口号 > 255:端口号必须放在 dx 中
mov dx, 3f8h
in al, dx       ; 从 3F8h 端口读 1 字节到 al
in ax, dx       ; 从 3F8h 端口读 2 字节到 ax

向端口写数据

asm
out 70h, al     ; 将 al 写入 70h 端口
mov dx, 3f8h
out dx, al      ; 将 al 写入 dx 指向的端口

注意:in/out 只能用 al(8位)或 ax(16位)作为数据寄存器。

CMOS RAM 芯片

CMOS RAM 用于保存实时时间和硬件配置,由电池供电,关机后数据不丢失。

  • 容量: 128 字节
  • 端口:
    • 70h:地址端口(写入要访问的字节索引)
    • 71h:数据端口(读出该字节的值)

访问方法:

asm
; 读 CMOS RAM 的第 N 个字节
mov al, N       ; N = 字节索引
out 70h, al     ; 告诉芯片:我要访问第 N 个字节
in  al, 71h     ; 读取数据

CMOS 时间数据单元(部分):

偏移含义
0
2
4
7
8
9年(后两位)

注意:所有值以 BCD 码存储。BCD 码:高 4 位=十位,低 4 位=个位。例如 0x23 = 23,不是十进制的 35。

shl 和 shr 指令(移位)

asm
shl 目标, 移位数    ; 逻辑左移(高位移入 CF,低位补 0)
shr 目标, 移位数    ; 逻辑右移(低位移入 CF,高位补 0)

移位数可以是立即数 1,或 cl 寄存器中的值(8086规定):

asm
mov al, 01010001b
shl al, 1           ; 左移1位:10100010b,移出位→CF=0

mov cl, 3
shr al, cl          ; 右移3位

应用:合并 BCD 码的十位和个位

asm
; 读出月份(BCD码),分解为两位数字显示
in al, 71h          ; al = BCD月份,如 06h = 6月
mov ah, al
mov cl, 4
shr ah, cl          ; ah = 十位(高4位 → 低4位)
and al, 0fh         ; al = 个位(低4位)
add ax, 3030h       ; 转为 ASCII 码('0' = 30h)

实战示例:读取 CMOS 时间(月份)

asm
assume cs:code

code segment
start:
    ; 读取月份(单元 8)
    mov al, 8
    out 70h, al
    in  al, 71h         ; al = BCD月份

    ; BCD → 两个 ASCII 字符
    mov ah, al
    mov cl, 4
    shr ah, cl          ; 十位
    and al, 0fh         ; 个位
    add ax, 3030h       ; 转 ASCII

    ; 在屏幕 0 行 0 列显示
    mov bx, 0b800h
    mov es, bx
    mov es:[0], ah      ; 十位字符
    mov byte ptr es:[1], 07h   ; 颜色:白色
    mov es:[2], al      ; 个位字符
    mov byte ptr es:[3], 07h

    mov ax, 4c00h
    int 21h
code ends
end start