標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第415回]

●PICの間接アドレッシングと直接アドレッシング

前回はPICの間接アドレッシングについて説明をしました。
PICではFSRレジスタとINDFレジスタを使ってRAMを間接的にアクセスします。
その仕組みは、じつは8080やZ80でHLレジスタを使ってメモリをアクセスするのと全く同じです、ということを説明しました。
今回はPIC18F4550のFSRとINDFについて、さらにすすんで説明をするつもりだったのですが、ちょっと予定を変更しまして、今回は前回の説明に、もう少しつけ加えたいと思います。

8080やZ80でHLレジスタを使ってメモリをアクセスする命令を書くとき、そのメモリを示すのに、8080アセンブラではMと書きますが、Z80のアセンブラでは、もっと明示的に(HL)というように書きます。
Mあるいは(HL)と書いても、Mや(HL)というレジスタが存在するわけではありません。

Mや(HL)を使う命令を、8080アセンブラやZ80アセンブラではMOV B,MやMOV C,(HL)というように書きます。
そのように表現していても、Mや(HL)がMOV B,Dなどと書いたときのDレジスタと同じように、CPU内部にあるレジスタではなくてメモリ上の場所を示しているということは、少しでも8080やZ80を使ったことのある方ならば、ごく普通に理解していたことだと思います。
そしてメモリ上のその場所(アドレス)は、HLレジスタを使って間接的に示されている、ということも多分それほど抵抗なく理解されていたのではないでしょうか。

8080では、レジスタはA、B、C、D、E、H、Lしかなくて、そのほかに演算で使うためのユーザー定義変数の格納場所はメモリ上に置くしかありませんでした。
したがって、そのメモリ上の場所(アドレス)を指定するために、最初は直感的にすぐに理解できる方法として、直接そのアドレスを指定する(直接アドレッシング)を学び、次に少し慣れてきたら、HLレジスタにそのメモリアドレスを入れておいて、それでメモリアドレスを指定する(間接アドレッシング)を学ぶ、という感じで、おそらくは無理なく間接アドレッシングを理解してきたことと思います。

8080やZ80では、アセンブラや機械語のコードの上では、あたかもCPU上にMや(HL)というレジスタが存在するかのように扱ってきたのですけれど、誰もそのMや(HL)がCPU上のレジスタである、などという誤解をすることはなかったでしょう。

Mや(HL)はメモリ上の場所を示している、と理解することに、恐らく何の抵抗もなかったのではないでしょうか。
それがHLを使ってメモリアドレスを指定する「間接アドレッシング」という手法である、ということさえも意識することなく、ごく普通にメモリ場所を指定するには、そうする(HLにアドレスを入れる)のだ、と理解してプログラムを書いてきたことと思います。

PICのFSRとINDFを使うレジスタアクセスも全く同じことをやっているのですけれど、これを理解するのにちょっと抵抗を感じる(じつは私がそうでした)のは、PICのレジスタの有り様にあるのだと思います。

8080のレジスタAに相当するのがPICではWです。
PICにはB、C、D、E、H、Lに相当する「レジスタ」は他にはありません。
そのほかはすべてPIC内部にありますけれど、じつはRAMの上に置かれた「レジスタ」なのです。

初期のPICでは、ですからそれをWと区別して「ファイル」と言っていたはずです。
でも1バイトのメモリ場所を「ファイル」と言うのは、直感的にはちょっと無理があります。
で、PICのData Sheetでも、RAM上に定義された特殊なシステム変数にも「register」なる言い方をするようになっています。

そこから理解の混乱が始まります(と思います)。
「PICの機械語はわからん、難しい」と言われるひとつの理由はそこにあるのではないか、と思われます。

PORTAもTRISBもFSRも全て、RAM上に置かれた変数なのです。
その意味ではユーザーがRAM上に置くDATA1とかCNTRとかというように任意に名前をつけて使う「ワーキングスペース」と全く同じものなのです。
それを8080のB、C、D、E、H、Lと同じように「レジスタ」と言ったりするものですから、PORTAやFSRがWと同じようにCPU内部のレジスタであるとイメージしてしまいやすいのです。
でも実際にはPORTAもユーザー定義のDATA1などと全く同じファイル(’f’)なのです。
いったいPICのそれは、レジスタなのかメモリ上の変数なのか、実際はメモリ上の変数に過ぎないのですけれど、どうもそのあたりがなんとなく混乱してつい錯覚してしまいそうになります。

直接アドレッシングも間接アドレッシングもメモリをアクセスするときに使う用語です。
たとえば、
movwf PORTA
も、
movwf DATA1
も、ともにRAM上の「場所」にWレジスタの値を送りますから、直接アドレッシングです。
直接アドレッシングと言うからには、メモリアドレスを直接指定しているはずです。
そう言われてみれば、movwf DATA1は、確かにそうかなあ、と思えないこともありません。
しかし、movwf PORTAになると、えー、それってレジスタでしょ?メモリとは違うのでは?という錯覚をおこしてしまうかもしれません。

実際にPIC16F88で試してみましょう。
[第411回]で作ったパルス出力プログラムに少し手を加えてみました。
直接アドレッシングの説明のための変更ですから、プログラムとしての意味は全くありません。


[注記]このプログラムにはミスがあります([第416回]参照)。

ユーザー定義変数として、プログラムの先頭部分で、アドレス20にdata1を定義しました。
そしてプログラムの中ほどのところで、
movwf PORTB
movwf data1
という命令を追加しています。
ごく普通の使い方ですが、これがメモリに対する直接アドレッシングであることを明らかにするために、その下に、直接メモリアドレスを指定して、同じ命令を書いてみました。
movwf 06(ここはmovwf 6と書くこともできます)
movwf 20
という部分です。

普通はこういう書き方はしないと思います。
PICの入門書などでは、こういう書き方は、多分紹介されていないはずだからです。
ええっ、こんな書き方でエラーにならないの?
と思われた方も多いのでは、と思います。
もちろん、エラーにはなりません。
そのことを確認する前に、以前にもお見せしましたが、PIC16F88のメモリマップをもう一度見てみましょう。


[出典]Microchip社PIC16F88Data Sheet

ちょっと見難いかもしれませんが我慢してください。
左上のほうにPORTBがあります。アドレスは06hになっています。
その下のほう、アドレス20h〜7FhはGeneral Purpose Registerになっています。ユーザー用の汎用メモリエリアです。
ほーら、こんなところまで「register」と書いてあります。
だから余計混乱してしまうのです。ここは「register」ではありません。この表全体が、全部メモリーです。
で、そのユーザー用エリアの20hにdata1を割り付けたのです。
ですからdata1のメモリアドレスは20です。

さて、これも前にお見せしたように、アセンブラによって出力されたリストで、さきほどの命令がどのように機械語に翻訳されたか確認してみることにしましょう。



movwf PORTBからmovwf 20は、プログラムアドレス000Bから000Eにあります。
movwf PORTBもmovwf 06も、どちらも機械語コードは0086です。
またmovwf data1もmovwf 20も、どちらも機械語コードは00A0で全く同じです。
なお、PICのアセンブルリストは[第413回]でも紹介しました。
そのときはPIC18F4550のリストでした。
このリストはPIC16F88のアセンブルリストです。
同じmovwfの機械語コードでもPIC18F4550とPIC16F88では全く異なっています。

ここではPIC16F88の機械語としての説明です。
PIC16F88のmovwfの機械語コードを見てみましょう。


[出典]Microchip社PIC16F88Data Sheet(赤線は筆者)

movwfは赤線で示しました。
機械語コードは表の右部分に示してあります。
movwfの機械語コードは、上位6ビットが00000で下位8ビットが1fff ffffになっています。ビット7が1でビット6〜ビット0にメモリアドレスが入ります。
PORTBはアドレス06にありますから、機械語コードの下位8ビットは、10000110(86)になります。
data1はアドレス20にありますから、機械語コードの下位8ビットは、10100000(A0)になります。

これでPICの普通のレジスタへのアクセスが直接アドレッシングであることが理解していただけたことと思います。
さてでは、いよいよ間接アドレッシングについて、そこのところがどうなっているのか、についてなのですが、時間がなくなってしまいました。また次回に続きます。
2010.1.7upload

前へ
次へ
ホームページトップへ戻る