標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第418回]
●PIC18F4550の間接アドレッシング
このところの何回かにわたってPICの間接アドレッシングについて説明してきましたので、大体のところはおわかりいただけたかと思います。
8080ではメモリの間接アドレッシングにはHLレジスタを使い、「M」というバーチャルなレジスタにアクセスすると、HLレジスタで示されたメモリにアクセスする、という仕組みになっていました。
8080アセンブラではMと表記しますが、Z80アセンブラでは(HL)と書きます。
いずれもAレジスタやBレジスタと同じような「レジスタ」として扱われますが、Mや(HL)という「レジスタ」がCPU内部にあるのではなくて、あくまでバーチャル(仮想的)なレジスタです。
PICの場合には、8080におけるHLレジスタとMに相当するものとして、FSRレジスタとINDFレジスタを使ってデータメモリの間接アドレッシングを行います。
8080のMがバーチャルなレジスタであったのと全く同様に、INDFレジスタもデータメモリ上に割り付けてありますが、そのメモリアドレスに実際に存在する「レジスタ」ではなくて、バーチャル(仮想的)なレジスタです。
PIC16F88などでは、FSRとINDFは1組しかありませんが、PIC18F4550では、なんと3組もあります。
しかもメモリアドレスを格納するFSRレジスタは、FSRHとFSRLのペアになっていて、PIC18F4550のデータメモリの全範囲(000〜FFF)をアクセスすることができます。
ただし、PIC18F4550のFSRH、FSRLペアレジスタは12ビットのアドレスを格納できますから、上記のように000〜FFFの範囲をアクセスできるのですが、PIC18F4550のデータメモリは000〜7FFの2KBしか実装されていませんから、800〜の範囲をアクセスしても実際にメモリとして利用することはできません。
ただ最後のF60〜FFFはシステム用のレジスタエリアになっていますから、この範囲をアクセスすることは可能です(可能ですけれど、この範囲を間接アドレッシングすることにメリットがあるか、というとそれは疑問です)。
PIC18F4550では下記の3組のレジスタを使ってデータメモリの間接アドレッシングを行います。
FSR0H、FSR0L、INDF0
FSR1H、FSR1L、INDF1
FST2H、FSR2L、INDF2
PIC16F88では、FSRレジスタにメモリアドレスを設定するのに、
movlw 20
movwf FSR
のようにしました(実際には、PIC16F88のデータレジスタは000〜1FFなので、FSRレジスタの8ビットだけでは足りません。不足する最上位の1ビットはSTATUSレジスタのIRPビットを使って指定します)。
PIC18F4550の場合でも、PIC16F88などと同じように、movlwを使って、
movlw 50
movwf FSR0L
movlw 03
movwf FSR0H
というようにすることができます(FSR0レジスタペアにメモリアドレス0350を設定)。
しかしPIC18F4550は、PIC16Fにはなかった命令が追加されていて、その追加された命令の中には、FSRに関するものもいくつか含まれています。
そのうちの1つにLFSR命令があります。
●LFSR命令
FSRレジスタペアにデータメモリアドレスを書き込む命令です。
これは便利な命令です。
movlwを使う前述の方法だと4ステップも必要だったところが、わずか1命令でできてしまいます。
[出典]Microchip社PIC18F4550DataSheet
たとえばFSR1H、FSR1Lにデータメモリアドレスの0123を設定するには、
lfsr 1,123
と書けばよいのです。
おお、これは8080のLXI H命令と全く同じですね。
FSR0、FSR1、FSR2の各レジスタペアに対して、lfsr 0、lfsr 1、lfsr 2の3通りの命令があります。
●POSTINC0…奇妙だけれども便利な「レジスタ」
PIC18F4550の間接アドレッシングには奇妙な「レジスタ群」があります。
今までずっと説明してきたINDFレジスタの進化形のようなレジスタです。
POSTINC、POSTDEC、PREINC、PLUSWの各のレジスタです。
実際には、FSR0、FSR1、FSR2と組になっていて、
POSTINC0、POSTDEC0、PREINC0、PLUSW0
POSTINC1、POSTDEC1、PREINC1、PLUSW1
POSTINC2、POSTDEC2、PREINC2、PLUSW2
の3組のレジスタ群があります。
この全てがINDFレジスタの代わりというか、INDFレジスタそのものとして間接アドレッシングに使われます。
たとえば、FSR0H、FSR0Lレジスタペアに0457というデータアドレスがセットされているときに、
movwf INDF0
という命令を書くと、wレジスタの値がデータメモリの0457番地に書き込まれます。
それと全く同じ使い方で、
movwf POSTINC0
と書くと、同じようにwレジスタの値がデータメモリの0457番地に書き込まれます。
しかしPOSTINC0は、それだけではないのです。
INDF0を使った場合FSR0レジスタは変化しませんから、たとえば連続するいくつかのデータメモリに値を格納したり、読み出したりする場合には、さきほどのmovwf INDF0(またはmovf INDF0,w)に続けて、
incf FSR0L
を書かなければなりません。
ところがFSR0Lは8ビットのレジスタですから、メモリバンクの境を越えるようなメモリアドレスを連続でアクセスするためには、
incfsz FSR0L …FSR0Lを+1し、もし結果が0なら次の1命令をスキップする
goto xxxx …処理を繰り返す
incf FSR0H …上位アドレスを+1する
というような命令を付け加える必要が出てきてしまいます。
そこのところが、POSTINCを使うと一気に済んでしまうのです。
movwf POSTINC0
のように使うと、wレジスタの値をFSR0レジスタペアで指定するメモリアドレスに書き込んだあと、「オートマチックに」FSR0レジスタペアがインクリメント(+1)されるのです。
このインクリメントはFSRnHとFSRnLを分けて行うのではなく、FSRnHとFSRnLをつないだ形でおこなわれますから、incf FSR0Lなどのさきほどの例のように、メモリバンクの境で上位アドレスのインクリメントに気を使う必要はありません。
たとえば01FFから0200へのインクリメントも問題なくこなしてくれます。
おお、このインクリメントの部分は、8080のINX H命令と同じ動作ですね。
すると。
そうです。
POSTDECは、間接メモリアクセス後に、FSRレジスタペアの値をデクリメントします。
そして、PREINCは、FSRレジスタペアを「先に」インクリメントしてから、間接メモリアクセスを行います。
さて、最後の、PLUSWですが、これはちょっと「やりすぎ」だと思います。
PREINCなのですが、さらにアドレスにwレジスタのゲタをはかせます。
ううう。
これは使ったことがありませんから(使う気にならない)、解釈に誤りがあるかもしれませんが、Z80のIX、IYレジスタを使った間接アドレッシングのような使い方になるのでは、と思います。
IX+dのdに相当する「オフセット」がwレジスタによって与えられるということのようです。
んでも、1つしかないwレジスタをオフセット指定に使ってしまったら、それで一体なにができるのでしょうかねぇ…。
ちょっと理解に苦しみます。
まあそんな面倒なものは置くとして、しかし、POSTINCとPOSTDECはなかなか気の利いた機能だと思います。
これがinstructionではなくて、register(しかもバーチャルな!)だというあたりが、いかにもPICだなあ、という気がします。
参考までに、PIC18F4550Datasheetの、INDIRECT ADDRESSING(間接メモリアクセス)の説明部分です。
[出典]Microchip社PIC18F4550DataSheet
[追記10.1.14]
余計なことかもしれませんが念のため。
Figure5−7はちょっと不適切です。これじゃ誤解してしまいます。
PIC18F4550は、Bank8〜Bank14にはRAMを実装していませんから、「direct」であろうと「indirect」であろうと、その間をアクセスしても全く無意味です。
またBank15についても、F00〜F5Fはアクセスしても無意味だと思います(確認はしていませんが)。
Figure5−7の使用例は、Bank0〜Bank7の全範囲を対象にしてアクセスするときには、「just a convenient way」であろうかと思います。
2010.1.13upload
2010.1.14追記
前へ
次へ
ホームページトップへ戻る