H8 300HTiny ROMのサム

こんにちは

現在H8 300Tinyの評価キット(デバイスは36079)を使用して、

ROMのサムを計算するプログラムを作成しています。

ROMの0x00000000番地から0x0001EFFF番地の値を加算しているのですが、

毎回サムの計算値が異なってしまいます。

チェックサムの関数は下記のようにしています。

#define ROM_STR_ADDR ((unsigned int)0x00000000)

#define ROM_END_ADDR((unsigned int)0x0001EFFF)

static void check_sum(void)
{
 unsigned char  *sum_addr;
 unsigned int sum_cnt;
 unsigned int sum_data = 0;

 sum_addr = ((unsigned char*)ROM_STR_ADDR);
 for(sum_cnt = ROM_STR_ADDR ; sum_cnt < ROM_END_ADDR ; sum_cnt++ )
 {
  sum_data += *sum_addr;
  sum_addr++;
 } 
}

HEWにて上記関数を実行して、その後Reset実行すると値が変わっていることがあります。

上記の関数が悪いか、他の関数が影響しているか調べている最中なのですが、

何かご存知のある方いましたら教えていただけますか?

  • 『H8S、H8/300シリーズ C/C++コンパイラ、アセンブラ、最適化リンケージエディタ コンパイラパッケージVer.7.00 ユーザーズマニュアル』の 258頁を見ると unsigned int は 2 バイトの型で取りうる値の範囲が 0~65535 とありますが、貼られているプログラムでは

    • アドレスを unsigned int にキャストしている為、下 16bit しか有効になっていない
    • for ループの有効アドレスの判定が ROM_END_ADDR 未満となっているため最終アドレスが計算されない

    以上の問題があると思います。

    #define ROM_STR_ADDR ((const unsigned char*)0x00000000L)
    
    #define ROM_END_ADDR ((const unsigned char*)0x0001EFFFL)
    
    static void check_sum(void)
    {
     const unsigned char  *sum_addr;
     unsigned int sum_data = 0;
    
     for(sum_addr = ROM_STR_ADDR ; sum_addr <= ROM_END_ADDR ; sum_addr++)
     {
      sum_data += *sum_addr;
     } 
    }
    

    とされてはどうでしょうか?

  • 今使用しているものです、良かったら使用してみてください。

    //サムコード生成

    unsigned long make_sum(unsigned char *buffer, long size)

    {

    long i;

    unsigned long a, b;

    a = 0;

    for(i = 0;i < size;i += 2) {

    b = (unsigned long)(buffer[i] & 0xff) * 256;

    b |= (unsigned long)buffer[i + 1] & 0xff;

    a = a + b;

    }

    return (~a & 0xffffffff);

    }

  • fujita nozomu様 IKUZO 様

    ご回答有難うございます。

    型やループ等、初歩的な間違いばかりで申し訳ないです…

    御二人のソースコードとても参考になりました。

    私の関数も悪いのですが、サムが違った際のメモリをファイル出力し、比較したところ

    不要なセクション(何も入っていない)がマッピングされていた部分に差分があった為、

    それも原因かもしれません。

    手当たり次第調査してみます。

  • 次のようにしたらどうですか。

    #define ROM_STR_ADDR (0x00000000)

    #define ROM_END_ADDR (0x0001EFFF)

    unsigned int sum_data ; // チェック・サムを入れる

    static void check_sum (void)

    {

    unsigned long sum_cnt ; // ループ・カウンタ

    unsigned char* sum_addr ; // 読み出すアドレス

    sum_data = 0 ; // ゼロ・クリアー

    sum_cnt  = ROM_END_ADDR - ROM_STR_ADDR + 1 ; // ループ・カウンタ設定

    sum_addr = (unsigned char*) ROM_STR_ADDR ; // 最初に読み出すアドレス

    do { sum_data += *sum_addr++ ; } // チェック・サム値の更新

    while ( --sum_cnt ) // データ数だけループ

    }

  • リカルド様

    頂いたコード試させていただきました。

    みなさんのコードを試してみて思ったのですが、

    チェックサム関数の処理が原因ではないと思いました。

    上記でいった不要なセクションについても

    削除したりしましたが、違うようです。

    根気強く調べてみます。

    ご回答有難うございました。

  • minさん

    注意点がひとつ、わたしの過去の経験ですが、sumを取るメモリの最後尾は0にクリアしないといけないこともあります、sum計算が16ビット単位のためでしょう、一番最後でゴミが入る場合がありますので、最後尾0のクリアは忘れずに、16ビット単位のデータであれば気にすることはありません。

  • IKUZO 様

    注意点有難うございます。

    確認してみました。

    メモリをいくつかのブロック単位に分け途中のサム値を配列に格納して何度か行ったところ、

    サムが途中から変わっているようでした。

    mapをみてみると上記の方法で絞っていったアドレスに「_sbrk」とあるのですが、

    メモリ管理用の関数らしいです(ヒープ領域確保用?)

    このファイルが悪さしているというのは考えられますかね?

  • min さん

    サムを取っている領域がROMであれば変わることはないはずですが、

    H8 300Hで外部拡張バスにROMを配置しているような場合、タイミングエラーでリードデータが化けるようなことがあるとサムが変化するかもしれません、安全性は担保できているでしょうか?

  • チョコです。

    >「_sbrk」とあるのですが

    H8は全く使ったことがないのですが、この名前は気になりますね。

    なんとなく、"ソフトウェア・ブレーク"を連想します。

    この番地の命令が実行時にソフトウェア・ブレーク用のコードに

    置き換えられているとかありませんか。

  • IKUZO様 チョコ様

    有難うございます。

    やはりROM内のデータが変わることはないですよね…

    一応チェックサムを行うのは内臓ROMとしてます。

    _sbrkについては調べてみたところ、

    不要な場合ビルドから除外していいとなっていたため除外して、

    mapに_sbrkがない状態でやりましたがかわらないようです。

    質問させていただきながら申し訳ないのですが、

    一旦この質問をクローズさせていただいて、

    原因などわかりましたらまた投稿します。

    有難うございました。