【テーブルデータ】
多くの並んだ定数データを順番に取り出したい時にテーブル方式を使います。
(ルックアップテーブルとも呼ばれます。)
PIC18Fxxxxシリーズでは、テーブルアクセス用の専用命令が追加されましたから
こういう時には便利に扱えます。
【定数データの作成】
テーブルアクセスをする時には、まず定数データをテーブルとして並べたものを
プログラムメモリエリアに作成する必要があります。
この定数データをプログラムエリアに確保する方法には、下記のようにいくつかの
方法があります。
(1) RETLW命令として確保する方法
これまでのPIC16Fシリーズの時と同じ方法で、RETLW kという命令で定数kを
取り出せるようにする方法です。
この場合には、「DT」という擬似命令を使います。
《例》 DT擬似命令の展開内容例
DT 0AAH, "ABC", '0', 0
このアセンブル結果は
0CAA 0C41 0C42 0C43 0C30 0C00
となり、これは下記と同じ結果となります。
RETLW 0XAA
RETLW 'A'
RETLW 'B'
RETLW 'C'
RETLW '0'
RETLW 0
(2) 1バイト毎のデータとして確保する方法
PIC18シリーズでは、プログラムメモリが16ビットありますから、1バイトごとの
データを2バイト分まとめて各ワードの中に格納することができ、効率良く格納
できます。このように格納するためには、「DB」という擬似命令を使います。
(逆にPIC16シリーズでDBを使うと上位2ビットが欠けたデータとなります。
PIC16シリーズの場合にはDAという擬似命令を使い7ビット×2とします。)
《例》 DB擬似命令の展開内容例
(LabelのアドレスはFEDC番地とします)
DB 0AAH, "ABC", '0', 0, 0F18H, Label
このアセンブル結果は
41AA 4342 0030 DC18
となり、1ワードの中に、上位、下位の順に格納されています。
これでバイトアドレス順に並んでいることになります。
さらに奇数個のデータの場合は、自動的に最後のデータの上位に
00のデータが追加されています。
また2バイトデータや、ラベルのアドレスをデータとして確保しようと
すると、下位バイトのみが確保され上位バイトは無視されます。
(3) ワードデータとして確保する方法
バイト毎ではなく、1ワードに1バイトずつのデータを確保するときには、「DW」
という擬似命令を使います。ただし、文字列の場合には、DBと同じようにパック
されて確保され、文字列データが奇数個のときには自動的に00が追加されます。
《例》 DW擬似命令の展開内容例
DW 0AAH, "ABC", '0', 0, 0F18H, Label
このアセンブル結果は
00AA 4241 0043 0030 0000 0F18 FEDC
となり、文字列はパックされていますが、1文字やその他のデータは
1ワード毎に、1個のデータが確保されていることが判ります。
そしてこの場合には2バイトデータやアドレスも確保されています。
(4) ワードデータとして確保する方法 その2
DWと同じように、数値データとASCII文字データは1ワードで1要素を格納し
文字列の場合には、1ワードに2文字分を確保する方法がもう一つあります。
「DATA」という擬似命令を使います。
《例》 DATA擬似命令の展開内容例
DATA 0AAH, "ABC", '0', 0, 0F18H, Label
これのアセンブル結果は、
00AA 4241 0043 0030 0000 0F18 FEDC
となり、DWと全く同じになっています。
【アクセス方法】
次は用意された定数テーブルデータを順に取り出すプログラムです。
こちらには大別して2種類の方法があります。
(1) RETLW命令の場合
これまでのPIC16シリーズと同じ方法で取り出す仕方です。ADD PCL命令を
使います。
この実際の例は下記のようになります。
この例は、数値からセグメントデータに変換するサブルーチンになっています。
この方法での注意は、PIC18Fシリーズではプログラムカウンタがバイト単位の
アドレスカウンタになったことで、ADD PCLの場合に加える数は2倍する必要
があることです。つまり「RETLW k」命令は1ワード命令なので、プログラムカウンタ
が+2づつ進むため、加えるWレジスタの値も2倍する必要があるということです。
さらに、2倍することで、演算結果でオーバーフローが起きないようにするためには
最大サイズが128個になってしまいます。
128個を超えると2倍したとき、ADD PCL,F命令でオーバーフローがおき、正しい
位置にはジャンプせず、128ワードだけ小さいアドレスにジャンプしてしまいます。
↓
またもう一つ注意が必要です。PCLレジスタに書き込むと、プログラムカウンタの
上位バイトも同時にPCLATH、PCLATUからコピーされて変更されます。
しかし、PCLATH、PCLATUレジスタはPCLの読み込み動作をしないと、現在値を
得ることはできず、00のままとなっています。そこで、現在のPCの値をPCLATH、
PCLATUにコピーするためPCLの空読みが必要になります。これでこのサブルーチン
がどこにあってもアドレスxx00さえ跨がなければ正常に動作します。
(2) テーブルアクセス命令の場合
新たに追加されたテーブルアクセス関数を使う方法です。
下記がその実際の例で、上記と同じ、数値からセグメントデータに変換する
サブルーチンとなっています。
この例ではDB擬似命令ですべて1バイトのデータをパックして1ワードに格納して
います。
そして、テーブルアクセスのポインタである、TBLPTRU、TBLPTRH、TBLPTRL
にテーブルの先頭アドレスを代入するのですが、そのときには、
UPEER、HIGH、LOW という擬似命令が便利に使えます。使い方は下記の
ようにします。
そしてこの3バイトのポインターに変数のWレジスタの内容を加算しますが、
この場合にはバイト単位で扱いますから2倍する必要はありません。
その代わり、TBLPTRの上位への桁上げもきちんと計算する必要があります。
このテーブルアクセスを使えば、プログラムメモリ全部をテーブルにすることが
可能になります。