当然可以!下面是关于**内存映射 I/O(MMIO)与端口映射 I/O(PMIO)**的详细对比和简明解释。
🧠 一文看懂:MMIO vs PMIO
在操作系统或底层硬件编程中,CPU 需要与外设(比如键盘、鼠标、网卡、显卡)通信。常见的 I/O 编程方式有两种:
- MMIO(Memory-Mapped I/O,内存映射 I/O)
- PMIO(Port-Mapped I/O,也叫 IO-Mapped I/O,端口映射 I/O)
🟢 一、核心区别总结
对比项 | MMIO(内存映射 I/O) | PMIO(端口映射 I/O) |
---|---|---|
地址空间 | 使用主内存地址空间 | 使用独立的 I/O 地址空间 |
访问指令 | 普通内存访问指令(如 MOV ) | 特殊 I/O 指令(如 IN / OUT ) |
CPU支持 | 所有现代 CPU(通用支持) | x86 特有(如 Intel/AMD) |
指令简洁性 | 更灵活,兼容 C 语言指针 | 不方便高级语言直接访问 |
总线控制 | 通常与内存统一总线 | 需要额外控制线(IO/M 控制信号) |
地址范围 | 与 RAM 共享地址空间 | 限制:x86 中最多 64KB(0x0000-0xFFFF) |
复杂性 | 设计上更灵活统一 | 控制器实现较简单 |
🔵 二、原理示意
1. MMIO(Memory-Mapped I/O)
外设的寄存器被映射到内存地址空间的一部分。CPU 通过读写特定的地址,就像访问内存一样与设备通信。
#define UART0_BASE 0x10000000
*(volatile char *)(UART0_BASE) = 'A'; // 向串口发送数据
访问过程:
- CPU 发出地址 → 总线判断是否为设备地址 → 转到设备控制器 → 读写完成。
2. PMIO(Port-Mapped I/O)
CPU 使用专门的 IN
/ OUT
指令,通过 I/O 地址空间来读写外设。
mov dx, 0x60 ; 键盘端口
in al, dx ; 从键盘读入一个字节
访问过程:
- CPU 发出 I/O 地址 + IO/M 控制线 = 1 → 外设响应端口 → 传输数据。
🟠 三、使用场景举例
场景 | 使用方式 |
---|---|
Linux 内核驱动 | 大多采用 MMIO |
BIOS、早期 DOS 程序 | 常用 PMIO(因为早期设备资源有限) |
嵌入式系统 | 更常用 MMIO,因其统一、简洁 |
x86 PC 上的显卡、南桥芯片 | 两者混用(PCI 设备多用 MMIO) |
🔴 四、优劣对比分析
✅ MMIO 优点:
- 访问方式统一(和内存一样),易于移植和高级语言编写;
- 不需要专门指令,支持更多寄存器;
- 地址范围大,可用 32/64 位地址访问。
❌ MMIO 缺点:
- 会占用一部分地址空间;
- 需要设置页表/内核映射才能访问外设地址(可能增加复杂性);
- 缓存策略需注意(如需设置为不可缓存)。
✅ PMIO 优点:
- 不占用主内存地址空间;
- 控制逻辑简单,适合早期硬件;
- 不易被误操作(必须通过特殊指令访问)。
❌ PMIO 缺点:
- 指令不通用(非 x86 架构不支持);
- 编程不如 MMIO 灵活;
- 地址空间有限(最多 64K);
🟣 五、总结一句话
MMIO 是现代主流、灵活统一的设备访问方式;PMIO 是历史遗产,更适用于特定体系结构(如 x86)的早期硬件设计。
🧩 补充:Linux 如何使用 MMIO?
在 Linux 驱动开发中,你常会看到:
void __iomem *reg = ioremap(0x10000000, 0x1000);
writel(0x1234, reg);
ioremap()
映射设备物理地址到虚拟地址;writel()
等内核函数用于访问 MMIO 寄存器。
发表回复