本当に初心者の人に捧げるコンピューター入門


補足 その5−A

本当の機械語について

 ここでは本文にあるような偽機械語では飽き足らないという人のために、本物の機械語についてちょっとだけ説明しましょう(それでも3章になっちゃいましたが)
 ちなみにここは本文の機械語の話を読んでいるという前提で書いてますので、まだ読んでいない人はとりあえず本文を読むことを強く推奨します。
(だったら途中にリンクなんて張るなって?まあまあその場の筆の勢いということで・・・)

なんで偽物などを?



 本物の機械語の説明をしようと思ったら、どうしても実際のCPUの仕組みに関して説明しなければなりません。ところCPUの種類が変われば機械語も変わってしまう上に、様々な設計上の制限があって話が必要以上にややこしくなってしまいます。

 本当に初心者の方なら、ここまで読んだ限りではコンピューターにはCPUメモリー外部入出力装置があるということしか知らないはずです。それでもなんとか理解できるようにとない知恵を絞ったあげくがあのような偽機械語でした。

 機械語とはCPUが違えばみんな違っています(同じ機械語が使えるCPUがいわゆる互換CPUです)そこでこれから説明するのはZ−80という8ビットCPUの機械語です。このCPUは古いせいもあって構成が非常にシンプルなので、まあ何とか説明可能です。

 ちなみに、Z−80というのはその昔PC−8001やMZ−80などで使われていたCPUです。インテル社の作った8080というCPUをザイログ社が拡張して作った物で、多分8ビットのCPUのなかでは最も優れた物だったでしょう。
 クロック数は2メガヘルツ(4メガに拡張可能)64Bまでのメモリーが使用できました。現在のCPUと比較するとおもちゃのようなものですが(ペンティアムなら200メガヘルツで4Bまでのメモリーが使える!)実は今でもマイコン炊飯ジャーなどの「マイコン」として現役のCPUです。
 うろ覚えですが、秋葉原に行けば20円ぐらいで売っているそうです。


本物の機械語と本文の偽機械語はどう違う?



 まず、実際のコンピューターでは今でもメモリーには0〜255までしか書けないので、ちょっと大きな数を指定する時には、引数が2バイト〜4バイトの長さになります。

 しかしもっと大きな違いは、本物のCPUは偽機械語でやっていたようにメモリーを直接読んで演算することができないということです。
 偽機械語では加算のために例えば以下のように書いていました。

ADD X Y (これはX番地のメモリーの内容にYという値を足せと言う意味でした)

 ここでちょっと考えてください。この計算をするためにはCPUはどうしなければならないでしょう?

 まず少なくともX番地のメモリーの内容をCPUの中に読み込んで記憶しておかなければなりません。それからYという値を読んで、覚えている値と足して、その結果をX番地のメモリーに書き込む、という動作をするわけです。
 偽機械語では上記の動作が1行で書けてしまいましたが、本物の機械語ではこの動作をそれぞれ別に書いてやらなければなりません。つまり、

  1. メモリーからデータをCPU内部に読み込む
  2. 計算する
  3. 計算結果をメモリーに書き込む
と3行書かなければならないのです。
 どうしてこんなに面倒くさいことをするのでしょう?その理由は高速化をするためなのです。
 例えば10+20+30を計算してX番地のメモリーに保存する場合、偽機械語では以下のように書くことになります。

  LD  X  10
  ADD  X  20
  ADD  X  30

これはどういう動作になるかというと

  1. X番地に10を書き込む
  2. X番地の値をCPUに読み込む
  3. 読み込んだ値に20を足す
  4. 計算結果をX番地に書き込む
  5. X番地の値をCPUに読み込む
  6. 読み込んだ値に30を足す
  7. 計算結果をX番地に書き込む
という7つの動作になります。ところで上をよく見ると、X番地のデータを読んだり書いたりやたらに繰り返しています。
 しかしCPU内部には読み込んだデータを保存しておくためのちょっとしたメモリーがあります。このメモリーをレジスタといいますが、これを直接操作できれば上の計算は次のようになるでしょう。

  1. あるレジスタに10を書き込む
  2. そのレジスタの値に20を足す
  3. そのレジスタの値に30を足す
  4. 計算結果をX番地に書き込む
7行あったのが4行に減りました。その分だけ速度は上がったわけです。
 Z−80のできた頃はCPUもスピードが遅かったので、この程度の差で済みました。ところが最近はCPUの計算速度はものすごく向上しています。ペンティアムなどはZ−80の1000倍は速いでしょう。

 ところがメモリーにデータを読み書きする速さはあのころから大して向上していないのです。よくて10倍というところでしょうか。それにこれだけ速くなってくると、配線の長さも速度に効いてきます。メモリーはCPUの外にあるので、CPU内部のレジスタを読み書きするのに比べたら絶対に遅くなります。
 するとメモリーからデータを読んだり書いたりしている間はCPUは何もすることがないので遊んでしまいます。いくら速くても遊んでいられてはたまりません。

 つまり偽機械語のようなやり方をしていると、ペンティアムを使ってもZ−80並のスピードしか出なくなってしまうのです。

 そういうわけで、本物の機械語ではメモリーのデータをCPUのレジスタに読む動作とレジスタの値を計算する動作が別々になっているのです。

レジスタ



 それではCPUの中のレジスタとはどういう物なのでしょう?さっきの説明の通り、これはメモリーの一種です。しかしレジスタは本体のメモリーと違ってアドレスで管理されているわけではありません。

 レジスタとは例えば8ビットや16ビット(最近の物では32ビットとか64ビット)の長さの独立した数字を入れられる箱のようなもので、それぞれに以下のような名前がついています。

<Z−80のレジスタ>
記号 長さ コメント
A 8bit アキュームレータと呼ばれる。足し算などの計算をする場合はこれを使わなければならない。
B,C 8bit 汎用レジスタ。自由に使える。BとCを一組にして16ビットのレジスタとして使うこともできる(そのときにはBCレジスタと言われる)。繰り返し命令の時には繰り返し回数をセットする。
D,E 8bit 汎用レジスタ。自由に使える。自由に使える。DとEを一組にして16ビットのレジスタとして使うこともできる(そのときにはDEレジスタと言われる)
H,L 8bit 汎用レジスタ。自由に使える。HとLを一組にして16ビットのレジスタとして使うこともできる(そのときにはHLレジスタと言われる)。繰り返し命令の時にはメモリーのアドレスをセットする。
I 8bit 割り込みレジスタ。割り込みアドレスを入れておく(割り込みに関してはいつか詳しく説明するのでそれまで待っていてください)
R 7bit リフレッシュレジスタ。CPUが内部的に使用する。
IX,IY 16bit インデックスレジスタ。あるメモリーに書かれている内容の示すアドレスに・・・という処理の時使う。
SP 16bit スタックポインタ。CPUが内部的に使用する。
PC 16bit プログラムカウンタ。プログラムが現在何番地の命令を実行しているかを入れておくレジスタ。
F 8bit フラグレジスタ。ここに書かれた値の各ビットがゼロフラグ、符号フラグ、キャリーフラグ、パリティーフラグ*などに対応している。

 本体のメモリーはどのメモリーも同じような物です。100番地のメモリーも1345番地のメモリーも同じように扱うことができます。
 しかしレジスタは一本一本が原則としてちがった用途を持っています。右に各レジスタの一般的な用途を記しています。本物の機械語を使うときには、各レジスタの用途のことも理解しておかないとプログラムは動きません。

  • なおZ−80のには裏レジスタといって上記のレジスタセットがもう1セット内蔵されていて大変便利でした。

* パリティーフラグ

 パリティーという言葉は自分でモデムの設定をしたことがある人ならば、聞き覚えがあるかも知れません。
 パリティーフラグというのは主に外部入出力機器からデータを受け取るときに使います。 このフラグは得られたデータを2進法で表した数字に

1が偶数個あれば 0
1が奇数個あれば 1

になります。これは何なんでしょう?

 これは主にデータ通信の誤り訂正に使います。例えばモデムは電話線を通じてデータ転送をしますが、電話線というのは非常にノイズが乗りやすい物です。普通に話していてもバックでガーガー音がしていて相手の声が聞き取りにくいことはよくあります。モデムも同じで、こういうノイズがあると送ったデータが相手に正しく届かないことがあるわけです。
 しかしだからといって電話会社に文句を言っても仕方ありません。ならばどうすればいいのでしょう?

 ここで二進法で0010という値を相手に送ったとして、途中でノイズが乗って3桁目の0が1に変わって0110という値になってしまったとしましょう。受け側では送り手が0110を本当に送ったのかそれともノイズの結果こうなったのか分かりません。
 しかし次のようなルールにしておくとどうでしょう?

送るデータの1の数が奇数個だったら最上位桁を1にして偶数個にしておく

 すると0010という値は1が1個なので1010に変換して送られます。

 こうすると4桁分のデータを送れるはずが3桁分のデータしか送れなくて無駄のようです。しかしここでもし3桁目にノイズが乗って1に変わったとしたら1110になります。これは1の数を数えると3個です。これは何かおかしいですね。もし相手が0110を送りたかったら1の数は偶数なので、最上位桁には何もせず0110そのままが来るはずです。普通だったら1の数が奇数個のデータは絶対来ないはずなのです!

 つまりこういうルールでデータの転送をすれば、受け側が数字を見ただけで何か間違いがある!ということが分かるわけです。
 なおこれは誤り訂正の手法の中では最も基本的なものです。実際のモデムなどではこれと共にもっと高度な誤り訂正手段も使われています。


 というわけで少し長くなったので、次の補足その5−Bで実際の機械語命令を解説します。


前へ 目次へ 次へ