Z80Golf , 53 36 34 byte
-16 byte terima kasih kepada @Lynn -2 byte terima kasih kepada @Neil
Karena ini hanya kode mesin Z80, ada banyak xxd -runsintables dalam kode ini, jadi miliki hexdump yang dapat dikembalikan:
00000000: ddb6 2120 10dd b615 280c 003e 62ff 3e65 ..! ....(..>b.>e
00000010: ffff 3e70 ff76 003e 62ff 3e65 ffff 3e70 ..>p.v.>b.>e..>p
00000020: ff76 .v
Cobalah online! (penguji lengkap dengan Python)
Penjelasan
z80golf adalah mesin Z80 hipotetis Anarki Golf, di mana call $8000adalah putchar, call $8003adalah getchar, haltmembuat penerjemah keluar, program Anda ditempatkan $0000, dan semua memori lainnya diisi dengan nol. Membuat program yang tahan radiasi dalam perakitan cukup sulit, tetapi teknik yang secara umum bermanfaat adalah menggunakan instruksi idempoten satu byte. Sebagai contoh,
or c ; b1 ; a = a | c
hanya satu byte, dan a | c | c == a | c, sehingga dapat dibuat tahan radiasi dengan hanya mengulangi instruksi. Pada Z80, beban langsung 8-bit adalah dua byte (di mana yang langsung berada di byte kedua), sehingga Anda dapat memuat beberapa nilai ke dalam register dengan andal juga. Inilah yang awalnya saya lakukan di awal program, sehingga Anda dapat menganalisis varian yang lebih panjang yang saya arsipkan di bagian bawah jawaban, tetapi kemudian saya menyadari bahwa ada cara yang lebih sederhana.
Program ini terdiri dari dua muatan independen, di mana salah satunya bisa rusak oleh radiasi. Saya memeriksa apakah byte telah dihapus, dan apakah byte yang dihapus itu sebelum salinan kedua payload, dengan memeriksa nilai beberapa alamat memori absolut.
Pertama, kita harus keluar jika tidak ada radiasi yang diamati:
or a, (ix+endbyte) ; dd b6 21 ; a |= memory[ix+0x0021]
jr nz, midbyte ; 20 10 ; jump to a halt instruction if not zero
Jika ada byte yang dihapus, maka semua byte akan bergeser dan $0020akan berisi yang terakhir 76, jadi $0021akan menjadi nol. Kami mampu memancarkan awal program, meskipun hampir tidak ada redundansi:
- Jika lompatan offset
$10dihilangkan, maka radiasi akan terdeteksi dengan benar, lompatan tidak akan diambil, dan offset tidak akan masalah. Byte pertama dari instruksi selanjutnya akan dikonsumsi, tetapi karena itu dirancang agar tahan terhadap penghapusan byte, ini tidak masalah.
- Jika opcode lompat
$20dihilangkan, maka lompatan offset $10akan mendekodekan sebagai djnz $ffe4(menggunakan byte instruksi berikutnya sebagai offset - lihat di atas), yang merupakan instruksi loop - decrement B, dan lompat jika hasilnya bukan nol. Karena ffe4-ffffdiisi dengan angka nol nop, dan penghitung program membungkus, ini akan menjalankan awal program 256 kali, dan akhirnya melanjutkan. Saya kagum ini berhasil.
- Menghapus
$ddakan membuat sisa dari decode snippet as or (hl) / ld ($1020), hl, dan kemudian geser ke bagian selanjutnya dari program. Tidak orakan mengubah register penting, dan karena HL adalah nol pada saat ini, penulisan juga akan dibatalkan.
- Menghapus
$b6akan membuat decode sisanya seperti ld ($1020), ixdan melanjutkan seperti di atas.
- Menghapus
$21akan membuat decoder memakannya $20, memicu djnzperilaku.
Perhatikan bahwa menggunakan or a, (ix+*)menyimpan dua byte lebih ld a, (**) / and a / and aberkat pemeriksaan terintegrasi untuk nol.
Kita sekarang perlu memutuskan mana dari dua salinan payload yang akan dieksekusi:
or (ix+midbyte) ; dd b6 15
jr z, otherimpl ; 28 0c
nop ; 00
; first payload
ld a, 'b' ; 3e 62
rst $0038 ; ff
ld a, 'e' ; 3e 65
rst $0038 ; ff
rst $0038 ; ff
ld a, 'p' ; 3e 70
rst $0038 ; ff
midbyte:
halt ; 76
otherimpl:
nop ; 00
ld a, 'b' ; 3e 62
; ... ; ...
rst $0038 ; ff
endbyte:
halt ; 76
Dua salinan dipisahkan oleh nop, karena lompatan relatif digunakan untuk memilih di antara mereka, dan radiasi bisa menggeser program dengan cara yang akan membuat lompatan melewati byte pertama setelah tujuan. Selain itu, nop dikodekan sebagai nol, yang membuatnya mudah untuk mendeteksi byte yang digeser. Perhatikan bahwa tidak masalah payload mana yang dipilih jika sakelar itu sendiri rusak, karena kedua salinan tersebut aman. Mari kita pastikan bahwa itu tidak akan melompat ke memori yang tidak diinisialisasi, meskipun:
- Menghapus
$ddakan membuat dua byte selanjutnya decode sebagai or (hl) / dec d. Clobbers D. Bukan masalah besar.
- Menghapus
$b6akan membuat pengkodean yang lebih lama tanpa dokumen dec d. Sama seperti di atas.
- Menghapus
$15akan membaca $28alih - alih sebagai offset, dan eksekusi akan dilanjutkan pada $0c, seperti di bawah ini.
- Ketika
$28menghilang, $0cditerjemahkan sebagai inc c. Muatan tidak peduli c.
- Menghapus
$0c- untuk itulah gunanya. Jika tidak, byte pertama dari muatan akan dibaca sebagai lompatan offset, dan program akan melompat ke memori yang tidak diinisialisasi.
Payloadnya sendiri cukup sederhana. Saya pikir ukuran kecil dari string membuat pendekatan ini lebih kecil dari satu loop, dan lebih mudah untuk membuat posisi independen seperti ini. The edi beepmengulangi, jadi saya bisa mencukur habis satu ld a. Juga, karena semua memori antara $0038dan $8000adalah memusatkan perhatian, aku bisa jatuh melalui itu dan menggunakan lebih pendek rstvarian dari callinstruksi, yang hanya bekerja untuk $0, $8, $10dan seterusnya, hingga $38.
Pendekatan yang lebih tua
64 byte
00000000: 2e3f 3f2e 3f3f 7e7e a7a7 201f 1e2b 2b1e .??.??~~.. ..++.
00000010: 2b2b 6b00 7ea7 2814 003e 62cd 0080 3e65 ++k.~.(..>b...>e
00000020: cd00 80cd 0080 3e70 cd00 8076 003e 62cd ......>p...v.>b.
00000030: 0080 3e65 cd00 80cd 0080 3e70 cd00 8076 ..>e......>p...v
58 byte
00000000: 2e39 392e 3939 7e7e a7a7 2019 3a25 00a7 .99.99~~.. .:%..
00000010: 2814 003e 62cd 0080 3e65 cd00 80cd 0080 (..>b...>e......
00000020: 3e70 cd00 8076 003e 62cd 0080 3e65 cd00 >p...v.>b...>e..
00000030: 80cd 0080 3e70 cd00 8076 ....>p...v
53 byte
Yang ini memiliki penjelasan dalam riwayat sunting, tetapi tidak terlalu berbeda.
00000000: 3a34 00a7 a720 193a 2000 a728 1400 3e62 :4... .: ..(..>b
00000010: cd00 803e 65cd 0080 cd00 803e 70cd 0080 ...>e......>p...
00000020: 7600 3e62 cd00 803e 65cd 0080 cd00 803e v.>b...>e......>
00000030: 70cd 0080 76 p...v
Bagaimana jika: output non-kosong baik-baik saja alih-alih berbunyi bip
1 byte
v
haltBiasanya program, tetapi jika radiasi menghapusnya, maka memori akan penuh dengan nol, membuat $8000eksekusi dalam jumlah tak terbatas, mencetak banyak byte nol.