GR-SAKURA
GR-KURUMI
GR-COTTON
GR-CITRUS
GR-PEACH
GR-KAEDE
GR-ADZUKI
GR-LYCHEE
GR-ROSE
GR-MANGO(*)
SNShield
Web Compiler
IDE for GR
TOPPERS関連
女子美コラボ
その他
※プロデューサミーティング中
作り方使い方資料
イベント関連
作品記事
体験記事
ライブラリ
ツール
その他・過去ファイル
GR-KURUMI の EEPROM ライブラリは pfdl.a という謎のライブラリをリンクし内部で使用しています。
ライブラリ本体の pfdl.a とヘッダファイルの pfdl.h と pfdl_types.h が標準のテンプレートに含まれるため EEPROM ライブラリを使用しなくとも pfdl.a が使用できそうですが、不具合、あるいは改善すべき点がみつかったので報告いたします。
ヘッダファイルの pfdl.h と pfdl_types.h は C++ のプログラムからインクルードされることを考慮されていないため、C++ のプログラムから利用するためには
extern "C" { #include <pfdl.h> #include <pfdl_types.h> }
とする必要があります。
pfdl.a のバージョン文字列を取得(?)する PFDL_GetVersionString() という関数は
/*GR-KURUMI Sketch Template Version: V2.01*/ #include <Arduino.h> extern "C" { #include <pfdl.h> #include <pfdl_types.h> } void setup() { Serial.begin(9600); pfdl_u08* version = PFDL_GetVersionString(); Serial.println((uint16_t)version, HEX); Serial.println((const char*)version); } void loop() { }
等とすれば利用できます。
2行目が文字列で、1行目がそのアドレスということであり、ビルドの際に生成された .map ファイルを確認すると
*(PFDL_COD) PFDL_COD 0x000085a6 0x1c ./gr_common/libraries/EEPROM/utility/pfdl.a(pfdl_version.o) 0x000085a6 PFDL_GetVersionString 0x000085a6 PFDL_GetVersionString 0x000085af PFDL_VERSION_STRING
文字列と関数の両方が PFDL_COD というセクションに配置されていることがわかります。
PFDL_GetVersionString() の関数プロトタイプ宣言は pfdl.h で定義されており
extern pfdl_u08* PFDL_GetVersionString(void) __attribute__ ((section ("PFDL_COD")));
となっていますが、PFDL_GetVersionString() の機能が ROM に配置された PFDL_VERSION_STRING のアドレスを返すのであれば
extern const pfdl_u08* PFDL_GetVersionString(void) __attribute__ ((section ("PFDL_COD")));
となっているべきです。
PFDL_COD セクションは gr_common/rl78_R5F100GJAFB.ld では
.text : { PROVIDE (_start = .); *(.text P .stub .text.* .gnu.linkonce.t.*) *(PFDL_COD) ; KEEP(*reset_program.o(.text)) KEEP (*(.text.*personality*)) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) *(.interp .hash .dynsym .dynstr .gnu.version*) PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); . = ALIGN(2); KEEP (*(.init)) KEEP (*(.fini)) } > ROM
と定義されており、.text セクションの次に配置されるようなっていますが、.text セクションの次ではリンクした際に RL78/G13 の Mirror 領域に配置される保証がなく、.text セクションがある程度の大きさになった場合、PFDL_COD セクションが Mirror 領域を超えて PFDL_GetVersionString() で取得した文字列 PFDL_VERSION_STRING が参照できなくなります。
/*GR-KURUMI Sketch Template Version: V2.01*/ #include <Arduino.h> extern "C" { #include <pfdl.h> #include <pfdl_types.h> } void setup() { Serial.begin(9600); pfdl_u08* version = PFDL_GetVersionString(); Serial.println((uint16_t)version, HEX); Serial.println((const char*)version); } void loop() { __asm __volatile( " .rept 0x3000\n" " nop\n" " .endr\n" ); }
PFDL_VERSION_STRING は Mirror 領域に配置される標準の .rodata セクションか、あるいは別名の Mirror 領域に配置されるセクションに配置するべきでしょう。
pfdl.a に含まれる関数のコードは PFDL_COD セクションに配置されていますが、これも同様に .text セクションか、別名のセクションに配置するべきでしょう。現状の pfdl.a のまゝ PFDL_COD セクション全体を Mirror 領域に配置する方法も考えられますが、Mirror 領域で参照できる ROM の領域は容量全体の一部でしかなく、そこにコードを配置するのは勿体ないことです。文字列とコードはセクションを別にするべきです。
まとめると
以上です。
0x1000~ に配置されると RL78/G13 ではミラー領域を通して PFDL_VERSION_STRING にアクセスすることはできないので、ひょっとすると関数のプロトタイプ宣言は __far を加えた
extern __far const pfdl_u08* PFDL_GetVersionString(void) __attribute__ ((section ("PFDL_COD")));
が正しいのかもしれません。pfdl.a と仕様が同一かは不明ですが、『データ・フラッシュ・ライブラリ Type04 日本リリース版』として公開されている CC-RL 版と CA78K0R 版は関数プロトタイプ宣言が
extern __far pfdl_u08* __far PFDL_GetVersionString(void);
となっており、__far 領域に配置された文字列を返すようなっています。
尤も、現在の GNURL78 ツールチェーンでは C++ は __far ポインタのサポートがなく __far ポインタを返す関数は C++ からは使いづらいため、PFDL_GetVersionString() の仕様としては __far ポインタでない方が望ましいと思います。
pfdl_version.o で PFDL_GetVersionString() と PFDL_VERSION_STRING[] が同一のセクション PFDL_COD に配置されるコードは、例えば
#include "pfdl_types.h" extern pfdl_u08 __far* PFDL_GetVersionString(void) __attribute__ ((section ("PFDL_COD"))); __attribute__ ((section ("PFDL_COD"))) pfdl_u08 __far PFDL_VERSION_STRING[] = "DRL78T04U1301GV104"; pfdl_u08 __far* PFDL_GetVersionString(void) { return PFDL_VERSION_STRING; }
C では以上のような書き方になると思いますが、これをコンパイルすると
$ rl78-elf-gcc -Wall -Wextra -Os -S pfdl_version.c pfdl_version.c:6:55: error: PFDL_VERSION_STRING causes a section type conflict with PFDL_GetVersionString __attribute__ ((section ("PFDL_COD"))) pfdl_u08 __far PFDL_VERSION_STRING[] = "DRL78T04U1301GV104"; ^ pfdl_version.c:8:17: note: 'PFDL_GetVersionString' was declared here pfdl_u08 __far* PFDL_GetVersionString(void) ^ $
セクションが矛盾しているというエラーとなってしまうので、オリジナルのソースはアセンブラで書いている気がします。
セクション名を下記のように変更すれば
#include "pfdl_types.h" extern pfdl_u08 __far* PFDL_GetVersionString(void) __attribute__ ((section (".text.pfdl_getversionstring"))); __attribute__ ((section (".frodata.pfdl_version_string"))) pfdl_u08 __far PFDL_VERSION_STRING[] = "DRL78T04U1301GV104"; pfdl_u08 __far* PFDL_GetVersionString(void) { return PFDL_VERSION_STRING; }
セクションの矛盾が解消するためコンパイルは通る様になります。
$ rl78-elf-gcc -Wall -Wextra -Os -S pfdl_version.c $
また、セクション名が .text.~ や .rodata.~ となっていると、リンカスクリプトに特別なセクションを用意する必要がなくなる点でもメリットがあります。
という点に対応するとすると pfdl_version.c の内容は以下が適当ではないかと思います。
extern const char* PFDL_GetVersionString(void) __attribute__ ((section (".text.pfdl_getversionstring"))); __attribute__ ((section (".rodata.pfdl_version_string"))) const char PFDL_VERSION_STRING[] = "DRL78T04U1301GV104"; const char * PFDL_GetVersionString(void) { return PFDL_VERSION_STRING; }