最適化をしないコンパイル
現在(少し前)のフレームワークでは、最適化をしない「-O0」場合、大量にリンクで失敗する。
これは、「static」なオブジェクトの実態が無い為で、以前は最適化が標準となっているので、あまり問題にならなかった。
※static なオブジェクトと言っても、リソースを必要とするような実装は無く、最適化すると、実態を持たないものだった。
それでも、最適化しない場合、実態は必ず必要なので、リンクできずに実行バイナリーを作れず停止する。
たとえば、このような感じ・・・
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief CMT 定義基底クラス
@param[in] base ベース・アドレス
@param[in] per ペリフェラル
@param[in] VEC ベクター型
@param[in] ivec 割り込みベクター
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <uint32_t base, peripheral per, typename VEC, VEC ivec>
struct cmt_t {
...
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief CMCR レジスタ
@param[in] ofs レジスタ・オフセット
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <uint32_t ofs>
struct cmcr_t : public rw16_t<ofs> {
typedef rw16_t<ofs> io_;
using io_::operator =;
using io_::operator ();
using io_::operator |=;
using io_::operator &=;
bits_rw_t<io_, bitpos::B0, 2> CKS;
bit_rw_t <io_, bitpos::B6> CMIE;
};
static cmcr_t<base + 0x00> CMCR;
...
};
typedef cmt_t<0x00088002, peripheral::CMT0, ICU::VECTOR, ICU::VECTOR::CMI0> CMT0;
「CMCR」は、「cmcr_t」テンプレートクラスの「static」オブジェクトとなっている。
このオブジェクトは、「cmt_t」テンプレートクラスのメンバーで、実際には、「実態」となる物を定義する必要がある。
これが、テンプレートクラスでは無い場合、別にソースコードを作成して、その中で、staticなオブジェクトとして宣言しておく。
テンプレートクラスの場合、それはできないので、ヘッダーに特殊な書き方で定義する。
typedef cmcr_t<base + 0x00> CMCR_;
static CMCR_ CMCR;
};
template <uint32_t base, peripheral per, typename VEC, VEC ivec>
typename cmt_t<base, per, VEC, ivec>::CMCR_ cmt_t<base, per, VEC, ivec>::CMCR;
上記のように、定義には、「CMCR」オブジェクトの型「cmtt<base, per, VEC, ivec>::CMCR」が必要なので、ペリフェラルの定義全部を大幅に書き換える必要がある。
何度か、修正しようと思った事もあったが、修正範囲が広く、自分には、それほど必要な機能でも無かったので、割愛してきた。
しかし、「-O0」にしないと、デバッガーで止めたりできないとの事で、この莫大な修正を行い、プルリクを送ってくれた方がいたので、このリクエストを受けて、マージする事にした。
※非常にありがたい修正で、修正したソースの分量もすさまじく、この修正を入れる事で、より良い物になるのは明白だ。
ただ、最近、RX72Nの為に色々と、改変している最中で、そのままマージしても、コンフリクトする事は明白なので、内容を精査しながら少しづつマージする事にした。
このプルリクを送ってくれた「Sinsjr2」さんには大変感謝しており、この場を借りて御礼申し上げます。
※自分以外でこのフレームワークを使っている人は、何人くらいいるのだろうか?
少なくとも一人はいる事が判ったw
普通のクラスをテンプレートクラスにするメリット
先ほどの説明で、static なオブジェクトの実態について、通常のクラスの場合は、別にソースを作成して記述する事を説明した。
しかしながら、そうすると、ヘッダーの他にソースコードが増えて、Makefile でソースを列挙する必要が出てくる。
これを回避する方法がある。
普通のクラスを無理やりテンプレートにする方法で、boost などでも使われている。
たとえば、以下のクラスをテンプレート化すると・・・
class flash_io
{
flash_io() { }
};
template <class _> class flash_io_
{
flash_io_() { }
};
typedef flash_io_<void> flash_io;
知ってはいたが、以前に実験した時、サイズが少しだけ大きくなるので、敬遠していた。
しかし、最近の RX マイコンは、サイズをあまり気にする程、ROM が小さくないので、存分に使うべきかもしれない・・
Makefile の機能追加
「make」は、「-e」オプションを使うと、外部から、内部で使っている環境変数をオーバーライド出来る。
-e, --environment-overrides
環境変数が makefile 中の記述に優先する
たとえば、最適化は、
OPTIMIZE = -O3
となっており、
W10./d/Git/RX/FIRST_sample/RX72N % make clean
W10./d/Git/RX/FIRST_sample/RX72N % export OPTIMIZE=-O0
W10./d/Git/RX/FIRST_sample/RX72N % make -e
とすれば、最適化無しで、コンパイルする事が出来る。
しかし、少し工夫して、「debug」と「release」と二つの状態を設ける事にした。
※「release」は元々固定となっている。
BUILD = release
#BUILD = debug
どちらかを有効にする事で、release(リリース版)と、debug(デバッグ版)を作成可能とした。
※事前に「clean」を行ってオブジェクトを全部廃棄する必要がある。
また、これは、変数をオーバーライド出来るので、「通常」を「release」としておく。
さらに、
ifeq ($(BUILD),debug)
CC_OPT += -g -DDEBUG
CP_OPT += -g -DDEBUG
OPTIMIZE = -O0
endif
ifeq ($(BUILD),release)
CC_OPT += -DNDEBUG
CP_OPT += -DNDEBUG
OPTIMIZE = -O3
endif
BUILD 変数により、オプションをいくつか追加している。
これで、かなり自由にオブジェクトの生成を制御できるようになった。
全体ビルドシェルコマンドの強化
プロジェクトは、最近はかなり大きくなっており、サンプルの数も増えて、メンテナンスに苦労が多い。
そこで、ディレクトリーを巡回して、「Makefile」を見つけたら、「make」を起動するスクリプトを shell で作成してある。
W10./d/Git/RX % sh all_project_build.sh help
Usage: all_project_build.sh options [clean]
-debug debug build, 'OPTIMIZE=-O0'
このスクリプトに「-debug」オプションを追加してある。
RX600 ディレクトリの「最適化無し」対応状況
2020-04-24 07:14:47 Friday
ファイル | 対応 | ファイル | 対応 | ファイル | 対応 | ファイル | 対応 | ||||
---|---|---|---|---|---|---|---|---|---|---|---|
bus.hpp | O | cmt.hpp | O | dmac.hpp | O | icu.hpp | O | ||||
cac.hpp | O | can.hpp | O | cmpc.hpp | O | cmtw.hpp | O | ||||
crc.hpp | O | crca.hpp | O | doc.hpp | O | drw2d.hpp | O | ||||
dsmif.hpp | O | dtc.hpp | O | edmac.hpp | O | elc.hpp | O | ||||
eptpc.hpp | O | etherc.hpp | O | exdmac.hpp | O | flash.hpp | O | ||||
glcdc.hpp | O | gpt.hpp | O | iwdt.hpp | O | lvda.hpp | O | ||||
mmcif.hpp | O | mpc.hpp | O | mpu.hpp | O | mtu3.hpp | O | ||||
pdc.hpp | O | pmgi.hpp | O | poe3.hpp | O | port.hpp | O | ||||
ppg.hpp | O | qspi.hpp | O | r12da.hpp | O | riic.hpp | O | ||||
rspi.hpp | O | rtc.hpp | O | s12adc.hpp | O | sci.hpp | O | ||||
scif.hpp | O | sdhi.hpp | O | sdram.hpp | - | sdsi.hpp | # | ||||
src.hpp | O | ssi.hpp | O | ssie.hpp | O | system.hpp | O | ||||
tmr.hpp | O | tpu.hpp | O | usb.hpp | O | usba.hpp | O | ||||
wdta.hpp | O |
※ Ox:中途(現状、必要な部分だけ)
※ X 今後アップデート予定
※ # 実装中
最適化無しでコンパイル、リンク出来るプロジェクト
FIRST_sample
SCI_sample
SDCARD_sample
AUDIO_sample
FLASH_sample
RAYTRACER_sample
SIDE_sample
NESEMU_sample
FreeRTOS
主要なプロジェクトは大体大丈夫と思う。
自動変換スクリプト
複雑な構造の場合は、一筋ではいかないものの、簡単なスクリプトで変換は「できる」・・
s/static \(.*\) \([0-9A-Z]*\);/typedef \1 \2_;static \2_ \2;/
s/;static/;\
static /
これは、sed による変換スクリプトで、static 宣言された行で、オブジェクト名を分けて、typedef、static を部分コピーする。
次に、行を分けて、二行にする。
※ただ、全てに対して上手くいく訳ではないのだが・・・
次にテンプレートクラスの実態を生成する。
/static.*;/!d
s/static/template <uint32_t base, peripheral per> typename glcdc_t<base, per>::/
s/_ /_ glcdc_t<base, per>::/
※これは、glcdc.hpp クラス用だ、テンプレートの型が違う場合に、微妙に作り替えないとならない・・・
それにしても sed は便利で強力なツールだ・・