よく使う命令は暗記をしていた16進世代

takeoka氏(以下、takeoka):takeokaです。低レイヤー、長い人生、そして……まぁ、格調が低い話をします。

私は16進世代です。若い人にはわからないかもしれませんが、昔はTK-80しかなく、assembleしてくれる機械なんて持っていなかったので、みんなアセンブラ・ニーモニックでバーっとプログラムを書いて、それが終わったらおもむろに16進コードへの変換を手でやっていました。だからよく使う命令は、基本的に暗記していました。

あれですね。HLレジスタへのimmediateのloadは「21」とか、Aレジスタへのimmediate loadは「3E」とか、サブルーチンコールは「CD」とか、リターンは「C9」とかです。

友だちの中には、「どうせ16進にするんだから、ニーモニックなんか覚える意味がない」とか言って、16進コードしか覚えない強者が何人もいました。私が大学入った時に入れ替わりで卒業した先輩も、「あいつは16進でしかしゃべれなかった」とか言っていました。

そんな感じで僕は16進世代ですが、僕の上の世代はオクタルでしゃべる人が多くて「8進なんでやねん?」と思ったので、今日の話です。

伝説のコンピューターPDP-11

PDP-11はみんなが大好きUNIXとCが作られた機械です。伝説の機械で、僕もけっこう使っていました。

レジスタマップを見ると、レジスタは8個。8個なので3bitでちょうどいいです。一応、UNIXはod(octal dump)があって、hd(hex dump)というコマンドはありません。結局オクタルが大好きなんです。PDP-11はlittle endianマシンで、odのデフォルトは16bit単位です。「命令コードがdumpできると便利だな」みたいな感じですね。

あと、Cができた時から「¥007」とか書くと、オクタルではどんな文字コードでも書けました。この頃は16進で書けるようになっていますが、当時は書けませんでした。

見ると、一応レジスタとアドレッシング・モードというのが組になっています。これはMC68000の頃には「直交性」と言って、あるレジスタに対してすべてのアドレッシング・モードが全部使えます。

(スライドを示して)これはレジスタの値を取る。これはレジスタで指されているところを取る。これは「*p++」です。「*p++」がなぜあるかというと、PDP-11の機械語にあったからです。これの1Byte版と……charとshortかな。shortはintなんですけれど。

そういうのがあって、転送命令の場合、ソースレジスタには今のアドレッシング・モードが使えるので、このレジスタの中を使ってメモリから取ってくるとか、置くこともできます。対称性があって、メモリからメモリ転送もできます。

結局これはRegisterで8個なので3bitで、このアドレッシング・モードが8通りなので3bit。(スライドを示して)この組でソースとデスティネーションを表します。命令が16bitしかなくて、ソースとデスティネーションを入れると満杯になるので、一応、2オペランド。今の普通のRISCは3オペランドですが、dstとsrcで、2オペランドになっています。

これ全体が豆知識なのですが、PDP-11は、引き算の時は「sub dst, src」と書くと、「dst-src」ですが、なぜかcmp命令は「cmp dst, src」と書くと引き算の方向が反対で、私はビビりました。

(スライドを示して)このように、これ3bit3bit3bit、8進数で書いていたとすると、ここだけちょろっと4bitぐらいあります。jump命令も、一応3bit3bitが基本です。これはオフセットを大きく取りたいので、ちょっと大きいです。サブルーチンコールもレジスタ間接になっていることが多いので、これはRISCと同じで退避レジスタですね。

これは、PDP-11が大好きな人が好きなコンソールです。(スライドを示して)ここがデータや命令を置く時のスイッチですが、3bitずつ色分けがされていて、否が応にもオクタルマシンですね。アドレスが長い時があるのでちょっと長いですけど、(スライドを示して)16bit目はここまでですね。

PDP-11を意識しているZ80の先祖Intel 8080

時代が回って 、私たちのZ80の先祖です。Z80はこれ(Intel 8080)の上位互換です。なので、8080とZ80の16進コードは基本同じです。

アセンブラ・ニーモニックを見ると、明らかにPDP-11を意識しています。命令語は8bitですが、フィールドは3bitです。レジスタは8個。8bitレジスタが8個ぐらいあるように見えます。

そうすると、(スライドを示して)これはRISCでの転送命令でこれも2オペランドですが、ソースとデスティネーションで3bitずつです。ADDはAレジスタが対象と決まっています。(スライドを示して)ここが実はまたちょっと3bitでできています。それからINR、DCRも対象レジスタも3bitです。

このように8080は、アセンブラ・ニーモニックを見ても、このようなレジスタ構成を見ても、すごくPDP-11を意識しています。MC68000がPDP-11を真似したと言いますが、あれは汚いアーキテクチャで、とても私は認めることはできません。

世界最初のスーパーコンピューターCray-1

そう言いながら、次に調べるのはCray-1です。世界で最初のスパコンですね。Cray-1も、「え、アセンブラなんか使うの?」みたいな、やっぱりアセンブラを覚える気がしない人がたくさんいます。一応64bit1ワードで、そこに命令が4つだけ入ります。たまに32bit命令があります。

次に、一応レジスタ構成チェックします。ベクトル・レジスタは、0から77と、78個のデータが置けます。これはもっと短くてもいいです。その長さはベクトル長・レジスタで指定します、それは今回はどうでもいいのですが。このベクトル・レジスタが0から7まで、8個あって、これも8個です。昔の機械は大事なものは全部8個です。

(スライドを示して)ここがオペレーションコードを入れます。src src dst、そして(スライドを示して)命令コードです。一応この4が、この最上位ビットが4の1の1です。それから(スライドを示して)ここの3bitはfloating addです。vector float add命令は171、あとdst, src, srcで2オペランドですね。

アセンブラ・ニーモニックの文法はすごいです。普通(スライドを示して)ここにaddとかを書くのですが、デスティネーションレジスタの番号を書いて、スペース空けて、次のレジスタ番号を書いて、足すで、一応「F」をつけて、レジスタ番号を書きます。ここに「F」があるとfloat addとわかります。

この場合、Cray-1通の人は「いちいちこんなしょーもないもん書かんでええやんけ」と171の何番何番何番といって覚えています。例えばfloating vector multiは161なので、もう171や161がパッと頭に浮かんで、バババッと8進数で書いてしまう。「これが普通やろ」と言われて私は「えー!」となりました。

今度はスパコンの反対で「記号処理や」と言って、LISPマシンのマクロ命令だすと。そうすると、微妙なのですが、主なフィールドは全部3の倍数になっています。オペコードが(スライドを示して)このへんにあって、ここは4ですが、基本3です。この3と6はアドレスのオフセットとかに使うやつですね。この時はこの3と6を足して9bitのデータを示すものだったりします。

最後ですが、MIPSはスカスカやなと。RISC-Vもスカスカやなと。immediateが頭になければいいですねと以前言ったことがあります。

ARMはなんか変なエンコードがされていて、僕はARMは嫌です。以上です。