在20世纪60年代Univac计算机上运行Minecraft服务器及其他应用

Hacker News Top 新闻

摘要

一位爱好者成功在修复的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 辅助函数

相似文章

Plexus P/20 模拟器

Hacker News Top

一款全新的开源 WebAssembly 模拟器,重现 1980 年代 Plexus P/20 Unix 服务器,让用户可在浏览器中运行 SystemV Unix。

一人,双内核,与大量RISC-V

Hacker News Top

QRV Systems的Yuri Zaporozhets在FPGA上构建了一台基于RISC-V的个人计算机和一台大型机,并两次重写了QNX。他最新的操作系统QSOE正在FOSS世界中引起关注。

我的服务器现在是一部手机

Hacker News Top

作者用一台运行 Termux 的 CMF Phone 1 家用服务器取代了 Hetzner VPS,详细介绍了安装 postmarketOS 的种种陷阱,最终使用 Android 搭配 Termux、runit、Tailscale 和 Caddy 来托管 Surf 和财务追踪器等 Web 应用。