CANメールボックスにlongでデータを書くとポインターがずれる?

使用しているチップは、RX64Mです。空いているCANのメールボックス(MB16)に、データを転送する処理ルーチンをインライン関数BuffCopy8()で行っています。
少しでも処理が速くなるように、8バイトのデータ転送をlongのポインターで2回のコピーで実現しました。
しかし、そうすると、不具合が発生するのです。
まずは、画面を添付しておりますのでご覧ください。

見にくいかと思いますのでテキストで書きますと、

static void BuffCopy8(void *dest, void *src)
{
  unsigned long *sp = src, *dp = dest;
  *dp++ = *sp++; <------(1)
  *dp = *sp;
}

となります。これがインライン展開された逆アセンブラリストは、こうなっています。

       mov.l [r7],r4                      ;; 元データの先頭4バイトを、r4にコピー
  add #0x90206,r14,r3        ;; r3 がCAN MB16のDATA[0]のアドレス
  add #0x9020a,r14,r14      ;; r14がCAN MB16のDATA[4]のアドレス
  mov.l r4,[r3] <---(1)            ;; r4のデータをCAN MB16.DATA[0に4バイトコピー
  mov.l 4[r7],r1                      ;; 4[r7]元データの5バイト目からの4バイトを取り出す
  mov.l r1,[r14]                       ;; データ4バイトを転送

ここで、問題のレジスタの値は以下の通りになっています。

  r3 = 0x90306                       ;; = MB16.DATA[0]
  r14= 0x9030a                       ;; = MB16.DATA[4]

そして、画像は、(1)を実行した所です。通常であれば、r3レジスタがさしている
ML16.DATA[0]から4バイトのデータが書き込まれると思うのですが、
黄色く着色されている通り、実際には2バイト前の0x90304から書き込まれてしまいます。
実際こきこまれているr4の値は 0x4018102であり、その内容が

0x90304 0x4018
0x90306 0x10
0x90307 0x02

と書き込まれています。ちなみに、このシステムはビックエンディアンになっています。
コンパイラが変なコードを出しているというわけでもないのに、実際に走らせると、
変な動作になってしまうという、理解に苦しむ状態です。

どなたか、これの動作の仕組みをご存じないでしょうか。

  • 転送先、転送元でアクセス時のサイズに制限があったりするエリアを使用していませんか?特定のレジスタでは2バイトアクセス、4バイトアクセスなどを強制する場合があります。CANは使ったことないですが、EtherCATなんかは仕様としてDualPortRAMの読み書きはエリアの両端は2バイト単位でやらないとエリア切り替えやロック処理がおかしなことになります。

  • わわいです

    RXってのは32ビットCPUってことになってまして、4バイトのバス幅を持ってます。

    で、ここで4バイト変数をアクセスする場合は、4バイトアライメントされたアドレスでアクセスされます

    ってことで、アドレス0x90306から4バイトってのはアクセスできません

    # で、ARMなんかでは不正なアライメントアドレスのアクセスは例外が発生して落ちてくれたという
    # 覚えがあるんですが、RXの場合はしれっとムリヤリ4バイトアライメントでアクセスしてくれるんですね

  • Shoji Yamamotoさん

    かわいさん

    ご返信ありがとうございます。

    いや、そうなんですね、いままであまりlongの変数は使ってことがなかったので、気を付けないといけませんね。それにしても、実際に指しているポインターと違うところに、エラーなく書き込まれる仕様というのは、困りもんです。

    でも、そういう仕様ということであるなら、そういう使い方をしないといけませんね。

    とにかく、すっきりしました。ありがとうございました。

  • 本筋とは違うのですが
    #include <stdint.h>

    して

    uint8_t, uint16_t, uint32_t, uint64_tを使えるようにしとくといいかなと思います。longは開発環境によっては必ずしも64bitじゃないので。int <= longですのでintと同じ場合があります。RXマイコンはint < longですが。あとよっぽどのことがない限りmemcpyを使うのがいいと思います。なんだったらDTCやDMACを使えばいいと思います。