データ・コンテキスト内の実行シンボル(その2)

昨日の続き


「MPLAB ASM30/LINK30 and Utilities User’s Guide」の「5.8 USING EXECUTABLE SYMBOLS IN A DATA CONTEXT」に該当する話が書いてある。一度目を通したはずだが、理解せずに忘れてしまったようだ。


要は、プログラム・アドレスは24bitで、データ・アドレスは16bitと異なり、しかもテーブル命令とPSV参照でアクセスの仕方も異なるから、きちんと手順を踏んでアクセスする必要があるということ。手順には以下の特殊演算子を利用する。


関連する特殊演算子(Special Operators)
特殊演算子概要処理
tblpage(name)シンボルnameに対するテーブル命令アクセスのページを取得(24bitアドレス>>16)を8bit化
tbloffset(name)シンボルnameに対するテーブル命令アクセスのポインタを取得(24bitアドレス&0x00FFFF)を16bit化
psvpage(name)シンボルnameに対するPSVデータ・ウィンドウのページを取得(24bitアドレス>>15)を8bit化
psvoffset(name)シンボルnameに対するPSVデータ・ウィンドウのポインタを取得((24bitアドレス&0x00FFFF)|0x008000)を16bit化


すべてシンボル名やセクション名を元に定数で置換されるので、アセンブル時に展開される。


テーブル命令におけるアクセス例(tblrdl.b)。

.text
TEXT1: .string "Hello world!\n"
mov #tblpage(TEXT1), w0
mov w0, TBLPAG
mov #tbloffset(TEXT1), w0
tblrdl.b [w0], w1


PSVにおけるアクセス例(read,byte)。

.text
TEXT1: .string "Hello world!\n"
mov #psvpage(TEXT1), w0
mov w0, PSVPAG
mov #psvoffset(TEXT1), w0
mov.b [w0], w1


.textセクションには暗黙のcode属性が付く。.string(.asciiや.ascizも)directiveは、属性がcodeのセクションのとき、bit23-16を.fillupperで指定されたフィル値で埋め、bit15-0にのみデータを割り付ける。このため、PSVでも文字列に正しくアクセス可能である。
複数シンボルをアクセスするとき、毎度TBLPAGEやPSVPAGEを切り替えなければならず面倒だ。そのような場合、1つのセクションにまとめ、このセクションの先頭をページにするとよい。ただし、セクションが中途半端なところにあるとアクセス範囲が減ってしまう。データが少なければ気にせずともよいが、基本的にセクションは16bit境界(0x??0000)に配置した方がよい。
そのように固定データをセクションにまとめたテーブル命令のコード例は以下の通り。セクションconst_dataにまとめたが、同一ページ内にデータが含まれれば良く、それさえ保証されていればコードと混在しても良いし、tblpageの指定がシンボルでもセクション名でも良いし、tblpageの値が16bit境界でなくても良い。

.section const_data, code, address(0x10000)
TEXT1: .string "Hello world!\n"
TEXT2: .string "Good mooning!\n"
.text
mov #tblpage(const_data), w0
mov w0, TBLPAG
mov #tbloffset(TEXT1), w0
tblrdl.b [w0], w1
mov #tbloffset(TEXT2), w0
tblrdl.b [w0], w1
ROMが小さく先頭に配置されている製品なら、TBLPAGE=PSVPAGE=0とした方が簡単でデバッグもしやすい(移植時に注意)。この辺はページ境界とROMの割付位置に依存するので、各製品のメモリ・マップをよく見て検討すること。
また通常リンカ・スクリプトでセクション配置を決めるため、ソース側でのアドレス指定は避けるべきだが、カスタム・リンカ・スクリプトを書くのも面倒なのでこのようにした。


PSVアクセスのときは次のようになる。この例では意図的に0x600から割り付けている(16bit境界ではない)が、データが0x600〜0xFFFFの範囲であれば問題は無い。

.section const_data, code, address(0x600)
TEXT1: .string "Hello world!\n"
TEXT2: .string "Good mooning!\n"
.text
mov #psvpage(const_data), w0
mov w0, PSVPAG
mov #psvoffset(TEXT1), w0
mov.b [w0], w1
mov #psvoffset(TEXT2), w0
mov.b [w0], w1