2

PCIバスを介してVMEブリッジチップ(Tundra Universe II)への32ビット未満の読み取りを実行しようとしています。VMEブリッジチップはVMEバスに接続され、ターゲットによってピックアップされます。

ターゲットVMEアプリケーションはD32(32ビットのデータ幅読み取り)のみを受け入れ、それ以外は無視します。

VMEウィンドウにマップされたビットフィールド構造を使用する場合(メインメモリにnmapされます)、24ビットを超えるビットフィールドを読み取ることができますが、それ以下のものは失敗します。すなわち:-

struct works {
    unsigned int a:24;
};

struct fails {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct main {
    works work;
    fails fail;
}
volatile *reg = function_that_creates_and_maps_the_vme_windows_returns_address()

これは、構造体が32ビットとして読み取られることを示していますがたとえばreg-> fail.aの構造体を介した読み取りが失敗すると、Xビットの読み取りに因数分解されます。(Xは16または8の場合がありますか?)

したがって、質問は次のとおり
です。a)これはどこで縮小されますか?コンパイラ?OS?またはツンドラチップ?
b)実行された読み取り操作の実際のサイズはどれくらいですか?

私は基本的にチップ以外のすべてを除外したいと思います。そのドキュメントはWeb上にありますが、PCIバスを介して要求されたデータ幅が32ビットであることが証明できる場合、問題はTundraチップのせいにすることができます。

編集:-
具体的な例、コードは次のとおりです:-

struct SVersion
{
    unsigned title         : 8;
    unsigned pecversion    : 8;
    unsigned majorversion  : 8;
    unsigned minorversion  : 8;
} Version;

だから今私はこれに変更しました:-

union UPECVersion
{
    struct SVersion
    {
        unsigned title         : 8;
        unsigned pecversion    : 8;
        unsigned majorversion  : 8;
        unsigned minorversion  : 8;
    } Version;
    unsigned int dummy;
};

そして、基本の主な構造体:-

typedef struct SEPUMap
{
    ...
    ...
    UPECVersion PECVersion;

};

だから私はまだすべてのベースラインコードを変更する必要があります

// perform dummy 32bit read
pEpuMap->PECVersion.dummy;

// get the bits out
x = pEpuMap->PECVersion.Version.minorversion;

また、元のコードのように、2回目の読み取りで実際に実際の読み取りが再度行われないかどうかをどのように知ることができますか?(ユニオンを介してすでに読み取られたビットを使用する代わりに!)

4

9 に答える 9

2

の値が気になりますsizeof(struct fails)。1ですか?この場合、 へのポインターを逆参照して読み取りを実行するとstruct fails、VME バスで D8 読み取りを発行するのが正しいように見えます。

にフィールドを追加してみることができunsigned int unused:29;ますstruct fails

于 2009-12-04T13:42:08.360 に答える
1

Ian - 読み書きするもののサイズを確認したい場合は、このような構造体を使用しないことをお勧めします - 失敗した構造体のサイズはわずか 1 バイトである可能性があります - コンパイラは無料です最適化などに基づいて何をすべきかを決定する-intまたは一般的にサイズを保証する必要があるものを使用して明示的に読み取り/書き込みを行い、次に、持っていないユニオン/構造体に変換するなどの他のことを行うことをお勧めしますそれらの制限。

于 2009-12-04T13:42:50.883 に答える
1

たとえば、Linux カーネルには、メモリ マップド IO の読み取りと書き込みを明示的に処理するインライン関数があります。新しいカーネルでは、インライン アセンブリ命令に要約される大きなマクロ ラッパーですmovlが、古いカーネルでは次のように定義されていました。

#define readl(addr) (*(volatile unsigned int *) (addr))
#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
于 2009-12-04T17:02:05.083 に答える
1

前に説明した gcc フラグ -fstrict-volatile-bitfields を使用し、ビットフィールド変数を volatile u32 として定義する方法は機能しますが、定義されるビットの総数は 16 より大きくなければなりません。

例えば:

typedef     union{
    vu32    Word;
    struct{
        vu32    LATENCY     :3;
        vu32    HLFCYA      :1;
        vu32    PRFTBE      :1;
        vu32    PRFTBS      :1;  
    };
}tFlashACR;
.
tFLASH* const pFLASH    =   (tFLASH*)FLASH_BASE;
#define FLASH_LATENCY       pFLASH->ACR.LATENCY
.
FLASH_LATENCY = Latency;

gcc にコードを生成させる

.
ldrb r1, [r3, #0]
.

これはバイト読み取りです。ただし、typedef を

typedef     union{
    vu32    Word;
    struct{
        vu32    LATENCY     :3;
        vu32    HLFCYA      :1;
        vu32    PRFTBE      :1;
        vu32    PRFTBS      :1;
        vu32                :2;

        vu32    DUMMY1      :8;

        vu32    DUMMY2      :8;
    };
}tFlashACR;

結果のコードを次のように変更します

.
ldr r3, [r2, #0]
.
于 2015-03-11T09:52:16.420 に答える
1

発行する読み取りサイズを決定するのはコンパイラです。32 ビットの読み取りを強制するには、次を使用できますunion

union dev_word {
    struct dev_reg {
        unsigned int a:1;
        unsigned int b:1;
        unsigned int c:1;
    } fail;
    uint32_t dummy;
};

volatile union dev_word *vme_map_window();

volatile 修飾されたポインターを介してユニオンを読み取るだけでは、ユニオン全体の読み取りを強制するのに十分でない場合 (そうなると思いますが、コンパイラに依存する可能性があります)、関数を使用して必要な間接指定を提供できます。 :

volatile union dev_word *real_reg; /* Initialised with vme_map_window() */

union dev_word * const *reg_func(void)
{
    static union dev_word local_copy;
    static union dev_word * const static_ptr = &local_copy;

    local_copy = *real_reg;
    return &static_ptr;
}

#define reg (*reg_func())

...その後(既存のコードとの互換性のために)アクセスは次のように行われます:

reg->fail.a
于 2009-12-05T02:10:15.223 に答える
0

I had same problem on ARM using GCC compiler, where write into memory is only through bytes rather than 32bit word.

The solution is to define bit-fields using volatile uint32_t (or required size to write):

union {
    volatile uint32_t XY;
    struct {
        volatile uint32_t XY_A : 4;
        volatile uint32_t XY_B : 12;
    };
};

but while compiling you need add to gcc or g++ this parameter:

-fstrict-volatile-bitfields

more in gcc documentation.

于 2014-09-01T20:51:47.080 に答える
0

唯一の解決策は、
1) メイン構造体をすべて 32 ビット int (unsigned long) として編集/作成すること、
2) 元のビットフィールド構造体を保持すること、
3) 必要な各アクセス、
3.1) 構造体メンバーを32 ビット ワードをビット フィールド構造体にキャストし、
3.2) 必要なビット フィールド要素を読み取ります。(書き込みの場合は、このビット フィールドを設定し、単語を書き戻します!)

(1) これは同じです。なぜなら、「main/SEPUMap」構造体の各メンバーが持つ組み込み型が失われるからです。

エンドソリューション:-
代わりに:-

printf("FirmwareVersionMinor: 0x%x\n", pEpuMap->PECVersion);

これ :-

SPECVersion ver = *(SPECVersion*)&pEpuMap->PECVersion;

printf("FirmwareVersionMinor: 0x%x\n", ver.minorversion);

私が持っている唯一の問題は書くことです!(書き込みは読み取り/変更/書き込みになりました!)

// Read - Get current
_HVPSUControl temp = *(_HVPSUControl*)&pEpuMap->HVPSUControl;

// Modify - set to new value
temp.OperationalRequestPort = true;

// Write
volatile unsigned int *addr = reinterpret_cast<volatile unsigned int*>(&pEpuMap->HVPSUControl);

*addr = *reinterpret_cast<volatile unsigned int*>(&temp);

そのコードをメソッドに整理するだけです!

#define writel(addr, data) ( *(volatile unsigned long*)(&addr) = (*(volatile unsigned long*)(&data)) )
于 2009-12-07T13:21:36.670 に答える