C のbit fieldの話です。
実際にどのようなコードになるかはコンパイラ依存になりますが、Cではビットフィールドが定義できます。教科書の例で行くと、
struct { unsigned int ready: 1; unsigned int enable: 1; unsigned int receivedByte: 8; }receiver;
このように定義することで、readyに1bit、enableに1bit、receivedByteに8bit割り当てた構造体を定義できます。符号を考えたくないので、通常はunsigned intを使います。(ちなみにint を与えた場合は実装依存です。)
このように定義された構造体に対して操作を行うと、操作の対象を対応するbitのみにできます。実際に教科書の例を見てみましょう。
int data; struct { unsigned int ready: 1; unsigned int enable: 1; unsigned int receivedByte: 8; }receiver; int main(void){ receiver.receivedByte = 0xE1; /* 追加 */ data = receiver.receivedByte; receiver.ready = 0; receiver.enable = 1; }
receivedByteに何かしらの値を入れないと、何をしている分からないので、0xE1の代入をを追加しました。
gccでコンパイルして、pcspimで動くようにしたアセンブラがこちらです。
.text .align 2 .set nomips16 main: .frame $fp,8,$31 # vars= 0, regs= 1/0, args= 0, gp= 0 .mask 0x40000000,-8 .fmask 0x00000000,0 .set noreorder .set nomacro addiu $sp,$sp,-8 sw $fp,0($sp) move $fp,$sp lw $2, receiver srl $2,$2,22 andi $2,$2,0xff sw $2, data lw $3, receiver li $2, 2147418112 # 0x7fff0000 ori $2, $2,0xffff and $2, $3,$2 sw $2, receiver lw $3, receiver li $2,1073741824 # 0x40000000 or $2, $3,$2 sw $2, receiver move $sp,$fp lw $fp,0($sp) addiu $sp,$sp,8 j $31 nop .data data: .word 0 .data receiver: .word 0
pcspimで実行してみると、このような結果になります。
dataが0xE1になるのは良いのですが、receiverの所には0x78400000という見慣れないパターンが来ています。パタヘネのIn More Depth IMD 2.20-1を見るとビットフィールドとして、このように説明されています。
教科書通りの割り振りなら0xE1, 1, 0の順にビットが並んで0x00000386にならないといけません。なぜ同じにならないかというと、ビットフィールドと実際のメモリ上の割り付けがコンパイラによって違うからです。メモリ上の割り付けを規格で定めていないので、あるコンパイラは使用しているビットを右に詰め、別のコンパイラが違う割り付けをしても全く問題無いわけです。
0x78400000に関してはこの図を見てください。
gccは左(MSB)からビットを割り当てるため、この値になっています。