在20世纪60年代Univac计算机上运行Minecraft服务器及其他应用
摘要
一位爱好者成功在修复的1960年代UNIVAC 1219B(仅250 kHz CPU、90 KB内存)上运行Minecraft服务器、NES模拟器、Web服务器和现代加密算法。
暂无内容
查看缓存全文
缓存时间: 2026/04/21 12:53
# 在 1960 年代 UNIVAC 计算机上运行 Minecraft 服务器及更多
来源:https://farlow.dev/2026/04/17/running-a-minecraft-server-and-more-on-a-1960s-univac-computer
快看!我在一台 1960 年代的 UNIVAC 1219B 上跑起了 Minecraft 服务器:
Nathan 站在 UNIVAC 1219B 旁,旁边的笔记本正运行 Minecraft。
这是 NES 模拟器渲染的《弹球》首帧:
电传打字纸上的 NES《弹球》标题画面 ASCII 图。
……以及用“叠打”技术打印的自拍:
电传打字纸上的 Nathan ASCII 肖像。
我们还跑了更多疯狂的东西,包括:
- OCaml 程序 \(\!\)
- Web 服务器
- Curve25519 + AES 加密
- BASIC 解释器
- ELIZA
- 《俄勒冈之旅》《Wordle》《战舰》等游戏
……还有好多!全部在一台 **250 kHz**、仅有 **90 KB RAM** 的 1960 年代计算机上完成。我就好这口!痴迷于把代码塞进奇怪的地方并碾碎技术限制。这是我最雄心勃勃的项目,花了我和其他人大约 8 个月。
项目源码在此(https://github.com/nathanfarlow/univac-1219-riscv)。也请看 TheScienceElf 的视频(https://youtu.be/rU8sCbwB8XU)!
---
## UNIVAC 是台怪机器
UNIVAC 1219B 超级古怪,几乎处处与现代编程作对:
- **18 位字长。** 地址和值都是 18 位!连 2 的幂都不是。
- **反码算术,但又不太像。** 现代机用[补码](https://en.wikipedia.org/wiki/Two%27s_complement)表示有符号整数,这台机用[反码](https://en.wikipedia.org/wiki/Ones%27_complement),但带[有符号零](https://en.wikipedia.org/wiki/Signed_zero)的恼人差异,得靠我们逆向。
- **寄存器少得可怜。** 一个 36 位寄存器 `A` 可拆成 `AU:AL` 单独访问,外加一个 18 位 `B` 寄存器。
- **内存仅 40 960 字。** 总共 90 KB,要同时放代码和运行时数据。
- **分体内存。** 这 40 960 字被切成 10 个 bank,得提前配置指令访问哪个 bank。
该机原本给海军用,读雷达信号并指挥火炮。确实是工程奇迹。下图左为计算机,右为(半残)磁带机。
UNIVAC 1219B 及其磁带机,展于 Vintage Computer Federation 博物馆。
旁边是电传打字机,我们与机器的接口。你可以打字给 UNIVAC,它也能回打;所有内容打在一张纸上,就是 stdin 和 stdout。
带防尘罩、纸卷和键盘的 Model 35 电传机。
全球仅存两台 UNIVAC 1219,均由 Vintage Computer Federation 从约翰斯·霍普金斯大学抢救而来。这是唯一能开机的。
项目之前,所有程序都是手写的 UNIVAC 汇编。我们要让 C 编译起来!
---
## 初遇 VCF East 2025
我第一次见到它是在 2025 年 4 月的[VCF East](https://vcfed.org/vcf-east-2025/)。Bill 和 Steven 正在机上跑演示程序。Duane、Bill、Steven 过去 10 年做了大量修复工作。
亲眼见到它真让人激动:闪烁的灯、电传机的嗒嗒声、机油味……我当时就知道得让点疯狂的代码跑起来,不止 fizzbuzz。我要 NES 模拟器,我要 OCaml。这硬件到底能推多远?
---
## 需要模拟器和汇编器
首先得有 UNIVAC 汇编语言的汇编器,以及能跑汇编程序的模拟器。幸运的是,Duane 多年前用 BASIC 写了个汇编器,还用 VB.NET 写了个模拟器。
VCF 结束后不久,[TheScienceElf](https://www.youtube.com/c/TheScienceElf)用 Rust 重写了[新的汇编器和模拟器](https://github.com/TheScienceElf/UNIVAC-1219),参考了[手册扫描件](http://www.bitsavers.org/pdf/univac/military/1219/)和 Duane 的实现。
Rust 版**飞快**,比真机快 400 倍,比 VB.NET 版快 40 000 倍。后面做模糊测试时,这速度必不可少。
此时两个模拟器都还不够硬件级精确,但足够开工!
---
## 先用 wee 试跑 C 编译器
有了模拟器,怎么跑 C?最快验证路线是用我旧项目 [wee](https://farlow.dev/2025/05/02/wee),一个超小指令集,曾把 C 编译到各种怪地方。
能跑,但糟得离谱。一个简单的 fizzbuzz 占约 27k 字,整机内存的 67%。算前 100 行 fizzbuzz 要花整整一分钟。想跑真正的复杂程序,显然不可行。
---
## 上 RISC-V 模拟器才是正道
得比 wee 更聪明。选项很多,先定两个主要目标:
1. 跑真实、大型、有趣的程序。最好直拉 GitHub 代码就能上机。速度不必**极限**快。
2. 保住 sanity。
### 得用真编译器,比如 LLVM 或 GCC
跑真程序需要:
- **完整 C 标准库。** 这里用了 [picolibc](https://github.com/picolibc/picolibc)。
- **软浮点及其他合法化。** 得支持 float、double、int32、int64 等,哪怕 UNIVAC 没有硬件支持。
- **死码消除 + 体积优化。** 90 KB 得精打细算。
- **多语言。** 想支持 Rust、C++、Zig 等。
### 直接给 UNIVAC 写后端行不通
给 UNIVAC 写 LLVM/GCC 后端绝对噩梦,会违背“保住 sanity”目标。反码、18 位字、分体内存,全得硬塞进现代编译器。
就算搞定,C 的 int 会是 18 位反码。C 标准允许(C23 前),但现实代码大多假设 ≥32 位补码,现成程序会炸。
### 于是模拟 GCC 已支持的目标,比如 RISC-V
思路:用 GCC 把 C 编译到 RISC-V,再在 UNIVAC 上写个 RISC-V 模拟器跑它。
多香:
- **一次搞定。** 写一遍模拟器,再也不用碰 UNIVAC 汇编。
- **可模糊测试。** 随机生成 RISC-V 程序,跑模拟器和参考模拟器,比较寄存器最终状态,就能验证正确性。
- **增量多巴胺。** 有篇老博文说要把项目拆成能持续给反馈的小阶段。RISC-V 基础指令集只需实现 38 条,目标清晰,逐条勾选即可。
- **二进制紧凑。** 一条 RISC-V 指令可高效编码成 2 个 18 位 UNIVAC 字,日后还能加压缩扩展或自定义压缩。
### 模拟更慢,但没关系
代价是每条指令都得解码模拟。优化后,平均 40 条 UNIVAC 指令才能模拟 1 条 RISC-V。于是 250 kHz 的 UNIVAC 相当于 6 kHz 的 RISC-V 机。
……挺不错了!跑真复杂程序的瓶颈是 40k 字内存,这条路线空间效率最佳。
---
工具链高层流程:
1. 写 C。
2. 用 GCC 编译到 RISC-V。
3. 把每条指令重编码成适合 UNIVAC 的格式,2 字/指令。
4. 把重编码后的指令追加到模拟器源码后。
5. 汇编成 `.76` 磁带文件,上机。
写一千行 UNIVAC 汇编前得有靠谱工具链,我先用几周准备:
1. Emacs 主模式。
2. OCaml 工具链:解析、模拟、重编码 RISC-V,带往返模糊测试。
3. 差分模糊器:用 [mini-rv32ima](https://github.com/cnlohr/mini-rv32ima) 做金标准。
4. 高效用例缩减器(移植 [Lithium](https://github.com/MozillaSecurity/lithium))。
这投资血赚。
### Claude 还不会写 UNIVAC 汇编
Claude Code 很香——给我写了整个 Emacs 模式。我日常写 OCaml 也靠它。但即使给足手册、模拟器、差分模糊器,它写 UNIVAC 汇编还是翻车。不怪它,UNIVAC 汇编确实太怪。
不管怎么提示,此时它就是搞不定反码、左循环移、右算术移、`CPAL` 对 `0` 行为特殊等细节。
### 我会写 UNIVAC 汇编
程序员总有得撸起袖子硬干的时候。几天内我敲完约一千行 UNIVAC 汇编,实现 38 条基础 RISC-V 指令。过程居然挺爽!
Emacs 里打开带语法高亮的 UNIVAC 汇编文件。
Emacs 模式提供语法高亮和指令时序提示。
模糊测试立刻抓虫并最小化复现。一旦某指令通过 fuzz,我就放心继续;先不管效率,只求正确。
### 第一个 C 程序跑起来了!
fuzz 全绿后,我跑起第一个 C 程序。……几乎成功!RISC-V 地址转 UNIVAC 地址有小 bug。我把 fuzzer 升级抓虫,修完后再跑 C 程序就全通了!真想给过去的自己磕一个。
fizzbuzz 跑通。BASIC 解释器跑通。甚至 [smolnes](https://github.com/binji/smolnes)(NES 模拟器)也跑通!
……唯一问题是真机渲染《弹球》首帧要 20 小时(模拟器 3 分钟)。博物馆可等不了 20 小时,NES 计划完了?
差得远;咱把性能榨干就行。
---
## 再快 30 倍
我们的 UNIVAC 模拟器会统计真机运行时间,给优化提供靶子。
我盯俩指标:
- 所有 fuzz 程序的总运行时间,衡量指令平均表现
- NES demo,我真正关心的代表基准
### 把活从运行时挪到编码时
最关键的优化是把 RISC-V 指令重编码成对 UNIVAC 最友好的格式。RISC-V 指令 32 位,我们提前变换,结果塞进 2 个 18 位字。
看 RISC-V 规范时我惊了:立即数位在指令里是打乱的!
RISC-V JAL 指令编码图(官方规范)
……哈?([来源](https://msyksphinz-self.github.io/riscv-isadoc/html/rvi.html))
软件模拟器得花大量周期移位掩码重组立即数。据说这对硬件方便?我们可耗不起,于是提前把位排好,写进给 UNIVAC 的重编码里。
操作码同理。判断指令类型常要查分散的位,我们直接给每种指令分配一个紧凑操作码。
更极端的是 `SRLI`/`SRAI`。UNIVAC 不能变长移位,得运行时动态生成移位指令再执行。但生成指令的工作也能提前做!对 `SRLI`/`SRAI`,**我们直接在载荷里塞一条现成的 UNIVAC 指令**,到时解压、写 RAM、执行。
这些变换**技术上**让我们失去了对自修改代码的支持,但换速度太值。
### 让热路径更快
经典优化手段在 UNIVAC 上一样管用:
**删死码。** 我把用例最小化工具拿来删模拟器指令,只要 fuzz 还过就继续删,真找出能扔的代码!
**跳转表。** 最高效的指令分派就是按操作码跳表。
**指令重排与寄存器活性。** 少存少取内存,就能快。
**内联。** 子程序跳转返回有开销,小函数直接内联。
### 用 OCaml 宏系统管内联
内联换速度,但没宏系统就会复制粘贴到维护地狱。我写了个简易 OCaml 宏:三反引号里的 OCaml 可直接注入汇编。好玩 🐪
示例减少重复代码:
在文件中定义的 OCaml 辅助函数
相似文章
@Rainmaker1973:这位计算机科学专业(辅修数学)的毕业生在《我的世界》中建造了一台32位的红石计算机 [ ryan_boulds]
一位计算机科学专业(辅修数学)的毕业生利用红石电路在《我的世界》中打造了一台功能完备的32位计算机。
Plexus P/20 模拟器
一款全新的开源 WebAssembly 模拟器,重现 1980 年代 Plexus P/20 Unix 服务器,让用户可在浏览器中运行 SystemV Unix。
Memo-1:从零构建的6502计算机,使用Minitel作为终端
对Memo-1的描述,一款从零构建的基于65C02的计算机,为乐趣和学习而设计,包含详细的内存映射、VIA和ACIA规格,以及用于摇杆和音调生成的BASIC例程。
一人,双内核,与大量RISC-V
QRV Systems的Yuri Zaporozhets在FPGA上构建了一台基于RISC-V的个人计算机和一台大型机,并两次重写了QNX。他最新的操作系统QSOE正在FOSS世界中引起关注。
我的服务器现在是一部手机
作者用一台运行 Termux 的 CMF Phone 1 家用服务器取代了 Hetzner VPS,详细介绍了安装 postmarketOS 的种种陷阱,最终使用 Android 搭配 Termux、runit、Tailscale 和 Caddy 来托管 Surf 和财务追踪器等 Web 应用。