0

マイクロコントローラーのディスクリート IO チェックに関連する次の問題を最もエレガントに解決する方法について質問があります。

.c ファイルの内容:


struct transfers {
uint32t *RegisterAddr;
uint8_t RegBit;
};

static const struct transfers DIO[] = {
{ REGA_ADDR, 3},
{ NULL, 1},
{ NULL, 12},
{ REGB_ADDR, 2},
{ NULL, 7},
{ REGC_ADDR, 5},
{ REGD_ADDR, 1}
};

inline uint32t Dinputs(const uint8_t n){

  uint32_t DIO_Data = 0;
  uint32_t RegData;

  for (uint8_t i = 0; i < n; i++) {

    if (DIO[i].RegisterAddr != NULL) RegData = *DIO[i].RegisterAddr;

    if ((RegData & (1 << DIO[i].RegBit)) == 0) DIO_Data |= (1 << i);
  }
  return DIO_Data;
}

void testfunction(void) {

  uint32_t DIO_Data = Dinputs(N_USED);
}

N_USED が 7 に定義され、REGx_ADDR も有効なレジスタ アドレスであると定義されている場合、 --O3 --funroll-loops を使用してコンパイルした後に期待される結果は、testfunction の次の同等の C コードのように速度が最適化されます。

  uint32_t DIO_Data = 0;
  uint32_t RegData;

  RegData = *REGA_ADDR;
  if ((RegData & (1 << 3)) == 0) IO_Data |= (1 << 0);
  if ((RegData & (1 << 1)) == 0) IO_Data |= (1 << 1);
  if ((RegData & (1 << 12)) == 0) IO_Data |= (1 << 2);
  RegData = *REGB_ADDR;
  if ((RegData & (1 << 2)) == 0) IO_Data |= (1 << 3);
  if ((RegData & (1 << 7)) == 0) IO_Data |= (1 << 4);
  RegData = *REGC_ADDR;
  if ((RegData & (1 << 5)) == 0) IO_Data |= (1 << 5);
  RegData = *REGD_ADDR;
  if ((RegData & (1 << 1)) == 0) IO_Data |= (1 << 6);

ARM v7 用の GCC コンパイラを使用しています。これは、testfunction によって呼び出される上記のインライン関数 Dinputs を使用すると、最適化されたマシン コード出力で期待どおりに機能しますか? Dinputs 関数の展開とインライン化を強制する可能性はありますか? あまり重要ではありませんが、念のため: 上記の例の構造体転送 DIO は、展開されたインライン関数によってのみ使用されるため、コンパイラがこのデータをオブジェクト ファイルのデータ セクションに引き継ぐ必要はありません。予想される動作は何ですか。これ?

私のプロジェクトで同等のコードを使用したくない理由は、コンパイル時に N_USED が 0 から 7 の範囲 (この例では) である場合、多くの追加のプリプロセッサ コマンドが必要になり、他の DIO を使用するバリアントが必要になるためです。テーブルは、コードではなくテーブルを交換するだけで、より簡単に定義できます。

4

0 に答える 0