Re: [問題] volitile 在語言上的需求

看板C_and_CPP (C/C++)作者 (惡水上的大橋)時間14年前 (2011/07/31 13:41), 編輯推噓8(8023)
留言31則, 4人參與, 最新討論串2/2 (看更多)
--前文恕刪-- : → WPC001:volatile應該就是避免使用cache而已...跟其他硬體有關 07/30 23:50 : → WPC001:比如說DMA... CPU以為那區已經被快取了,而直接使用快取內的 07/30 23:51 : → WPC001:資料... 就會發生錯誤, 或是CPU還把資料放在快取,但硬體卻 07/30 23:51 : → WPC001:需要記憶體上的內容以寫到別的裝置上... 就會發生錯誤 07/30 23:51 : 推 littleshan:volatile不是避免使用cache,而是避免使用register 07/31 00:25 : → littleshan:實際上cache還是會發生作用 07/31 00:26 : 推 softwind:"避免使用register" <- 把它背下來!!! 07/31 00:56 : 推 Favonia:到底volatile是什麼意思由實作決定,可是文件常常都不齊:( 07/31 01:02 : → Favonia:gcc的文件: gcc.gnu.org/onlinedocs/gcc/Volatiles.html 07/31 01:02 並不是避免使用 cache, 在某些 MPU + NAND Flash 或是其他儲存單元的 Controller 對特定記憶體(這邊指的是MPU或CPU上的)位址做存取會影響到腳位輸出,而這些腳位 藉由特定的順序拉高拉低來讓外部的儲存元件吐資料到 Data Bus 上... 直接舉例... ╭───╮CE:Chip Enable ╭───╮ │ M │───────────│ F │ │ │OE:Output Enable │ L │ │ P │───────────│ A │ │ │WE:Write Enable │ S │ │ U │───────────│ H │ ╰───╯ ╰───╯ Addr. Bus ------------\------------ Address Bus, Data Bus 腳位 Data Bus 就不一一畫出... ------------\------------ 如果想要 Flash 乖乖吐資料到 Data Bus 上可能有下列幾個步驟 1. 先把要存取的位址丟到 Addr. Bus 上 3. MPU 從 Data Bus 上 Latch 資料 2. CE, OE 拉 Low 4. 重新把 CE, OE 拉 High 步驟一可能沒啥問題,但是步驟 2 到步驟 4 就是可能出問題的地方 在上層也許只是寫 *(IO_PORT_CE_ADDR) = 0; //然後也許 Delay 個一點點時間... 然後 buf = *(IO_PORT_DATA_BUS); 最後又把 CE 拉高 *(IO_PORT_CE_ADDR) = 1; 然後又繼續跳下一個位址,就上層來看就只是想說我把 CE,OE 這樣 0 1 0 1 高低變換 我切幾次照理說...我 compile 出來的 binary 應該就要讓硬體電路跳動幾次吧... 如果沒有加 volatile 關鍵字的話 那麼是有很大的機率會被聰明的 compiler 給 省略掉....因為 compiler 會認為你在做下面這樣的事情... int CE = 1; for( i = MEM_START; i < MEM_END; i ++ ) { CE = 0; . . do something in the loop . . CE = 1; } 反正最後結果 CE 都等於 1 對吧...就數字帳面上來看當然沒錯 但是中間那個變動就有 可能被吃掉,那外部的 Controller 或是 Flash 沒有收到 CE,OE 之類的腳位變化自然不 會把新的資料吐在 Data Bus 上,但是 MPU 在步驟 3 依然會去 Data Bus Latch 資料呀 所以就會怎麼撈都是撈到過期的資料... 以上如果有錯歡迎指正 要鞭也小力一點... 謝謝 >w<||| -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 111.184.32.168

07/31 21:09, , 1F
這是一種; 不過l大推文裡的那個也是很常見的例子:)
07/31 21:09, 1F

07/31 21:10, , 2F
個人認知是, 避免compiler對該變數的存取做最佳化, 使得
07/31 21:10, 2F

07/31 21:11, , 3F
該變數的每一次讀寫都確實在其存在的記憶體位址上發生作
07/31 21:11, 3F

07/31 21:11, , 4F
用. 所以禁止compiler直接塞結果/常數, 禁止compiler直
07/31 21:11, 4F

07/31 21:12, , 5F
接用register取代對address的存取...etc:)
07/31 21:12, 5F

07/31 22:13, , 6F
其實我覺得volatile這關鍵字根本就不該存在
07/31 22:13, 6F

07/31 22:14, , 7F
如果想要直接存取address,應該把對應的asm包成函式
07/31 22:14, 7F

07/31 22:16, , 8F
可是有的operation很常被使用說, 包成asm還要擔心平台相
07/31 22:16, 8F

07/31 22:18, , 9F
容問題說. Ex: 存取MMIO, 不同的MMIO有不同的讀寫方式,
07/31 22:18, 9F

07/31 22:19, , 10F
包成asm使用上不知要如何保持彈性@_@" 至於說asm, 是因
07/31 22:19, 10F

07/31 22:19, , 11F
為不知道為什麼build win64時不知道為什麼禁止我用int 3
07/31 22:19, 11F

07/31 22:20, , 12F
所以不太確定是不是可以用同樣的asm來實作....@_@"
07/31 22:20, 12F

08/01 03:33, , 13F
喔…這就是為何PIC老師建議學生用ASM寫的原因 (._.?)
08/01 03:33, 13F

08/01 23:25, , 14F
不需要歐... 那 mem map IO 都不用搞摟~
08/01 23:25, 14F

08/01 23:36, , 15F
既然有不同的讀寫方式,不就更應該用asm來寫
08/01 23:36, 15F

08/01 23:36, , 16F
因為compiler產生的code只會有一種啊
08/01 23:36, 16F

08/02 09:52, , 17F
可能小弟說的不清楚, 像MMIO整比DW r/w, 罩mask只監看某
08/02 09:52, 17F

08/02 09:53, , 18F
個bit, read回來update某幾個bit再回寫...等; 用C/C++直
08/02 09:53, 18F

08/02 09:55, , 19F
接寫只要var有掛volatile只要簡單的一兩行, 把這些操作
08/02 09:55, 19F

08/02 09:55, , 20F
都寫成asm是不是比較麻煩/可讀性也較差@_@"
08/02 09:55, 20F

08/02 09:56, , 21F
另外還有個鳥例子, 遇過某global var在main thread被跑
08/02 09:56, 21F

08/02 09:57, , 22F
loop檢查是否歸0, 然後有個DPC的thread時間到了會去更新
08/02 09:57, 22F

08/02 09:57, , 23F
它(像counter), 之前遇過一個bug就是因為該global var沒
08/02 09:57, 23F

08/02 09:57, , 24F
宣告成volatile, compiler在main thread的loop裡直接用
08/02 09:57, 24F

08/02 09:58, , 25F
reg暫存住那個global var, 導致DPC做完了該var都沒更新
08/02 09:58, 25F

08/02 09:58, , 26F
到, 然後就無窮迴圈卡死在那邊了XD
08/02 09:58, 26F

08/02 10:42, , 27F
不需要把bit operation都寫成asm呀,讀寫各一個就好
08/02 10:42, 27F

08/02 10:43, , 28F
罩mask就 read(...) & mask
08/02 10:43, 28F

08/02 10:43, , 29F
update就是 write(read(...) | update_bit)
08/02 10:43, 29F

08/02 10:44, , 30F
這樣不是比較清楚自己在做什麼嗎?
08/02 10:44, 30F

08/02 22:23, , 31F
喔~~是說只要read/write的部份直接用asm包喔, 誤會了XD
08/02 22:23, 31F
文章代碼(AID): #1EDEhsnw (C_and_CPP)
文章代碼(AID): #1EDEhsnw (C_and_CPP)