一个 16 字节程序能做什么?

在 Outline Demoparty 2026 上,有人交出了一段 x86 real-mode DOS 程序。只有 16 bytes。它在 VGA 文本显存里长出谢尔宾斯基式分形,又把同一份字节直接送进 PC Speaker,变成粗糙但有结构的方波声音。

最有意思的地方不在“老电脑还能玩”。16 字节太小,小到没有空间写完整初始化、兼容层、音频驱动和解释器。硬件约定、数学结构、内存初态,全被挤到台面上。

16 字节到底做了什么

它跑在 DOS/BIOS 约定下,目标很明确:用文本显存当画布,用 XOR 当规则,用 PC Speaker 当输出端。

关键点位置 / 指令实际作用
显示初始化int 10h进入 BIOS 文本模式,屏幕通常看起来被清空
显存位置0xB800VGA 文本缓冲区,字符字节和颜色属性字节交错存放
主循环lodsb / sub si,57 / xor [si],al读取一个字节,调整指针,再用 XOR 改写显存
声音输出out 61h,al把同一字节写到 PC Speaker 控制端口

VGA 文本模式不是抽象画布。它就是一段内存。典型文本屏幕里,每个字符占两个字节:一个 ASCII 字符,一个颜色属性。

BIOS 初始化后,屏幕可能看起来是空的,但内存里并不空。常见状态会出现空格 0x20 和灰字黑底属性 0x07 这类规律数据。程序吃的正是这些位。

lodsb 读出当前字节,xor [si],al 把它和另一个位置的字节做 XOR。XOR 没有进位,只做位翻转。某一位沿着显存传播,就会出现类似 Stephen Wolfram 初等元胞自动机 Rule 60 的结构,也就是谢尔宾斯基三角形那种空洞递归的影子。

声音没有单独生成。

out 61h, al 把刚参与画面计算的字节送到 PC Speaker 控制端口。端口 61h 里的 Bit 1 会影响扬声器控制。于是,字符数据中的某些位变化,在扬声器上变成方波开关节奏。

图案不是配乐。图案本身被当成了声音信号。

还有一个小细节决定了它不是普通扫屏。lodsb 会让 SI 自动前进一步,后面的 sub si,57 又把它拉回去,所以净移动是 -56 字节。

文本模式一行常按 80 字节解释时,-56 相当于反向斜切。画面因此会形成斜向推进、柱状闪烁的结构。步进也拉长了循环节奏,声音的基频随之降低,听起来更慢、更沉。

它为什么漂亮:同一份数据干三件事

这段程序最漂亮的地方,是它不把功能分开。

现代软件喜欢分层:渲染层、状态层、音频层、驱动层、兼容层。分层当然有价值。没有分层,浏览器、AI 工具、协作软件都做不起来。

但分层也会让人忘掉机器。

这里刚好反过来。同一段 0xB800 文本显存,既是画布,也是计算空间,还是音频信号源。字符位被 XOR 改写,画面出现分形;同一字节写到 61h,扬声器发出方波。

“天下熙熙,皆为利来。”放到软件工程里,也可以粗暴改一句:天下层层,皆为抽象来。抽象让系统可维护,也让成本变得不透明。

16 字节把这层遮布扯掉了。

它没有跨平台承诺。不同 BIOS、真实机器、DOSBox、PCem,显存初始状态和端口模拟细节都可能不同。画面纹理、声音节奏、启动时的那点随机感,都可能变。

如果要完全一致,可以写更多初始化代码:清显存、固定寄存器、设定状态、规避模拟器差异。问题是,那就不再是 16 字节作品。

这正是 demoscene 的题目。限制不是瑕疵,限制就是规则本身。

对懂一点汇编、复古计算和底层的人,这类作品最适合拆开看:看 SI 怎么走,看 0xB800 的字符/属性字节怎么参与计算,看 61h 的 Bit 1 怎么把位模式变成声音。别急着把它移植成现代程序。先在 DOSBox、PCem 或真机上对比运行差异,差异本身就是材料。

对关心软件膨胀的人,它给的动作更简单:回到自己的系统里,找一层真正有成本的抽象。启动慢,是资源加载的问题,还是框架链路的问题?界面卡,是渲染慢,还是状态同步绕远?别把“复杂业务”当万能挡箭牌。

这段 16 字节程序不能替代现代工程。它只提醒一件事:有些复杂,是问题需要;有些复杂,是团队已经看不见机器了。

我的判断:小代码不是玩具,是一面反光镜

我不太买账那种简单骂法:现代软件都臃肿,所以古早代码更高贵。

不成立。

今天的软件要处理安全、国际化、字体、输入法、GPU、网络、权限、云同步、可观测性。拿 16 字节去要求浏览器、IDE、AI 产品,属于错位比较。

但这段程序依然有批判性。它批判的不是“代码多”,而是“代码多到没人知道代价在哪里”。

很多产品变慢,并不是因为功能真的复杂到无解。它可能只是多了一层 SDK、多了一套埋点、多了一轮远程配置、多了一次无意义的渲染。每一层都说自己很小,合起来就成了用户体感里的慢。

16 字节作品的残酷之处在这里:它没有地方藏浪费。

一条指令要同时服务多个目标。一次读写要同时改变画面和声音。一个环境假设要同时带来效果和风险。它把工程关系压到最紧,压到每个字节都必须交代用途。

这也解释了为什么它不该被夸成“音乐生成器”。PC Speaker 发出的只是由位模式触发的方波节奏。它没有现代意义上的音色设计、采样控制、编曲结构,也没有稳定跨平台输出。

它更像一个硬件诗句。短,硬,靠约束成立。

接下来真正该观察的,不是谁能把 16 字节吹得更神,而是不同环境下它怎么变:

  • BIOS 文本模式初始化是否一致;
  • 0xB800 初始内容是否残留;
  • DOSBox、PCem、真实硬件对 61h 的模拟差异;
  • sub si,57 这类步进变化如何改变画面周期和声音节奏。

这些变量不会削弱作品,反而说明它的本质:它不是封装好的产品,而是把硬件、数学和偶然性绑在一起的小实验。

我喜欢它,正因为它不完整。

完整软件追求遮蔽差异。这个 16 字节程序反过来展示差异。它让我们看到,所谓“运行结果”,从来不是代码单方面决定的。机器、环境、初始状态,都在共同写这幅图、这段声音。

回到开头那个问题:16 字节能做什么?

它做不了现代应用。也不需要做。

它只要让人重新看见机器,就已经够了。少到极限时,工程美学不靠口号,靠每一个字节承担后果。