- Wake up! 16b là một intro DOS x86 real mode 16 byte được công bố tại Outline Demoparty, tạo đồng thời fractal Sierpinski và âm thanh bằng bộ đệm văn bản
- Với
int 10h và thiết lập ds=0xb800, nó dùng mẫu màn hình khởi tạo của chế độ văn bản 40x25 làm không gian tính toán, nên byte khoảng trắng và màu sắc ảnh hưởng đến đầu ra
xor [si], al hoạt động giống như phép cộng không carry, tạo nên cấu trúc Sierpinski ở bit 1, đồng thời gửi cùng byte đó tới loa PC bằng out 61h, al
- Vòng lặp thực tế di chuyển -56 byte mỗi lần lặp rồi reset sau 8.192 bước, âm thanh hạ xuống một quãng tám và trên màn hình xuất hiện mẫu bị xén chéo thành 10 cột ký tự
- Môi trường chạy, như bản vá
0xB000 cho MDA/Hercules hay khác biệt về trạng thái BIOS và RAM, sẽ làm thay đổi kết quả; các artifact phần cứng tự nhiên trở thành một phần của sizecoding
Cấu trúc cốt lõi của intro x86 16 byte
- Wake up! 16b là một intro assembly DOS x86 real mode 16 byte được công bố tại Outline Demoparty ở Ommen, Hà Lan vào tháng 5 năm 2026
- Nó dùng bộ đệm văn bản VGA/CGA làm không gian tính toán để tạo ra fractal Sierpinski vô hạn trên màn hình, đồng thời gửi cùng dữ liệu đó tới cổng loa PC để phát âm thanh
- Toàn bộ mã chỉ gồm 16 byte
int 10h ; 2바이트
mov bh, 0xb8 ; 2바이트
mov ds, bx ; 2바이트
L:
lodsb ; 1바이트
sub si, byte 57 ; 3바이트
xor [si], al ; 2바이트
out 61h, al ; 2바이트
jmp short L ; 2바이트
- Trong quá trình phát triển, tác giả đã thử dùng cellular automata chung cho cả đồ họa lẫn âm thanh, khai thác lệnh assembly đa hình mà
add [bx+si],al trở thành 0x0000, cũng như các kỹ thuật sizecoding tái sử dụng byte và opcode bằng cách nhảy vào giữa lệnh
- Tác phẩm trước đó là "M8trix", một intro 8 byte và 7 byte từ năm 2014 tạo hiệu ứng các ký tự giả ngẫu nhiên lan trên màn hình; trong Wake up! 16b, âm thanh xuất hiện trước rồi hiệu ứng hình ảnh mới ăn khớp vào sau
Màn hình văn bản đã được khởi tạo
int 10h đặt video mode 0, tạo ra lưới chế độ văn bản 40x25
mov bh, 0xb8 và mov ds, bx đặt data segment ds tới địa chỉ bộ đệm văn bản VGA/CGA là 0xb800
- Khi BIOS xóa màn hình, nó không điền bộ nhớ bằng 0 mà lấp đầy 2.000 ô ký tự bằng byte ký tự
0x20 (space) và thuộc tính màu 0x07 (xám sáng trên nền đen)
- Màn hình trông có vẻ trống, nhưng trong bộ nhớ vẫn còn một mẫu đồng nhất, và trạng thái khởi tạo này ảnh hưởng đến cả âm thanh lẫn đầu ra hình ảnh
- Dữ liệu trước và sau vùng video memory nhìn thấy được, cùng cả cách khởi tạo sau thao tác “clear screen”, đều hòa vào kết quả, tạo nên âm thanh thô ráp và khác lạ hơn dự kiến
Tổng tích lũy và cấu trúc nhị thức
- Nếu chỉ xét cấu trúc toán học, có thể giả định trạng thái ban đầu là 0 thay vì
0x20, dùng add thay cho xor, tiến 16 byte mỗi lần, và al bắt đầu từ 2
- Một DOS segment có đúng 65.536 byte, và nếu di chuyển mỗi lần 16 byte thì cần 4.096 bước để đi hết segment
- Vì 4.096 là bội số của 256, tức kích thước thanh ghi 8 bit, nên khi segment wrap quanh, carryover sẽ được căn chỉnh và
al quay về 2 ở đầu mỗi lần quét
- Việc liên tục cộng giá trị giữa các ô tạo thành tổng tiền tố (prefix sum), và các giá trị triển khai giống như dãy hệ số nhị thức được scale lên gấp đôi
- Quan sát nhiều lượt đi qua 16 ô đầu tiên cho thấy giá trị được tích lũy theo từng hàng; vì là giá trị 8 bit nên phần vượt quá 256 sẽ wrap lại và xuất hiện thành giá trị nhỏ hơn
XOR và cấu trúc Sierpinski
- Theo tính chất tổ hợp mô-đun 2, tam giác Sierpinski xuất hiện, và bit này được xuất trực tiếp ra loa PC
- Ở mức bit, phép cộng không carry chính là XOR, nên mã dùng
xor [si], al thay cho add
- Giá trị khởi đầu 2 ở dạng nhị phân là
00000010, nên chỉ bit 1 đổi trạng thái giữa 0x00 và 0x02
- Mẫu này tương ứng với rule 60 của cellular automata sơ cấp
- Theo định lý Lucas, mẫu này trùng với bit 1 của bảng cộng, và trong bảng thì các vị trí có bit 1 bật lên được biểu diễn bằng
2
Cách dữ liệu trở thành âm thanh
out 61h, al gửi byte đã tính toán tới cổng 61h nối với loa PC
- Bit 1 của cổng
61h quyết định trạng thái đẩy màng loa ra ngoài hay kéo vào trong
- Mã tính fractal bằng XOR, ghi kết quả vào bộ nhớ, rồi ngay lập tức gửi chính byte đó ra cổng loa
- Các giá trị 1 và 0 sinh ra từ fractal tạo thành sóng vuông (square wave) có độ rộng xung và tần số biến đổi tự nhiên; khi phát theo từng dòng, nó trở thành một bytebeat tự đồng dạng và gần như bất biến theo nhịp độ
- Âm thanh đầu ra không chỉ trộn dữ liệu từ bộ đệm văn bản mà còn từ phần byte còn lại của cả segment 64KB; do trong đó có mã shadowed video ROM BIOS nên kết quả nghe thô ráp và funky hơn so với bytebeat sóng chữ nhật chồng lớp theo dòng Sierpinski được kỳ vọng
Bước 56 byte: quãng tám và độ xén chéo
- Mã thực tế không di chuyển 16 byte mỗi lần mà, nhờ kết hợp
lodsb và sub si, byte 57, lùi -56 byte ở mỗi vòng lặp
- Mức dịch chuyển này giúp lấp đầy màn hình một cách thưa hơn nhưng vẫn không làm bộ đệm âm thanh quá lớn, đồng thời được dùng để tái hiện hiệu ứng hình ảnh kiểu M8trix
-
Âm thanh
- 56 không chia hết 65.536
- Mã chỉ ghé thăm các offset là bội số của 8, và chỉ reset sau khi đi qua 8.192 bước cùng 7 lần wrap
- Khi độ dài chu kỳ tăng gấp đôi, tần số cơ bản giảm còn một nửa nên âm thanh hạ xuống một quãng tám
-
Hình ảnh
- Trên màn hình rộng 80 byte, dịch -56 byte tương đương tiến 24 byte, tức 12 cột
- Chỉ có 10 cột khác nhau thực sự được ghé thăm
- Fractal không hiện thành một hình kín mà xuất hiện như 10 cột ký tự bị xén chéo, di chuyển lên phía trên màn hình
- Tam giác thực tế rộng 8.192 “pixel”, nhưng mỗi dòng ký tự chỉ có 80 byte, nên có thể cảm nhận chuyển động nhưng khó thấy trực tiếp toàn bộ cấu trúc
- Nếu vẽ liền mạch mà không bỏ qua pixel hoặc dùng màn hình lớn hơn nhiều, có thể nhìn thấy tam giác
Chạy trên phần cứng thực
- Scener miragept đã vá địa chỉ từ
0xB800 sang 0xB000 mà MDA dùng để có văn bản màu xanh phù hợp với MDA/Hercules và chạy nó trên phần cứng thật
- Thiết bị được dùng không phải máy IBM chính xác, mà là một 286 có card EGA hỗ trợ giả lập MDA/Hercules cùng một màn hình MDA thật
- Âm thanh ghi lại có lẫn tiếng ồn nền liên tục của chính cỗ máy, còn màn hình IBM 5151 có độ lưu phosphor dài, khiến nó không lý tưởng cho hiển thị cực nhanh
- Do thay đổi byte địa chỉ nên âm thanh hơi khác đi, nhưng chương trình vẫn hoạt động đúng ý, và ở nửa sau, cấu trúc Sierpinski còn hiện rõ hơn bản gốc
- Tùy theo emulator và phiên bản BIOS, các artifact còn lại trong RAM sẽ khác nhau; mã lại thực hiện XOR lên trạng thái bộ nhớ đó nên đầu ra rất nhạy với môi trường chạy
- Có thể xóa bộ nhớ trước để có đầu ra đồng nhất hơn, nhưng sẽ cần thêm byte; cách chấp nhận trạng thái phần cứng tự nhiên vẫn là một phần hấp dẫn của sizecoding
Tài liệu liên quan
1 bình luận
Ý kiến trên Hacker News
https://youtu.be/b-Fa6HtvGtQ?si=LpQszgA9_K-m3V3-
Cả hai đều hóm hỉnh và thích thử nghiệm. Parker thiên về toán học chính thống hơn, còn Mould thì băng qua nhiều lĩnh vực và rất biết cách khơi đúng ham muốn làm thí nghiệm/DIY
Nếu thích video này thì tôi cực kỳ khuyên nên xem thêm cả hai kênh
https://www.youtube.com/@standupmaths
https://www.youtube.com/@SteveMould
Demo đó thậm chí còn không có âm thanh
Đây thực sự là một công trình phi thường, một kiệt tác đủ sức làm tác phẩm nghỉ hưu. Thực tế hơn thì chắc rồi cũng sẽ lại bị lôi kéo đuổi theo trên một kiến trúc khác thôi
Bravo
https://www.youtube.com/watch?v=QKLhH_ANwIc
Cộng đồng size coding của chúng tôi từng nghĩ mình đã khám phá hết mọi mẹo cellular automata từ vài năm trước, rồi Plex xuất hiện và cho thấy không phải vậy ♥
Tôi không biết đã từng có bài viết nào về tác phẩm tiền thân là m8trix chưa, nhưng hồi nó ra mắt vào năm 2014 tôi có mổ xẻ thử một lần: https://scot.tg/2014/05/31/amazing-code-density/
Tất cả đều quá đẹp, đúng là nghệ thuật đích thực. Điều đáng tiếc là trong ngành này, với AI này nọ, thường chẳng có mấy cơ hội để tạo ra những thứ như vậy