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 -r
unsintables 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 $8000
adalah putchar, call $8003
adalah getchar, halt
membuat 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 $0020
akan berisi yang terakhir 76
, jadi $0021
akan menjadi nol. Kami mampu memancarkan awal program, meskipun hampir tidak ada redundansi:
- Jika lompatan offset
$10
dihilangkan, 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
$20
dihilangkan, maka lompatan offset $10
akan 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-ffff
diisi dengan angka nol nop
, dan penghitung program membungkus, ini akan menjalankan awal program 256 kali, dan akhirnya melanjutkan. Saya kagum ini berhasil.
- Menghapus
$dd
akan membuat sisa dari decode snippet as or (hl) / ld ($1020), hl
, dan kemudian geser ke bagian selanjutnya dari program. Tidak or
akan mengubah register penting, dan karena HL adalah nol pada saat ini, penulisan juga akan dibatalkan.
- Menghapus
$b6
akan membuat decode sisanya seperti ld ($1020), ix
dan melanjutkan seperti di atas.
- Menghapus
$21
akan membuat decoder memakannya $20
, memicu djnz
perilaku.
Perhatikan bahwa menggunakan or a, (ix+*)
menyimpan dua byte lebih ld a, (**) / and a / and a
berkat 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
$dd
akan membuat dua byte selanjutnya decode sebagai or (hl) / dec d
. Clobbers D. Bukan masalah besar.
- Menghapus
$b6
akan membuat pengkodean yang lebih lama tanpa dokumen dec d
. Sama seperti di atas.
- Menghapus
$15
akan membaca $28
alih - alih sebagai offset, dan eksekusi akan dilanjutkan pada $0c
, seperti di bawah ini.
- Ketika
$28
menghilang, $0c
diterjemahkan 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 e
di beep
mengulangi, jadi saya bisa mencukur habis satu ld a
. Juga, karena semua memori antara $0038
dan $8000
adalah memusatkan perhatian, aku bisa jatuh melalui itu dan menggunakan lebih pendek rst
varian dari call
instruksi, yang hanya bekerja untuk $0
, $8
, $10
dan 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
halt
Biasanya program, tetapi jika radiasi menghapusnya, maka memori akan penuh dengan nol, membuat $8000
eksekusi dalam jumlah tak terbatas, mencetak banyak byte nol.