工程師在設計指令集體系結構時,在將某些二進制代碼指定為指令時會遵循什麼程序或協議(如果有)。例如,如果我有一條說10110是加載指令的ISA,那麼二進制數字從何而來?是否從狀態表中為表示加載操作的有限狀態機建模?
編輯: 經過更多研究之後,我相信我要問的問題與如何分配各種CPU指令的操作碼有關。可以使用10011的操作碼來指定ADD;一條加載指令可能指定為10110。為指令集分配這些二進制操作碼有什麼思路?
工程師在設計指令集體系結構時,在將某些二進制代碼指定為指令時會遵循什麼程序或協議(如果有)。例如,如果我有一條說10110是加載指令的ISA,那麼二進制數字從何而來?是否從狀態表中為表示加載操作的有限狀態機建模?
編輯: 經過更多研究之後,我相信我要問的問題與如何分配各種CPU指令的操作碼有關。可以使用10011的操作碼來指定ADD;一條加載指令可能指定為10110。為指令集分配這些二進制操作碼有什麼思路?
這取決於ISA的年齡。
在手工設計的早期,甚至更進一步地,當從離散邏輯組裝CPU時,邏輯設計將首先出現並被大大減小,然後ISA位模式將成為需要的任何值。使最小的邏輯工作。
因此,可能存在使某些多路復用器能夠將ALU輸出連接到GP寄存器文件的輸入的控制信號的特定模式,還有一些指示ALU加,減,AND,OR等的控制信號,和一些地址位到寄存器文件中。這三組信號將在指令內形成字段。每個組將保持在一起,其詳細含義從該單元(ALU等)的設計中產生,但是直到您設計指令解碼器之前,這些組可以以任何順序排列。 (x86足夠舊,如果您在正確的位置查看,您可以檢測到其中的某些部分-它不是全新設計,而是藉鑑了較舊的8080)
以後的ISA可能會被“清理”並變得更加常規和易於使用,並且硬件有時會通過“微碼”在它們和實際的硬件級控制信號之間進行轉換。這些被稱為“ CISC”或“複雜指令集編碼”。 x86“ Rep”指令前綴就是一個簡單的例子-它使以下指令重複多次,從而省去了編寫FOR循環的麻煩。
後來(在1980年代)又回到了一種簡單的直接編碼樣式(RISC-精簡指令集編碼),您可以在ARM處理器中看到這種樣式。這是由於當時的ASIC尺寸較小,並且希望在其上放置32位CPU,因此復雜的指令集解碼器沒有多餘的容量,無法將整個CPU降低到大約20,000門。(這也是暫時的性能提升,因為人們還沒有開發出使CISC解碼器更快的技術-大約在1995年,奔騰Pro就出現了)
如今,這無關緊要-CPU一次讀取幾條指令,並投入數百萬個晶體管對其進行解碼,重新排序並一次執行盡可能多的指令,以加速可能已編寫的程序最古老的ISA。
如果將相似的指令組合在一起,則會出現模式。這在ARM中非常明顯,ISA手冊實際上向您顯示了指令字的哪一位對應於功能,寄存器選擇等。但是也可以從 X86推論得出。
最終,操作碼的“功能”部分進入某種二進製到單字節的解碼器,該解碼器實際上激活了特定功能或流水線操作序列。它們通常與任何狀態機的內容都不相關,除非我們考慮使用需要狀態機進行解碼的變長指令。
某人坐下來對它們進行了定義。
良好的ISA將使解碼器盡可能簡單。
例如,使用ALU指令,您可以讓操作碼的某些位直接發送到ALU的控制線中。
在許多情況下,隨著ISA的增長,選擇是相當隨意的,或者基於“最合適的位置”。但是,MOS 6502是芯片的一個很好的例子,在該芯片中,嘗試從有限的晶體管中盡可能多地擠壓ISA設計受到了很大的影響。
觀看這段視頻,特別是從34:20開始,解釋6502是如何反向工程的。
6502是1975年推出的8位微處理器。儘管它的閘門數量比Z80少60%,但速度卻是Z80的兩倍,儘管它受到更多限制(在寄存器等方面),但它彌補了帶有精美的指令集。
它僅包含3510個晶體管,這是由一小群人用手工拉出的,它們是由一小群人爬過一些大的塑料板,這些塑料板隨後被光學收縮,從而形成了6502的各個層
如下所示,6502將指令操作碼和時序數據傳遞到解碼ROM,然後將其傳遞到“隨機控制邏輯”組件,其目的可能是在某些複雜情況下否決ROM的輸出。
在視頻中的37:00,您可以看到解碼ROM的表,該表顯示輸入必須滿足哪些條件才能為給定的控制輸出獲得“ 1”。您也可以在此頁面上找到它。
您可以看到此表中的大多數內容在各個位置都有X。讓我們舉個例子吧
011XXXXX 2 X RORRORA
這意味著操作碼的前3位必須為011,G必須為2;別的都無所謂。如果是這樣,則名為RORRORA的輸出將為true。所有ROR操作碼均以011開頭;但是還有其他說明也以011開頭。這些可能需要由“隨機控制邏輯”單元過濾掉。
因此,基本上,選擇了操作碼,以便需要彼此執行相同操作的指令在其位模式中具有某些共同點。您可以通過查看操作碼表來查看此內容;所有“或”指令均以000開頭,所有“存儲”指令均以010開頭,所有使用零頁尋址的指令的格式均為xxxx01xx。當然,某些指令似乎並不“合適”,因為其目的不是要具有完全規則的操作碼格式,而是要提供功能強大的指令集。這就是為什麼需要“隨機控制邏輯”的原因。
我在上面提到的頁面上說,ROM中的某些輸出行出現了兩次,“我們認為這樣做是因為它們無法將所需的某些行的輸出路由,所以他們將同一行在另一個位置。”我可以想像工程師們一個接一個地繪製這些門,然後突然意識到設計中的缺陷,並試圖提出一種避免重新啟動整個過程的方法。
通常,您會將ISA分為功能組。(對於邏輯優化或整潔而言)有意義的是,互補對通過單個位更改(加載與存儲)來區分,並且您具有影響解碼決策樹的某些位層次結構。
最終,為功能塊分配任意位(與在指令中放置“數據”字段相反)只會對總體設計效率產生很小的影響-但您有很多選擇有關如何根據您的感受來“優化” ISA編碼的重要參數。
指令編碼之間很難兼顧。
使解碼變得簡單,為此,您需要一組簡單的字段,每個字段可以分別解碼,然後路由到執行引擎的單獨部分。
將盡可能多的功能打包到有限大小的指令字中。這就導致了諸如特殊的常量格式之類的事情,該格式可以對各種通用數字進行編碼。
向前和向後兼容性。如果將功能分配給所有可能的操作碼,那麼您將沒有空間擴展以後的體系結構。如果要添加到現有體系結構,則必須將新指令放入備用操作碼中。
蘭迪·海德(Randy Hyde)出色的著作(如果有些過時了)彙編的藝術在 3.3.4控制單元和指令集和正在關注。
早期(馮·諾依曼之前)計算機系統中的程序通常“硬連線”到電路中。也就是說,計算機的佈線確定了計算機將要解決的問題。為了更改程序,必須重新佈線。一項非常艱鉅的任務。計算機設計的下一個進步是可編程計算機系統,它使計算機程序員可以使用一系列插座和插頭線輕鬆地“重新佈線”計算機系統。一個計算機程序由一組行的孔(插槽)組成,每行代表程序執行期間的一個操作。程序員可以通過將電線插入所需的指令的特定插座中來選擇多個指令之一。
然後,他演示了相當吸引人的內容,並詳細演示了前幾對插件代表指令的方式,接下來的插件對源和目標進行編碼。當然,今天沒有人再“插入”了,但是對於真正的ISA來說,操作碼中的位基本上與以前的插入工作相同。
您最終得到這樣的東西: