復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります!
[第534回]
●テーブル参照
とうとう大晦日になってしまいました。
このところずっとテーマ違いのままきています。
年が明けましたら少しずつ、テーマ別に再整理したいと思っているのですが、果たしてその時間がありますかどうか…。
前回からの続きです。
やっとテーブル参照の説明にたどりつきました。
下は前回もお見せしたメインプログラムのリストですが、ここでは前回も説明しましたようにテーブルを参照しています。
loop clrf cntr clrf udmk loop1 movlw 0a;=10 movwf limit loop2 bsf PORTE,2 movf cntr,w call Htable movwf t1Hdata movf cntr,w call Ltable movwf t1Ldata call t25ms bcf PORTE,2 call t25ms btfsc udmk,0 goto downcount incf cntr,f decfsz limit,f goto loop2 ;set downcount incf udmk,f decf cntr,f goto loop1 downcount decf cntr,f decfsz limit,f goto loop2 goto loop ; |
テーブル参照の仕組みです。
wレジスタにキーになる値をいれてテーブルの先頭アドレスをCALLすると、キーによって選択された結果の値がwレジスタに入ってリターンしてきます。
下はメインプログラムでCALLする2つのテーブルです。
; org 400 ; Htable addwf PCL,f retlw 0d8 retlw 0dc retlw 0e0 retlw 0e4 retlw 0e8 retlw 0ec retlw 0f0 retlw 0f4 retlw 0f8 retlw 0fc ; Ltable addwf PCL,f retlw 0f0 retlw 0d8 retlw 0c0 retlw 0a8 retlw 90 retlw 78 retlw 60 retlw 48 retlw 30 retlw 18 ; end |
テーブル参照はコード変換と考えることができます。
Htableはキーが00のときにD8Hを、01のときにDCHを、02のときにE0Hを、というようにそれぞれ値が選択されます。
その仕組みはこうです。
PCLはプログラムカウンタの下位8ビットです。
addwf PCL,fを実行する時点でプログラムカウンタにはその次のアドレスが入っています。
その値にwレジスタの値を加算したものがPCLの新しい値になります。
この命令の実行によってプログラムカウンタが更新されますから、その結果は次にそのプログラムカウンタが示すアドレスにジャンプして、そこにある命令が実行されることになります。
addwf PCL,fの次に並んでいる命令はretlw命令ばかりです。
retlw nn は、nnをwレジスタに入れてリターンする命令です。
この仕組みによって、wレジスタの値が示す位置に置かれたretlw命令の値がwレジスタに入れられて戻ってきます。
さて。
長々とここまで説明をしてきました理由は、上のリストに書かれた ORG 400 にありました。
HtableとLtableの置かれているアドレスは400H番地台です。
ところがPCLは8ビットですから、上位ビットの値である’4’はaddwf PCL,fでは計算できません。
ですから、普通にこういうプログラムを書くとプログラムが期待した通りには実行されずに大抵は暴走してしまいます。
そのような場合でも正しくテーブル参照が実行できるように用意されているのがPCLATHレジスタです。
PCLATHレジスタについては[第513回]〜[第515回]で説明をしました。
あらかじめPCLATHにテーブルのあるアドレスの上位5ビットを入れておくことで、テーブル参照が正しく実行されるようになります(PICのプログラムカウンタは13ビットです)。
しかしこのPCLATHについては、ネット上ではかなり誤解されているところもあるようです。
そこで今回のサンプルプログラムでPCLATHについて本当のところを確認してみたのです。
やれやれ。
やっと、結論までたどりつけました。
ネット上ではPCLATHが文字通りプログラムカウンタの上位カウンタそのものである、と解釈して混乱してしまっている方などのページも見受けられます。
正確に言いますとPCLATHはプログラムカウンタ(の上位5ビット)ではありません。
言うならばプログラムカウンタの仮レジスタのようなものです。
PCLATHは通常の命令では全く参照されません。
ではどういうときにPCLATHが使われるかと言いますと、addwf PCL,f のようにプログラムカウンタの値を変更するような命令が実行されたときに、PCLATHが使われます。
PCLが変更されると同時に、PCLATHの(下位5ビットの)値がプログラムカウンタの上位5ビットに入れられます。
この働きによって、メインプログラムから離れたアドレスにあるテーブルでも参照することができるようになります。
実はPCLATHが参照される命令が他にもあります。
それはgotoとcallです。
そのことをテーブル参照と合わせて説明しているページもあります。
そのように説明をしながら、筆者自身が誤解をしてしまっているのではないかと思われるサイトなどもあるようです。
PCLATHについてよく理解しないまま、gotoやcallでも使われるなどという説明をしますと、それならテーブルと同じように上位アドレスが異なっているアドレスに置いたサブルーチンや割込みプログラムをcallするときにもPCLATHに値を設定しなくてはいけないのではないか、などという誤解をしてしまいます。
実はそのような混乱を避ける目的で、PCLATHについての説明図を引用しましたときに、わざとgoto、callに関する部分をカットしてお見せしました([第514回])。
本当はこういう図になっています。
[出典]Microchip Technology Inc. PIC16F882〜887Data Sheet
図の中でPCHとあるのがプログラムカウンタの上位5ビットです。
PCHはプログラムで直接書き換えることはできません。
図の上側がテーブル参照に関係する部分です。
instruction with PCL as Destination という説明がついています。
意訳すると「PCLを書き換える命令」です。
図の下がgoto、callに関する部分です。
PIC16Fのプログラムカウンタは13ビットです。
ということはアクセスできる範囲は00000 00000000〜11111 11111111です。
つまり0000〜1FFFの範囲です。
バイトで表現すると8KBです。
ところでこれも[第514回]で少し書いたことですが、PIC16Fのgotoやcallのマシン語コードのオペランドは11バイトしかありません。
ということは2KBの範囲しか直接アクセスできないことになります。
そこでプログラムメモリを2KBずつのバンクに分割しているのです([第514回]参照)。
そして上の図の下半分の説明は、PCLATHを使った、バンクを越えてアクセスする仕組みを説明している図です。
その図のように、gotoやcallが実行されるときには、PCLATHの2ビットの値がプログラムカウンタの上位2ビットに入れられるのですが、そのような仕組みに気を使わなければならないのは、プログラムが2KBを越えるような大きなプログラムを書くときだけですから、普通はこのことは考えなくてもよいと思います。
しかし、もしも2KBを越えるような大きいプログラムを書くときには、図からわかりますように、PCLを書き換える命令で使われるPCLATHの値と、goto、callで使われるPCLATHの値が2ビット重なっている点に十分注意する必要があります。
今回でちょうど終わるようにしたいと思っていたのですが、いろいろ書いておりますうちに、今回も時間切れになってしまいました。
この続きは次回に説明することにいたします。
今年一年拙文にお付き合いいただき有難うございました。
来年もよろしくお願いいたします。
皆様よいお年をお迎えください。
ワンボードマイコンでCP/Mを![第534回]
2013.12.31upload
前へ
次へ
ホームページトップへ戻る