前回は、プログラムを転送するのに必要なダウンロード回路 マイコンを知る最適なプログラム言語
を作成しました。電子回路を知らない哲さんですが、実体の
配線図を啓二さんがかいてくれたので、その通りに半田付け
して、何とかこなしました。今日は、プログラムに関する話
を聞くようです。
哲 :こんちは、やってきたぞ。 啓二:おう、今日はプログラム言語の話だ。 哲 :待ってました。やはり、C言語だろう。 啓二:C言語の前に、アセンブリ言語をやる。 哲 :C言語の方が簡単だろうが。 啓二:それは、OSをもったマシンでの話だ。 OSなしのマイコンで、C言語を使うときは、スタート アップルーチンと呼ぶ、プログラムを走らせないとならない。 このプログラムは、アセンブリ言語で作成する必要がある。 哲 :結局、アセンブリ言語を知らないと、C言語のプログラムを 書いても、動かせないってことか。 啓二:そう。それに、アセンブリ言語をやると、そのマイコンの 内部がよくわかるので、C言語でプログラムを書くときに 役に立つんだ。 哲 :ふーん。そうなんだ。 啓二:まず、アセンブリ言語をマスターする前に、78kの プログラミングモデルを説明する。 哲 :何だ、それ。 啓二:コンピュータは、I/Oやメモリからデータを入力し、 加工し、出力する機械なんだ。 その加工するときの台や机をレジスタと呼ぶ。これは CPUの中にある。 プログラミングモデルは、まず、レジスタ構成がどう なっているかを示すんだ。 哲 :レジスタは、データを加工するための机か。 啓二:まず、レジスタのサイズは8ビットで、汎用に使えるのが 8個ある。一部は、2つまとめて16ビットで使える。 この図で言うと、A、X、B、C、D、E、H、Lが8ビット レジスタ、AX、BC、DE、HLをまとめて、RP0、RP1 RP2、RP3が16ビットレジスタでインデクスレジスタに 利用できる。 レジスタでデータを加工した結果、データが、どういう状態で あるかを一時的に保存しておくフラグレジスタがある。 PSWというが、F(フラグレジスタ)と呼ぶマイコンもある。 8ビットすべて0だとか、MSB(最上位ビット)が1になって いるとかだ。 PCは、プログラムカウンタで、命令を格納しているアドレスを 入れておく。 まあ、ユーザーが直接PCの内容を操作することはないけれど。 哲 :データの加工方法を書いてあるのが、プログラムということか。 啓二:そうだな、でも、加工方法だけじゃない。 どこから取出して、どこに持っていくだとか、イベントを監視して 動作順序をかえるなんてこともできる。 一度、自分でマイコンを開発してみると、こういうところはよくわかる。 哲 :そんなあ、マイコンを開発するなんて、とてもじゃないが無理だよ。 啓二:おい、そういうことを言っていると、若い連中にすぐ水をあけられるぞ。 CPLDやFPGAを使って、大学でマイコンを設計・開発させる講義もあるん だからな。こんな程度のボードで、マイコンを実現できるんだから。 哲 :わかった、わかった。マイコンでロボットを動かせるようになったら、 挑戦してみるよ。ところで、C言語でポインタがよくわからないと悩む ソフト屋が多いんだが、アセンブリ言語やると、そんな悩みを解決して パリバリやるようになると、聞いたことがあるんだけれど、そうなのか。 啓二:人によりけりだが。まず、アセンブリ言語では、メモリのイメージを 把握しないとプログラムできない。メモリは、アドレスとデータという 2つで考えないとならないから。 アドレスを中味にもつ変数がポインタで、データを中味にもつのが 単なる変数と考えるとよい。 哲 :メモリの図をかくと、左をアドレスとして、データを入れる箱を右に かくなあ。アセンブリ言語でプログラムを書くときは、この図を頭に イメージするといいのか。 啓二:そういうこと。PC(プログラムカウンタ)は、アドレスを内部に 保存しているレジスタと言える。しかし、そのアドレスは、あくま でも、命令が入った箱につけた番地になる。 インデクスレジスタは、アドレスもデータを入れることが可能だが、 そのマイコンが持っているメモリのどのアドレスも指定可能にする か、もうひとつベースレジスタなんていうのを用意して、そのレジ スタの中味とインデクスレジスタの中を加減算し、目的となるアド レスを生成したりするんだ。 哲 :ふーん、そういう概念がない段階で、C言語を触るのは、 ちょっと危険だな。 そういえば、C言語は、高級言語のアセンブラというような 言い方をした解説書も見た記憶があるぞ。 啓二:かなり、昔の解説書だな。 メモリがアドレスとデータの2つで表現されることがわかれば、 C言語のポインタと使い方も、わかってくるさ。 哲 :アセンブリ言語の最初の一歩は、メモリモデルとプログラミング モデル、これらを理解することか。 うーん、具体的にプログラムしてみないとイメージできないなあ。 啓二:じゃあ、これをやってみるか。 コップAにミルク、コップBにコーヒーが入っている。AとBの 中味を交換する方法を答えよ。 哲 :簡単だよ、コップCを用意して、A→C、B→A、C→Bと すればいい。 これが、アセンブリ言語のプログラムとどう関係するんだよ。 啓二:大いに関係するさ。コップAとBを、メモリに確保する。 そして、コップCをレジスタとするんだ。 コップAとBの中味は、メモリのデータとして入っている。 これを78kの命令で実現すると、次のようになる。 DSEG CUP_A: DB 'a' CUP_B: DB 'b' CSEG START: MOV A,CUP_A MOV B,A MOV A,CUP_B MOV CUP_A,A MOV A,B MOV CUP_B,A MAIN: BR $MAIN MOVというのは、転送命令だ。正確にいうと、複写命令だが。 哲 :へえー、こんな風になっているんだ。 CUP_A、CUP_Bがメモリのデータをいれる箱につけた名札(label) になるんだな。 啓二:アドレッシングを知ると、これ以外の方法でもできる。 もうひとつ、イメージがわく例をだそう。 1+2+・・・+10の結果を求めよ。 哲 :積算用の変数とカウンタを使えばできるなあ。 ループを構成する命令とカウンタが、10と等しいか 小さいかを判定する命令も知らないとなあ。 また、加算命令の記述方法も必要だ。 啓二:カウンタを使うにも、積算用変数を用意するのも、すべて レジスタですませないとならない。 実は、10+9+・・・+1とする方が簡単なんだ。 哲 :何故だ。 啓二:レジスタの内容がすべて0かどうかを、フラグで示されるからさ。 カウンタが10かどうかを判定するには、一度カウンタから 10を差し引いて、0になるかどうかを計算する。 フラグを利用すると、その引き算が不要になる。 哲 :カウンタを+1、−1するような便利な命令ってあるのか。 啓二:マイコンにもよるけれど、78kはもっている。 C言語のi++やi--は、それぞれinc、decという 命令に展開される。 i += 1;とすると、inc命令を利用しないこともある。 Cコンパイラにも依存するけれど。 で、例としてあげた内容のソースは、こんな感じかな。 DSEG RESULT: DS 1 CSEG START: MOV A,#10 MOV B,A MOV A,#0 MAIN: ADD A,B MOV C,A DEC B MOV A,B CMP A,#0 BZ $MAIN_EXIT MOV A,C BZ $MAIN MAIN_EXIT: MOV A,C MOV RESULT,A MAIN_STOP: BR MAIN_STOP 哲 :何となく、わかるな。 啓二:そうか。この程度でも、命令を調べたり、アドレッシングの 方法に何があるかを知らないと駄目なんだ。 哲 :CSEG、DSEGは、セグメント指定だな。8086では、これで結構 泣かされたからなあ。でも、本当のセグメントの意味は、違うと 知ってIntelやMicroSoftなら許されることだと改めて思ったよ。 啓二:そういうこと。今日は、これまで。