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クロック減ったー(゚∀゚)ー!
……でもこれ、もしかしてレジスタの数足りないんじゃなかろか(;´Д`)