■経緯について 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モジュール)の確認 ・最適化によるアセンブラコードの違いを確認 ・場合によってはソースコードを修正して対応する ・その他全てのドライバの確認(共通問題の可能性が高い)
何か情報お持ちの方がいましたら教えていただきたく、よろしくお願いいたします。
以上
シェルティさん、こんにちは。NoMaYです。(私のPCのCPUが古過ぎてCC-RX V2.04以降が使えず回りくどいレスですが)>私の環境(CC-RX V207、最適化2)では不再現でした。>特定コンパイルオプションの条件下において不正なコードが出力されるといったところで、>USBドライバ自体には問題がないように感じました。この部分は、私だけでなくて、ふじさんも気になる文面かと思いますが、生成されたコードは、ふじさんのNGコードの方では無くてOKコードの方だった、ということでしょうか?ふじさんのNGコード ≠ シェルティさんがCC-RX V2.07 最適化2で試された結果
(参) 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で試された結果
もしくは
あと、細かいところですが、ふじさんとじまさんの以下の文面はアセンブラに不慣れゆえの書き間違いかな、と思われます。以下の(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です。>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 voidrx630_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_tsil_rew_mem(const uint32_t *mem){ uint32_t data; data = *((const volatile uint32_t *) mem); ←ここに__evenaccessが無いのはリスク要因な気が、、、 return(data);}Inline voidsil_wrw_mem(uint32_t *mem, uint32_t data){ *((volatile uint32_t *) mem) = data; ←ここに__evenaccessが無いのはリスク要因な気が、、、}