15

我已经对位可寻址微控制器进行了一些研究。在我的路径中遇到的唯一一个是英特尔 MCS-51(维基页面),它今天仍然非常常用......我想知道你是否可以直接在 C 中解决一些问题,例如在 SFR 区域wiki 8051内存架构

我在 SFR 中寻址的位,它们是直接位寻址的,还是字节寻址的位域中的按位运算,或者完全是别的什么?

具体来说,从这里开始:检查是否设置了单个位,看起来该位是直接用 MOV 操作的,我想知道这在 C(带扩展名)中是否可行,或者它只是看起来像按位运算,但在背景有一些只使用字节的编译器吗?

作为后续问题,是否有任何可寻址的现代处理器?

4

6 回答 6

9

在纯 C 中(没有任何扩展,无论它们是什么),您可以将变量声明为位字段。它可以节省大量打字时间,并且不易出错。

这是一个示例程序。它使用具有相同大小的常规类型的联合声明一个位字段。

#include <stdio.h>

int main(int argc, char *argv[])
{
    typedef struct 
    {
        union
        {
            struct {
                int bit0:1;
                int bit1:1;
                int bit2:1;
                int bit3:1;
                int bit4:1;
                int bit5:1;
                int bit6:1;
                int bit7:1;
            };
            unsigned char byte;
        };
    } EigthBits;

    EigthBits b;

    b.byte = 0;
    printf("Will be 0 ==> %d\n", b.byte);

    b.bit4 = 1;
    printf("Will be 16 ==> %d\n", b.byte);
}

将打印此输出:

    将是 0 ==> 0
    将是 16 ==> 16

例如,将值设置为控制寄存器上的各个位很有用。您可以设置更多位(如int two_bits:2;)以满足您的需要。

于 2012-04-10T02:42:31.910 回答
8

这并不少见。例如,SDCC(小型设备 C 编译器)是 MCS-51 的流行编译器。您可以在此处找到手册。最相关的部分是 3.4.1,它描述了 MCS-51 的语言扩展:

3.4.1.6 __bit

这是一个数据类型和一个存储类说明符。当一个变量被声明为位时,它被分配到 8051 的位可寻址内存中,例如:

 __bit test_bit;

向该变量写入 1 会生成汇编代码:

 D2*00 setb _test_bit

位可寻址存储器由 128 位组成,位于数据存储器中从 0x20 到 0x2f 的位置。除了这个 8051 特定的存储类之外,大多数架构都支持 ANSI-C 位域4。根据 ISO/IEC 9899 位和没有显式带符号修饰符的位域被实现为无符号。

于 2012-04-10T02:44:12.300 回答
6

在 C 中,您通常读取一个字节,然后屏蔽您想要的位,但某些特定于处理器的编译器会为您预定义寄存器甚至单独的位。例如,Keil Cx51 User's Guide 定义了bitsfr数据类型。

你会使用这样的sfr类型:

sfr P0 = 0x80;    // Port 0 is accessed at address 80h.
P0 = 0x20;        // Write 20h to Port 0.

要使用 byte-at-a-time 方法,您需要执行以下操作:

#define SFR (* (unsigned char *) 0x80)  // Address of SFR is 0x80.

#define BIT0 0x01  // LSB of any byte
#define BIT1 0x02
#define BIT2 0x04
. . .
#define BIT7 0x80  // MSB of any byte

// Read BIT1 of SFR. sfrBit1 is 1 if BIT1 is set, 0 if not.
unsigned char sfrBit1 = SFR & BIT1  ?  1 : 0;

// Set BIT0 of SFR.
SFR |= BIT0;

// Clear BIT2 of SFR.
SFR &= ~BIT2;

为方便起见,您可以定义实用程序宏来设置和清除各个位:

#define SET(reg, bit) reg |=  (1 << bit)  // Sets a bit in reg.
#define CLR(reg, bit) reg &= ~(1 << bit)  // Clears a bit in reg.

SET(SFR, 1); // Set BIT1 
CLR(SFR, 2); // Clear BIT2
于 2012-04-10T02:18:15.100 回答
2

处理器 8051 定义了一些指令来寻址单个位以清除为 0、设置为 1 或测试该值,如果该位被设置或清除,则在条件分支之后绕过以下代码。

这些指令非常有效,仅使用 2 个字节。第一个字节定义指令,第二个字节是操作数,用于标识要使用的位,总共 256 位。

前 128 位引用 16 个 SFR 字节(地址 0x80 的位 0 至 7 用于 P0,位 8 至 15 用于 SFR 的地址 0x88 用于 P1,等等,直到位 120 至 127 用于 SFR 0xF8)。

接下来的 128 位,如上面 Hans Pasant 所述,引用 0x20 和 0x2F 之间的 16 字节内部 RAM。

8051实际上读取整个字节,测试,设置或清除指定位并将所有8位写回同一位置(测试除外)。除了高效之外,这些指令也不会修改任何寄存器,例如 R0 到 R7、累加器等。

C 编译器可以轻松接受超过 128 个“__bit”变量,并用大多数人描述的经典二进制掩码操作替换上面提到的高效汇编代码。但是,Keil 编译器实现的最简单的解决方案是在使用超过 128 位变量时声明错误。

有一些 DSP 和图形处理器可以处理指定的位数。这在编写高效的压缩算法、一些绘图例程等时非常有用。例如,德州仪器 (TI) 的 TMS34010 可以为每个存储器访问定义两组使用不同位数的寄存器。例如,循环可以使用第一组中的寄存器一次读取 3 位,并使用第二组中的寄存器写入 11 位。在内部,内存控制器仍在读取 16 位,并回写 16 位,并且仅修改每个 16 位字内的指定位数。所有的内存操作都在引用一个位,而不是一个字。例如,程序计数器在执行每条指令时增加 16。如果低位不为零,硬件将创建异常,

The inventors of the C language predicted that one day there could be some processor which could be bit addressable. They explained that the current restriction of reading/writing an entire word when using the bit structures (as described by Ixe013) could be lifted in the future. Unfortunately, the bit addressable processors did not gain much attention in the software world.

于 2013-02-04T12:41:52.740 回答
1

在“C(带扩展)”中一切皆有可能,因为带扩展的 C 可以是任何方言,为您带来相当于天上馅饼的编程。

在 ISO 标准 C 中,最小的单独可寻址存储单元是字节,由字符类型表示。

通过访问周围位的整个单元来执行对位(甚至结构的位字段成员)的访问。

如果处理器可以寻址位,那么可能的一种方法是通过 C 编译器的内联汇编语言,如果它有这样的东西。或外部链接的汇编语言例程。

于 2012-04-10T02:19:02.587 回答
1

这取决于您的意思,即“解决方法”。编写一些将执行此类操作set_bit(address, bit, value)的函数没有问题。get_bit(address, bit, value)但是至少get_bit会返回一个字节。char

字节寻址限制自然来自大多数现代计算机使用的硬件。这与硬盘驱动器的 512 字节扇区非常相似,这是读取或写入的最小 IO 操作。然而,这并不能阻止您向其写入单个字节和位。

于 2012-04-10T02:26:10.680 回答