CPU空操作的原理是什麼?
起因:和同學探討彙編語言,其中有個NOP指令空操作
經過:在intel的官網上查詢過指令集,對NOP給出的說明只有「此時控制器不發出控制信號」我想知道:這個「不發出控制信號」是怎麼做到的,如果能有整個控制器的實現原理就更好了,我的《計算機組成原理》上只有簡單介紹,想知道更多請問CPU方面有沒有類似《一個操作系統的實現》這樣的書?
最近在利用空餘時間寫一個兼容MIPS32指令集架構的CPU,儘管它和Intel的不同,但MIPS對nop指令的處理方式可以給你一點啟發。
首先上過計算機體系結構課的你一定知道,現代CPU都採用流水線結構。在一個簡單的五級流水的MIPS32處理器中,五級流水分別實現的邏輯操作是:取指、解碼、執行、訪存、回寫。
(圖片來自網路,侵刪)在取指階段,cpu從內存中代碼區讀取指令,然後將其送入解碼階段進行解碼。那麼解碼階段做了什麼呢?要了解這一點,我們先來看看指令本身長什麼樣子,以移位操作指令sll為例,其在彙編語言中的用法為:
sll rd, rt, sa
意思是將地址為rt的通用寄存器的值向左移sa位(空出來的位置用0填充),得到的結果保存到地址為rd的通用寄存器中。(寄存器在上面那張圖中就是解碼階段上方的那個「Register file」方塊)
這麼一條彙編指令用32位二進位表達將會是這個樣子:
這下清楚了,解碼其實就是在識別、拆解指令碼,並準備好數據(這個數據可能來自寄存器,也可能就來自指令)送給執行階段去執行特定的計算。至於訪存和回寫在幹什麼,與此問題無關,就不做介紹了。
有意思的來了。我們來看看nop指令長什麼樣吧:
沒錯,全0。這就有問題了,按照剛才SLL指令的說明,SLL指令是通過前六位和後六位唯一確定的,那麼nop指令被送往解碼階段後,不就會被當成SLL指令么……你別說,還真是。按照sll指令的解碼和執行方案,nop指令會被解釋成這樣:
sll $0, $0, 0
意思是把地址為$0的寄存器的值拿出來,左移0位,再存到地址為$0的寄存器當中去……那麼寄存器$0里保存著的是什麼呢……MIPS32架構規定$0的值只能為0。
所以nop指令被CPU當成sll指令做了一次無意義的移位操作,實際上等於什麼都沒做,只是佔用了一級流水線,如 @龔黎明大大所說,用來作流水線填充,白白佔用1個T的等待時間。
這個應該是用作流水線填充的吧。作用就是白白佔1個T的等待時間。我覺得不用追究太多,搞IC設計的很多這麼搞,無非是某些運算資源當前被佔用了,或者數據還沒來,插一級等待。書當然有:《CPU自製入門》,日本人寫的,用FPGA寫了個精簡指令集的CPU。
用51舉個簡單的例子吧。下圖是51執行NOP時給控制信號賦值部分的源碼。
一些基本的控制信號是要有的,比如第一行的程序計數器相關的信號,需要向繼續讀取指令的。第二行是更新狀態的使能信號,告知下一周期的狀態。
51用作學習還是很好的,進一步了解有關流水線之類的處理運行細節可以去讀一些開源處理器比如leon3之類的源碼。辛辛苦苦寫這麼多。。球贊球回復球關注!
Intel是怎麼做的倒是不得而知哦,不過對於nop可以有很多種處理方式
例如像其他人說的那樣,讓nop變成其他某個指令的pseudo instruction,而這個指令又不會修改任何arch state以及沒有什麼副作用,那麼就好了
不過其實你仔細觀察,會發現編譯器生成的代碼中有很多nop,當然他的作用也是多種多樣,例如說對齊,或者放在delay slot中等等。那麼你想,對於一個追求高性能的cpu來說,浪費issue queue以及func unit顯然不是一個好主意,因為這些資源本來就很寶貴,然而卻拿來做完全沒有用的事情。以及,如果還要讀register file的話,那麼便是更大的開銷了。而且,對於一個OoO的CPU來說的話,莫名其妙插入一個nop而沒有任何特殊語義的話,也很難說清他到底有什麼影響。。他會讓誰delay呢到底多少個cycle呢?那就不得而知了。所以。。簡直是百害無一利
所以這樣的話。。那就不要真的執行他就好了,也就不會再白白浪費各種資源了,例如說直接在rob中把他標記成executed就好了
但事情有時候也不會這麼簡單,因為有時候,出於某種原因,你就是想真的執行他,讓他佔用各種資源卻不做任何事情,那麼這就需要存在多種nop了,執行的和不執行的。而更進一步,既然有int的nop,那麼對於float point呢?於是又需要引入一種nop
大概就是這樣,當然這些也並不是針對Intel的。。因為我也不知道Intel是怎麼做的
雖然有些答非所問,但是這裡所說的是一些比較通用的做法,也會在其他architecture中見到,也是希望大家對這些東西能夠有一個更全面的認識
我舉個簡單的不能再簡單的栗子。
手畫,將就看吧。
如圖,這是一個簡化的三級流水線,執行單元只能算加減法和「空操作」。橫軸為時鐘周期,縱軸為指令順序。
假設第一條指令是加法,第二條是空指令,第三條為減法指令。減法指令減數來自加法指令結果,取指階段必須準備好所有數據。
在T3周期(第三列)時,CPU的三個部分,也就是流水線的三級,分別處理 第三條指令的取指,第二條指令的執行,第一條指令的寫回。
顯然,T3時刻才會寫到寄存器的值不可能在T2時刻就被第二條指令取到。所以,編譯器會在加法和減法指令間插一條空指令以等待數據。這是空指令存在的意義(還有其他的暫且不說)
「不發出控制信號」我感覺用代碼描述更方便些。
case(op) //取值範圍012,0為空操作,1為加,2為減
2"h0: result &<= result; //保留上一條指令的結果不變,將其寫入寄存器
2"h1: result &<= op1 + op2;
2"h2: result &<= op1 - op2;
endcase
也就是說,在這個栗子里空指令可以理解成直接給輸出一個默認值,加法器和減法器不會輸出有效的結果(在電路里還是會以op1和op2進行加減法,但是不會賦值給result)。
從T3到T4,兩條指令的結果都已經寫入寄存器,但是看寄存器的內容還是加法指令執行完的樣子,第二條指令就好像沒執行一樣。
以上。
dota去了,同學在催……
樓主想問的是指令邏輯是怎樣實現的吧,找本hp的cod看看。
簡單把cpu pipeline的每一級機構看成一個自身寄存器和控制器的自動機,他的控制信息和數據由前級的pipeline提供,並向下一級輸出控制信息和數據。時鐘信號驅動下,前端解碼出指令控制信息以及從cache之類取出數據,一級一級沿流水線傳下去。實現nop就很輕簡單了,解碼器將nop指令解碼後輸出控制信息讓下級流水線叫他啥也不幹比如不更改各種寄存器,控制信息一級一級傳下去就行了。外行瞎答的,可能我不太準確。編譯器將高級語言程序編譯成指令,cpu根據指令執行從而完成程序所指定的操作。所有操作的具體體現就是數據的改變以及cpu狀態的改變。空操作指令不會對數據以及cpu的狀態產生影響。
你只要知道什麼是時鐘信號你就明白了。。。
計算機的CPU在計算的時候,是一步一步來的。。。
這裡的每一步就是一個時鐘周期。
在這個時鐘周期裡面,控制器控制數據線和指令線發出信號,完成對應操作。
例如取指啦,計算啦。。
所謂的空操作,就是在這個時鐘周期裡面。數據線和指令線沒有信號。。
就好像你彈琴一樣,每一拍彈一個音。但是有一拍,作為彈琴控制器的你沒彈。這就是個空操作。。。
推薦閱讀:
※如何評價 VBA 語言?
※怎麼評價 Idris 語言?
※為什麼 Belleve的答案總是那麼高大上,想理解他的問題答案,需要哪些領域知識和前置知識?