在复古计算机修复与现代化改造的浪潮中,将原始 Z80 CPU 替换为现代可编程芯片已成为一种趋势。PicoZ80 项目的出现标志着这一领域的重大突破 —— 它不仅是一个简单的模拟器适配器,更是一个能够在硬件层面完美复现 Z80 总线时序的 drop-in 替代方案。本文将从指令集兼容层、时序仿真与硬件边界检测三个维度,系统阐述构建此类替代实现的核心工程要点。
指令集兼容层的架构设计
构建 Z80 兼容层的首要挑战在于如何处理那些「未文档化」的指令与边缘行为。Z80 虽然拥有完整的官方指令集,但其在漫長發展歷史中沉淀了大量未公开指令与隐含行为,这些细节直接影响老旧软件的兼容性。在 PicoZ80 的设计中,开发者选择了 redcode 维护的 Z80 C 语言模拟器库作为核心,该库以高精确度和完整的未文档化 opcode 支持著称。工程实践表明,单纯依赖自行编写的模拟器往往会在标志位处理或位操作指令上出现细微偏差,而这些偏差可能导致诸如《Zork》等经典文字冒险游戏无法正常运行。
在指令集兼容层的实现层面,开发者采用了双核分工策略:RP2350 的第二个核心专门负责 Z80 指令的热循环执行,通过服务 PIO FIFO 来处理 Z80 总线事务,并将每个地址解析为内存映射中的对应块。这种设计的优势在于,它将指令执行与总线通信完全解耦 —— 核心一专注于指令解析与执行,核心零则处理 USB 桥接、固件协调、文件 I/O 以及 ESP32 命令转发等非实时任务。指令模拟器与 PIO 总线接口之间的通信延迟被严格控制在最小范围内,因为内部循环被保留在 SRAM 中执行,且 512KB 的 RP2350 内置 SRAM 被用作内存块指针的快速查找表。
周期精确时序仿真的实现路径
周期精确(Cycle-accurate)是 Z80 替代实现的核心技术指标。与普通模拟器不同,周期精确意味着每一个总线周期 —— 包括取指、内存读写、I/O 操作 —— 都必须严格按照原始 Z80 的时序要求执行,任何偏差都可能导致依赖精确时序的老程序出错,例如磁带录音机控制软件或自定义串口通信协议。PicoZ80 利用 RP2350 可编程 I/O(PIO)状态机实现了这一目标,这是一套完全独立于 Cortex-M33 内核的硬件状态机,能够以确定性方式处理高速 I/O 而无需 CPU 介入。
具体而言,PicoZ80 的 Z80 总线接口由三个 PIO 块实现,每个块包含四个状态机器。PIO 零负责地址与数据总线 —— 处理 16 位地址总线(A0 至 A15)和双向 8 位数据总线(D0 至 D7),同时运行的 z80_addr 与 z80_data 程序能够同步推送地址字并驱动或采样数据字节。PIO 一处理控制信号与周期执行 —— 包括总线请求与响应、MREQ、IORQ、RD、WR、M1、RFSH、HALT、INT、NMI、WAIT、CLK、RESET 等全部 12 条控制信号,以及取指、内存读写、I/O 读写等完整的总线周期序列。PIO 二则专注于主机时序、重置、刷新与等待状态 —— 其中 z80_wait 状态机通过可配置的 tcycwait 参数向主机总线插入额外的 T 周期等待状态,以满足较慢外设或 BANKED ROM/RAM 的时序要求。
时序仿真的另一个关键要素是 T1 同步。Z80 在每个总线周期的 T1 上升沿将有效地址放在总线上,精确捕捉这一时刻对于依赖主机时钟的应用程序至关重要 —— 包括软件延时循环以及磁带电机控制和串口位翻转等时间敏感的 I/O 操作。z80_sync 程序专门用于检测 T1 上升沿并通过 IRQ 信号通知核心一,从而确保 RP2350 内部内存操作不会引入可感知的时序漂移。这种架构确保了即使核心一正在服务 PSRAM 访问或虚拟设备调用,总线接口仍能以确定性方式做出响应。
硬件边界检测与虚拟化框架
硬件边界检测是 drop-in 替代实现区别于纯软件模拟的关键所在。在真实的 Z80 系统中,CPU 与内存、外设之间存在复杂的电气交互 —— 包括总线请求(BUSREQ)/ 总线响应(BUSACK)握手、等待状态(WAIT)插入、以及不可屏蔽中断(NMI)的即时响应等。PicoZ80 必须完全模拟这些行为,才能在不修改主机硬件的情况下正常工作。
在硬件边界检测的实现上,项目采用了三层内存模型来确保边界行为的确定性。第一层是 RP2350 SRAM(512KB,零等待状态)—— 一个包含 128 个 32 位 membankPtr 值的数组,每个值对应 64KB Z80 地址空间中 512 字节的块,为每个总线事务提供 O (1) 的块类型查找。第二层是外部 PSRAM(8MB,通过 SPI 访问)—— 它承载 64 个 64KB 的 RAM 或 ROM 块,以及 64KB 的 memPtr 指针数组、64KB 的 memioPtr 函数指针数组和 64KB 的 ioPtr I/O 函数指针数组。第三层是 16MB SPI Flash—— 存储引导加载程序、两个应用程序固件槽、ROM 镜像和配置 JSON。
内存块支持 512 字节粒度的灵活配置,块类型包括:PHYSICAL(直通真实主机硬件)、PHYSICAL_VRAM(带额外等待状态的视频 RAM 直通)、PHYSICAL_HW(主机硬件寄存器直通)、RAM(PSRAM 支持的读写)、ROM(PSRAM 支持的只读,写周期被静默忽略)、VRAM(PSRAM 支持的视频 RAM,写周期同时镜像到物理主机 VRAM)、FUNC(虚拟设备,每次访问触发 C 函数调用)以及 PTR(每字节重定向,使 512 字节块的每个字节可以指向任何其他块或类型)。这种灵活性使得 picoZ80 能够精确模拟原始系统的内存布局,同时提供现代存储扩展能力。
工程实践中的关键参数
在实际部署中,若要在特定 vintage 计算机上成功使用 picoZ80,需要关注以下工程参数。首先是 CPU 频率与电压配置 ——RP2350 系统时钟建议设置为 300MHz,PSRAM SPI 时钟设置为 133MHz,核心电压根据时钟频率设置为 1.10V 或更高,这些参数直接影响指令执行速度与 PIO 状态机的响应能力。其次是等待状态参数 tcycwait—— 对于视频 RAM 区域(如 MZ-700 的 0xD000-0xDFFF),典型值设为 2,以匹配显示时序要求;对于高速 RAM 区域可设为 0 以获得最佳性能。第三是 T1 同步参数 tcycsync—— 启用后可使内部内存操作与主机时钟上升沿对齐,确保延时循环等时序敏感代码的正确执行。
配置通过 SD 卡上的 config.json 文件管理,无需重新编译即可调整内存映射、ROM 镜像和驱动程序选择。每个配置槽可存储最多 64 个 ROM 镜像和 64KB 的精简化 JSON 配置,活动槽记录在分区表中,可通过网络界面或引导时按住相应按钮进行切换。这种设计极大降低了适配新机型的门槛 —— 为新的 Z80 主机添加支持只需编辑配置文件,必要时在代码库中添加小型 C 驱动程序来处理新的 I/O 行为。
资料来源:PicoZ80 项目官方文档(eaw.app/picoz80/)及 Z80 CPU 用户手册(Zilog UM0080)。