【问题标题】:Faking register reads in C在 C 中伪造寄存器读取
【发布时间】:2011-07-28 20:14:22
【问题描述】:

我有一个没有操作系统的嵌入式系统的现有代码库。我试图让它使用 x86 gcc 而不仅仅是交叉编译器来构建,作为能够在主机上进行单元测试的第一步。不幸的是,到处都是直接的寄存器读写,而不是使用提供的抽象层。当然,一种选择是解决这个问题;将直接寄存器访问替换为对 GPIO 访问函数的调用。我希望通过引入一个宏(仅在 x86 构建中使用)来重新定义代码片段,例如

myvar = (GPIOC->IDR >> 6) & 0x03;   // Read bits 6 and 7
GPIOD->CRL &= 0xFFFFFF0F;

类似于:

myvar = (myGpiocIdrReadFunc() >> 6) & 0x03;   // Read bits 6 and 7
myGpiodClrWriteFunc() &= 0xFFFFFF0F;

GPIOx 被#定义为指向物理地址的指针。当然,如果我尝试使用 x86 构建的可执行文件直接读取和写入我的 PC 上的地址,那将是访问冲突。不幸的是,如果我尝试这样的事情:

#define GPIOC->IDR { myGpiocIdrReadFunc() }

编译器不喜欢那个“->”,说“宏名后面缺少空格。”

如果你以前解决过这类问题,你是怎么解决的?

【问题讨论】:

  • 我认为目标不仅仅是盲目地让I/O“成功”,而是让这种I/O产生副作用?否则,您可以只使用带有 CRL 元素的结构 (GPIOD)。
  • @Yann:我将发布相同的(re:structs)作为答案,如果你发布一个,我会为你的答案 +1。
  • 同意@Yann:你是要模拟硬件还是只是想忽略它?你知道,通常它实际上会做一些事情。
  • 我希望能够设置“读取”值并检索“写入”值。

标签: c macros embedded arm cpu-registers


【解决方案1】:
typedef struct {
    int IDR;
    int CRL;
} gpio_t;

gpio_t c;
gpio_t d;

gpio_t * GPIOC = &c;
gpio_t * GPIOD = &d;

当编译器向你发出尖叫时,继续将IDR 之类的寄存器添加到struct

编辑在看到您实际上想要模拟值的评论后,我编辑了答案,您可以这样做,但请记住,您需要像在硬​​件中一样初始化它们。

【讨论】:

    【解决方案2】:

    您似乎是在从字面上替换源中的那个字符串之后。你为什么不直接用像sed 这样的非交互式编辑器来做呢?您可能有一个构建系统,它可以根据架构进行替换。

    【讨论】:

    • 哦,当然...定义我自己的抽象函数,当为目标构建时,执行实际的读取和写入,当为 x86 构建时,执行我想要的。我希望避免修改原始源代码,因为我还没有访问目标硬件的权限以确保我不会破坏任何东西,但请小心,这可能是正确的方法。
    【解决方案3】:

    如果来自 hexa 的解决方案不够充分,这里有第二个选项,它允许您实际模拟所引用的寄存器的行为(包括副作用等)。不利的一面是,这需要 C++(并且您现有的 C 代码可以编译为 C++,这通常是一个困难的要求),并且结构不直接使用本机类型,而是使用一些别名。

    您可以定义一个实现operator=operator int 以及您可能需要的任何其他访问功能(&= 等)的类。如果 struct GPIOC 指向的字段属于您可以更改的类型,那么您可以简单地更改该类型以引用您的寄存器类。

    大概是这样的:

    #ifdef USE_REAL_HW
    
    typedef volatile uint32_t HW_REGISTER32;
    
    #else // (USE_REAL_HW not defined)
    
    template<class T>
    class RegisterAbstractionClass {
    public:
        const T operator= (const T value) {
            data = value;
            return value;
        };
        operator const T() {
            return data;
        };
        // Other operators...
    protected:
        volatile T data;
    };
    
    typedef RegisterAbstractionClass<uint32_t> HW_REGISTER32;
    
    #endif // (USE_REAL_HW)
    
    typedef struct {
        HW_REGISTER32 IDR;
        HW_REGISTER32 CRL;
    } gpio_t;
    

    (请注意,上面的内容有些简化:IDRCRL 在这种情况下的行为相同,而硬件可能并非如此。)

    【讨论】:

      【解决方案4】:

      您的#define 似乎是错误的。为您的测试系统上的宏尝试“#define MyGpiocIdrReadFunc() x86ReadFunc()”。当然,您需要用 MyGpiocIdrReadFunc() 替换来自 GPIOC->IDR 的所有读取。您还需要实现该功能。这可能与修复代码以使用您提到的抽象层一样多。

      【讨论】:

        【解决方案5】:

        我认为这并不容易。

        请注意,SFR 通常是volatile,并且许多算术运算都是原子的。所以,代码

        GPIOD->CRL &= 0xFFFFFF0F;
        

        不等于

        setter(CLR_reg, getter(CLR_reg) & 0xFFFFFF0F);
        

        另外请注意,可能存在一个忙于等待中断的循环,甚至是中断处理程序。

        【讨论】:

        • 这无济于事。他试图伪造它。
        • 你说的很对。也许我可以用我自己的抽象函数替换所有直接寄存器访问,然后为交叉构建#define 这些函数调用回到直接访问......呃。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-02
        • 1970-01-01
        • 2013-01-19
        • 1970-01-01
        • 2012-06-15
        • 1970-01-01
        • 2013-11-22
        相关资源
        最近更新 更多