相信大家应该都玩过《仙剑》。SDLPal 作为它的开源引擎重实现,能跑官方 DOS/98 原版资源,这些年也添了不少新功能。一晃十几年过去,从 Windows 出发,Linux、Android、macOS、iOS,还有各种掌机主机,基本都覆盖到了。但最让人意难平的是,作为起点的 DOS 平台却一直缺席。
去年暑假,我终于没忍住,以jayschwa的SDL2 DOS版为基础,自己动手开搞 DOS 移植。这个SDL2是 DJGPP 的,在 DOSBox 上通过 VBE2 能显示真彩画面,但一到实机就各种翻车。在 VirtualBox/QEMU 里折腾了好久总算把自己真机画面点亮了,还没来得及高兴,接下来的声音又难倒了我——DOS 驱动现代音频硬件本来就够头痛,SDL 的音频模型还依赖多线程,这在 DOS 下几乎是死路一条。
于是接下来,我选择绕开 SDL,先把原版那种“时钟 ISR 里发 OPL 指令”的老路走通。幸好前几年 SBEmu 和 VSBHDA 横空出世,现代系统上总算也能用这个办法了。用了相当久的业余时间,之前 SDLPal 中为软件合成做的 OPL 增强终于被我磕磕绊绊地backport到了硬件上(幸亏了PalMusicFan 设计、Louyihua 实现的单 OPL3 FM 立体声),顺便也给 Windows/Linux 加了直接利用硬件 OPL 的路径——比如 CMI8738 这张在 Win11 x64 下居然还有驱动的老声卡。macOS 本来也想顺便搞了,但苹果那边 x86 路线说停就停,只好作罢。
然后,一个意外惊喜砸过来了:AJenbo 搞定了 SDL3 的 DOS 后端并进了上游!不但补全了 VGA 模式,还把之前我觉得不可能的“多线程”(靠手搓协程实现的黑科技)和音频(通过 SoundBlaster API 直连 SBEmu/VSBHDA)都给补齐了。万事俱备,我赶紧把之前写好的那套 ISR hook 框架搬到 SDL3 上,适配了原版的VGA视频模式,又给 SDL3 提了几个补丁完善调色板动画之类的优化。
于是现在 SDLPal 终于能在 DOS 上跑了。配置嘛,从奔腾1到zen3 5600 都试过没问题(有模拟有实机)。更低或更高的配置也可能跑得动——就算没浮点协处理器的 CPU 都可以用 djgpp 的 emu387 顶着——但性能就不好说了。如果你是 UEFI Only、没有 CSM 的机器,也可以试试用 CSMWrap 来启动进 DOS——不过目前还没听说有人成功跑进sdlpal,欢迎挑战。
跟原版 DOS 仙剑比起来,主要有这些变化:
能用官方的 Win95 版资源在 DOS 上跑,这是开天辟地头一回(但AVI解码对奔腾1就有点过于费劲了,最低也得MMX166这个级别才能解得比较顺)。但毕竟是现代逆向移植,最低配置做不到原版的 386 级别。但好处是不再受 580K 常规内存限制——DJGPP 能用 4G 空间,就算常规内存只剩 100K(主要是 SB DMA 占的,用 realopl 还能再省 50K),照样全功能运行。不过前提是总内存要大于 12M。
显示方面,低端机上默认用原版 VGA 模式,对 98 版 AVI 做了兼容处理,每个视频预生成调色板和 LUT,但 VGA 下颜色还是差点意思,这个确实没办法。机器好一点的,可以在配置里关掉 DOSForceMode13h 切到 VESA 模式,这个模式下AVI可以原样呈现了;分辨率可以自己试,我最高试到 1080P,看 log 就知道你的显卡支持哪些(但DOS下IO瓶颈颇为严重,平时最好是别把LogLevel开到0,也就是Debug)。但有一点,DOS 下全是软渲染,分辨率越高 CPU 越累,而且除了AVI什么变化都不会有。至于其他平台上高分辨率上最大的优势GLSL支持——也研究了一下有没有可能通过mesa llvmpipe支持,但测试结果表示单核无SIMD环境还是别想这么多了(哪位兄台折腾出了DOS上的真多核并发的话务必知会我一声)
音乐方面,现在可以在OPL3上播放立体声版的原版RIX(原版是在OPL2模式里播的,左右声道一样)。REALOPL(OPLCore=REAL)是默认,有硬件 OPL 的老机器能跑,用 SBEmu/VSBHDA 的新机器也能跑。CMI8738 这张卡甚至可以直接免驱用高位 I/O 端口: 用 Craig Hart 的 PCI.exe 查出基址,加上偏移 0x50(CMI8738 的硬件手册有写),填进 RealOPLPort 就行。CPU 够劲的话,Nuked(最精确也最吃配置)/DBINT/DBFLT/MAME 这些 OPL 软合成器、Timidity/TinySoundFont 波表 MIDI、MP3/Ogg/Opus 背景音乐替换,都能跟其他平台一样用。不过DOS原版的MPU-401支持还没有,留待以后了(2026.8:已追加)
文字方面,用了基于 Unicode/Unifont 的通用字库,也支持 BDF 扩充。翻译上支持大部分非复杂排版语言,但目前只听说英文社区搞了一个语言包。
致敬:
PalMusicFan——测试狂魔、灵感来源、精神支柱
SDL DOS补丁集合的全体作者
Vogons 上帮忙在实机测试的兄弟们
SDLPal全体开发者和贡献者
仙剑早期研究者
SBEmu / VSBHDA 开源项目
狂徒创作群
大宇资讯
使用方法:选择最新的build下载后,将解压后的sdlpal.exe放在pal.exe同层目录启动即可,游戏内正常退出后同目录会有配置文件sdlpal.cfg生成,后续按需要编辑使用即可(DOS版尚未实现配置的GUI修改)
推荐BGM:动力火车《终于明白》、Arika《Blan_》二选一
以此,告慰青春。
Gemini 解答
技术背景与定位
SDLPal 是基于开源 SDL 库对《仙剑奇侠传》(DOS / Win95 版)游戏引擎的逆向工程重实现。传统的 SDLPal 普遍面向现代操作系统,而该项目通过 DJGPP(GCC 的 32 位 x86 DOS 移植版)将 SDLPal 重新移植回 DOS 环境。
这一移植依赖了近年 SDL3 上游合并的 DOS 后端、DPMI 保护模式扩展、以及 SBEmu / VSBHDA 等现代声卡虚拟化中间件,使得基于现代跨平台代码架构的游戏引擎能够在实机 DOS 和纯软渲染环境下运行。
核心技术要点与机制解析
1. 内存模型与 DPMI 突破
- 突破 640KB 常规内存限制:DOS 原版《仙剑奇侠传》使用 DOS 扩展器(如 DOS/4GW 等)突破常规内存,而 SDLPal DOS 版基于 DJGPP 编译,运行于 32 位 DPMI(DOS Protected Mode Interface,通常依托 CWSDPMI)保护模式下,享有扁平寻址空间(Flat 4GB Address Space)。
- 常规内存(Low Memory)占用机制:保护模式程序本身占用扩展内存,但声卡 DMA 缓冲区、中断服务例程(ISR)入口跳板以及部分 BIOS/VBE 接口调用必须位于首兆(1MB)以下的常规内存中。文中提到实机仅剩 100KB 常规内存仍可运行,是因为 DJGPP 将大部分堆栈和代码段搬移到了扩展内存,只在常规内存池分配极少量的 DOS 传输缓冲区(Transfer Buffer)。
2. 多线程与音频模型差异
- SDL 的多线程音频模型:标准 SDL 音频驱动依赖 OS 级抢占式线程(如 pthread)定期调用音频回调填充缓冲区。
- DOS 环境的实现机制:
- 硬件中断(ISR)直驱:DOS 原版引擎通过挂载 PIT 8253/8254 定时器中断(
INT 08h或INT 1Ch)周期性向 OPL 芯片端口写入寄存器数据。- SDL3 协程模拟:DOS 下原生不存在内核态抢占式多线程。SDL3 的 DOS 后端使用用户态协程(通过切换栈指针与寄存器上下文,如
setjmp/longjmp或ucontext原理)实现协作式“假多线程”,在主循环空闲或主动 yield 时切出执行音频渲染与事件轮询。- 关于多核(SMP)的讨论(跟帖):
- DOS 本质运行在实模式或单核 DPMI 保护模式,BIOS/ACPI 启动 AP(Application Processor)核需要发送 INIT-SIPI IPI(处理器间中断)并在保护模式/长模式下初始化多核调度器。
- 回复中提到的
smp.vxd是针对 Windows 9x 的 VxD(虚拟设备驱动),利用 Ring 0 特权级唤醒次核并接管硬件调度;而在纯 DOS/DPMI 环境下,缺乏内核态抢占式调度器和内存屏障管理,直接运行真正的多核pthread仍存在巨大的架构壁垒。3. 硬件音频与现代声卡映射(CMI8738)
- 传统 ISA 声卡:标准 Sound Blaster / AdLib 将 OPL 芯片直接映射在固定的 ISA I/O 端口(通常为
0x388-0x38B,SB 为0x220等)。- PCI 声卡直接访问:CMI8738 等 PCI 声卡在 PCI 配置空间中被分配了一段 Base Address Register(BAR)。CMI8738 芯片内部集成了兼容 OPL3 的 FM 核心,其硬件规格书定义了在 PCI I/O 空间基地址偏移
+0x50处映射该 FM 寄存器。因此在 DPMI 拥有in/out端口 I/O 特权级(IOPL=3)的前提下,程序无需装载专有 DOS 驱动,只需读取 PCI 配置空间查出基地址即可直接向硬件端口写 OPL 数据。- 虚拟化方案:SBEmu / VSBHDA 利用 CPU 的 VT-x 硬件虚拟化或 Trap(捕捉)I/O 端口访问,把针对
0x220、0x388的旧 ISA 端口访问动态重定向至现代 HD Audio 或 AC97 PCI 设备,使免驱动硬件模拟成为可能。4. 视频渲染与模式处理
- VGA 模式(Mode 13h):
320x200 256色(8-bit 调色板)。针对 Win95 版 16-bit / 24-bit 的 AVI 动画,必须在运行时进行色彩空间转换,通过离线生成 LUT(查找表)和抖动算法降采样映射到 256 色 VGA 调色板中。- VESA 模式(VBE):高分辨率(如 1080P)依赖 VBE 2.0+ 线性帧缓冲区(LFB,Linear Frame Buffer)。高分辨率下帧率骤降属于必然现象:纯软渲染器在向显存 PCI/AGP/PCIe 总线逐像素写入(
memcpy)时,受到未经硬件加速的总线 I/O 写入带宽和 CPU 单核算力限制。
技术结论与使用限制
- 环境依赖:该二进制为 32 位 DPMI 程序,需搭配 386 以上处理器,最低内存建议 16MB 以上(若包含视频解码堆栈建议更高)。
- UEFI 启动限制:纯 UEFI 环境去除了传统 BIOS 中断(
INT 10h、INT 13h等)与 CSM(兼容支持模块),DOS 系统及依赖实模式/BIOS 调用的 DPMI 扩展器无法直接引导。CSM 包装层(如 CSMWrap)仍处于实验阶段,兼容性较低。- 性能调优:在低配置实机或未开启硬件加速的虚拟机中,应强制锁定
DOSForceMode13h并使用REALOPL硬件直通或轻量级软合成器(如DBINT),避免使用高开销的NukedOPL或高分辨率 VESA 软渲染。
| 评分人 | 分数 | 时间 |
|---|---|---|
| AlexZhang | +5 | 2026-08-09 14:31 |

精华I