簡體   English   中英

如何分配給 C++ volatile 結構?

[英]How to assign to a C++ volatile struct?

對於硬件驅動程序,我需要一種將 8 x uint32_t 的 C++ 結構寫入 8 個連續 32 位硬件寄存器塊的方法。 這是我的代碼:

#include "stdint.h"

typedef struct
{
    uint32_t a[8];
} TCmd;

class MyClass {
    public:
        void writeCommandBlock( TCmd* ap_src)
        
        {
             TCmd * p_dest = reinterpret_cast< TCmd*>(0x40080000); // base register address
             *p_dest = *ap_src;
        }
};

int main()
{
    MyClass m;

    TCmd cmd;
    cmd.a[0] = 12;

    m.writeCommandBlock(&cmd);
}

(實際的結構將具有位域,並且寄存器地址將由常量定義)。

我想使用一個簡單的賦值運算符(如上所示):

*p_dest = *ap_src;

因為我正在使用 ARM Cortex M4 處理器並希望使用 ldm/stm 指令,從而產生如下內容:

        ldr     r1, [sp, #4]
        ldr     r0, [sp]
        ldm     r1!, {r2, r3, r12, lr}
        stm     r0!, {r2, r3, r12, lr}
        ldm     r1, {r2, r3, r12, lr}
        stm     r0, {r2, r3, r12, lr}

這應該比 memcpy 等更快。

當我啟用優化時問題就來了 - 分配被優化了。 所以我將 p_dest 聲明為 volatile:

volatile TCmd * p_dest = reinterpret_cast< TCmd*>(0x40080000);

但賦值行隨后給出錯誤:

<source>:16:21: error: no viable overloaded '='
            *p_dest = *ap_src;
            ~~~~~~~ ^ ~~~~~~~
<source>:3:9: note: candidate function (the implicit copy assignment operator) not viable: 'this' argument has type 'volatile TCmd', but method is not marked volatile
typedef struct
        ^
<source>:3:9: note: candidate function (the implicit move assignment operator) not viable: 'this' argument has type 'volatile TCmd', but method is not marked volatile
1 error generated.
Compiler returned: 1

請問我該如何解決這個問題?

我假設您不希望 TCmd 易失,因此構建它的速度很快,並且只有對硬件寄存器的最終提交應該是易失的。

這個怎么樣:

#include <cstdint>
#include <array>
#include <algorithm>

using TCmd = std::array<uint32_t, 8>;

class MyClass {
    public:
        void writeCommandBlock(const TCmd & ap_src) 
        {
             volatile uint32_t * p_dest = reinterpret_cast<volatile uint32_t *>(0x40080000); // base register address
             std::copy(&ap_src[0], &ap_src[ap_src.size()], p_dest);
        }
};

int main()
{
    MyClass m;

    TCmd cmd;
    cmd[0] = 12;

    m.writeCommandBlock(cmd);
}

注意:使用 gcc 和 -O2 這會變成一個循環,使用 -O3 會展開為 8 個加載和存儲。 但循環似乎是更可取的代碼。

雖然ldm操作碼可能更可取,但我相信stm寄存器上的 stm 是未定義的。 至少在 RaspberryPI 之類的設備上,設備接口非常脆弱,可能會做錯事。

您可能還應該在寫入之后添加一個內存屏障,以確保它確實發生並完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM