古典的な8ビット時代のアイデアを使用することでした(それに非常に同じプロセスを適用した後)、ロールオーバーと次のバイトにそれらを適用するビットを切り取ると思いますRCL(キャリー付きで左に回転する)はDEC counter + JNZ
でインターリーブされています。なぜなら、x86 DEC/INC
命令はゼロフラグにしか影響せず、キャリー(ミステリー解決済み)に影響するのはなぜですか?
ので、コードは、これらの線に沿って行くだろう:
mov edi,address_of_last_byte
mov edx,count_of_bytes
mov cl,1
clc ; clear CF
loop_1_bit_left:
rcl byte [edi],cl ; CF -> LSB, MSB -> CF
dec edi ; preserves CF! Goes from last byte to first one
dec edx ; preserves CF! Decrement counter
jnz loop_1_bit_left ; till whole buffer is shifted
; CF has last bit, will be thrown away unless you do something about it
は今、これが望まれるためにたくさんの葉...
をバッファのMSBを保存する方法は?私はまず、シフト後に必要なバッファサイズを計算します(new_length = arg_length +(shift + 7)/ 8))。入力をコピーし、MSBの切り捨てに伴う問題を解決するarg_lengthバイト、new_lengthバイトをシフトしないでください。
しかし、別の問題、パフォーマンスがあります。現代のx86 CPUのrcl
は残念ながら遅いので、このように315ビット分シフトするなどは非常に悪い考えです。しかし、あなたはする必要はありません。すでに入力された数字をnew_lengthバッファに39バイトだけ(最初に向かって)コピーするだけで、最初に312ビットだけシフトできます。そして、残りの3ビットは上記のループによって1つずつシフトします。
さらに出力バッファを十分にパッドする場合は、dword/qword rcl
バリアント(32b/64bコード)を使用して、同時により多くのバイトを処理できます。 (実際にあなたの説明から、出力バッファを割り当てる責任を負うのは誰か分かりませんが、もしあなたのコードが何らかの形でスタックに戻ってくるのであれば、私はABIがシフト量に従って動的に成長したバッファで可能ですまたはヒープに割り当て、上に数バイトを追加することで、最後の通常のバイトの後に数バイトを変更できます。代わりにdword/qwordと4/8Bアライメント(!)アドレス以上で作業できます。
EDIT:rcl
/rcr
のword
/dword
参照する変異体は、配列全体に大きな数は、x86のリトルエンディアンの方法を以下であり、ループは正しい++ /を、次のされている場合にのみ正しく動作します - ビットb0-7はバイト配列のオフセット+0にあり、ビットb80~b87は+10オフセットにあり、右へのシフトはMSB(+10)b87からLSB(+0)b0へ向かいます。私の最初のbyte [edi]
の例では、MSBがオフセット+0で始まりLSBが+で終わるので、ビッグエンディアンであると予想されているので、ビットは人間の順序で見ることができます。b0、リトルエンディアンは視覚的にバイトグループ(b7 .. b0 b15 .. b8 ... ... ... b87 ... b80)ごとに視覚的に「逆転」しています...少なくとも私はそう思います、とても混乱し始めました。コードを片方向に書くだけで、簡単なコーナーケースの単体テストを作成し、結果を検証し、期待通りの結果を出すことができます。 :D
はちょうどそれはCFの内容を破壊してしまうようあなたは、このような場合のsub edi,4
(sub rdi,8
)でedi
を更新しないことを確認し、その代わりに、アドレッシングモードによって行わ簡単な計算のlea edi[edi-4]
方法を利用します。そして、正確に/4 || /8
の値を持つようにカウンタを調整してください。
最高のパフォーマンスを得るには、1つのビットで1から7ビットシフトする価値があります.2ビットから7ビットへのシフトのためには、rcl
バージョンをそのまま使用してください。 16bのバッファの読取り/書込みを処理し、シフトアウトされたビットを上半分に保持するために、例えば32bレジスタを使用して、目標値を1回で実行する。または、これまでのところでは、shl/and/or
の1ビット版がプロファイルされている可能性があります。rcl
より速くはありません。コンパイラによってrcl
が使用されていないため、特定のCPUは、単一のrcl
よりもいくつかのshl/and/or
命令を好むかもしれません。
楽しい事実:私は一人で完全に書いた私の非常に最初のZ80アセンブリコードがこれをやっていた、左メモリ1ビットの一つの巨大なエリアをシフト(および右)。その巨大なメモリ領域は実際にはZX SpectrumコンピュータのビデオRAMだったので、1ピクセル(ZXは1ビット/ピクセル)で画像を左右に効果的に動かしていました。
そして私はCFを1回転から他の回転に使用することはできないことを認識していたので、別にビットをマスクして別のレジスタにコピーし、そこから新しいバイトなどに戻します。
私はそれを書き、実行して(バグのためにZXをリセットしました)、バグを修正して実行し、画像がどのように動いているのを見ました... 10倍遅く(毎秒約3フレーム) 「全能高速アセンブリコード」から期待される。その後、私の友人が私にそれを回転させる方法を教えてくれました。コードを20FPSのどこかに走らせました(それでも、私は「高速アセンブリ」でさえ無制限ではなく、私のコードをZXの画面上で見栄えの良いものを入手する)。
'edx'の最大値はいくらですか?左にシフトすると、必要に応じて長さを増やすか、長さを同じにするために結果を切り捨てますか? – user3386109
@ user3386109私は長さを増やす必要があります。 – gigiman
'shld'を使うことができます – harold