内存映射 C++ 对象非硬件成员

Memory-mapped C++ objects non hardware members

我正在使用 C++ 为一块内存映射硬件开发一个驱动程序,我定义了一个代表该设备的 class。它看起来像这样:

class device
{
method1();
method2();

private:
device_register reg1;
device_register reg2;

}

class 有两个文件:device.cpp 和 device.h。成员变量表示设备本身的实际寄存器。现在我想定义更多不是设备本身实际寄存器的成员,但我不能在 class 内定义它们,因为如果我这样做,它们将在设备的内存映射位置定义,其中可能包含其他 devices/registers。如果我将它们定义为 public,那会破坏标准布局并且 class 将不再起作用。

所以我所做的是将它们定义为 class 定义之外的全局变量。问题是如果我定义了多个对象,它们都会共享这些全局变量,但我希望每个对象都有自己的,我该怎么做?

也许您可以使用单独的 class 和指向当前“设备”的指针


class device_glob {

private :
  device * mmaped_device;
  int other_attrib;
};

你可以在映射位置分配ctor中的设备。然后您需要将其集成到您正在使用的任何注册表系统中,以便 references/pointers 当前进入设备。

您应该为寄存器创建一个单独的 POD(普通旧数据)结构,因为即使不添加额外的数据成员,非 POD class/struct 也可能会破坏您的内存映射。在 POD 类型中,第一个数据成员的偏移量保证为 0,这正是您所需要的。在非 POD 类型中,并不总是遵循此合同,例如它可能会被 vtables 或 RTTI 中断。的确,您可以尽职尽责地避免仅更改会更改第一个数据成员的偏移量的更改,但更可靠的解决方案是坚持所有 POD 要求,以便标准要求您的编译器执行您想要的操作。

可以在 cppreference here 中找到对 POD 类型的要求,但一个简单的助记符是,除了原生类型成员之外什么都没有的结构将始终是 POD。

您还应该确保寄存器被标记为“volatile”,尽管我有一种预感,如果您已经有一个特殊的“device_register”typedef,它包含一个 volatile 说明符。在这种情况下,您不需要在自己的结构中添加一个额外的结构。

示例:

struct MyPeripheralRegisters
{
volatile device_register reg1;
volatile device_register reg2;
};

class MyPeripheralDriver
{
private:
  MyPeripheralRegisters* hardware = MY_MEMORY_MAPPED_ADDR;
  int my_private_state;
public:
  void method1();
  void method2();
};

这种内存映射组件的模式在嵌入式驱动库中经常使用,所以它有最小惊讶原则。