1

誰かが循環バッファインデックスの観点からビットマスキングがどのように機能するかを説明できますか?具体的には、次のコードで:

#define USART_RX_BUFFER_SIZE 128     /* 2,4,8,16,32,64,128 or 256 bytes */
#define USART_RX_BUFFER_MASK ( USART_RX_BUFFER_SIZE - 1 )


    ISR(USART_RX_vect)
    {
        unsigned char data;
        unsigned char tmphead;

        /* Read the received data */
        data = UDR0;
        /* Calculate buffer index */
        tmphead = ( USART_RxHead + 1 ) & USART_RX_BUFFER_MASK;
        USART_RxHead = tmphead;      /* Store new index */

        if ( tmphead == USART_RxTail )
        {
            /* ERROR! Receive buffer overflow */
        }

        USART_RxBuf[tmphead] = data; /* Store received data in buffer */
    }

インデックスをビットマスキングした結果、インデックスがラップアラウンドすることはわかっています。私の質問はなぜですか?また、なぜ「USART_RX_BUFFER_SIZE」は2の累乗でなければならないのですか?

ありがとうございました

ジョー

4

2 に答える 2

5

これを理解するには、いくつかのバイナリを理解する必要があり、バイナリ演算を理解する必要があります。

ご存知かもしれませんが、コンピューター内のすべてのものは、1と0のシーケンスである2進数で格納されます。これは、理論的には、メモリ内の任意のデータ文字列を数値として扱うことができることを意味します。あなたのコードはusinなのでchar、私はそれらに焦点を合わせます。

Cでは、charsは符号付きまたは符号なしのいずれかです。これには、符号なしを使用することが重要です。2の補数表現については説明しませんが、signedを使用すると壊れてしまうと言えば十分ですchar。Acharは1バイトであり、通常は次のように8ビットと見なされます。

00000000 -> 0
00001001 -> 9

基本的に、各ビットは2の累乗を表します(ここではMSBを最初に使用しています)。したがって、2番目の数値は2^1 + 2^3 = 1 + 8 = 9です。したがって、配列にインデックスを付けるためにどのように使用できるかがわかります。

ビット単位の演算は、一部のデータの個々のビットを操作します。この場合、バイナリ( )を使用しており、バイナリ&適用する動作はビットマスキングと呼ばれます。

data   - 00101100
mask   - 11110110
       ----------
result - 00101100

ご覧のとおり、結果のビットは1に設定されており、dataとの両方maskが1になっています。

次に、バイナリ表現に戻ります。各ビットは2の累乗であるため、2進数の2の累乗は、0の1つを使用して表すことができます。

01000000 - 64

そして、ちょうど63のよう1000 - 1 = 999に。01000000 - 1 = 0011111100111111

これを使用すると、次のインデックスを作成するときに、次の操作を実行することがわかります。

(a + 1) & 00111111

aが(たとえば)10の場合、次のようになります。

(00001010 + 1) = 00001011 (11)
 00001011 & 00111111 = 00001011

したがって、マスキングは変更されませんでしたが、63の場合:

(00111111 + 1) = 01000000 (64)
 01000000 & 00111111 = 00000000 (0)

したがって、64(65番目の要素であるためエラー)にインデックスを付けようとするのではなく、最初に戻ります。

これが、バッファサイズが2の累乗でなければならない理由です。そうでない場合、マスクは適切に計算されず%、ビットマスキングではなく、モジュロ()または比較を使用する必要があります。ほとんどのプロセッサでは通常単一の命令であり、&必要なサイクルが非常に少ないことを考えると、ビット演算子は非常に高速であるため、これは重要です。モジュロは単一の命令である場合がありますが、おそらく整数除算であり、ほとんどのプラットフォームでは従来、非常に低速です。また、比較には、いくつかの命令、レジスタ、および少なくとも1つのジャンプが必要になります。

于 2012-07-23T06:11:29.180 に答える
-1

ジョンは書いた:

モジュロについての2番目のコメントですが、マイクロでは、if(a> b)a / = MODULUSよりも「a%=MODULUS」の実行に10〜20倍の時間がかかることがわかりました。–ジョンU2012年8月3日17:01

しかし、まだ除算があります:a / = MODULUSであるため、効率はモジュロ演算と同じです。

于 2013-01-02T22:54:40.800 に答える