RP2040 的 PIO(可编程 I/O)子系统是复古计算机卡带仿真领域的强大工具,特别是针对 ZX Spectrum 和 Amiga 等机的磁带加载协议。这些协议依赖精确的波形时序,如 ZX Spectrum 的 pilot tone(约 806μs 高 / 低脉冲)和数据位(0 位约 1333μs,1 位约 667μs),传统 CPU bit-banging 难以维持纳秒级精度,而 PIO 状态机(State Machine, SM)可独立运行,达到系统时钟(133MHz)级别的确定性执行。
PIO 的核心在于 2 个 PIO 块,每个块 4 个 SM,共 8 个 SM,每个 SM 执行共享 32 条指令的 PIO 汇编程序。SM 配备 OSR(输出移位寄存器)、ISR(输入移位寄存器)、X/Y Scratch 寄存器、双向 FIFO(TX/RX),以及 DMA/IRQ 接口,支持 FIFO 与 CPU/DMA 无缝数据流。指令集仅 9 种:JMP、WAIT、IN、OUT、PUSH、PULL、MOV、IRQ、SET,支持 [delay] 槽(0~31 周期)和 side-set(并行设置最多 5 引脚)。例如,SET pins, 1 [10] 可精确生成 10 周期高脉冲,结合 clkdiv(16.8 定点分频)调整 SM 频率,实现 μs 级波形。
针对 ZX Spectrum 卡带(EAR 端口,3.5mm 单声道音频,~1200-4000Hz),协议分 pilot(2168 脉冲对齐)、sync1(806μs 高 + 1606μs 低)、sync2(668μs 高 + 1606μs 低)、数据位(pilot 后边沿对齐,0: 1333μs 高 + 1333μs 低;1: 667μs 高 + 1333μs 低)。Amiga 类似,但 FAST/SLOW 模式下时序不同(pilot 240μs/480μs)。PIO 优势:一个 SM 生成时钟 / 数据波形,另一个处理数据流(DMA 从 SD 卡读取 .tap/.tzx 文件),CPU 仅监控。
工程实现中,先用 pioasm 汇编 .pio 文件生成 .h(如 maxduino.pio)。典型 PIO 程序:
.program cassette_tx
loop:
pull block ; 从 TX FIFO 拉 32 位数据块
mov osr, ~x ; 反转位序(MSB 先)
bitloop:
jmp x-- bitloop ; X 递减至 0
out pins, 1 ; 输出 LSB 到 OUT pins(bit-bang)
set pins, 1 [pilot_delay] ; 高脉冲,延迟 pilot_delay 周期
set pins, 0 [sync_delay] ; 低脉冲
jmp !osre bitloop ; OSR 空时拉新数据
配置 SM:pio_sm_config c = cassette_tx_program_get_default_config (offset); sm_config_set_out_pins (&c, ear_pin, 1); sm_config_set_clkdiv (&c, div); pio_sm_init (pio0, sm0, offset, &c); pio_sm_set_enabled (pio0, sm0, true)。关键参数:
- SM 频率:sysclk /clkdiv,目标~1MHz(ZX pilot ~1.2kHz,周期~833 cycles)。133MHz / 133 = 1MHz,精确匹配 μs 级:pilot 高 806μs → 806 cycles,高 clkdiv=165(133MHz/165≈806kHz)。
- 延迟槽:[n] = n / SM_freq(μs)。pilot 高:n = 806μs * SM_freq;数据 0 高:n=667μs * freq。
- FIFO 阈值:autopull=true, pull_thresh=8,确保流式无中断。
- Side-set:sideset_count=1, sideset pins for EAR(GPx),指令侧带 set。
- DMA 链:DMA0 从 SD → PIO TX FIFO,IRQ 同步多 SM(一 SM 波形,一 SM 校验)。
落地清单:
- 硬件:RP2040 板(如 Pico),3.5mm JACK(GP0 EAR OUT),SD 卡槽(SPI GP1-4),复古机 EAR IN。
- 固件:CMake 添加 pio_add_program (pio0 cassette_tx.pio),UF2 刷入。SD 加载 .tap 文件,解析块头(pilot/sync/data len)。
- 参数表(133MHz sysclk):
| 协议 | 元素 | 高 (μs) | 低 (μs) | clkdiv | 高 delay | 低 delay |
|---|---|---|---|---|---|---|
| ZX Pilot | 高 / 低 | 806 | 806 | 165 | 133 | 133 |
| ZX Data0 | 高 / 低 | 1333 | 1333 | 200 | 267 | 267 |
| ZX Data1 | 高 / 低 | 667 | 1333 | 200 | 133 | 267 |
| Amiga SLOW | Pilot | 240 | 240 | 278 | 67 | 67 |
- 监控 / 回滚:UART 日志 SM IRQ(rx_fifo () 检查溢出),示波器验波形(±5% 时序容忍)。风险:时钟漂移→动态 clkdiv 校准;长 tape(>10min)→DMA 优先级高,避免 CPU 饥饿。
- 优化:多 SM 并行(SM0 pilot/sync,SM1 data),JOIN_TX FIFO 双倍缓冲。
实际项目如 MaxDuino 使用 PIO 精确仿真多协议,支持 ZX/Amiga/MSX 等,加载速度达原生 100%。相比 CPU 轮询,PIO 零 jitter,功耗低(空闲 <1mA)。
资料来源:
- RP2040 数据手册 PIO 章节。
- ZX Spectrum 卡带格式规范(WOS)。
- MaxDuino 项目(retrogamecoders 评测)。