CPU的組成


  前面差不多理清了計算機組成的一些重要概念,由MCU是包含了CPU,當然還有存儲器以及一些外設,為了對MCU有更好的理解,先拿其中的CPU說起吧,話不多說,先來一張概圖:

有了這個結構圖,別慌,一步步的分部分分析就會明白,也很清晰了。

  首先來看ALU(ALU拆開為Arithmetic Logic Unit)中文名為算術邏輯單元,我們前面講的概念CPU中的CPU中的算術運算(加減),邏輯運算(左移右移),在這里就成了它,操作數給到ALU,ALU運算后會產生結果,但光有結果往往還不夠的,要知道有時候比如不夠減了,或者位溢出了,那結果里得有這個狀態阿。於是我們設計了程序狀態寄存器(Program Status Register)用來記錄這些結果狀態標志,提到這里,不妨說一下,ALU要是能不斷運算,那得有數給它才行吧,看到圖中的R0,……R3方塊了吧,那就是CPU的通用寄存器(可以用來存取操作數),ALU可以從這里取,而且算完了還可以放到這里面。但提到這里就會有疑問,這些寄存器是不是足夠多到把我們的操作數放下呢,答案是否定的,不得不說,這些寄存器資源非常寶貴,所以我們操作數往往有時單單從它取還不夠的,還得從外面存儲器里取才行(內存或硬盤),對於結果也是,不能總放在寄存器里把(寄存器大多存放中間結果)。當我們運算完后,往往需要把結果送到存儲器里,這就理清了ALU的操作數來去了,但不知道發現沒有,到底是誰告訴我們ALU什么時候該取數呢,從哪里取,放在哪。想到我們概念CPU里就會發現我們指令里有些控制做加減,有些還控制數據流向的指令。這下好了,這正是圖上另一個大方框里表示的,不過在這里給起了一個名字叫控制單元CLU(Control Unit),它對應着我們概念CPU中的指令功能一樣(指令解析+數據流向),它與其他的連接關系,這里就大可說一番,那一根連到外圍存儲器的線,那就是告訴外面存儲器該干嘛干嘛,別干等阿,一根線連到結果Result,Result得告訴我們控制器阿,不然結果都已經不對了,還執行也沒意義了。另外三根線都與ALU有直接關系,一根控制外圍存儲器與ALU取操作數的,另外一根是ALU與與寄存器取數的,還有一根就是告訴ALU該干嘛干嘛的,分析到這里,肯定又會有疑問,那這些指令又是哪來的,放在哪呢?

  一般我們指令是程序員編好了直接放在存儲器(這里我將內存什么的都統稱為這個,而且程序我也默認是已編譯為二進制的)里的,我們知道存儲器就好像一個個抽屜一樣,每個抽屜都有編號,就像葯店后面的小櫃子樣的(這個比喻是否讓你想到了指針呢哈哈哈),只不過這些編號是事先約定的叫地址,我們只要把這些指令一條條的放到不同的地址就好了,等到執行的時候再一條條的執行,這樣就會想到那怎么樣就使得程序一條條的執行了呢。人們發明了程序計數器(或者稱之為指針控制寄存器把),它能夠自動對地址累加,里面存儲的永遠是下一條執行的指令對應的地址,在指令執行的時候,不總是按順序往下的,有時候中斷或者碰到程序跳轉指令的時候,指令會跳轉到另一個地方,完全執行完了再回到原來的位置進行執行,那怎么回來呢,首先會想到的就是我再增加一個寄存器用來保存返回地址的,別說,早期CPU還真是這么設計的,當然此話的言下之意便是現今的CPU不是這樣的,因為后來發現隨着程序的變大和子程序調用的增多(比如中斷嵌套加深等等情況),導致設計的寄存器越來越多,而且寄存器的個數就確定了程序嵌套的個數,這就顯然不符合人們的習慣阿,明顯限制程序員的發揮了。於是人們想了想產生一個好的idea,那就是棧的概念(Stack Register),分為PUSH(壓棧)和POP(出棧)兩個操作,完美解決了這個問題,但需要遵循一個條件(First in Last out)

  圖中還有一個寄存器漏掉了,那就是變址寄存器(Index Register),可稱之為地址寄存器,這個寄存器可用來存儲一條指令或是一個存儲單元的地址,方便尋址的。對於MCU可能就是一個簡單的存放存儲單元地址的,但對於計算機里的CPU來說其范圍就大了,其可包含基址,變址和相對地址,其尋址方式也更多樣化,拿一個標准的MCU來說,大致具有以下寄存器:

累加寄存器(數據寄存器) Accumulation Register

變址寄存器(地址寄存器)Index Register

指針寄存器 Stack Pointer Register

程序計數器 Program Counter,簡稱PC

程序狀態字寄存器 Program Status Word,簡稱PSW

 (這個有別名,條件代碼寄存器 Condition Codes Register)

 

  話題最后,說一下堆棧,需要注意的是堆和棧是兩個不同的概念,堆是內存里一段連續空間,可以用來存數據,而棧可以存取局部變量數據或返回地址,棧指針寄存器就是用來存取這個返回地址的,但指針寄存器一般保存的就是下一步的返回地址,你程序調用多了,那肯定是保存你上一步調用的返回地址,所以可聯想到這個棧肯定是后進先出,另外棧和堆分別占用不同存取空間,但堆可能自上往下放,棧則可能自下往上放,所以這就可能發生堆棧溢出問題(即一個存儲單元可能發生堆和棧搶占關系),若這樣,則就可能不是返回地址,這時程序就有可能跑飛了(程序執行的地方完全無法預料,多提一下,在實際產品中一般程序需要加個看門狗喂狗Watch Dog Timer,一旦跑飛不喂狗了,程序就復位了,這樣至少不至於死機),一般棧的使用還有注意的是放了東西就記得要拿走(這個點與C語言里的malloc申請空間有點相似),比如PUSHA->PUSHB->POPB->POPA,壓棧后記得后面一定得出棧,,而且順序不能弄錯了,否則就還原不了現場了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM