此程式於2026年5月在荷蘭Ommen的Outline Demoparty發表,是一個探索16位元組x86組合語言中演算法密度的作品。
大家好。我三十多年前在一台老舊的IBM PC與單色綠色螢幕上學習程式設計,一直想為這個系統創作程式。過去15年我創作了超過100個小型開場動畫。最近雖然不太活躍,但Plex的精彩16位元組作品「Rainbow Surf」激勵我重新挖掘舊有的草稿並開始動手。
這個程式的誕生來自於平常的嘗試。我在玩細胞自動機來產生圖形與聲音,並發現了許多縮小程式碼的技巧。實際上包括:a) 多態組合語言指令,例如 add [bx+si],al(0x0000) b) 跳入指令中間以節省位元組並重複使用操作碼。在數百次的小實驗中,這個聲音特別吸引我。
當我展開剩餘程式碼並移除多餘部分時,我很難理解真正發生了什麼。我看著經過多次精簡後留下的簡單公式,自己也沒想到這麼少的位元組竟有如此深奧的解釋。
我2014年的原創作品「M8trix」已經能在螢幕上散布偽隨機字母(8位元組,後來7位元組),我一直想讓它「聽起來好聽」。但在「wakeup」的開發過程中,聲音是先行的。既然「你聽到的就是你看到的」,這點其實無所謂,但「16位元組將謝爾賓斯基聲音轉成矩陣雨」會是個不錯的副標題=)
以下是16位元組的x86實模式DOS組合語言。執行時,它利用視訊記憶體作為計算空間,繪製無限的謝爾賓斯基分形,同時用該幾何圖形驅動喇叭發聲。
程式以標準BIOS中斷 int 10h 開始,設定視訊模式0,提供40x25的文字模式網格。接著資料段(ds)指向0xb800,即VGA/CGA文字緩衝區的記憶體位址。
當BIOS清除螢幕時,並非將記憶體填滿絕對零。每個字元空間佔兩個位元組:ASCII字元與色彩屬性。所有2000個位置被設為0x20(空白)與0x07(淺灰底黑字)。螢幕看似空白,但記憶體已填滿均勻的模式。
這種交織與共感遠超過我在其他小型開場動畫中見過的。我甚至認為它揭示了比使用迭代函數系統玩「混沌遊戲」且無亂數生成器更深的數學秘密與關聯。這次我希望你能從根本理解你所聽到的數學,而非只是「在這裡做個運算然後聲音變有趣」。
純數學來看:假設狀態為零而非0x20,使用加法代替異或,且每步前進16位元組。假設累加器al從2開始。
DOS段大小正好是65,536位元組。每步16位元組意味著正好4,096步遍歷整個段(65536/16=4096)。此時si會整齊地回繞至0x0000。
在儲存格間相加產生部分和。因為4096是256(8位元暫存器大小)的倍數,進位在段回繞時完美對齊,al在每次掃描開始時乾淨地重設為2。
數值遵循二項式序列,並乘以2:
以下是前16步逐行累積的情況:
回到組合數學。根據特殊定律,模2運算下會出現謝爾賓斯基三角形。此特定位元被送入喇叭,其他位元被忽略。
分離位元平面的原因是無進位加法等同於異或,這也是為什麼用異或而非加法。
程式從2(二進位00000010)開始,只有第1位元在0x00與0x02間切換,完美對應基本細胞自動機規則60。
Lucas定理保證這與加法表中的第1位元相符。你可以自行驗證('2'代表第1位元被設定):
61h埠口與PC喇叭介面相連。第1位元推動喇叭振膜向外(1)或向內(0)。程式透過異或計算分形,寫入記憶體,並將該位元組直接送入喇叭埠口。
分形的1與0產生方波,脈衝寬度與頻率自然變化:
逐行播放時,產生自相似、幾乎節奏不變的位元節拍。
更妙的是:不僅文字輸出至喇叭,64KB段的剩餘位元組也會輸出,這裡包含了陰影化的視訊ROM BIOS程式碼,這是使聲音帶有朋克且粗糙感的秘密成分,與預期的謝爾賓斯基線性疊加矩形波位元節拍有明顯差異。
為了重現M8trix效果,儲存格必須以不讓聲音緩衝區過大且螢幕字元稀疏分布的方式散佈。
因此程式不以16位元組為步進。sub si, byte 57加上lodsb表示每次迭代向後移動56位元組。
56無法整除65,536。程式只訪問8的倍數偏移,需8192步並回繞7次後重設。這使週期長度加倍,基頻減半,聲音下降一個八度。
在80字元寬螢幕上向後移動56位元組相當於向前移動24位元組(12欄)。只訪問10個不同欄位。分形不以實心圖像繪製,而是斜向剪切成10根字元柱向上移動。
場景製作者miragept基於此動機進行了錄影:
模擬器與不同BIOS版本會在RAM中留下微妙差異。因程式對現有記憶體做異或,輸出對環境高度敏感。若先清除記憶體則輸出會非常均勻,但會浪費寶貴位元組。接受硬體的自然狀態正是縮小程式碼魅力的一部分。感謝閱讀。