简体   繁体   English

从寄存器中读取2位

[英]reading 2 bits off a register

I'm looking at a datasheet specification of a NIC and it says: 我正在查看NIC的数据表规范,它说:

bits 2:3 of register contain the NIC speed, 4 contains link state, etc. How can I isolate these bits using bitwise? 寄存器的位2:3包含NIC速度,4包含链接状态等。如何使用按位隔离这些位?

For example, I've seen the code to isolate the link state which is something like: 例如,我已经看到了隔离链接状态的代码,如下所示:

(link_reg & (1 << 4))>>4 (link_reg&(1 << 4))>> 4

But I don't quite get why the right shift. 但我不明白为什么正确的转变。 I must say, I'm still not fairly comfortable with the bitwise ops, even though I understand how to convert to binary and what each operation does, but it doesn't ring as practical. 我必须说,即使我理解如何转换为二进制以及每个操作的作用,我仍然对bitwise操作不太满意,但它并不像实际那样响。

It depends on what you want to do with that bit. 这取决于你想用这个位做什么。 The link state, call it L is in a variable/register somewhere 链接状态,称之为L在某个变量/寄存器中

    43210
xxxxLxxxx

To isolate that bit you want to and it with a 1, a bitwise operation: 要使用1,按位运算来隔离您想要的那个位:

  xxLxxxx
& 0010000
=========
  00L0000

1<<4 = 1 with 4 zeros or 0b10000, the number you want to and with. 1 << 4 = 1,带有4个零或0b10000,您想要和的数字。

status&(1<<4) 

This will give a result of either zero or 0b10000. 这将产生零或0b10000的结果。 You can do a boolean comparison to determine if it is false (zero) or true (not zero) 您可以进行布尔比较以确定它是假(零)还是真(非零)

if(status&(1<<4))
{
   //bit was on/one
}
else
{
   //bit was off/zero
}

If you want to have the result be a 1 or zero, you need to shift the result to the ones column 如果要将结果设为1或0,则需要将结果移至1列

  (0b00L0000 >> 4) = 0b0000L

If the result of the and was zero then shifting still gives zero, if the result was 0b10000 then the shift right of 4 gives a 0b00001 如果和的结果为零,则移位仍为零,如果结果为0b10000,则右移4为0b00001

so 所以

(status&(1<<4))>>4 gives either a 1 or 0;

(xxxxLxxxx & (00001<<4))>>4 =
(xxxxLxxxx & (10000))>>4 = 
(0000L0000) >> 4 = 
0000L

Another way to do this using fewer operations is 使用较少操作的另一种方法是

(status>>4)&1;
xxxxLxxxx >> 4 = xxxxxxL
xxxxxxL & 00001 = 00000L

Easiest to look at some binary numbers. 最容易看一些二进制数。

Here's a possible register value, with the bit index underneath: 这是一个可能的寄存器值,下面是位索引:

  00111010
  76543210

So, bit 4 is 1. How do we get just that bit? 所以,第4位是1.我们怎么得到这一点? We construct a mask containing only that bit (which we can do by shifting a 1 into the right place, ie 1<<4 ), and use & : 我们构造一个仅包含该位的掩码 (我们可以通过将1移动到正确的位置来做,即1<<4 ),并使用&

  00111010
& 00010000
----------
  00010000

But we want a 0 or a 1. So, one way is to shift the result down: 00010000 >> 4 == 1 . 但我们想要0或1.因此,一种方法是将结果向下移动: 00010000 >> 4 == 1 Another alternative is !!val , which turns 0 into 0 and nonzero into 1 (note that this only works for single bits, not a two-bit value like the link speed). 另一种选择是!!val ,它将0变为0,非零变为1(注意,这仅适用于单个位,而不是像链接速度那样的两位值)。

Now, if you want bits 3:2, you can use a mask with both of those bits set. 现在,如果你想要位3:2,你可以使用掩码同时设置这两个位。 You can write 3 << 2 to get 00001100 (since 3 has two bits set). 你可以写3 << 2来获得00001100 (因为3有2位设置)。 Then we & with it: 然后我们&它一起:

  00111010
& 00001100
----------
  00001000

and shift down by 2 to get 10 , the desired two bits. 然后向下移动2得到10 ,即所需的两位。 So, the statement to get the two-bit link speed would be (link_reg & (3<<2))>>2 . 因此,获得两位链接速度的语句将是(link_reg & (3<<2))>>2

you can use this to determine if the bit at position pos is set in val : 你可以使用它来确定位置pos的位是否设置在val

#define CHECK_BIT(val, pos) ((val) & (1U<<(pos)))

if (CHECK_BIT(reg, 4)) {
    /* bit 4 is set */
}

the bitwise and operator (&) sets each bit in the result to 1 if both operands have the corresponding bit set to 1. otherwise, the result bit is 0. 如果两个操作数都将相应的位设置为1,则按位和运算符(&)将结果中的每个位设置为1.否则,结果位为0。

If you want to treat bits 2 and 3 (starting the count at 0) as a number, you can do this: 如果要将位2和3(从0开始计数)视为数字,则可以执行以下操作:

unsigned int n = (link_get & 0xF) >> 2;

The bitwise and with 15 (which is 0b1111 in binary) sets all but the bottom four bits to zero, and the following right-shift by 2 gets you the number in bits 2 and 3. 按位和15(二进制为0b1111)将除了底部四位之外的所有位设置为零,并且随后的右移2将获得位2和3中的数字。

The problem is that isolating bits is not enough: you need to shift them to get the correct size order of the value. 问题是隔离位是不够的:您需要移动它们以获得值的正确大小顺序。

In your example you have bit 2 and 3 for the size (I'm assuming that least significant is bit 0), it means that it is a value in range [0,3]. 在您的示例中,您有第2位和第3位的大小(我假设最低有效位是位0),这意味着它是范围[0,3]中的值。 Now you can mask these bits with reg & (0x03<<2) or, converted, (reg & 0x12) but this is not enough: 现在,您可以使用reg & (0x03<<2)或转换(reg & 0x12)来屏蔽这些位,但这还不够:

reg   0110 1010 &
0x12  0000 1100
---------------
0x08  0000 1000

As you can see the result is 1000b which is 8, which is over the range. 如您所见,结果是1000b ,即8,超出范围。 To solve this you need to shift back the result so that the least significant bit of the value you are interested in corresponds to the least significant bit of the containing byte: 要解决此问题,您需要移回结果,以便您感兴趣的值的最低有效位对应于包含字节的最低有效位:

0000 1000 >> 2 = 10b = 3

which now is correct. 现在是正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM