GR-CITRUSでCS+のRXシリアルデバッガを使えるようにしてみた(実装編)

[CC-RX&CS+編の追加により更新しました。2017/01/27]
GR-CITRUSでCS+のRXシリアルデバッガが使えたら便利そうな気がしましたので、以下のことをしてみました。
(IDE for GR編CC-RX&CS+編、実装編、の3本立てブログの1つです。)

予め必要な情報

RXシリアルデバッガ
製品情報

統合開発環境CS+ (旧CubeSuite+)
製品情報
オンラインヘルプ

RX63N,RX631
製品情報
オンラインドキュメント
RXv1命令セットアーキテクチャ

やったこと

RXシリアルデバッグモニタ

・リセットボタンでUSBMSCファームウェア(改)へ遷移する処理を追加
・ROMコードを調べて通常スケッチならMSBUSBファーム(改)へ遷移する処理を追加
・ただし上記のどちらもMSBUSBファーム(改)が消去されていたら遷移しないようにする
・可変ベクタが0xFFE00000にあるプログラムの実行やデバッグが出来るようにする仕組みを追加(V2.0)
・GR-CITRUSのSerial1(5Vトレラント)でTX/RXをオープンドレイン出力/CMOS入力に設定する

USBMSCファームウェア

・RXシリアルデバッグ出来るようにセクション配置を変更
・RXシリアルデバッグ出来るように可変ベクタのコピーをRAM上に持たせる(デバッグビルドのみ)
・RXシリアルデバッグ出来るようにフラッシュ書き換えのサスペンド/レジュームに対応(デバッグビルドのみ)
・RXシリアルデバッグ出来るようにPLL クロック発振安定待機時間を変更(デバッグビルドのみ)
・ファームウェアの出口にx86のDebugBreak()風なデバッグ例外強制発生関数を配置(デバッグビルドのみ)
・528Kバイトまでしかフラッシュ書き換え出来ない不具合の修正(V2.0)
・外部バスを有効にしてしまっている不具合(GR-CITRUSでは表面化せず)の修正(V2.0)
・ファームウェアとモニタのバージョン(まとめて1つ)とタイプを表す文字列を0xFFFF0500から埋め込む(V2.0)

USBMSCファームウェアアップデートプログラム

・USBMSCファームウェアソースコードから不要なコードを大幅に削って作成
・プログラムの出口にx86のDebugBreak()風なデバッグ例外強制発生関数を配置(デバッグビルドのみ)
・CC-RXのリンカ機能を活用してUSBMSCファームウェア(改)とRXシリアルデバッグモニタのバイナリを一体化

ソースコード一式(ただしRX_Serial_Debugger_V30000.zipから解凍したファイルは除外しています)

GR-CITRUS-RXSDBG-SRC-20161129.zip
GR-CITRUS-RXSDBG-SRC-20161217.zip

(1) プロジェクトファイル

プロジェクトファイルには以下のものがあります。(e2 studioのプロジェクトからCS+のプロジェクトへ変更しています。
USBMSCファームウェアやUSBMSCファームウェアアップデートプログラムをRXシリアルデバッグしたかったからです。
現状、e2 studioはRXシリアルデバッグをサポートしていません。)

ビルド環境検証用(e2 studio⇔CS+間で同一初期ファームウェアバイナリが生成出来ることをチェックする為)

・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_20160714.mtpj

ビルド用(別途RX_Serial_Debugger_V30000.zipを解凍して該当フォルダに上書きして下さい)
(リンク順のエクスポート/インポートに使用した.mtlsファイルも念の為に同梱しておきました。)

・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\citrus_usbfw_updater_build_all.mtpj
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\citrus_usbfw_updater.mtsp
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\citrus_usbfw_updater.mtls
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw.mtsp
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw.mtls
・Bootloaders_cspproj\RX_Serial_Debugger_V30000\Serial_Debugger\RX63N\monitor_citrus_serial1_OpenDrain.mtsp

デバッグ用(ただしモニタのデバッグは出来ません) 兼 ブックマーク箇所確認用
(ブックマークは.mtudファイルに保存されていますので、mtudファイルの'UserName'の部分をWindowsの自分の
ユーザ名に変更してから、CS+でmtpjファイルを読み込んで下さい。)

・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\citrus_usbfw_updater.mtpj
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\citrus_usbfw_updater.UserName.mtud
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw.mtpj
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw.UserName.mtud
・Bootloaders_cspproj\RX_Serial_Debugger_V30000\Serial_Debugger\RX63N\monitor_citrus_serial1_OpenDrain.mtpj
・Bootloaders_cspproj\RX_Serial_Debugger_V30000\Serial_Debugger\RX63N\monitor_citrus_serial1_OpenDrain.UserName.mpud

RXシリアルデバッガ動作確認用

・Bootloaders_cspproj\RX_Serial_Debugger_V30000\Sample_Project\RX63N\sample_citrus_rxsdbg.mtpj
・Bootloaders_cspproj\RX_Serial_Debugger_V30000\Sample_Project\RX63N\sample_citrus_rxsdbg.UserName.mtud

(2) ビルド方法

以下のmtpjファイルをCS+ for CCで開いてビルドして下さい。(CS+ V4.01.00とCC-RX V2.03.00を使用しました。)

・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\citrus_usbfw_updater_build_all.mtpj

ビルド終了後、生成された以下のbinファイルをcitrus_rxsdbg_Serial1_OpenDrain.binにリネームして下さい。

・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\DefaultBuild\citrus_usbfw_updater.bin



(3) デバッグ方法

以下のmtpjファイルをCS+ for CCで開いてRXシリアルデバッガでデバッグすることが出来ます。

・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\citrus_usbfw_updater.mtpj
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw.mtpj




(4) ソースコードの確認方法

以下のmtpjファイルをCS+ for CCで開いてブックマークを順次追うことで確認することが出来ます。
(ただし変数宣言をしているだけのような箇所はブックマークに登録しませんでした。)

・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\citrus_usbfw_updater.mtpj
・Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw.mtpj
・Bootloaders_cspproj\RX_Serial_Debugger_V30000\Serial_Debugger\RX63N\monitor_citrus_serial1_OpenDrain.mtpj





(5) ソースコードについて補足

殆どの箇所はソースコードを見れば意図が分かると思いますが、以下の7箇所については分かり難いと思いますので
補足しておきます。

(5-1) r_flash_api_rx600.cの全般 (citrus_usbfwとcitrus_usbfw_updaterに同じものが2つあります)

もともとは、フラッシュROMの消去処理実行中と書き込み処理実行中は全面的に割り込み禁止にする処理になって
いましたが、それだと割り込み禁止時間が長くなり過ぎてしまい、RXシリアルデバッガが通信が切れたと判断して
デバッグを中断してしまうことが頻発しました。

そこで、RX63N,RX631のハードウェアマニュアルを参照して、処理実行中に割り込み要求フラグが立ったことを検出
した時にサスペンド/レジュームを行うようにしてみたところ、そのようなことは起きなくなりました。(もっとも、
充分な数の試行回数(例えば100回)を決めた上で修正前後の発生頻度を計数して比較した訳ではありませんので、
厳密ではありませんが。)

ただし、ハードウェアマニュアルによると、何度でも任意のタイミングでサスペンド/レジュームが行える訳では無く、
ある処理単位(ハードウェアマニュアルによる表現では『パルス印可中』という処理単位)において素早くサスペンド
出来るのは、消去処理(多分そこそこ長時間)では1回のみ(他方、書き込み処理(多分そこそこ短時間)では0回)と
なっているようでしたので、以下のような発想でやってみました。

・RXシリアルデバッガの接続確認は300msec程度の間隔で行われる(RXシリアルデバッガのマニュアルより)
・RXシリアルデバッガの接続確認は40バイト程度の通信で行われる(RXシリアルデバッガのマニュアルより)
・115Kbpsで40バイト程度の通信なら4ms程度なので、10ms程度通信が無ければ、その回の接続確認は終わった筈
⇒ 割り込み要求フラグが立ったら即サスペンド、割り込み要求フラグが10ms降りたままならレジューム、としよう

RX63N,RX631 ユーザーズマニュアル ハードウェア編 「47.5 サスペンド動作」
ルネサス→リソース→/resource/lib/jpn/online_docs/um/RX/RX63N_RX631_ja/?Flashmemory#TOC_47_5

(5-2) r_flash_api_rx600.cの209行目 (citrus_usbfwとcitrus_usbfw_updaterに同じものが2つあります)

以下のインラインアセンブラ関数では240回ループが回るのですが、普通にインラインアセンブラ関数記述すると
この関数の呼び出し側をRXシリアルデバッガでステップオーバーした時に非常に時間が掛かって(インライン展開
されているのでステップ実行が480回繰り返される?)しまい、ちょっと気が滅入ってしまったので、以下のような
小細工で関数の呼び出し側が通常のBSR命令による呼び出しになるようにしました。それだとステップオーバーが
すぐに終わります。

#pragma inline_asm _inline_rxsdbg_cpu_Delay10us
static void _inline_rxsdbg_cpu_Delay10us( void )
{
    mov.l   #0F0H, r1
?:  sub     #1, r1
    bnz     ?-
}
#pragma noinline rxsdbg_cpu_Delay10us
static void rxsdbg_cpu_Delay10us( void )
{
    _inline_rxsdbg_cpu_Delay10us();
}


CS+ユーザーズマニュアル 「4.2.3 #pragma指令 (5)アセンブラ記述関数インライン展開」
ルネサス→ツールサポート→/autoupdate/support/onlinehelp/ja-JP/csp/V4.01.00/CS+.chm/Compiler-CCRX.chm/Output/ccrx04c0204y.html#96980

CS+ユーザーズマニュアル 「4.2.3 #pragma指令 (4)関数のインライン展開記述」
ルネサス→ツールサポート→/autoupdate/support/onlinehelp/ja-JP/csp/V4.01.00/CS+.chm/Compiler-CCRX.chm/Output/ccrx04c0204y.html#19230

(5-3) 可変ベクタのRAMへのコピー

Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\src\HwResourceForUSB\resetprg.cの156行目

RXシリアルデバッガの制限事項で可変ベクタをフラッシュROMの先頭(GR-CITRUSでは0xFFE00000)に置く必要が
あるのですが、USBMSCファームウェアではユーザプログラムの書き込み時に一旦消去されてしまいます。実は、
可変ベクタには、RXシリアルデバッガが通信用SCIの割り込みベクタを埋め込んでいるのですが、これが消えてしまい
ますのでRXシリアルデバッガが通信が切れたと判断(というか実際に通信が切れてしまいます)してデバッグを中断
してしまいます。そのせいで、そこから先をデバッグすることが出来なくなってしまって、ちょっと気が滅入ってしまった
ので、以下の処理で可変ベクタのコピーをRAMに持つようにしました。

#if defined(RXSDBG) // for RX Serial Debugger
#if 0 // for experiment
    /////* Copy RX Serial Debug Monitor from ROM to RAM because this application uses CODE FLASH API */
    ////memcpy((void *)rxsdbg_monitor, (void *)RXSDBG_MONITOR_ADDR, RXSDBG_MONITOR_SIZE);
#endif

    /* Re-initialise the MCU processor word */
    memcpy((void *)interrupt_vector, __sectop("INTERRUPT_VECTOR"), sizeof(interrupt_vector));
    ivrxsdbg = (unsigned long *)__sectop("P_UserApplicationArea");
    for(ivno = VECT(SCI0, RXI0); ivno <= VECT(SCI12, RXI12); ivno += 3)
    {
        if(ivrxsdbg[ivno] != 0)
        {
            interrupt_vector[ivno] = ivrxsdbg[ivno];
            interrupt_vector[ivno + 1] = ivrxsdbg[ivno + 1];
#if 0 // for experiment
            /////* No need to redirect because interrupt handler is already in RAM */
            ////interrupt_vector[ivno] += 0;
            /////* Redirect from address of monitor code on ROM to address of copied monitor code in RAM */
            ////interrupt_vector[ivno + 1] -= (RXSDBG_MONITOR_ADDR - (unsigned long)rxsdbg_monitor);
#endif
        }
    }
    set_intb((void *)interrupt_vector);

#if 0 // for debug
    set_psw(0x00020000);
    set_psw(0x0E030000); /*  Permit only high priority interrupt */
    while(1)
    {
        ivno = (ivno >= INTERRUPT_VECTOR_NUM) ? 0 : ivno + 1;
    }
#endif
#endif

(5-4) 可変ベクタの先頭の4バイト

Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\src\HwResourceForUSB\ritable_rx63n.srcの39行目

USBMSCファームウェアアップデートプログラムをRXシリアルデバッグ出来るようにする為には可変ベクタを
フラッシュROMの先頭(GR-CITRUSでは0xFFE00000)に置く必要があります。他方、USBMSCファームウェアアップ
デートプログラムで初期ファームウェアをアップデート出来るようにする為には初期ファームウェアの仕様
によりフラッシュROMの先頭からプログラムが始まっている必要があります。この2つを妥協させる為に可変
ベクタの先頭の4バイトはベクタデータではなく分岐命令(3バイト)と00(1バイト)を埋め込むようにしました。

__RI_INT_VECTOR:
;       .LWORD  _usbc_cstd_DummyIntFunction     ;vector0
        .BYTE   38H ;BRA.W  _PowerON_Reset_PC   ;vector0
        .WORD   _PowerON_Reset_PC - __RI_INT_VECTOR
        .BYTE   00H ;padding (BRK)
        .LWORD  _usbc_cstd_DummyIntFunction     ;vector1
        .LWORD  _usbc_cstd_DummyIntFunction     ;vector2
        .LWORD  _usbc_cstd_DummyIntFunction     ;vector3
        .LWORD  _usbc_cstd_DummyIntFunction     ;vector4


(5-5) r_usb_PMSC_apl.cの先頭のbebugbreak()というインラインアセンブラ関数

Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\src\SmplMain\APL\r_usb_PMSC_apl.cの87行目
Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\src\SmplMain\APL\r_usb_PMSC_apl.cの71行目

RXシリアルデバッガの通信に使っているSCIレジスタやポート設定レジスタが初期化されたタイミングと接続確認の
通信のタイミングが重なったり、初期化されたままの状態で接続確認の通信が来たりすると、RXシリアルデバッガが
通信が切れたと判断してデバッグを中断してしまうのですが、正にそのようなことがUSBMSCファームウェアにおいて
書き込んだプログラムへ遷移した時に起きます。ちょっと気が滅入ってしまったので、以下のインラインアセンブラ
関数を作成して、そうなる手前の箇所に埋め込んで強制的にデバッグ例外を発生させてブロックするようにしました。

#if defined(RXSDBG) // for RX Serial Debugger
#pragma inline_asm debugbreak
static void debugbreak(void) { ?: bra.b ?- + 01h ; .byte 0x2E, 0x01 }
// 0x2E is 1st code of bra.b PC + 01h
// 0x01 is 2nd code of bra.b PC + 01h and is the debug exception code of RX such as 0xCC (int 03h) of x86
// If you want to start from PC + 02h, you need to change PC by yourself or to make a CS+'s Python script
#endif

なお、以下のワーニングが出力されますが、どの記述に起因しているかは調べていません。(理由が何であるにせよ、
目印として使えそうなので丁度いいかも知れない、と思ってしまっているからです。)

W0551001:Destination address may be changed

ちなみに、CS+のヘルプで確認しても以下の通り書かれているだけでした。

W0551001 [メッセージ] Destination address may be changed.
  [説明] 分岐先が期待するものと異なる位置になる可能性があります。
  [対処方法] アドレッシングモードが最適選択されないように分岐命令のオペランドを記述してください。

(5-6) PLLクロック発振安定待機時間

Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\src\SmplMain\RX63nSakura.cの2488行目
Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\citrus_usbfw_updater\src\SmplMain\RX63nSakura.cの725行目

RXシリアルデバッグモニタの先頭でPLLWTCRを一度0x0Eに設定しているのですが、どういう訳か異なる値を書くと、
RXシリアルデバッガが通信が切れたと判断(というか実際に通信が切れているのだと推測しています)してデバッグを
中断してしまいます。面倒なことに、PLLWTCRの設定値は、USBMSCファームウェア(0x0F)とスケッチ(0x0E)で違う値に
なっていて、RXシリアルデバッグモニタでの設定値を0x0Fにすると、USBMSCファームウェアのデバッグ時には問題が
起きなくなりますが、スケッチのデバッグ時に同じ問題が起きるようになります。USBMSCファームウェアでの設定値を
0x0Eにしてしまう手もあったのですが、他にもデバッグ時のみ細工していることもあり以下のようにしました。

        /* PLL wait control register(Default:4194304cycle)
        b4-b0   PSTS     PLL wait time set bit
        b7-b5   Reserved 0
        */
#if !defined(RXSDBG)
        SYSTEM.PLLWTCR.BYTE     = 0x0F;
#else // for RX Serial Debugger
        SYSTEM.PLLWTCR.BYTE     = 0x0E;
#endif


RX63N,RX631 ユーザーズマニュアル ハードウェア編 「11.2.10 PLLウェイトコントロールレジスタ(PLLWTCR)」
ルネサス→リソース→/resource/lib/jpn/online_docs/um/RX/RX63N_RX631_ja/?Low_Power_Consumption#TOC_11_2_10

(5-7) Nチャンネルオープンドレイン出力

Bootloaders_cspproj\RX_Serial_Debugger_V30000\Serial_Debugger\RX63N\hwsetup_citrus_serial1_OpenDrain.cの136行目

GR-CITRUSのSerial1(5Vトレラント)のTXをNチャンネルオープンドレイン出力で使用している理由ですが、以下に
書いたように、FT232RLのRXDピン(TXピンの相手側)をFT232RLのVCCIOピンからプルアップする構成にしておけば、
USBシリアル変換モジュールとGR-CITRUSの電源投入順序を気にしなくてもよくなるからです。(FT232RLの絶対
最大定格ではRXDピン(に限らず)の入力電圧範囲は -0.5V to +(VCC+0.5)V でした。他方、RX631の絶対最大定格
ではGR-CITRUSのSerial1のTXであるP21ポート(など一部のポート)の入力電圧範囲は -0.3V ~ +5.8V でした。)

GR-CITRUSでCS+のRXシリアルデバッガのモニタをビルドする時のHardwareSetup()
ルネサス→Rulz→/gr_user_forum_japanese/f/gr-citrus/3731/gr-citrus-cs-rx-hardwaresetup/18637#18637

(6) datフォルダについて

Bootloaders_cspproj\Okamy-citrus_usbfw-27afb53591b1\datフォルダにUSBMSCファームウェアとRXシリアルデバッグ
モニタを以下のようにupdate_ffff0000_ffffcfff.datとupdate_ffffd000_ffffffff.datの2つのバイナリファイルに
切り分けて置いています。(USBMSCファームウェアのFFFFD000~FFFFFFFFのアドレス範囲はRXシリアルデバッグモニタ
無しのUSBMSCファームウェアアップデートプログラムを作成出来るようにと考えて出力するようにしてみたのですが、
RXシリアルデバッグモニタの同一アドレス範囲で上書きされるようになっていますので、今のところは未使用です。)

  USBMSCファームウェア RXシリアルデバッグモニタ
update_ffff0000_ffffcfff.dat FFFF0000~FFFFCFFFのアドレス範囲 未出力(この範囲にはコードが無い)
update_ffffd000_ffffffff.dat  FFFFD000~FFFFFFFFのアドレス範囲(未使用) FFFFD000~FFFFFFFFのアドレス範囲



これらを切り出したり取り込んだりする設定は以下の通りです。

(6-1) USBMSCファームウェア(切り出し)



(6-2) RXシリアルデバッグモニタ(切り出し)



(6-3) USBMSCファームウェアアップデートプログラム(取り込み)




(7) USBMSCファームウェアとRXシリアルデバッグモニタのバージョンとタイプを表す文字列の表示プログラム

V2.0からは、USBMSCファームウェアとRXシリアルデバッグモニタのバージョン(まとめて1つ)とタイプを表す文字列を
0xFFFF0500から埋め込んでおくようにしました。文字列は単純にC言語の文字列形式になっていますので、V2.0だけを
扱うのであれば簡単なコードで済むのですが、V1.0や公式版には文字列が埋め込まれていませんので、それらにも
対処しようとすると以下のようなちょっと面倒なコードが必要になります。

    if (memcmp((void *)0xFFFF0500, (void *)"GR-", 3) == 0)
    {
        strncat((char *)g_buf, (char *)0xFFFF0500, 256);
    }
    else if (memcmp((void *)0xFFFF0500, (void *)"\xFF\xFF\xFF", 3) == 0)
    {
        strcat((char *)g_buf,
"GR-CITRUS Unofficial USB MSC Firmware (Bootloader)\r\n\
with RX Serial Debug Monitor for Serial1(5V tolerant)\r\n\
configured as OpenDrain output(TX1), CMOS input(RX1)\r\n\
Version 1.0 [29 Nov 2016]\r\n"
        );
    }
    else if (memcmp((void *)0xFFFF0500, (void *)"\x21\x15\x66", 3) == 0)
    {
        strcat((char *)g_buf,
"GR-CITRUS Official USB MSC Firmware (Bootloader)\r\n\
Version 20160714\r\n"
        );
    }
    else
    {
        strcat((char *)g_buf,
"Unknown USB MSC Firmware (Bootloader)\r\n"
        );
    }


IDE for GRやFIT USBモジュールでの具体的なコードと表示例は以下の通りです。(ちなみに、FIT USB
モジュールの場合は、そもそもV1.0や公式版では動作しません。)

(7-1) IDE for GRの場合

コード:
ShowVersion.ino


表示例:




(7-2) FIT USBモジュールの場合

コード:
r_usb_pcdc_echo_apl.cの修正その1
r_usb_pcdc_echo_apl.cの修正その2


表示例: