z80 golf(7)

ところで、菊やんさんの「Hello, world!」(id:kikx:20071230)が凄すぎる。


00000000: 13 INC DE
00000001: 4E LD C,(HL)
00000002: D5 PUSH DE
00000003: 35 DEC (HL)
00000004: 0A LD A,(BC)
00000005: 3C INC A
00000006: F2 20 63 JP P,6320h
00000009: 6B LD L,E
0000000A: 71 LD (HL),C
0000000B: 6E LD L,(HL)
0000000C: 76 HALT
0000000D: 1F RRA
0000000E: 2B DEC HL
0000000F: 6E LD L,(HL)
00000010: 6B LD L,E
00000011: 6B LD L,E
00000012: 64 LD H,H
00000013: 47 LD B,A

コードサイズこそ20Bと、19Bには及ばないが、見た瞬間に私は身震いをした。これはかなりの力作である。ご本人は「やぼな解説はしない」とのことなので、私がやぼな解説をしてみる。


・「Hello, world!」の文字列は、逆順に0013hのアドレスから0008hのアドレスに埋まっている。ただし1減らしてある。これは文字列中にHALT(76h)を持ってくるため。


文字列全体をデクリメントすることでこの文字列中にhaltを見出した。私は、デクリメントでencodeしたのではhaltが現れるからfall thoughできない(のでこのencodeは使えない)と判断していたのに、「haltが現れるから使える」と感じたその発想と、これで完成させてしまう腕力ともに尋常じゃない。


・0番地の13hは、INC DEでありながら、同時に「Hello, world!」の終端からスタートするカウンタとして機能している。ここから、ダウンカウントされていく。INC DEと13h という定数とのダブルミーニング


・DEレジスタは、先頭のINC DEと、その直後のPUSH DEとペアで、戻りアドレス(0001h)を積むのに使用されている。初回のみINC DEされるのでDEはずっと1であり、INC DEというコード自体が無害化されている。


なお、0番地は、(HL) などでアドレッシングしやすいので、レジスタが0で初期化されていて開始アドレスが0固定のZ80のGolfでは使えるテクだと思う。


・JP P,6320h(6320hは 'Hello, world!'の'd!'の部分)のJP P,がミソで、20hの次にF2h(JP P, )をスキャンしたときに、この命令が負数(80h以上)なので、ここでブランチせずにfall throughして、HALTに到達する。だから、「JP P,」はある意味、自己言及的である。これもGolfで使えるテクだと思う。


ちなみに、菊やんさんは、こういう風に1つの命令に複数の意味を持たせるのが非常にうまく、Rule30の驚異の21バイトのコード(id:kikx:20071231)では3つの意味を持たせてある命令が出現する。