# 計算機概論 ## Overall View * 從what到how do computer works。 * what是指知道如何透過高階層的指令,讓電腦做我們想做的事情。 * how是指知道電腦接受指令,軟體硬體怎麼配合做那些事情,也就是知道電腦底層在做的事情。 * 資工系的學生和外系差在知道how,知道底層memory,硬體如何運作,所以設計方法解決問題可能會更有效率。 ## Coding * 最底層是透過0跟1來儲存,可以減低大部分noise。如Morse code及Braille都是binary code。 * Morse code是透過長和短訊號來表示字元 * Braille是盲人點字系統,共有六個點透過凸和平來表示。 * * 二進位來儲存非常方便,十進位是因為手指數目然後成為慣用,要熟悉兩個的轉換。 2^10 = k(千) , 2^20 = m(百萬) , 2^30 = G(十億)。 * 16進位是2進位的簡化版本,**可以把4個bit變成1個digit**。而1個byte=8個bit。 (32進位把5個bit變成1個digit不方便使用,且一個digit要有32種可能不好記憶) * * Unsigned Number 直接儲存,每個bit代表2的某個次方。 * Signed Number(看成是一種protocol,端看編碼系統規定如何) * Sign+Magnitude:直觀,但有兩個0,且不行加法。 第一個bit代表正負號,剩下的bit就是unsigned number的值。 * 2’s Complement: * 不會有重複數字 * 可直接加法,減法可用加法處理 * 第一個為signed bit * 可以用MSB extend使bit數變多 正數:剩下的bit就是unsigned number的值。 負數:正負數之間關係為,取complement再加1(或是說$2^N$-x = -x)。 * 2's complement中 **-a 的表示法整理** * 1.先把a表示出來,接著對所有bit取complement,接著加1。 * 2.不考慮signed bit,直接把2^n^-a這個正數寫出來 * 3.先把a表示出來,從右到左找第一個1,把此1左邊所有bit取complement * Character sets(也可看成一種protocol) * ASCII * ANSI * Unicode * 實數 IEEE ## Logic * 1.Boolean Algebra布林代數 * Boolean variables: 0 or 1 * Boolean Operation: and(乘), or(加), not(^--^) * NOT>AND>OR * 2.Define a function * 1.Description,透過文字、自然語言去描述。 * 2.Algebraic form,透過代數去描述。 * 3.Enumeration,透過窮舉所有可能。 * 因為Boolean Function的variable只有0,1比較單純,可以透過窮舉去證明function,一般general的例子比較不容易達到。 * 3.Truth Table * 用窮舉方式來表達Boolean Function。 * 一或多個Input, 一個Output。 * Number of Functions * N input ->2^N^ rows -> 2\^2\^N functions * Demorgan Law * NOT(xy)=NOT(x)+NOT(y) * NOT(x+y)=NOT(x)NOT(y) * 給定任意F可以用來得到F'。 * Bubble Pushing * Demorgan Law的應用 * 可以把AND gate轉成OR gate加上三個not * 可以把OR gate轉成AND gate加上三個not * 轉換的過程就像是在擠泡泡一樣 * Sum-Of-Product * 系統性的,把任何Boolean Function,用且只用And,Or,Not表達。 * 1.先列出該Boolean Function的Truth Table。 * 2.對函數值是1的部分,用and term去表達,把所有input串起來。 * 3.把所有and term的結果or起來。 * Product-Of-Sum * 系統性的,把任何Boolean Function,用且只用And,Or,Not表達。 * 1.先列出該Boolean Function的Truth Table。 * 2.對函數值是0的部分,用or term去表達,把所有input串起來。 * 3.把所有or term的結果and起來。 |x|y|Truth| |-|-|-| |0|0|0| |0|1|0| |1|0|1| |1|1|1| f = x~y + xy f'= (~x+y)(~x+~y) f = (x+y)(x+~y) f'= ~x~y + ~xy * 兩種方式比較及互相轉換 * 因為列出function的Truth Table之後,一個是關注0的部分,一個是關注1的部分,因此可以決定怎麼表達比較簡潔。 * f 和 f' 之間的轉換,可以直接透過demorgan's law,而且若一者為sop則另一者為pos。 * f 的sop和pos之間的轉換,通常要透過Truth Table,然後關注另外一部分。 * Universality * 最基本的邏輯閘gate,可以組合出任何組合電路(Truth Table中的任何一種function)。 * {And, Or, Not} * product of sum * sum of product * {And, Not} * a|b = \~(\~a&~b) * {Or, Not} * a&b = \~(\~a|~b) * {Nor} * ~a = a nor a * a|b = \~(a nor b) * a&b = \~(\~a|~b) * {NAND} * ~a = a nand a * a&b = \~(a nand b) * a|b = \~(\~a&~b) * 4.Digital System * Analog:signal是連續的 * Digital:signal為0或1 * Accuracy and reliability. * Staggeringly fast and cheap. * 5.Controlled Switch 電磁開關(Relay) * 透過電流驅動磁力影響另一條的電流 * Not:一個switch本身就是 * Nor:兩個switch串聯起來 * Or:兩個switch串聯起來,再加output取相反 * And:把兩個input先取相反,再把兩個switch串聯起來 * NAND:兩個switch並連起來 * **Principle of Information Hiding** * 大部分的時候,我們不會在意電路內部怎麼設計的,我們只需要知道這個電路的,功能、input、output,然後可以正確地拿來使用就可以。 * Multiway Gate:也可以用2-input的類似形式,擴充到n-input。 * 6.Boolean Function to Circuit * 運用sum of product技巧,可以只用and,or,not和wire去描述任何boolean function * 1.用boolean variable去表示input及output * 2.**列出function的truth table** * 3.列出sum of product表示的boolean expression * 4.直接把expression轉成circuit * 7.Optimal Circuit * 如果考慮**空間**:可能越少gate越好 * 如果考慮**時間**:可能length越短越好 * 也可能考慮:設計時間短,不容易犯錯,容易擴展 * 8.Hierachy Design * 因為要達到時間越短或空間越少,的設計成本,可能太高了。 * 關鍵是:用**小部分兜成大部分**。 * 2bit or -> 4bit or * 2bit and -> 4bit and * 2bit xor -> 4bit xor * 1bit 加法 -> 多bit 加法 * 9.Karnaugh Map(K map) * 簡化電路方法,目標為使用更少的gate實現相同功能。 * 同樣可以選擇要關注0的部分或是1的部分。 * * 一般的形式,可以用在2~4的變數情況,超過5個變數則要使用電腦輔助。 * 詳細的操作方法略,總之希望把某些bit的判斷省略。 * * 之前有提到product of sum和sum of product,兩種電路實作起來的gate數是不一樣多的。 * 所以可以推測得知,Kmap的簡化電路,把大部分重複之處的地方刪除,但不能保證留下來的gate是最少的或最佳的。(化簡後仍可選擇用POS或SOP實作。) * 10.Mux,Dmux * Mux的功用是,依照selector的值,決定要把input的哪一部分傳給Output * DMux的功用是,依照selector的值,決定要把input傳給Output的哪一部分,而Output其他部分為0 ## ALU * 1.**1-bit half adder** * input:x, y * output:sum, carry * * sum = x xor y * carry = x & y |x|y|sum|carry| |-|-|-|-| |0|0|0|0| |0|1|1|0| |1|0|1|0| |1|1|0|1| * 2.**1-bit full adder** * input:x, y, Cin * output:S, Cout * * sum = xor(x, y, Cin) = odd(x, y, Cin) * carry = maj(x, y, Cin) * |x|y|Cin|Sum|Cout| |-|-|-|-|-| |0|0|0|0|0| |0|0|1|1|0| |0|1|0|1|0| |0|1|1|0|1| |1|0|0|1|0| |1|0|1|0|1| |1|1|0|0|1| |1|1|1|1|1| * 3.任意bit加法器都可以製作出。 * 也許會考慮用truth table然後用sum of proudct製作出電路,但4bit加法器就有2^9^=256列,128bit加法器就有2^257^列,在實務上是做不到的。 * * 但可以考慮用hierachy的概念,用小元件組合成大元件。 * 兩個1-bit加法器,可構造成2-bit加法器。 * 兩個2-bit加法器,可構造成4bit加法器。 * ...,可構造出任意bit加法器。 * 4.減法一:**1-bit subtractor** * input:x, y, bin(上一位有沒有像我借位) * output:d, bout(我需不需要像下一位借位) |x|y|bin|d|bout| |-|-|-|-|-| |0|0|0|0|0| |0|0|1|1|1| |0|1|0|1|1| |0|1|1|0|1| |1|0|0|1|0| |1|0|1|0|0| |1|1|0|0|0| |1|1|1|1|1| * 5.減法二:利用加法器做減法 * x-y = x+(-y) = x + (~y+1) * 重複利用已經有的加法器 * input:x, ~y * Cin=1 * 6.Shifter: * input:x0\~x3,s0\~s3 * output:z0\~z3 * z0\~z3是x0\~x3經過向左shift之後得結果,shift的位數根據s0\~s3的哪一個bit是1來決定(保證只有一個是1) * * z0 = s0‧x0 + s1‧0 + s2‧0 + s3‧0 * z1 = s0‧x1 + s1‧x0 + s2‧0 + s3‧0 * z2 = s0‧x2 + s1‧x1 + s2‧x0 + s3‧0 * z3 = s0‧x3 + s1‧x2 + s2‧x1 + s3‧x0 * 根據這個關係是就可以做出對應的電路 * 7.N-bit Decoder * 以上一個shifter例子來說,用s0\~s3來控制shift的位數,是很方便來實作shifter的電路,但 * 使用者不一定正確的輸入讓s0\~s3只有一個bit是1 * 這樣浪費硬體成本,2^4^->4種(其實只要2bit就夠了) * Decoder的目的是,把二進位的數字轉換成特定一bit為1的形式。 * Input:N bit二進位數字 * Output:2^N^ bit 資料 * 在input數字的位置的bit為1,其他位置的bit為0 * 可以輕易地由sum of product 實作。 * 8.N-bit Encoder * Encoder的目的是,把一串資料,挑出bit為1的位置,用二進位的數字表達。 * Input:2^N^ bit 資料 * Output:N bit二進位數字 * 挑出bit為1的位置 * 可以輕易地由and, or實作。 * 9. 1 HOT OR * 處理有很多種運算,然後根據哪一條線是on起來選擇特定的那一個運算 * 方法就是 * 先把各個bit,選擇的線和運算的結果線and起來 * (因為選擇線只有一條會on,所以and起來後只有一條非0) * 最後再把所有結果or起來 * 當然也有別種實作方法,但這樣很簡潔易懂 * 10.ALU(Arithmetic logic unit) * CPU的執行單元 * 支援以下運算 * 加法和減法 * And * Xor * 左移和右移 * 11.Toy ALU * Input:A[16], B[16], select[3], subtract, shift direction * Output:Out[16] * |sel|2|1|0| |-|-|-|-| |加減|0|0|0| |and|0|0|1| |xor|0|1|0| |位移|0|1|1| |out=B|1|0|0| * 電路會先把各種運算結果製造出來,最後再根據sel用one hot or選擇所要的作為Out。 * 12.Hack ALU * Input:x[16], y[16], zx, nx, zy, ny, f, no * Output:Out[16], zr, ng * * zx和nx,先後決定要不要把x設為零,要不要把x設為~x。 * zy和ny,同理。 * f = 1 表示 out = x+y,0則是x&y。 * zr表示out是否為0,ng表示out是否為負數。 |zx|nx|zy|ny|f|no|out| |-|-|-|-|-|-|-| |1||1||1||0| |1|1|1|1|1|1|1| |1|1|1||1||-1| |||1||1||x| |1||||1||y| |||1||1|1|!x| |1||||1|1|!y| |||1|1|1|1|-x| |1|1|||1|1|-y| ||1|1|1|1|1|x+1| |1|1||1|1|1|y+1| |||1|1|1||x-1| |1|1|||1||y-1| |||||1||x+y| ||1|||1|1|x-y| ||||1|1|1|y-x| |||||||x&y| ||1||1||1|x\|y| ## Sequential Logic * 1.Combinational circuits和Sequential circuits * 理論上combinational circuit就可以組裝成一台電腦了,但是用到的硬體可能是exponential成長的,而且不能記憶之前的狀態。 * Sequential 電路,把Output接回來當作下一round的input。 * 因此有記憶的功能,或是說他有state概念。 * 需要有clock的幫忙 * 2.Flip-Flop * 可以記憶一個bit的電路 * **是register、memory、counter的基本元件** * 3.S-R flip flop |S|R|Q~t~| |-|-|-| |0|0|Q~t-1~| |0|1|0| |1|0|1| |1|1|X| 或是 Q=S+(~R)Q |S|R|Q~t-1~|Q~t~| |-|-|-|-| |0|0|0|0| |0|0|1|1| |0|1|0|0| |0|1|1|0| |1|0|0|1| |1|0|1|1| |1|1|0|X| |1|1|1|X| * 電路和truth table可以互轉,雖然在sequential中比較複雜但仍然可以。 * SR flip-flop可以由兩個NOR實作 * SR flip-flop可以由電磁開關實作 * 但要注意到delay問題 * 4.D flip-flop |Q~t~| |-| |Q~t-1~| |Q~t-1~|Q~t~| |-|-| |0|0| |1|1| * 5.Clock * 另外的裝置,用來處理delay問題 * 可以分成positive edge trigger或是negative edge trigger * 只有在trigger的瞬間可以把訊號傳出去 * Clock用來控制電路的一致性,所有的sequential logic都會和clock相連。 * 以頻率為單位,代表一秒內有幾個cycle * clocked SR flip flop * input為 S,R,Clock * output為 Q * 在clock為1的瞬間Q會去判斷S或R的值 * * 內部實際上是用Clock和S、R互相AND起來 * clocked D flip flop * 直接透過clocked SR flip flop就可以實作 * input為 D, clock * output為 Q * 在clock為1的瞬間Q會等於D的值 * * 實作方式是把D接到S,~D接到R * 6.Register暫存器 * 把clock和write接起來,稱為enable write * D flip-flop把clock位置input接入enable write,本身就是1bit的暫存器 * 同樣方式把D flip-flop串接起來就直接形成了n bit的暫存器 * 7.Register file暫存器堆 * 提供n register,每個bit是k bit * * 透過addr來identify我要存取哪一個暫存器 * 透過w來決定要不要從input寫入16bit。 * * 實作方法為 * 把addr先decode之後,n個register中每個的clock input就是colck和w和addr一起AND起來,只有在這三條線都是1的時候才會更改到register的值 * 最後再用multiplexer根據addr決定要output哪一個register的值 * 8.k-wide-n-to-1-multiplexer * k wide表示每個input有幾bit,n表示有幾種input選擇 * 先處理1-wide-n-to-1-multiplexer,透過truth table把sel對應的值和input AND起來,再把所有可能OR起來就得到。 * 只要把input每個bit用一個1-wide-n-to-1-multiplexer處理即可得到k-wide-n-to-1-multiplexer。 * 9.Memory * 簡易的memory component包含 * Register * Main Memory * Program Counter * 可以用register file方式實作memory,但是這樣製作成本會很高,真實世界的memory都是用DRAM來達到,而且位置會離CPU很遠。 * Toy Machine中 * Word : 16bit * Memory address : 8bit (256個memory) * Register name : 4bit (16個register) * * program counter (PC):存8bit的記憶體位置 * instruction register (IR):存16bit的instruction * 10.Memory Bank * n個register,每個k bit * 透過input address來指出要access哪一個register,並且output該register的值 * 透過w決定是否要更改該register * Toy Machine中 * 256-by-16 main memory * 16-by-16 register ## Toy Machine Programming * 1.Introduction * General-purpose,理論上能夠做到任何一台電腦能做到的功能 * 只是說會受到memory和time的限制 * 范紐曼型架構,也就是code和data會放在相同位置,這種電腦稱為**儲存程式電腦**。 * 2.Toy Machine 包含 * Switches * Light * Memory : 256 by 16 bits * Program counter : 8 bits * Registers : 16 by 16 bits * Arithmetic-logic unit(ALU) * Standard input, standard output * 3.Program and Data * Program是由多行instruction組成,儲存在記憶體,每一行就是16bit通常是從10開始儲存。 * Data是由16-bit word組成,通常存在memory前面00到0f。 * program counter(PC)會記錄現在要執行哪一行instruction,一開始會initial成10。然後每次會把該行instruction讀到instruction register(IR)裡面執行。 * 4.Instruction( Machine Code如何表達) <table>  <tr>  <td>-</td>  <td>15</td>  <td>14</td>  <td>13</td>  <td>12</td>  <td>11</td>  <td>10</td>  <td>9</td>  <td>8</td>  <td>7</td>  <td>6</td>  <td>5</td>  <td>4</td>  <td>3</td>  <td>2</td>  <td>1</td>  <td>0</td>  </tr>  <tr>  <td>Fmt1</td>  <td colspan="4">op code</td>  <td colspan="4">dest d</td>  <td colspan="4">source s</td>  <td colspan="4">source t</td>  </tr>  <tr>  <td>Fmt2</td>  <td colspan="4">op code</td>  <td colspan="4">dest d</td>  <td colspan="8">addr</td>  </tr> </table> op|FMT|Instruction -|-|- 0|1| halt 1|1| add 2|1| subtract 3|1| and 4|1| xor 5|1| shift left 6|1| shift right 7|2| load address 8|2| load 9|2| store A|1| load indirect B|1| store indirect C|2| branch zero D|2| branch positive E|1| jump register F|2| jump and link * 5.一些常見指令寫法 * LOAD和STORE * 70XX,直接讀constant XX到R0 * 80XX,把mem[XX]的值,讀到R0 * A00Y,把mem[RY]的值,讀到R0 * * 90XX,把R0的值,寫入mem[xx] * B00Y,把R0的值,寫入mem[RY] * 第FF的memory位置為stdin、stdout位置,可以和使用者互動。 * 9xFF:從stdout寫 * 8xFF:從stdin讀 * JUMP * C0XX:直接跳到YY位置 * E和F是一組的 * FFXX:跳到XX位置,並把return address存在RF * EF00:跳到RF所存的return address位置 * 70XX:把constant XX 讀到R0裡 * 0000:停止,確保程式不會執行預期外code * 1AB0:A = B+0,有move效果 * 1000:No operation,有時候會需要。 * 6.加法 ```clike= // C = A + B 10: 8A00 RA ← mem[00] 11: 8B01 RB ← mem[01] 12: 1CAB RC ← RA + RB 13: 9CFF mem[FF] ← RC 14: 0000 halt ``` * 7.乘法 * 可以用連加法來實作,但是loop可能會跑太多次 * 可以用shift來實作, ```clike= 14: CA18 if (RA == 0) pc ← 18 15: 1CCB RC ← RC + RB 16: 2AA1 RA ← RA - R1 17: C014 pc ← 14 18: 9CFF mem[FF] ← RC 19: 0000 halt // a存在RA,b存在RB,c存在RC int c = 0; while (a != 0) { c = c + b; a = a - 1; } ``` * 下面的例子,因為要處理>=的情況,所以只能用do while形式來寫 ```clike= 15: 2221 R2 ← R2 - R1 //i-- 16: 53A2 R3 ← RA << R2 //a<<i 17: 64B2 R4 ← RB >> R2 //b>>i 18: 3441 R4 ← R4 & R1 //(b>>i) & 1 19: C41B if (R4 == 0) goto 1B 1A: 1CC3 RC ← RC + R3 // c + (a<<i) 1B: D215 if (R2 > 0) goto 15 1C: 9CFF mem[FF] ← RC 1D: 0000 halt // i 初始成16,R1永遠是1 int c = 0; for (int i= 15; i >=0; i--) if (((b >>i) & 1) ==1) c = c + (a << i); ``` * 8.其他例子 * Fibonacci ```clike= 12: 9AFF print RA 13: 1AAB RA ← RA + RB 14: 2BAB RB ← RA - RB 15: C012 goto 12 16: 0000 halt //b初始成0,a初始成1 //b' = a ; //a' = a+b ; ``` * * read and sum ```clike= 11: 8AFF read RA 12: CA15 if (RA == 0) pc ← 15 13: 1CCA RC ← RC + RA 14: C011 pc ← 11 15: 9CFF write RC 16: 0000 halt //sum存在RC裡,初始成0 //程式直到讀到0000才停下來 ``` * * Reverse ```clike= //讀到0000為止,存在mem RA之後連續位置 13: 8CFF read RC 14: CC19 if (RC == 0) goto 19 15: 16AB R6 ← RA + RB 16: BC06 mem[R6] ← RC 17: 1BB1 RB ← RB + R1 18: C013 goto 13 //從讀到的最後位置開始,印出直到RA位置 19: CB20 if (RB == 0) goto 20 1A: 16AB R6 ← RA + RB 1B: 2661 R6 ← R6 – R1 1C: AC06 RC ← mem[R6] 1D: 9CFF write RC 1E: 2BB1 RB ← RB – R1 1F: C019 goto 19 20: 0000 halt ``` * 9.Buffer overrun * 當程式設計不當,使得array明明宣告固定size,使用者卻可以更改到更大的size時 * 使用者可能可以巧妙設計,讓原程式執行使用者輸入的指令 * 此時程式就lose control * 許多viruses and worms都用此種技巧 ## Toy Machine Architecture * 1.複習現在有的元件 * ALU * 兩個16 bit INPUT,一個16bit OUTPUT * 功能為:由3+2bit來控制 * Add/subtract, * and, * xor, * shift left/right, * copy input 2 * k wide n to 1 Multiplexer * 把n to 1的1 bit multiplexer重複k bit。 * Flip Flop * SR flip flop可以組裝成D flip flop * Register * 把DFF再加上write enable控制 * Register file * 多個register一起記憶,在透過multiplexer決定要對哪一個register操作。 * 這裡的register file提供**dual read**,也就是可以一次讀出兩個直給ALU使用,因為指令常常會需要。 * Memory * 可以直接用register實做 * Clock * positive edge trigger * on: fetch phase * off: execute phase * 2.如何建構processor * Develop instruction set architecture (ISA) 決定要有那些指令,每個指令的規格、形式為何 * Determine major components 決定完成這些功能需要使用那些元件 * Determine datapath requirements 看看data在這些元件的先後順序,適時使用memory和multiplexer * Analyze how to implement each instruction 設計control讓元件達到正確功能 * 3.4bit Counter 的architecture input|semantic| -|-|- 00|c=0| 01|c=in| 10|c=c+1| 11|c=c-1| * 4.Stack 的architecture W|OP|operation -|-|- 0|0|read 0|1|top 1|0|push 1|1|pop