从寄存器中读取2位

时间:2012-10-17 03:28:35

标签: c bit-manipulation

我正在查看NIC的数据表规范,并说:

寄存器的2:3位包含NIC速度,4包含链接状态等。如何使用按位隔离这些位?

例如,我已经看到了隔离链接状态的代码,如:

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

但我不明白为什么正确的转变。我必须说,即使我理解如何转换为二进制文件以及每个操作的作用,我对bitwise运算仍然不太满意,但它并不像实际那样响。

5 个答案:

答案 0 :(得分:2)

这取决于你想用这个位做什么。链接状态,称之为L在一个变量/寄存器

    43210
xxxxLxxxx

要隔离您想要的位,并使用1,按位操作:

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

1<<< 4 = 1,带有4个零或0b10000,您想要和的数字。

status&(1<<4) 

这将产生零或0b10000的结果。您可以进行布尔比较以确定它是假(零)还是真(非零)

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

如果您希望结果为1或0,则需要将结果移至1列

  (0b00L0000 >> 4) = 0b0000L

如果和的结果为零,则移位仍为零,如果结果为0b10000,则右移4为0b00001

所以

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

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

使用更少操作执行此操作的另一种方法是

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

答案 1 :(得分:1)

最容易查看一些二进制数字。

这是一个可能的寄存器值,位索引在下面:

  00111010
  76543210

所以,第4位是1.我们怎么得到这一点?我们构造一个只包含该位的掩码(我们可以通过将1移到正确的位置来做,即1<<4),然后使用&

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

但我们想要一个0或1.因此,一种方法是将结果向下移动:00010000 >> 4 == 1。另一个替代方案是!!val,它将0变为0,非零变为1(请注意,这仅适用于单个位,而不是像链接速度那样的两位值。)

现在,如果你想要比特3:2,你可以使用掩码同时设置这两个比特。您可以编写3 << 2来获取00001100(因为3设置了两个位)。然后我们&用它:

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

并向下移2以得到10,即所需的两位。因此,获得两位链接速度的语句将是(link_reg & (3<<2))>>2

答案 2 :(得分:0)

您可以使用它来确定位置pos中的位是否设置在val中:

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

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

如果两个操作数都将相应的位设置为1,则按位和运算符(&amp;)将结果中的每个位设置为1.否则,结果位为0.

答案 3 :(得分:0)

如果您想将第2位和第3位(从0开始计数)视为数字,您可以这样做:

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

bitwise和15(二进制为0b1111)将除了底部四位之外的所有位设置为零,并且随后的右移2将获得位2和3中的数字。

答案 4 :(得分:0)

问题是隔离位是不够的:您需要移动它们以获得值的正确大小顺序。

在您的示例中,您有第2位和第3位的大小(I&#39; m假设最低有效位是位0),这意味着它是范围[0,3]中的值。现在,您可以使用reg & (0x03<<2)或转换后的(reg & 0x12)屏蔽这些位,但这还不够:

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

如您所见,结果是1000b,即8,超出了范围。要解决此问题,您需要移回结果,以便您感兴趣的值的最低有效位对应于包含字节的最低有效位:

0000 1000 >> 2 = 10b = 3

现在是正确的。