RX用FITのUSBドライバをCS+6環境でコンパイル最適化レベル2以上にしたときの不具合

■経緯について
 CS+4環境で開発済みであり安定動作できているRX71M用FWプログラムがあります。
 このFWを最新のCS+6環境に置き換えるための作業過程で、USBホストドライバで
 不具合事象が発生しました。

■不具合事象
 CS+6(V6.01.00)/ビルドツールCC-RX V2.08.00環境でビルドしたFWでは、
 USBメモリの認識ができなくなってしまったことが判明。再現率100%

■調査状況について
 ・再現率100%のため、切り分け調査を開始
 ・切り分け調査した結果、USBホストドライバの一部ソースコードの最適化
  コンパイルが影響していることが判明。

■確認済み環境
 CS+4(V4.00.00)/ビルドツールCC-RX V2.05.00:問題なし
 CS+6(V6.00.00)/ビルドツールCC-RX V2.07.00:不具合事象あり
 CS+6(V6.01.00)/ビルドツールCC-RX V2.08.00:不具合事象あり

■USBHドライバの対象ソースコード
 \rx_fit\FITModules\r_usb_basic\src\hw
  - r_usb_creg_access.c
  - r_usb_hreg_access.c

■最適化レベル毎の再現性
 最適化レベル2(-optimize=2) コード・サイズ重視の最適化(-size) : NG(不具合再現)
 最適化レベル2(-optimize=2) 実行性能重視の最適化(-speed)   : NG(不具合再現)
 最適化レベル1(-optimize=1) コード・サイズ重視の最適化(-size) : OK
 最適化レベル1(-optimize=1) 実行性能重視の最適化(-speed)   : OK
 最適化レベル1(-optimize=1) コード・サイズ重視の最適化(-size) : OK
 最適化レベル0(-optimize=0)                                             : OK

■不具合の出るコードの例と暫定対策の例
 \rx_fit\FITModules\r_usb_basic\src\hw
  - r_usb_hreg_access.c
  void hw_usb_hset_rwupe (usb_utr_t *ptr, uint16_t port)
  {
      if (USB_PORT0 == port)
      {
      #if 0 // ★NG 元のコード
          ptr->ipp->DVSTCTR0.WORD |= USB_RWUPE;
          #else // ★OK こちらの書き方なら問題なし
          ptr->ipp->DVSTCTR0.WORD = ptr->ipp->DVSTCTR0.WORD | USB_RWUPE;
          #enfif
      }
  }

■今後の調査について
 引き続き、根本原因を究明し、対策の検討を進めたいと考えています。
 ・コンパイラのエラッタ確認(既知なのかどうか)
 ・ルネサスが公開している最新ドライバ(FITモジュール)の確認
 ・最適化によるアセンブラコードの違いを確認
 ・場合によってはソースコードを修正して対応する
 ・その他全てのドライバの確認(共通問題の可能性が高い)

何か情報お持ちの方がいましたら教えていただきたく、よろしくお願いいたします。

以上

  • ふじさん

    こんにちは、シェルティです。ルネサス社員です。

    本件ご不便をおかけしております。
    コンパイラチーム、USBチームに報告しました。
    じまさんも仰っている通りなのですが、特に量産製品の開発をされている場合は、
    弊社営業や特約店にご連絡いただくか、問い合わせ窓口に連絡するのが良いです。
    本サイトにおいてはRXマイコンに関しては私が可能な限り拾い上げて関係者に連絡しておりますが
    本来業務の外側での対応となりますので、限界があります。

    私見ですが、ご教示いただいた条件以外に何かが潜んでいると思われます。
    私の環境(CC-RX V207、最適化2)では不再現でした。
    特定コンパイルオプションの条件下において不正なコードが出力されるといったところで、
    USBドライバ自体には問題がないように感じました。
    各リストファイル(*.lst)の先頭の方にCOMMAND PARAMETERというのが出力されていて、
    -isa=rxv2 のようにコンパイルオプションが列挙されていると思います。
    書き出していただけますか?

    以上です
  • シェルティさん、こんにちは。NoMaYです。(私のPCのCPUが古過ぎてCC-RX V2.04以降が使えず回りくどいレスですが)

    >私の環境(CC-RX V207、最適化2)では不再現でした。
    >特定コンパイルオプションの条件下において不正なコードが出力されるといったところで、
    >USBドライバ自体には問題がないように感じました。
    この部分は、私だけでなくて、ふじさんも気になる文面かと思いますが、
    生成されたコードは、ふじさんのNGコードの方では無くてOKコードの方だった、
    ということでしょうか?

    ふじさんのNGコード ≠ シェルティさんがCC-RX V2.07 最適化2で試された結果

    ■CS+6(V6.01.00)/ビルドツールCC-RX V2.08.00】
     最適化レベル2:
    省略(by NoMaY))
    MOV.L #00000080H, R2
    OR 08H[R1].UB, R2 ← 皆さんが仰る通り unsigned short かつ __evenaccess のI/Oレジスタ対するコードとしては変ですね
    MOV.B R2, 08H[R1] ← 皆さんが仰る通り unsigned short かつ __evenaccess のI/Oレジスタ対するコードとしては変ですね

    (参) 4.2.5 キーワードの使用方法 - CS+ V6.01.00 > コンパイラ編 > コンパイラ言語仕様 > 拡張言語仕様 > キーワードの使用方法
    (1)指定サイズのアクセス記述
    tool-support.renesas.com/autoupdate/support/onlinehelp/ja-JP/csp/V6.01.00/CS+.chm/Compiler-CCRX.chm/Output/ccrx04c0205y.html

    __evenaccess <型指定子> <変数名>
    <型指定子> __evenaccess <変数名>

    宣言または定義したサイズで変数をアクセスします。
    変数の型のサイズでアクセスすることを保証します。


    ふじさんのOKコード(以下の3つは同じ) = シェルティさんがCC-RX V2.07 最適化2で試された結果

    ■CS+6(V6.01.00)/ビルドツールCC-RX V2.08.00】

     最適化なし:
    省略(by NoMaY))
    MOV.W 08H[R1], R2
    BSET #07H, R2
    MOV.W R2, 08H[R1]

     最適化レベル1:
    省略(by NoMaY))
    MOV.W 08H[R1], R2
    BSET #07H, R2
    MOV.W R2, 08H[R1]

    もしくは

    ■CS+4(V4.00.00)/ビルドツールCC-RX V2.05.00】

     最適化レベル2:
    省略(by NoMaY))
    MOV.W 08H[R1], R2
    BSET #07H, R2
    MOV.W R2, 08H[R1]

    あと、細かいところですが、ふじさんとじまさんの以下の文面はアセンブラに不慣れゆえの書き間違いかな、と思われます。以下の(a)と(b)に合致していませんので。

    11.5.4 V2.06以降【V2.05以前からの変更点】 - CS+ V6.01.00 > コンパイラ編 > 注意事項 > 旧バージョン・旧リビジョンとの互換性
    (1)ビット操作命令の出力を制御する方法の導入
    tool-support.renesas.com/autoupdate/support/onlinehelp/ja-JP/csp/V6.01.00/CS+.chm/Compiler-CCRX.chm/Output/ccrx11c0504y.html

    組み込み関数を使用せずに、コンパイラにビット操作命令を必ず出力させる場合は、
    次の条件をすべて満たすソース・プログラムを記述してください。
    (a) 定数値を代入する
    (b) 代入先を1バイト型で1ビット幅のビットフィールドにする
    (c) 代入先をvolatile 修飾する


    ふじさん

    >ビット操作命令出力の条件に合致しており、最適化しているためコンパイラ判断によるものとなっていました。
    ↓(むしろ以下の文面かと思われます)
    ビット操作命令出力の条件に合致しておりおらず、最適化しているためコンパイラ判断によるものとなっていました。

    じまさん

    >もしかしてマニュアルのビット操作命令出力の条件に合致したりしてないでしょうか。
    ↓(むしろ以下の文面かと思われます)
    もしかしてマニュアルのビット操作命令出力の条件に合致したり合致していなかったりしてないでしょうか。

  • こんにちは。NoMaYです。

    >OR 08H[R1].UB, R2 ← 皆さんが仰る通り unsigned short かつ __evenaccess のI/Oレジスタ対するコードとしては変ですね
    >MOV.B R2, 08H[R1] ← 皆さんが仰る通り unsigned short かつ __evenaccess のI/Oレジスタ対するコードとしては変ですね

    ちょっと待った! >> 自分
    変なのかな?

    r_ usb_basic_if.h

    typedef volatile struct st_usb0 * usb_regadr_t; ← ここに _evenaccess が無いですよね?

    typedef struct usb_utr      usb_utr_t;
    typedef void (*usb_cb_t)(struct usb_utr *, uint16_t, uint16_t);

    typedef struct usb_utr
    {
        usb_mh_t    msghead;        /* Message header (for SH-solution) */
        uint16_t    msginfo;        /* Message Info for F/W */
        uint16_t    keyword;        /* Rootport / Device address / Pipe number */
        union
        {
            usb_regadr_t    ipp;    /* USB module startAddress(USB0/USB1)*/
        #if USB_NUM_USBIP == 2
            usb_regadr1_t   ipp1;   /* USB module start address(USBA) */
        #endif /* USB_NUM_USBIP == 2 */
        };
        uint16_t    ip;             /* USB module number(0 or 1) */
        uint16_t    result;         /* Result */
        usb_cb_t    complete;       /* Call Back Function Info */
        void        *p_tranadr;     /* Transfer data Start address */
        uint32_t    tranlen;        /* Transfer data length */
        uint16_t    *p_setup;       /* Setup packet(for control only) */
        uint16_t    status;         /* Status */
        uint16_t    pipectr;        /* Pipe control register */
        uint8_t     errcnt;         /* Error count */
        uint8_t     segment;        /* Last flag */
        void        *p_usr_data;
    } usb_message_t;

    iodefine.h

    struct st_usb0 { ← ここにはコンパイラの仕様上 _evenaccess を記述出来ません
    ...
        union {
            unsigned short WORD;
    //      struct {
    //          unsigned short :4;
    //          unsigned short HNPBTOA:1;
    //          unsigned short EXICEN:1;
    //          unsigned short VBUSEN:1;
    //          unsigned short WKUP:1;
    //          unsigned short RWUPE:1;
    //          unsigned short USBRST:1;
    //          unsigned short RESUME:1;
    //          unsigned short UACT:1;
    //          unsigned short :1;
    //          unsigned short RHST:3;
    //      } BIT;
        } DVSTCTR0;
    ...
    };

    #define USB0        (*(volatile struct st_usb0     __evenaccess *)0xA0000) ← ここに _evenaccess が付いてますよね?

     

  • こんにちは。NoMaYです。

    分かった、、、(少なくとも)最新のUSBドライバのソースでは変更されてますね、、、

    r_usb_typedef.h

    typedef volatile struct st_usb0 __evenaccess * usb_regadr_t; ← ここに _evenaccess が付いてますね!

    typedef struct usb_utr      usb_utr_t;
    typedef void (*usb_cb_t)(struct usb_utr *, uint16_t, uint16_t);


    typedef struct usb_utr
    {
        usb_mh_t    msghead;        /* Message header (for SH-solution) */
        uint16_t    msginfo;        /* Message Info for F/W */
        uint16_t    keyword;        /* Root port / Device address / Pipe number */
        union
        {
            usb_regadr_t    ipp;    /* USB module startAddress(USB0/USB1)*/
        #if USB_NUM_USBIP == 2
            usb_regadr1_t   ipp1;   /* USB module start address(USBA) */
        #endif /* USB_NUM_USBIP == 2 */
        };
        uint16_t    ip;             /* USB module number(0 or 1) */
        uint16_t    result;         /* Result */
        usb_cb_t    complete;       /* Call Back Function Info */
        void        *p_tranadr;     /* Transfer data Start address */
        uint32_t    tranlen;        /* Transfer data length */
        uint16_t    *p_setup;       /* Setup packet(for control only) */
        uint16_t    status;         /* Status */
        uint16_t    pipectr;        /* Pipe control register */
        uint8_t     errcnt;         /* Error count */
        uint8_t     segment;        /* Last flag */
        void        *p_usr_data;
    } usb_message_t;

     

  • NoMaYさん

    こんにちは、シェルティです。

    >生成されたコードは、ふじさんのNGコードの方では無くてOKコードの方だった、
    >ということでしょうか?

    はい、そうです。
    私が動作確認に使ったコードはスマートコンフィグレータが出力したコードですね。
    RX Driver Packageの最新版(V114)に入っているものです。
    st_usb0 を見てみたら、__evenaccessが付いてました。

    解析ありがとうございます。答えにたどり着けて良かったです。

    以上です
  • ご協力ありがとうございます。最新ソースで対処されている可能性については最初から想定してはいたのですが調査が早く進み非常に助かります。
    とはいえ、すべての古いドライバに対してはもうそのままでは使えない可能性があるとなったいま、コンパイラの最適化を調整するしかなく、コンパイラとしてそれで良いのか疑問は感じます。

    現在、お客さまの技術アドバイザ的な立場で開発に携わっている事情もあり、すでに安定動作できているCS+4で作ったFW、ついでにいうとiTRON向けにドライバの改造や性能チューニングを要所要所で施しているため、最新FITへの置き換えやCS+6への移行はリスクが大きく、引き続きしっかり検討してみます。
    トライしてみようとは考えていますので、また何かあればご報告させていただきます。
  • ふじさん、こんにちは。NoMaYです。

    >iTRON向けにドライバの改造や性能チューニングを要所要所で施している
    その状況であれば、私は以下の対処案が有効かと思います。(余談ですが、おそらく、以下のスレッドの自作(というか移植というか)のiTORN(というかμITRON)のオープンソース実装のTOPPERS/ASPベースのプログラムは、動作しない、もしくは、何かしら問題が発生する、のでは無いだろうかと思っていて、また自己フォローを投稿しなければ、と思っているところです、、、)

    RX62NのUSBデバイスドライバについて
    japan.renesasrulz.com/cafe_rene/f/forum5/4314/rx62n-usb/28297#28297

    対処案を検討する前に、、、

    (1) 旧USBドライバの本件の該当箇所に__evenacessを記述してコードが想定通りに変化するか調べる
    (1a) 変化しなければ別の要因があると思われる
    (1b) 変化して期待したコードになれば対処案を検討する

    対処案

    (1) 最新のUSBドライバのソースの__evenacessの記述箇所を調べて旧ソースに反映する方法を検討する

    あと、少し気になっているのですが、CS+ 6で旧コンパイラを使用することは出来ます。ですので、以下の案もあるのではないだろうかと思います。(実際、私はCS+ 6でCC-RX V2.03を使用しています、、、)

    (2) お客様が望まれているのがCC-RXを最新にすることなのかCS+のIDEを最新にすることなのか確認する
    (2a) CC-RX V2.08の強い要望が無ければ、CS+ 6でCC-RXの旧コンパイラを使用する方法を提案する
    (2b) CC-RX V2.08を強く望まれるならば、コンパイラバージョンアップには相応の評価が避けられない点を理解して頂く

    余談ですが、上に書いたスレッドのTOPPERS/ASPのソースコードでは、__evenaccessへのケアがソースごとに違っているような印象でした。

    __evenaccessへのケアが有るソース例 (ただしuint8_tに対して__evenaccessは過剰な気もしますが)

    arch\rx630_ccrx\rx630_config.c

    /*
     *  割込み要因プライオリティレジスタアドレステーブル
     */
    volatile uint8_t __evenaccess * const ipr_reg_addr[ INHNO_MAX ] = {

        ICU_IPR000_ADDR,                /* No.16  バスエラー BUSERR */

    };

    /*
     *  割込み要求許可レジスタアドレステーブル
     */
    const IER_INFO ier_reg_addr[ INHNO_MAX ] = { (以下の構造体定義を参照 by NoMaY)

        { ICU_IER02_ADDR, ICU_IEN0_BIT },   /* No.16  バスエラー BUSERR */

    };

    arch\rx630_ccrx\rx630_config.h

    /*
     *  割込み制御用型定義
     */
    typedef struct ier_info {
        volatile uint8_t __evenaccess   *addr;
                 uint8_t                offset;
    } IER_INFO;

    __evenaccessへのケアが無いソース例 (少なくともvolatile uint32_t *mstpcrreg;に__evenaccessが無い)

    pdic\rx600\rx630_uart.c

    /*
     *  シリアルI/Oポート初期化ブロックの定義
     */
    typedef struct sio_port_initialization_block {
        volatile uint8_t    *ctlreg;        /* シリアルコントロールレジスタ(SCR) */
        volatile uint8_t    *modereg;       /* シリアルモードレジスタ(SMR) */
        volatile uint8_t    *extmodereg;    /* シリアル拡張モードレジスタ(SEMR) */
        volatile uint8_t    *statusreg;     /* シリアルステータスレジスタ(SSR) */
        volatile uint8_t    *tdreg;         /* トランスミットデータレジスタ(TDR)*/
        volatile uint8_t    *rdreg;         /* レシーブデータレジスタ(RDR) */
        volatile uint8_t    *bitratereg;    /* ビットレートレジスタ(BRR) */
        volatile uint32_t   *mstpcrreg;     /* モジュールストップコントロールレジスタ(MSTPCR) */
        volatile uint8_t    *ssrreg;        /* ステータスレジスタ */
        volatile uint8_t    *rxiirreg;      /* RXI用割込み要求レジスタ */
        uint8_t             tx_intno;       /* 送信(データエンプティ)割り込み番号 */
        uint8_t             rx_intno;       /* 受信(データフル)割り込み番号 */
        uint8_t             te_intno;       /* 送信(終了)割り込み番号 */
        uint8_t             sci_no;         /* SCIの番号(SCI0~SCI6) */
        uint32_t            mstpcr_offset;  /* MSTPCRの対応するビットオフセット */
    } SIOPINIB;

    もっとも、mstpcrregへの書き込みが以下のスタイルですので、TOPPERS/ASPの慣習では、(たまたま?)大丈夫そうですが、、、([追記] なお、sil_rew_mem()やsil_wrw_mem()のコードに__evenaccessが無いのは、将来のCC-RXのバージョンアップに対するリスク要因である、ような気がして来ましたが、、、)

    pdic\rx600\rx630_uart.c

    /*
     *  SIOドライバのシリアルモードレジスタ(SMR)
     */
    static void
    rx630_uart_setmode(const SIOPINIB *p_siopinib, uint8_t bitrate, uint8_t clksrc)
    {

        /*
         *  モジュールストップ機能の設定
         */
        sil_wrh_mem((uint16_t *)SYSTEM_PRCR_ADDR, (uint16_t)0xA502);    /* 書込み許可 */
        sil_wrw_mem((uint32_t *)p_siopinib->mstpcrreg,
            sil_rew_mem((uint32_t *)p_siopinib->mstpcrreg) & ~p_siopinib->mstpcr_offset);
        sil_wrh_mem((uint16_t *)SYSTEM_PRCR_ADDR, (uint16_t)0xA500);    /* 書込み禁止 */

    }

    include\sil.h ([追記] これでは呼び出し元の方に__evenaccessが有っても効かないような気がして来ました、、、)

    Inline uint32_t
    sil_rew_mem(const uint32_t *mem)
    {
        uint32_t    data;

        data = *((const volatile uint32_t *) mem); ←ここに__evenaccessが無いのはリスク要因な気が、、、
        return(data);
    }

    Inline void
    sil_wrw_mem(uint32_t *mem, uint32_t data)
    {
        *((volatile uint32_t *) mem) = data; ←ここに__evenaccessが無いのはリスク要因な気が、、、
    }

     

  • 業務多忙のため細かいご報告できず申し訳ございません。簡単に状況報告させていただきます。
    ・FW全体を最適化レベル2+USBドライバ修正(st_usb0に__evenaccess追加) ⇒ OK(評価不十分ですが一応OK)
    ・FW全体を最適化レベル1+USBドライバ修正(st_usb0に__evenaccess追加) ⇒ NG(USBメモリ接続するとフリーズ)
    となってしまいました。とりあえず、USBドライバだけの問題ではないようで、、引き続き調査してみます。

    今後、コンパイラ(CC-RX)の最新バージョンを使う場合、既存の(古い)ドライバはもうそのままでは使えないであろうという雰囲気がしてきました。。。
  • ※すみません。先ほどの報告に誤りがありました。
    ■状況報告(訂正版)
    ・FW全体を最適化レベル2+USBドライバ修正(st_usb0に__evenaccess追加) ⇒ OK(評価不十分ですが一応OK)
    ・FW全体を最適化レベル1+USBドライバ修正(st_usb0に__evenaccess追加) ⇒ NG(起動中フリーズ、USB未接続でもフリーズ)
    となってしまいました。とりあえず、USBドライバだけの問題ではないようで、、引き続き調査してみます。
    (FITだけでなくFIT以外のドライバも多くありますので・・・)

    ■今後について
    ・上記の調査を続けます。
    ・コンパイラ(CC-RX)の最新バージョンを採用する場合、既存の(古い)ドライバはもうそのままでは使えないことがわかりましたので、原因や影響範囲をしっかり把握したうえで、相応の評価を進めることを検討してみます。
    ・最終的には・コンパイラ(CC-RX)またはCS+6を使うのをやめるという結論になるかもしれませんが。。