ARMアセンブラ勉強中(4)

さらに高速化です(`へ´)。


LDM,STM命令を使えば、4バイト単位で複数のロード・ストアが出来て、しかも高速です。
ただし、4バイト単位でロードされるため、2バイト単位でストアするために透過色を上位・下位ワードにセットしてEORしてマスクを生成してANDしてADDして……とかやっていると、逆にクロック数が増えます。
これはまあ、ロードだけLDMでしておいて、ストアはハーフバイトで転送すればいいでしょう。

    // アセンブラルーチンに入る前に計算しておく
    uint32 iend8d = (width & 7) * sizeof( PixelTypeRGB565 );
    uint32 iend,iend8;
    
    // 下位ビット、上位ビットを取り出すためのマスク
    uint32 mask = 0xffff;
    
    ADD      iend,src,width,LSL #1
    SUB      iend8,iend,iend8d      ;8ループ展開の終了値を計算
    
    B        icomp8
iloop8:
    LDMIA    src!,{r1-r4}   ;4バイト×4をsrcから一気にロード。
                            ;しかもライトバック付き
    
    AND      r0,mask,r1
    CMP      r0,key
    STRNEH   r0,[dst,#0]
    
    AND      r0,mask,r1,LSR #16
    CMP      r0,key
    STRNEH   r0,[dst,#2]
    
    ....
    
    ADD      dst,dat,#16
icomp8:
    CMP      src,iend8
    BGE      iloop8

これで、ループ内のクロック数は、1回の転送が3.5クロックとして、それが8回。LDMIAが6クロック、ADD,CMP,BGEで5クロック。合計39クロック。
最初と比べると、半分以下までクロック数が落ちましたヽ(´ー`)ノ


でも、これにはちょっと問題があって、ARMだとソースビットマップのクリッピング位置が奇数の場合、端末リセットが掛かる可能性があります。
なんでかというと、ARMはLDR命令を4バイト境界でしか読み込めないからです。
なので、事前に4バイト境界まで転送した後に、↑のコードを書くことになります。



今度はインデックスカラーの最適化をするぞーヽ(´ー`)ノ



追記:

    uint32 key2 = key << 16;
    
    
    EORS     r0,key2,r1,LSL #16
    STRNEH   r1,[dst,#0]
    
    AND      r0,mask,r1,LSR #16
    CMP      r0,key
    STRNEH   r0,[dst,#2]

さらに8クロック減ったー(゚∀゚)ー!


……でもこれ、もしかしてレジスタの数足りないんじゃなかろか(;´Д`)