CS+ cc V8.04.00 r_main.c グロバール定義の変数に値が入らない

ターゲットRL78/G13で発生した問題ですが・・・・

R_main.cで定義したグローバル変数に値が入らない問題が発生して、頭を抱えていました。

定義した変数は、volatile uint16_t 型の1次元配列です。初期値を定義したら変数に値が入るようになった。(変な話です)

マップファイルの内容を確認する為に、変数/関数配列情報の出力オプションを有効にしたら何故かしら問題が解決ししました。

経験のある方は、おられませんか。

 

  • NoMaYさん、tanuです。

    ステップ実行で、確認すると構造体変数に値が入りますが、ループ終了でブレークし確認すると値が入りません。ウオッチの値を直接変更は可能です。また、メモリの内容もステップでは変わっていますが、構造体配列の場合に問題が発生します。通常の配列は、初期化されます。

    g_work_state[0]がステップ実行後の変数値で、g_work_state[1]以降がforループ終了時の変数値です。

    g_test_led_off_distance_count[]の配列は、問題なく初期化されます。

  • tanu様
    鈴木と申します。定義している変数に volatileをつけるとどうなるでしょうか
    代入しかしていない変数ですと、コンパイラの最適化によっては
    省略されることもあります。以上、よろしくお願いします
  • 回答有難う御座います。
    全ての変数に、volatileは必ず付けています。
    最適化は、嫌な経験が有りますので、コンパイラオプションも外しています。
  • tanu様、回答ありがとうございます。コード生成をお使いですね。
    変数の初期化を R_Systeminit()関数内で行っていないでしょうか?
    このハードウェア関連の初期化を行った後にRAMの初期化が実行されるので
    変数もクリアされます。(cstart.asm をご参照ください)
    以上、よろしくお願いします
  • tanuさん、こんにちは。NoMaYです。

    このソースコードであれば、次に確認したいことは、構造体初期化ループのループ終了条件に使用されている Work_No_num の値ですね。ソースコードによれば関数内ローカル変数では無いですし、逆アセンブル結果を見たところファイル内スタティック変数でもグローバル変数でも無いですので(逆アセンブル結果内に _Work_No_num を参照している箇所が無いですので)、#defineで値は 8 でしょうか?あと、 stage_num も同様に推測して、#defineで値は 5 でしょうか?

    それで、画面コピーの状況は以下のような手順での結果でしょうか?

    (1) 33行目以降のforループをi=0の初回だけはステップ実行した
    (2) i=1以降に関してはGo実行した

    また、今までの文面とあわせると以下のことでよいですか?

    (3) i=1以降に関しても、ステップ実行すると、期待したとおりに構造体配列がゼロクリアされる
    (4) 逆にi=0に関しては、Go実行させると、期待したとおりには構造体配列はゼロクリアされない

    そういう状況ですと、私が次に気になるのは以下の点です。

    (A) SPの値は幾つでしょうか?
    (B) ステップ実行で71行目に到達した時とGo実行で72目に到達した時と、どちらも i の値は 8 でしょうか?

    もっとも、work_state_clear()関数からはリターン出来ているようですので、可能性は低いか、ぎりぎりの状況だったか、という感じではありますけれど。

    あと、ウォッチウィンドウでの構造体配列g_work_state[]のアドレス表示によれば、この場所はR5F100xJ/R5F101xJのRAM領域の下端付近(下端が0xFAF00で構造体配置アドレスが0xFAF04)ですね。この場所はセルフプログラミングの予約領域で、デバッガもダウンロード時やソフトウェアブレークポイント設定/解除時はセルフプログラミングを使用しているのでデバッガの内部処理的には複雑なことが行われている領域ではあります。(もちろん変なことが起きないように辻褄合わせは念入りに行われているはずですが。) 対症療法的に、この予約領域をリンカのセクション設定で避けるようにすると回避出来る可能性もあるかもと思います。(予約領域は0xFAF00~0xFB2FFですね。)

    上の話は、対症療法というかデバッグの一環としてというか、そういうものですが、デバッグの一環として思い浮かぶ技法として、以下のような実行時チェックルーチンを埋め込んでみる手があります。(何が起きているのか、もう少し把握するためですけれど。)

    (a) 33行目からの for( i = 0; i < Work_No_num; i++ ){...} のループが終了した後、同様にfor( i = 0; i < Work_No_num; i++ ){...} のif文で構造体配列が期待したとおり 0 に初期化されているか確認する以下のようなコードを挿入して、Go実行させてみる。

        for( i = 0; i < Work_No_num; i++ ){
            既にある初期化ルーチン
        }

        以下のようなコードを挿入してみる
        for( i = 0; i < Work_No_num; i++ ){
            uint8_t Not_Initilized = 0;
            if( g_work_state[i].work_stage_no != 0){
                Not_Initilized = 1;
            }
            上記と同様なコード
            if( Not_Initilized != 0 )
            {
                nop(); その1 ← ここにハードウェアブレークを設定する(ソフトウェアブレークを出来るだけ避けてみる)
            }
        }
        nop(); その2 ← ここにハードウェアブレークを設定する(同上、ただしハードウェアブレークが1本なら上記と排他で設定する)

    こんな感じで様子を見てみる、という手もあるかと思いました。これで何が分かるかというと、Go実行している最中にはきちんと一度は初期化されているのかどうか、ということがわかるかと思います。(厳密には、想定外の場所を初期化していた、という可能性が残りますが。)

    (イ) 実行時チェックで失敗する(上記のnop() その1でブレークした) → すぐに次のステップに進める訳ではないですが情報としては有用だと思います
    (ロ) 実行時チェックに成功する(上記のnop() その1でブレーしなかった) → デバッガの不具合の可能性が濃厚になると思います

    ちなみに、通常配列g_test_led_off_distance_count[]はアドレスが0xFFE88ですので、くだんの構造体配列とはかなり離れた場所にありますね。

  • NoMaYさん、tanuです。
    nop();その1でブレークしました。
    初期化されていないようです。
    セルフプログラミング予約領域を避ける必要が有るかもしれません。
  • tanuさん、こんにちは。NoMaYです。

    > nop();その1でブレークしました。

    そうでしたか。念の為の再確認ですが、オンチップデバッグで実際に使われているマイコンはRL78/G13のR5F100xJもしくはR5F101xJなのですよね?具体的に型番は何でしょうか?

    > セルフプログラミング予約領域を避ける必要が有るかもしれません。

    実は、この実行時チェック区間でtanuさんのプログラムとしてセルフプログラミングが行われている訳ではないですので、理屈上は予約領域を避ける必要は無いはずなのです。予約領域の話がクローズアップされるケースは、ゼロクリアの実行時チェックに成功して、でも、ブレークしてウォッチウィンドウやメモリウィンドウで値を確認するとゼロクリアされてない、というケースなのです。

  • tanuさん、こんにちは。NoMaYです。
    >オンチップデバッグで実際に使われているマイコンはRL78/G13のR5F100xJもしくはR5F101xJなのですよね?具体的に型番は何でしょうか?
    P5F100PJAです。
    セクションの開始アドレス .bass/FB300で確認します。
  • tanuさん、こんにちは。NoMaYです。
    セクションの開始アドレス .bass/FB300で、なんと!クリアーされました。
  • tanuさん、こんにちは。NoMaYです。#tanuさんの前2つのリプライの先頭行がコピペミスで私のリプライのようになっちゃってます

    > セクションの開始アドレス .bass/FB300で、なんと!クリアーされました。

    ということは、予約領域辺りが、Go実行中(というかステップ実行以外では)アクセス出来なくなってしまっているのかなぁ、、、

    今思い浮かんだ可能性(思い付き)なのですが、work_state_clear()関数が実行される時、既にセルフプログラミングモードに入っていたりする、ということはあったりするのでしょうか?(いや、でも、それだと、そもそもブレークしないとかステップ実行出来ない、とかだったかも、、、)

    マイコンの不良の可能性もあるのかなぁ、、、