1

ARM Cortex-M4 CPU といくつかの周辺機器を含む組み込みシステムに取り組んでいます。ペリフェラルの 1 つには、CPU 側から (AHB バス経由で) アクセスできる SRAM のブロックが含まれていますが、アクセスはワード サイズのトランザクション (LDR を使用) である必要があります。バイトトランザクション(LDRB)を行うと例外が発生します。

私のコードでは、そのメモリ内の配列から値を読み取り、それをローカル変数に割り当てています。宣言は次のようになります。

typedef enum
{
     eType0 = 0,
     eType1 = 1,
} type_t;

type_t    arr_type;
uint32_t *array  = BUF_ADDR; // array on periph. memory
uint32_t  offset = 0;

arr_type = (type_t) array[offset]; // exception!

このコードを実行すると、メモリの読み取り時に例外が発生します。この割り当てによってアセンブリ コードが生成されることがあります。

LDRB R1, [R2, R3, LSL #2]; // R2=array, R3=offset

これは、括弧を追加して式を明示的にキャストした場合でも当てはまります。

type = (uint32_t) (array[offset]);

これを解決する方法は、代わりにarr_typeasを宣言することでした。さて、コードは次のとおりです。uint32_ttype_t

LDR R1, [R2, R3, LSL #2];

これは予想される動作ですか?array括弧とキャスト (ポインターの自然な型でない場合) により、コンパイラーは生成され、LDR命令されると思います。したがって、これはバグのように見えます。

4

2 に答える 2

3

コンパイラは通常、プログラム自体の観点から、あたかも 32 ビット ロードarray[offset]が実行されたかのように、動作する限り、任意のロード命令を使用できます。ロードされた値は に格納されるときに 8 ビットに切り捨てられるため、代わりにコンパイラが 8 ビット ロードを使用する場合、 にarr_type格納される値は変更されません。arr_type

メモリアクセスのサイズが重要であり、プログラム自体の外部に目に見える影響があることをコンパイラに伝えるには、volatile修飾子を使用する必要があります。

type_t    arr_type;
uint32_t volatile *array = BUF_ADDR;
uint32_t  offset = 0;

arr_type = (type_t) array[offset]; 

より一般的には、volatile何らかの種類のメモリ マップド I/O を実行するときに修飾子を使用する必要があります。アクセスが常に意図したサイズを使用して (可能な場合) 実行されることを保証するだけでなく、アクセスが削除または並べ替えられないことも保証します。

于 2016-03-04T18:11:14.737 に答える
1

フラグ --enum_is_int を使用してコンパイルすると、列挙型へのアクセスは 32 ビットになり、整列されます。

于 2016-03-04T18:33:01.390 に答える