上回說到程式的概念,就是將指令也納入計算機的輸入中,讓我們可以對機器下命令。這樣一來,計算機就不僅能做固定的工作,而是能依照程式設計師寫出的程式,做出各種不同的應用。今天我們繼續深入看看,「程式」究竟是長什麼樣子、如何運作的。
在講馮紐曼架構時,提到了儲存裝置「記憶體」可以用來存放資料和指令,為了要定義一份資料或是一個指令,需要先規定這個計算機的一個字(word)有多長,例如 16 bit 的 word 就是有 16 個 0 / 1 的意思,可以表示 0x0000000000000000 ~ 0x1111111111111111 共 2 ^ 16,也就是 65536 種可能。越大的 word 能表示的資料或指令就越多,例如目前主流使用 64 bit 的架構。
指令集是為了要讓 word 能表示指令,制定的一些規則,例如每個 word 的前 4 bit 用來表示指令,第二組 4 bit 表示資料輸入來源一,第三組表示資料輸入來源二,第四組表示資料輸出的位置。
這種是一般的算術指令,可以對指定的兩個暫存器中的資料做運算,然後把結果放到指定輸出的暫存器中。
另外還有資料儲存、載入的指令,以及控制程式流程的指令。例如載入指令可以將特定記憶體位址的資料放到指定暫存器中,讓算術指令使用;分支指令會檢查指定暫存器中的資料,如果為零的話就接著執行某個記憶體位址中的指令。因為它們使用到的資料不同,會是一個記憶體位址和一個暫存器位址,所以格式和算術指令有點不同。
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
-----------------------------------------------------------------------
| 算術指令 | 輸入暫存器 1 | 輸入暫存器 2 | 資料輸出暫存器 |
-----------------------------------------------------------------------
| 儲存載入指令 | | |
| / | 輸入暫存器 | 記憶體位址 |
| 流程控制指令 | | |
如果寫程式的時候,要一直在腦中想著指令的 0/1 排列組合
加法指令是 0x0001、載入指令是 0x0100、…
這樣恐怕太累了。
於是有人設計了組合語言和組譯器,讓程式設計師可以用
LW $1, 0x0011 (表示載入記憶體位址 0x0011 的資料放到暫存器1號
ADD $1, $2, $3 (將暫存器1號2號相加,結果放到暫存器3號
這樣的方式寫程式,再透過組譯器這支程式來將組合語言翻譯成電腦才看得懂的機器語言。
雖然組合語言已經比直接看一大串的 0 和 1 好多了,但其實還是很難懂。於是有人設計了「高階語言」,採用更容易懂的語法,並包裝一些用組合語言要好多指令才能做的事情,讓寫程式變得更容易。例如在用 C 語言寫完程式後,要使用C 的編譯器將高階語言翻譯成機器語言,才能交給電腦執行。