NOP命令と都市伝説
NOP命令とは
NOPとは機械語命令の一つで、「何もしない」という風変わりな命令です。何もしないという不思議な命令のせいか、この命令には様々な都市伝説が存在する様です。
NOP命令の都市伝説の例
これは昔のCPUには乗除算命令が無い事は知っているが、その理由までは知らない方々とってはつい信じたくなる典型的な都市伝説です。
上記の文頭に「嶋正利が」とか「ジョン・エッカートとジョン・モークリーが」とかの個人名が付くものもあります。勿論全くのデタラメです。
これも良く聞く話ですが、真相は「(低速機器との同期をとるために)NOP命令を時間調整に用いることを思いついた人がいた」です。他にもシリアル伝送の時間待ちや、ゲームプログラムの速度調整の為にNOP命令を使うことを思いついた人はおそらく世界中に大勢いると思います。しかし命令セットの設計時に実行速度を調整する目的でNOP命令を用意した人はおりません。
昔(1970年代以前)は「デバッガでブレイクポイントを置く」という今では当り前の手法も「未来の技術」でした。
従って、デバッグといえば「直接、機械語を書き換えて様子をみる」が主な方法でした。例えば「条件分岐命令」を「NOP命令」に置き換えて実行すると、条件の真偽とは無関係に分岐を阻止でき、次の命令語を強制実行させる事ができたのです。 しかし、この「NOPはデバッグ用に開発された」という説も前項の「時間調節」と同様、「NOP命令をデバッグに用いることを思いついた人がいた」が真相でしょう。
個人的にはこの話は気に入っているのですが明らかな都市伝説です。
(若い方々にとっては、この話、若干の説明が必要かと思いますので以下に書いてみます)
昔はヘキサダンプ(機械語命令に対応する0〜Fの文字が大量に印字された紙)を見てデバッグをした時代もありました。この見づらいヘキサダンプリストを少しでも見やすくするためにNOPの連続を見出しやしおりの代りに所々(サブルーチンの先頭や、大事なジャンプ先等)に挿入するという苦肉の策が必然的に生まれたのです。もちろん、これも単なるNOPの応用アイデアであり、NOPの誕生理由とは全く無関係です。
・DSP(digital signal processer)において、処理すべき演算がない時の命令として生まれた
このあたりになってくると、都市伝説というよりも単なる「誤まった知識」です。
しかし本気で信じている方も少なくない様です。コンピュータの歴史を少しでも齧れば、パイプラインやDSPの誕生と、NOPの誕生が同時期ではないことは直ぐに判ると思います。
NOP命令の誕生
NOP命令の誕生はいつなのか?
という訳で「何もしない命令」が何故存在するのかを調べてみることにしました。まずは、NOPが初めて登場したのは、いつ、どこのマシンなのかを調べてみました。
世界初の電子計算機にNOP命令はあったのか?
世界初の電子計算機であるアタナソフのABCコンピュータ(1939年11月)と、惜しくも2位のENIAC(1946年2月)は、両者共にプログラム内蔵方式では無いため、残念ながら「何もしない命令があったか?」という議論が成り立ちません。プログラムの変更は配線の変更やスイッチのON/OFFでも行われたため「配線を外したボード=何もしない命令」という理論がなりたってしまうからです。
BABYにはNOP命令はあったのか?
ここから先はプログラム内蔵方式のコンピュータに限定します。まずはBABYです。
BABYは正式名をSmall-Scale Experimental Machine (SSEM) といい、マンチェスタ大学にて1948年6月に稼動しています。
BABYは32bitマシンで1つの命令は16bitで構成され、その16bit中の上位3bitがオペコード(命令識別コード)です。オペコードが3bitですから、フルデコードすると8種類の命令が実装可能です。しかし調べてみるとBABYには7種類の命令しかありません。
「もしかしたら、デコードされていない命令こそが何もしない命令では?」と期待したのですが、現存する資料を解析したところ、「減算命令は、命令の最上位bitが0でも1でも良い」という仕様となってました。 これにより見かけ上8種類の命令が存在する(実は全く同じ動作の減算命令が2つ存在する)ことが判りました。残念ながらNOP命令や何もしない命令は存在しませんでした。
EDSACにNOP命令はあったのか?
次にEDSACです。1949年5月に稼動したマシンです。実験機的な色合いの強かったBABY比べ遥かに実用度が高く、「世界初の実用的なプログラム内蔵方式のコンピュータ」と言えるマシンです。
調べてみますと、なんとEDSAC には「何もしない命令」が存在していました。
EDSACは1命令が17bitであり、この「何もしない命令」は以下のコード(2進、?は任意)で表現されます。
EDSACの開発者は命令コードの記述の簡略化の為に、各命令に対し1つの文字を対応させました。例えば加算命令はAで、減算命令はSです。今で言うニモニックやアセンブラのご先祖様と言える記述法ですが、残念ながらの 「何もしない命令」に対応する文字はXで、NOPでもNでもありません。それでも「何もしない命令」の存在が確認できたのはEDSACが初めてでした。
EDSAC「何もしない命令」がある理由の考察は、後で詳しく述べたいと思います。
UNIVACにNOP命令はあったのか?
UNIVACは世界初の商用コンピュータです。1951年に販売が開始されています。
ここで言う「商用」とは、お金を払えば誰でも買えるという意味です。それまではコンピュータは軍や学校、研究機関などが専門家に開発を依頼する物で、普通の人がお店で買うものではありませんでした
最も初期のUNIVACコンピュータであるUNINAC-1011はオペコードが6ビットあり、フルデコードだと64種類の命令が実装可能ですが、実際には38種類の命令しかありません。つまりオペコードに割り当てられていない命令が30種類近くあることになりますが、それらが「何もしない命令」であったか否かは資料不足でわかりませんでした。また当時のマニュアルに明記されている38種類の命令の中にはNOPという言葉も、「何もしない命令」もありませんでした。
遂にNOP命令を発見! DECのPDPシリーズ
PDP (Programmed Data Processor) はDEC社が開発したコンピュータです。PDP-8やその後継機であるPDP-11が有名ですが、PDP-1が最初のPDPシリーズであり、1960年に販売が開始されています。
PDP-1は18ビットマシンです。先頭の5ビットがオペコードですが、オペコードが11111のときは、後に続くオペランドの各ビットが内部フラグをクリアしたり、入出力ポートを初期化するというミニ命令に対応していました。これらのビット列を沢山立てる(1にする)ことにより、フラグのクリアやポートの初期化などを一度にできるという便利かつ独創的な命令でした。
ではオペコードが11111のとき、続くオペランドの全ビット列を落とす(0にする)と当然「何もしない命令」となります。開発者も当然このことは熟知しており。当時のプログラマーズマニュアルにも「命令11 1110 0000 0000 は NOP(no operation)である」と明記されています。
私の調べた限り、NOPという言葉が正式に記載された初のコンピュータです。
マイクロコンピュータで考えるNOP命令の誕生理由
インストラクションデコーダーの設計過程とNOPの関係
例えば、オペコードの先頭ビットが立っていたら、アキュムレータへのロード関係の命令群、2ビット目が立っていたら、アキュムレータからのストア関係の命令群と決めることができるならば、インストラクションデコーダの設計は格段に容易になります。
この設計に従うと、先頭ビットと2ビット目が両方立っていたら、「アキュムレータへロードしたデータを再度同じ場所にストアする」という意味の無い命令が生まれます。普通はもったいないのでちょっとした工夫、例えば「先頭ビットと2ビット目が両方立っていたら、アキュムレータのインクリメント機能も動かす」などの小細工をして、「アキュムレータへロードしたデータをインクリメントして同じ場所にストアする」という様に意味のある命令にしてしまいます。
では、逆に、先頭ビットと2ビット目が両方とも立っていなければどうなるでしょうか? 何も小細工をしなければ「何もしない命令」、すなわちNOP命令が生まれるのです。
「NOP命令」自然発生説
この様に命令の各ビットに対し、何らかの意味を持たせるのがインストラクションデコーダの設計者の仕事です。特に「ビットが立っていた時に何かを行う」という考えでインストラクションデコーダの設計を進めた場合、全てのビットが0の場合にNOP命令となるのは極自然な結果なのです。これは、前述したEDSACの「何もしない命令」やPDPシリーズにおけるNOP命令もこのようにして生まれたと予想できます。
インストラクションデコーダの設計の結果、「何もしない命令」が複数生じる場合もあります。しかし混乱を避けるために普通は1つだけを「NOP命令」とし、他の「何もしない命令」は「未定義命令」とするようです。複数の「何もしない命令」のうち、どれを「NOP命令」にし、どれを「未定義命令」にするのかは開発者の自由ですが、候補の中に命令コードが0x0のものがあるなら、普通の感覚の持ち主ならそれを「NOP命令」にすることでしょう。
ちなみに NOPという言葉自体も、No Operationというありきたりの英語を短縮したものであり、誰が考えても同じになりそうです。一部ではNOPではなくNOOP(ヌープ)と短縮した言葉を使っていた所もあるようですが、いずれにしても、その時代のコンピュータの権威が命名したとかではなく、自然発生もしくは、それに近い形で生まれたのだと思います。
(注)未定義命令に関する補足
LSIの集積密度が低かった時代、命令のオペコードのビット数分の命令を実装をするのは大変なことでした。無理に命令を増やすより未定義命令を設ける方が現実的だったのです。 しかし、ここでいう未定義命令というのは、「何が起きるかお楽しみ」という命令ではありません。未定義命令も、内部での動作は決まっています。ただしそれらの命令は、「意味の無い命令」、もしくは内部の回路を単純化する際の副産物として生まれた「使い道が極めて限定される複雑な命令」なのです。
これらの「望まざる命令」は公式命令として公開されないのが普通です。なぜなら、これらを正直に公開してしまうと、「○○社の新チップは無駄だらけの命令体系だ」とか「複雑怪奇な命令が多くソフト開発者泣かせになる」などという噂が広まり、販売戦略上、宜しくないのです。 この様な未定義命令の中には、実質上何もしない命令、すなわちNOP命令が含まれる事もありますが、未定義命令とNOP命令は全く異なるものです。
終わりに
つまらないことでも、少し気合をいれて調べてみると意外な事実がわかり楽しいものです。WWWの進歩のおかげで、世界中の歴史的資料を自室で読むことが可能になったことも喜ばしいことです。今回この頁に書いたことは、筆者個人の推測も多々混じっています。すべてが真実だと言い張るつもちは毛頭ありませんので、新たな見解や、明らかな誤解などがあれば、是非お知らせねがいます。
尚、本文中では説明を省略しましたがインテルの4004は開発時期はPDPシリーズのかなり後です。
故に、既にNOP命令の意外な利用方法は世界に広まっていたと考えるべきで、当然4004の開発者も知っていたはずだと推測します。ですから、4004の開発者は初めからNOP命令を用意しようとしていた可能性も否定できません。是非、御本人にこのあたりの真相をうかがってみたいものです。
またこれも余談ですが、1970年代にインテルの8080と共に8bitCPUの東西横綱と呼ばれたモトローラの6800は、0x01が「NOP命令」で0x00が「未定義命令」となっています。これは4004の時代から0x0をNOPとしていたインテルのインストラクションデコーダ設計者に対する「独自性の宣言」だったのではないかと推測していますが、それを裏付ける文献や資料は見出せませんでした。
(2011年7月、2013年4月一部改変、2015年4月一部改変)