2017-01-10 9 views
4

私の顕微鏡には8051ベースの組み込みシステムがあり、デバッグ用のシリアルポートを持っています。メモリフットプリントを減らすために少し微調整を行うまで、シリアルポート出力機能を使いました。その後、正常に動作していた次の行は、変更の一部ではありませんでした。これはコンパイラのバグですか?

dbg_TxBuf[(dbg_TxBufProduceCount++) & (sizeof(dbg_TxBuf) - 1)] = ch; 

...停止しました。変数dbg_TxBufdbg_TxBufProduceCountは出力のみの機能と、(すべてでは変更されませんでした)シリアルポートISRで使用されるグローバル変数を、以下のとおりです。

#define DBG_TX_BUFFER_SIZE 16 // MUST be a power-of-2 (this line is actually in a separate file, not that it matters) 
volatile uint8_t xdata dbg_TxBuf[DBG_TX_BUFFER_SIZE]; // must be sized by a power-of-2, and MUST BE LESS THAN 256 since the 'count' vars are uint8 
volatile uint8_t xdata dbg_TxBufProduceCount; // akin to a 'head' index but more useful since it allows use of every byte in the buf 
volatile uint8_t xdata dbg_TxBufConsumeCount; // akin to a 'tail' index but more useful since it allows use of every byte in the buf 

具体的に何が起こっている方法は、コンパイラは今ラインを最適化していることですコードのdbg_TxBufProduceCountは、chdbg_TxBufに書き込まれる前に(メモリ内で)インクリメントされています。次に、シリアルポートISRは「時々」(実際には非常に頻繁に)、chと出力ポイントが書き込まれる前にdbg_TxBufConsumeCount != dbg_TxBufProduceCountが表示され、dbg_TxBuf[(dbg_TxBufConsumeCount++) & (sizeof(dbg_TxBuf) - 1)]が読み込まれます。したがって、シリアルポートで出力が壊れてしまいます。

ここでは、その行の8051解体だ:それは前の増分にdbg_TxBufProduceCountの値を使っていることに

935>  dbg_TxBuf[(dbg_TxBufProduceCount++) & (sizeof(dbg_TxBuf) - 1)] = ch; 
DC84: 9006D6 MOV DPTR,#dbg_TxBufProduceCount 
DC87: E0  MOVX A,@DPTR <--- loads the value in dbg_TxBufProduceCount into the A register 
DC88: FE  MOV R6,A  <--- saves a copy of it in R6 
DC89: 04  INC A   <--- increments it 
DC8A: F0  MOVX @DPTR,A <--- writes the incremented value 
DC8B: EE  MOV A,R6  <--- gets the original copy of ProduceCount back in A 
DC8C: 7C00  MOV R4,#00  Begin computing address of dbg_TxBuf[~]... 
DC8E: 540F  ANL A,#0F  <--- A = A & (sizeof(dbg_TxBuf) - 1) 
DC90: 24D8  ADD A,#0D8  <--- A is now the low byte of &dbg_TxBuf[~] 
DC92: F582  MOV DPL,A  <--- put that in DPL 
DC94: EC  MOV A,R4  <--- (an inefficient way of loading the... 
DC95: 3406  ADDC A,#06  <--- ...immediate value 0x06 into A) 
DC97: F583  MOV DPH,A  <--- DPTR now points to dbg_TxBuf[~] 
DC99: EF  MOV A,R7  <--- load 'ch' into A 
DC9A: F0  MOVX @DPTR,A <--- write 'ch' to *DPTR 

は、コンパイラが正しくポストインクリメント演算子を扱っている「ローカル」の視点から計算はdbg_TxBufにインデックスされますが、「グローバル」という観点からは、イベントのシーケンスを正しく処理できないようです。特に、dbg_TxBuf[]dbg_TxBufProduceCountの両方をvolatileと宣言しています。コンパイラは、dbg_TxBufProduceCountのインクリメントされた値をメモリに書き込んではならないのですが、の後には、chがメモリに書き込まれますか?

私はKeil 8051 Cコンパイラ、v7.10を使用しています。 V7.10がリリースされたとき、私は知りませんが、それは表示される2005年5月に終わったコンパイラへの支持

+0

[mcve]はどこですか?コンパイラは抽象マシンを厳密に実装する可能性が高いです。 'volatile'修飾子が何をすることができるのかを知りたいかもしれません。 – Olaf

+2

あまりにも手を振る。 Cコードを見るとアセンブリよりもはるかに役立ちます。 –

+1

@Olaf - 私は間違いなく「最小限」の部分を持っています。私がISRを含むすべてを含んでいれば、完全な部分を提供するのはちょっと時間がかかるでしょう。そのために、誰かがもっと詳細を望む場合に備えてアセンブリを含めました。本当に問題の要点は、私が「具体的に何が起こっているのか」に完全に含まれています..."パラグラフと"ローカルの観点から... "パラグラフ最後に残りの部分はあまり重要ではない詳細です。 – phonetagger

答えて

6

万一それがCHを書き込み後にメモリにdbg_TxBufProduceCountのインクリメント値を書き込むことがないようにコンパイラ記憶に?

いいえ理由はありません。 1つのステートメント内で実行される操作には、何も並べ替えが行われません。これは、2つの揮発性変数に書き込む単一のステートメントです。どちらの順序でも書き込むことができます。概念的には、それは何ら変わりません:abは揮発性であっても

i = a++ + b++; 

、コンパイラはいずれかの順序でそれらに書き込むためのコードを生成して自由です。 1つのステートメントの部分の評価の順番と、その命令の副作用が可視になる順序は不明です。

関連する問題