2017年9月16日 星期六

簡介RISC與CISC

前言

這是一篇為了非科班但是對RISC與對應的CISC這兩個縮寫及相關知識有興趣的同好所寫的入門文章,嚴格來說,這個領域其實是「計算機結構」的一部份,如果想要真正的完全了解,請研讀或參閱正規的教科書和課程。

電腦基本結構

開宗明義,RISC是 Reduced Instruction Set Computer的縮寫 ,翻譯為「精簡指令集電腦」,CISC則是相對的縮寫(Complex Instruction Set Computer,「複雜」指令集電腦),所以要完整的解釋這兩個縮寫,必須先解釋兩件事:首先,什麼是電腦?第二、什麼是電腦的「指令集」,最後才能解釋什麼是「擁有精簡/複雜指令集的電腦」。

以最簡單的方式來說,電腦是一種「可以記憶並處理(或者說運算)資訊的機器」;很多人都用過算盤或是那種只有數字和加減乘除的掌上型計算機,當需要計算很多數字,例如把幾十個數字各自照公式計算然後平均等等,會怎麼做呢?首先,你要有張紙,上面記錄要計算的數字,以及計算的公式,你看一眼公式,把數字打進計算機或算盤,根據公式計算,然後把計算結果寫回那張紙,完成工作;恭喜你,你做的事情就是現代電腦所做的事情。

在電腦出現前,也有很多同樣具備記憶和處理資訊能力的機器,例如算盤,但是電腦與之前這些「計算機器」最大的不同,在於電腦可以將「指揮電腦如何運算」當作是一種可以儲存及修改的資訊,換句話說,就是那張「紙」,以及從「紙上讀取公式和資料」的能力,讓電腦有了超越以往計算機器的能力。

在電腦中,那張上面寫了計算公式和數字的紙,稱為「記憶體」,無論是公式還是數字,都在這張紙上,而計算的結果最後也是寫回這張紙,但是記憶體跟真正的紙有點不太一樣,你可以把記憶體想像成一個黑盒子,裡面分成很多格,但是你一次只能讀或寫其中的一格,所以你需要給這個黑盒子一串數字,告訴它你現在要讀寫哪一格,這串數字稱為記憶體的「位址」(address)。
(當然,記憶體不是只有這種形式,不過這是最簡單以及最常用的一種機制)

至於從記憶體讀取公式和數字並加以計算的部份,古早以前,這部分分為控制和運算兩種單元,控制單元從記憶體中讀取公式和數字,然後送給運算單元產生結果,並將結果寫回記憶體,因為這兩個單元關係很密切,通常我們把這兩者合稱為「中央處理器」,也就是大家熟知的「CPU」,當然,這是很古老的說法,現在看到的「CPU」已經加了很多其他元件進去,但是基本上這兩個元件還在。


既然叫「電」腦,可想而知,你在計算數字時所做的:用眼睛看紙張上的符號、用手拿筆在紙上紀錄,這些動作,或是說「資訊的傳遞」,在電腦中都是用電來完成(至少目前是如此),正確的說法是藉由在電線上傳遞不同高低電壓的訊號(或是用電磁波,但是無論如何,原理是一樣的),電腦中不同的單元會互相傳送電磁訊號,所以以下所謂的「讀取」、「寫入」等等動作,其實就是藉由電磁訊號進行的資訊傳遞。

指令、指令集

電腦的基本運作方式如下:首先,CPU會先讀取記憶體的某格,得到一種「指揮電腦如何運算」的資訊,接著根據這個資訊,再從記憶體讀取要被處理的資料,並加以運算,運算後的結果再寫回記憶體,接著再讀取下一個指揮運算的資訊;這種「指揮電腦如何運算」的資訊稱為「指令」(Instruction),;一台電腦裡用來指揮運算的一連串指令和資料的組合,我們稱為「程式」所以我們現在的電腦有另外一個很拗口的名字,叫「內儲程式計算機」。
(另外,因為一些美麗的歷史錯誤,這個架構有時候會被冠上偉大的數學家John von Neumann的名字,被稱為von Neumann Architecture,有興趣的可以參閱維基百科相關介紹)

指令本身由特定的規則組成,而一台電腦所能接受的所有指令規則組合,我們稱為「指令集」(Instruction Set),指令集可以被視為是電腦所能了解的「語法」,要指揮一台電腦進行運算,程式的指令必須符合這台電腦的指令集規則,才能在這台電腦正確的執行;

不同廠商所設計的電腦系統,可能會有不同的指令集,而一種程式如果是以某種指令集語法所構成的話,通常也無法直接在另外一種指令集的電腦系統下執行;另外,即使是同一個廠商的電腦系統,新的系統有可能會在原有的指令集中加入新的指令格式與規則,所以為了新系統所寫的程式不見得可以在舊的系統下順利執行,如果系統可以執行舊系統的程式,我們稱這兩個指令集是「相容」的,以我們目前個人電腦的x86指令集為例,這個指令集雖然是Intel發展的,但是因為早期的一些商業協議(以及背後殘酷的專利與法律交鋒),AMD公司也可以製造有相容指令集的微處理器。


RISC之前

在電腦的發展初期,由於硬體能力的限制,指令集通常不太複雜,其實也沒有辦法太複雜,另一方面,當時高階語言和編譯器也還不成熟,所以多半還是以機器語言和組合語言為主,很快的,程式設計師發現這些指令不太夠用,不夠用並不是寫不出程式,而是有些比較複雜的程式,要用一大堆指令才能寫出來,但是在那個記憶體寸土寸金的年代,程式本身的大小當然越小越好,所以為了能做更多事情,電腦的結構和指令集有了一些改變。

首先,每個指令都要讀取和寫入記憶體這點其實很麻煩,剛剛上面提過,讀寫記憶體分成兩個步驟:先送出位址,再讀寫資料,一個典型的運算,例如 A = B + C ,需要讀取兩筆資料,寫入一筆,要做三次記憶體存取,指令本身就要容納三個位址,所以後來想出了一個方法:在CPU裡面另外增加一塊特別的記憶體,除了原先的指令以外,增加一些新的指令,可以指定運算的結果直接寫進這塊記憶體,也可以直接使用這塊記憶體的資料當作輸入,因為只有一個或兩個,所以不需要很長的位址就可以指定,指令本身長度就可以變短,換句話說如果多使用這些指令,程式就會比較小;這種特別的記憶體稱為「累加器」(accumulator),後來數量變多,也不限制只能存放運算後的結果,演變成一種存放「暫時放在CPU裡面的資料」的記憶體,稱為暫存器(registers)。

另外一方面,隨著越來越複雜的應用,指令集本身也變得越來越複雜,但是複雜的指令集表示要用複雜的電路來完成,對當時的電子工藝來說非常困難,所幸這個時候「微碼」(Microcode或是Microprogram)誕生,微碼是位於CPU內部的小程式,每個指令被讀進CPU後,指令的不同部分進一步被分解成對應的一系列微程式,再由CPU真正的電路一步步地完成,微碼的出現,一方面降低CPU電路設計的複雜度,另一方面也容許指令集提供更多複雜的指令給程式設計師,所以到了七零年代,大部分的電腦系統都採用了微碼設計,指令集也就越來越複雜。

為了解釋這些電腦的指令有多「複雜」,我們以DEC (Digital Equipment Corporation,迪吉多電腦公司)的VAX的指令集作為例子,VAX是DEC在七零年代中後期(精確的說,是1977年),以PDP-11為基礎發展出的小型32位元電腦系統,是當年很暢銷的電腦主機之一。

VAX的指令集非常的「正交」(orthogonal),這是個專有名詞,意思是指令格式中的不同部分,特別是指定運算資料來源的「運算元」部分非常的「各自獨立」;以VAX的算術運算為例,基本上有兩類,一類是兩個運算元,一類是三個運算元,例如加法:

A = A + B,這樣是兩個運算元(A、B);
C = A + B,就是三個運算元(A、B、C)
(這是用高階語言的表示法,真正的樣子是一串0與1的數字格式和代碼,這裡不多做解釋)

VAX的指令中,這些運算元A、B、C可以分別是暫存器或是用暫存器定址的記憶體,而且定址還不只一種模式,事實上光是以暫存器為基礎的記憶體定址模式就有十多種,而且一個指令中不同運算元的定址模式是各自獨立的,換句話說程式設計師可以任意、分別指定這些運算元在暫存器或是記憶體的某個位址,這對於寫組合語言來說很方便,但是硬體上可就麻煩透頂,首先,因為不知道指令有幾個運算元,前面的OPcode要先解碼完,才能接著把指令剩下的部分抓進去;接著,這些運算元要分別去解碼判定運算元定址方式,如果很不幸的都是記憶體,還要個別做記憶體位址的計算、轉換和存取,這些複雜的工作當然不可能直接用硬體一次搞定,所以需要用指令轉換成一連串內部的微程式,代價就是指令執行時間變長,而且不是只有那些長指令,即使是只使用暫存器的短指令,也因為微程式的關係導致變慢。

在指令集複雜化的同時,電子工藝和程式設計方式也有了改變;1960年代積體電路(IC)開始取代之前的電晶體,成為電腦的主要元件;七零到八零年代,IC演變為大型積體電路(VLSI),原先需要好幾片電路板的元件,現在可以用幾塊甚至單一一塊晶片就可以完成;而程式設計也從之前以組合語言為主,變成以編譯程式編譯的高階語言為主。

RISC的出現

1980年,加州大學柏克萊分校的David Patterson教授發表了著名的論文:"The case for Reduced Instruction Set Computer",在這篇論文中,Patterson和他的學生們分析了當時幾種主流電腦,包括上述的VAX、IBM  system/360等系統的指令集,以及幾種標準測試程式在這些電腦系統上編譯後的機械碼之後,歸納出以下的結論:
  • 大部分的高階語言程式所編譯出來的機械碼中,只會用到指令集中少部分,而且是比較簡單的指令。
  • 微碼和指令集的複雜化導致的不合理設計;舉例來說,VAX有個叫 INDEX的指令,用來計算陣列位址,同時檢查位址是不是超過陣列的邊界範圍,這個指令可以用幾個其他簡單指令做到,而且還比較快。
  • 電腦系統積體電路化的結果,會讓CPU內部速度與外部記憶體存取的速度差異越來越大。
根據這些結果,他們提出一個新的指令集設計概念,主張:

  • 指令集的設計應該盡可能的精簡,只有最常用、功能最單純的指令會被放入指令集,而且因應高階語言的普及,應該以能夠配合高階語言編譯器為主。
  • 盡可能不使用微碼以降低設計複雜度與提高執行速度。
  • 配置大量暫存器以降低對外部記憶體的存取頻率,同時只使用特定的指令存取外部記憶體,其他一般運算指令都使用暫存器作為運算元。
  • 所有的指令(除了記憶體存取相關的以外)盡量在一個機器週期(machine cycle)內完成。
他們把這樣的指令集設計的電腦系統稱為「精簡指令集電腦」,也就是 RISC,而之前這些電腦系統則稱為「複雜指令集電腦」(CISC);根據RISC概念,他們提出了一套指令集,就是所謂的Berkeley RISC,並在次年(1981年)時實作出第一顆RISC微處理器:RISC I。

RISC I


RISC I是顆32位元的處理器,指令長度也固定為32位元,只有31個指令,包括基本的加減法、移位和邏輯運算,沒有乘法指令(因為以當時的製程來說,乘法的運算電路太大太慢,而且乘法基本上可以用移位和加法指令取代);外部記憶體存取只限於load/store這兩種指令;這顆處理器有44420個電晶體,以5um NMOS製程製造,整顆晶片裡指令解碼和運算電路只佔了晶片面積的6%,其他都是暫存器(SRAM),RISC I一共有78個32位元暫存器,分為六組,這就是所謂的「暫存器框格」(Register Window)設計,這個機制比較有意思,它的原意是希望降低呼叫副程式時的暫存器和記憶體間的資料傳輸,但是這個機制本身其實也有點麻煩,所以只有幾家少數的RISC用過(RISC I、SUN SPARC以及Intel的i960),大部分其他RISC,像等一下會提到的MIPS就沒有。

雖然David Patterson他們創造了RISC這個縮寫,但是類似的概念其實很早就出現過;早在1965年,控制資料公司(Control Data Corp., CDC)的旗艦級大型電腦主機CDC6600也採用了類似的指令集設計概念;而1975年,由John Cocke領導設計的實驗性迷你電腦主機:IBM 801也是如此,但是都算是當時的「非主流」設計,並沒有獲得廣泛的重視;IBM 801的基本設計後來成為IBM  RS/6000以及著名的IBM POWER架構、Apple後來在Power Mac所使用的PowerPC RISC微處理器,以及SONY PS3所使用的cell處理器的基礎。

(不過CDC6600和IBM 801都不是RISC「微處理器」VAX雖然是CISC,但是也不是CISC「微處理器」,一開始我們有提到電腦的主要元件「CPU」,在一般人的印象裡,CPU就等於「微處理器」,是一塊晶片,但是在電腦發展的早期,CPU其實是好幾櫃子的電路板和真空管或是電晶體,加上密密麻麻的電線,後來技術進步後可以縮減到一片電路板以及上面的許多顆IC,CDC6600大約就是那時候的電腦,要到1971年,才由我們熟知的Intel公司,把一顆簡單的4 bit CPU所需要的全部元件放進一片有2300顆電晶體的晶片裡,做出第一顆「微處理器」4004,但是那時候微處理器的功能和速度還遠不是大型電腦主機的對手)

CDC 6600


在RISC I提出的同時,史丹福大學的John L. Hennessy教授提出了另外一套概念類似的指令集,稱為MIPS(其實這是個很拗口的縮寫:Microprocessor without Interlocked Pipeline Stages,無互鎖階段管線的微處理器),1984年開設了MIPS公司並量產R2000微處理器,MIPS的微處理器在一些高階繪圖工作站以及嵌入式系統被使用;後來這兩位「RISC教授」更合寫了兩本有名的計算機結構與組織教科書:Computer Architecture: A Quantitative Approach以及Computer Organization and Design: the Hardware/Software Interface。這兩本現在是很多大學資訊科系計算機結構相關課程的經典教科書。

到了1986年以後,幾乎所有當時的電腦系統廠商都推出過基於RISC概念的微處理器,有些廠商甚至直接放棄了自己原有的CISC系統;到了九零年代以後,即使是像Intel x86這樣的老牌CISC微處理器,在內部的設計上也或多或少的受到RISC設計概念的影響,如果有興趣,可以參閱本文作者所寫的這篇「淺談古代CPU:CISC廠的RISC(1)」

附帶一提,1983年,有家叫Acorn的英國小公司,因為找不到合用的微處理器,他們參考了RISC-I的相關論文,自己發展了一個稱為Acorn RISC Machine的架構,並在1985年做出第一個實作ARM2,這家公司後來改名Advanced RISC Machine,這個架構就是各位手上的手機和平板所用的各種ARM處理器的前身。

補充:有關RISC的一些常見誤解

  • RISC只是CPU「指令集」的一種設計概念,在電腦和CPU這塊領域,還有很多奇奇怪怪的術語和縮寫,像是多處理器或雙核心四核心、SMT、管線(pipeline)、Superscalar等等等等,這些都跟「指令集設計」沒有直接的關係,那些術語是實作CPU時的某些機制,跟是不是CISC或是RISC沒有關係;另外像是CPU的製程或時脈,跟RISC/CISC也沒有直接的關係。
  • 微碼/微程式並不是「因為」VLSI出現才消失的,以現在的電子工藝,大可以用VLSI做一片「使用微碼的超級CISC」微處理器,只是不會比較快而已。
  • 後來為了因應需要,新的RISC有加入一些新指令,像是對應多媒體應用而產生的向量運算等等之類的,基本上並不違反RISC的設計原則,會放進去是因為後來多媒體應用成為微處理機很重要的一項功能,常用的當然會放進去。

沒有留言: