2014年5月23日金曜日

ARMでビットリバーサル

ARMでビットリバーサルを行う方法について

inline uint32_t REV(uint32_t din) {
    uint32_t dout;
    __asm__("REV %[Rd], %[Rs1]" : [Rd] "=r" (dout) : [Rs1] "r" (din));
    return(dout);
}

inline uint32_t RBIT(uint32_t din) {
    uint32_t dout;
    __asm__("RBIT %[Rd], %[Rs1]" : [Rd] "=r" (dout) : [Rs1] "r" (din));
    return(dout);

}


RBITがビットリバーサルです
RBIT命令は32bitのI/Oなので、8bitの入れ替えをしようと思うと予期しない結果になります
解決手段としては
1) ビットシフトで移動する
2) エンディアン変換で移動する
3) ポインタで正常な位置から読み出す
    (もしくは最初にポインタでオフセットした位置に書き込む)
という方法があります

1と3については説明は不要だと思います

2のエンディアン変換はREV関数で行います
これも32bitI/Oです


動作確認については
    uint32_t data = 0x12345678;
    uint8_t *p = (uint8_t*)&data;
       
    xprintf("%02X %02X %02X %02X\n", p[0], p[1], p[2], p[3]);
    data = REV(data);
    xprintf("%02X %02X %02X %02X\n", p[0], p[1], p[2], p[3]);
    data = RBIT(data);
    xprintf("%02X %02X %02X %02X\n", p[0], p[1], p[2], p[3]);
という感じ
1回目のprintfでは78 56 34 12が出てきます
2回目はエンディアンを入れ替えた12 34 56 78が出てきます
3回目はビットリバーサルした結果の1E 6A 2C 48が出てきます

8bit変数のビットリバーサルを行いたい場合は
REV(RBIT( (uint8_t)hoge ))
という感じになります
REVとRBITはどちらが先でもいいはずです

でもビットリバーサルをやりたいだけならビットシフトのほうがらくだと思います


追記:2014-07-04
core_cm3.hに__RBIT及び__REV関数がありました
どちらも引数は32bitが1個 戻り値が32bit それぞれ符号無しです
やっていることはほぼ同じです

0 件のコメント:

コメントを投稿