この投稿は、俺ことブログ主の考える、最高のプログラミング遍歴ではないかと思われることをつらつら書いたものです。事実に基づくようにも見えますし、妄想の産物かも知れませんが、そのへんは読まれる方にご判断をおまかせします。
あ、でもできるだけ役に立つことを書こうと思ったので、そう思って読んでいただければ幸いです。
今回は、高校生時代の続きです。「高校生編1」はこちらです。
付属マニュアルだけで勝負する
ワンボードマイコンEX-80のCPUである8080Aのレジスタ構成や、フラグの意味、命令の種類も何となくわかってきました。すると、次は自分で何か作ってやろうと思うわけです。とはいえ、最初からゲームとか大それたものを作れるものでもない(アルゴリズムという考え方もなかった)ので、ちまちま計算させたりするのが関の山です。
当時、参考書と言えるものなどなく、唯一の参考書がキット付属のマニュアルでした。そこには、命令セットとその動作などが書かれているので、最低限のことは知ることができます。
足し算をやってみる
まずやってみるのは、足し算。はい、足し算です。1と2を足して3になる、それです。それってやって楽しいの?楽しいわけないでしょう。でもそれ以上のことはやれといわれてもできないんだから、しかたないでしょう。
しかも、足し算といっても、電卓のようにパネルから数値を入れて動かせるようなものなんか最初から作れるわけありません。プログラムに最初から数値を入れておき、それを計算させて結果を見るだけです。
ここから、8080Aの命令を少し出していきましょう。私が最初に作った足し算プログラムは、これです。
MVI A,10
MVI B,20
ADD B
何のことかわかりませんよね、今、プログラムの達人と呼ばれる方でもわからないという方が多いと思います。これは8080Aの機械語をニーモニック表示したものです。ニーモニック(mnemonic)とは「記憶を助ける」という意味で、覚えにくい16進数の機械語に、英表記を与えたものです。
16進数の機械語では、次のようになります。ニーモニック表記のプログラムを機械語に変換するのが、アセンブラ(assembler)と呼ばれるプログラムです。assembleとは、組み立てるという意味です。このため、ニーモニック表記のプログラムを「アセンブリ言語」と呼ぶこともあります。
3E 10 ; MVI A,10
06 20 ; MVI B,20
80 ; ADD B
MVIとはMove Immediateの略で、レジスタ(register)に直値を入れるという意味です。レジスタとは、コンビニなんかにあるレジと同じ意味で、記録簿とかいう意味です。つまり、何かを記録しておくCPUの一部分です。Aというのはレジスタの一つです。つまり、Aに10を入れるという意味です。次はわかりますね、Bというレジスタに20を入れます。そしてADDは文字どおりAddで、Aは隠れていますがAにBを足してAに入れろという意味です。
この命令が3つ動くと、最終的にAに30が残ります。EX-80には「モニタ」というシステムがあって、プログラムが止まると、その時点でのレジスタの値などをTV画面などに出してくれます。これによって、Aが30になっているのか、確認できるというわけです。
足す数を変えたいときにはどのようすればいいのよさ?これはわかりますね、10とか20とかのところを変更します。そう、前の投稿での改造のパターンと同じです。好きな数を入れればどんな足し算でもできますよ!
おいおい、たかが足し算にいちいち数値を書き換えてなんて面倒なコトさせるの?イマドキの方ならそう思うのでしょうね、私もそう思います。しかしこれは、命令の動きを理解するために必要なステップなのですから、一気にジャンプとか考えずに、地道にやっていくことも必要ですよ。
決まり事には従う
さて、だいぶ飛びましたが、ここで大事なことを一つ。決まり事には従いましょう、です。まったく触れてきませんでしたが、EX-80ではプログラムをどこに置くのかが決まっています。具体的には8200Hという場所です(最後のHは、それが16進数であるという意味)。そこにプログラムを置けば、誰かに干渉されることもなく、自由自在に動かせます。逆に、そこではなく、8100Hとか8000Hとかに置くと、そこは誰かに使われている可能性があるので、プログラムが壊されてしまったり、不可解な動作をすることもあり得ます。
決まり事はどんなシステムにもありますので、それには従いましょう。
引き算に応用してみる
足し算ができたら、そのまま引き算にも応用できます。ADD命令をSUB命令(Subtraction)に変えればいいのです。意外と簡単だと思いませんか? とはいえ、掛け算やりたいな~とか思ってもムダです。あ~ムダではないですが、8080Aには掛け算を行う命令はないんですね。当然、割り算もありません。じゃ、掛け算はできないの? 命令一発ではできませんが、掛け算を行う方法はあります。
この方法が、アルゴリズム(algorithm)というものです。日本語でいえば算法と呼ばれます。読んで字の如く、計算する方法ですね。そこで掛け算ですが、皆さん、掛け算を足し算だけで行うにはどうするでしょうか?
掛け算をアルゴリズムで実現する
5×6を計算しましょう。これは、5を6回足し算すれば求められます。式で書くとこういう感じです。
5+5+5+5+5+5+5
8080Aのプログラムにすると、こうなりますね。
MVI A, 0
MVI B, 5
ADD B
ADD B
ADD B
ADD B
ADD B
ADD B
最後にAには30が残ります。しかし、なんかスマートじゃないような気がしますよね。5×6じゃなくて5×8にするなら、「ADD B」を2個増やさなければなりません。
そういうときに使うのが、繰り返し(loop)の技法です。5×6を、「5を加える操作を6回繰り返す」というように表現するわけです。プログラムにするとこんな感じです。
MVI A, 0
MVI B, 5
MVI C, 6
LABEL:
ADD B
DCR C
JNZ LABEL
新しくCというレジスタも出てきました。ついでですが、8080AにはA, B, C, D, E, H, Lというレジスタがあります(他にもあるんですが、計算に使えるものということで)。LABELというのはプログラムのとある場所を示すのですが、実体はアドレスです。例では具体的なアドレスを書いていないのでLABELでごまかしています。DCRというのも初めて出てきていますが、1個減算する(Decrement)命令です。最後のJNZというのはJump if Non Zeroの略で、直前の計算がゼロでなければLABELにジャンプしろよ!という意味になります。
読み解くと、計算結果を入れるAを0にしておき、被乗数であるBを5にしておき、乗数であるCを6にしておきます。LABEL以降を見ると、被乗数をAに足して、乗数を1個減らし、これをゼロになるまで繰り返す、ということになります。これなら、BとCに入れる数値を変えれば、どんな掛け算にも対応できます。スゴいですね。
まとめ
上記のプログラムは学習用としては目的を果たしていますが、実際に使うものにするには欠陥だらけです。しかしそれをここでくどくど書くことは主旨に合いませんので、これまでにしておきましょう。こんな感じで、徐々に使える命令を増やしていき、複雑な動きをさせるプログラムを書けるようになってきます。
そうすると、ちょっとまとまったものを作ってみたいなと思うのが人情ですよね。次回は、そこ、行ってみましょう。