Closed. This question needs to be more focused。它当前不接受答案。












想改善这个问题吗?更新问题,使其仅关注editing this post一个问题。

4年前关闭。



Improve this question




最近,我们有了一个使用模板为裸机开发创建通用的高性能抽象的想法。

通常每个芯片制造商都提供如下的C header :
//Following structure is POD so we can rely on its memory layout
struct Periphery{
  volatile uint32_t reg1;
  volatile uint32_t reg2;
};

#define PERIPHERY0BASE 0x000000ab //address where does registers of periphery start
#define PERIPHERY1BASE 0x000000cd
static Periphery* PERIPHERY0 = (Periphery*)(PERIPHERY0BASE );
//or
#define PERIPHERY1 (Periphery*)(PERIPHERY1BASE )

我们的想法是然后创建特定于平台但对于给定外围类型通用的驱动程序:
template<int addr>
PeripheryDriver{
  static inline void doSomething(int foo){
    (PERIPHERY0*)(addr)->reg1 = foo;
  }
}
 //typedefs for different peripheries of the same type
typedef Periphery<PERIPHERY0BASE> Periphery0;
typedef Periphery<PERIPHERY1BASE> Periphery1;

然后将其用于独立于平台的模块,如下所示:
template<class P>
class DriverUser{
  DriverUser(){
    P::doSomething(0x00);
  }
};

所有这些的要点是我们可以在一个平台上从单个外围设备进行抽象,从而为具有相同结构的所有外围设备(例如定时器,Uarts等)创建通用驱动程序。此外,它还允许我们创建与平台无关的高性能模块,例如,我们可以创建高性能的引脚访问方式,该访问方式与汇编程序中编写的功能一样高效,但同时具有高度可重用性:
//normally would be in PCB specific header
typedef Pin<Port0, Pin0> Pin0;
typedef Pin<Port1, Pin7> Pin1;

//application specific code
typedef Pin0 TxPin;
typedef Pin1 RxPin;

void main(){
  SoftwareUart<TxPin,RxPin> my_uart(115200);
  my_uart.send("hello world");
}

这样就可以实现完全独立于平台的SoftwareUart,而在不使用宏的情况下,向TxPin写入High就像在汇编程序中一样高效。

我们的问题是,在某些平台上,制造商的 header 不包含
宏将为地址定义名称,但只能定义地址已转换为指针的宏,因此我们不能将其用作模板参数。
例如,PERIPHERY0BASE不适用于PERIHPERY0

我的问题是是否有任何解决方法可以保持效率?(重写寄存器定义除外)
在C++ 11中,我想使用constexpr创建函数,该函数将获取静态结构的地址,然后将其用作模板参数。不幸的是,我们不能指望C++ 11的可用性。有任何想法吗?我们是否需要修改/编写我们自己的寄存器定义?

最佳答案

抱歉,但是很难理解您的实际需求。如果我对您的理解正确,那么您需要一种通用的方法来从第三方 header 提供的指针中获取特定结构中的偏移量(假设您知道结构的对齐方式)。
如果您声称可以使用C++ 11 constexpr函数实现目标,请尝试对C++ 03使用模板。

我想您需要引入一个高级包装器,将指针转换为偏移量:

template <typename T, T ptr, unsigned TAlignmentMask>
struct AddrRetriever
{
    static const int value = (int)ptr & TAlignmentMask;
}

然后使用:
typedef Periphery<
    AddrRetriever<
        volatile void*, // use the type of the pointer vendor provides
        PTR_FROM_VENDOR,
        KNOWN_ALIGNMENT_MASK>::value
 > Periphery0;

作为附带说明,我建议阅读Practical Guide to Bare Metal C++。它将为您提供一些实现通用异步计时器,uart和其他外围设备的想法,如您所愿。

10-05 17:42