開放電腦計畫 -- 系統程式 2014 年 8 月出版 作者 : 陳鍾誠衍生自維基百科 ( 創作共用 : 姓名標示 相同方式分享授權 )

Size: px
Start display at page:

Download "開放電腦計畫 -- 系統程式 2014 年 8 月出版 作者 : 陳鍾誠衍生自維基百科 ( 創作共用 : 姓名標示 相同方式分享授權 )"

Transcription

1

2 開放電腦計畫 -- 系統程式 2014 年 8 月出版 作者 : 陳鍾誠衍生自維基百科 ( 創作共用 : 姓名標示 相同方式分享授權 )

3 開放電腦計畫 -- 系統程式 前言序授權聲明開放電腦計畫硬體 : 計算機結構軟體 : 系統程式參考文獻 CPU0 處理器 CPU0 指令集實作 :CPU0 的指令表虛擬機 - vm0 組譯範例 VM0 虛擬機設計結語組譯器 - as0 組譯範例 AS0 組譯器設計程式說明

4 結語編譯器編譯器 : 高階語言轉中間碼 - j0c 編譯器 : 中間碼轉組合語言 - ir2as 結語

5 前言 序 本書是 開放電腦計畫的軟體部份, 描述如何設計系統軟體的方法, 透過這本書, 我們希望讓 系統程式 這門課變成是很容易理解並實作的 我們相信, 透過實作的訓練, 您將對理論會有更深刻的體會, 而這些體會, 將會進一步讓您更瞭解 現代電腦工業的結構 是如何建構出來的 授權聲明 本書許多資料修改自維基百科, 採用創作共用 : 姓名標示 相同方式分享授權, 若您想要修改本書產生衍生著作時, 至少應該遵守下列授權條件 : 1. 標示原作者姓名 ( 陳鍾誠 + 維基百科 ) 2. 採用創作共用 : 姓名標示 相同方式分享的方式公開衍生著作 另外 當本書中有文章或素材並非採用姓名標示 相同方式分享時, 將會在該文章或素材後面標示其授權, 此時該文章將以該標示的方式授權釋出, 請修改者注意這些授權標示, 以避免產生侵權糾紛

6 例如有些文章可能不希望被作為 商業性使用, 此時就可能會採用創作共用 : 姓名標示 非商業性 相同方式分享的授權, 此時您就不應當將該文章用於商業用途上 最後 若讀者有需要轉貼或修改這些文章使用, 請遵守 創作共用 的精神, 讓大家都可以在 開放原始碼 的基礎上逐步改進這些作品

7 開放電腦計畫 如果您是資工系畢業的學生, 必然會上過 計算機結構 編譯器 作業系統 系統程式 等等課程, 這些課程都是設計出一台電腦所必需的基本課程 但是如果有人問您 您是否會設計電腦呢?, 相信大部分人的回答應該是 : 我不會, 也沒有設計過 光是設計一個作業系統, 就得花上十年的工夫, 遑論還要自己設計 CPU 匯流排 組譯器 編譯器 作業系統 等等 因此, 我們都曾經有過這樣的夢想, 然後在年紀越大, 越來越瞭解整個工業結構之後, 我們就放棄了這樣一個夢想, 因為我們必須與現實妥協 但是, 身為一個大學教師, 我有責任教導學生, 告訴他們 電腦是怎麼做出來的, 因此我不自量力的提出了這樣一個計畫, 那就是 開放電腦計畫, 我們將以 千里之行 始於足下 的精神, 設計出一台全世界最簡單且清楚的 電腦, 包含 軟體與硬體 從 2007 年我開始寫 系統程式 這本書以來, 就有一個想法逐漸在內心發酵, 這個想法就是 : 我想從 CPU 設計 組譯器 虛擬機 編譯器到作業系統, 自己打造一台電腦, 於是 開放電腦計畫 就誕生了! 那麼 開放電腦計畫的 產品 會是什麼呢? 應該有些人會認為是一套自行編寫的軟硬體程式, 當然 這部份是包含在 開放電腦計畫 當中的

8 但是 更重要的事情是, 我們希望透過 開放電腦計畫 讓學生能夠學會整個 電腦的軟硬體設計方式, 並且透過這個踏腳石瞭解整個 電腦軟硬體工業, 進而能夠達到 以理論指導實務 以實務驗證理論 的目標 為了達成這個目標, 我們將 開放電腦計畫 分成三個階段, 也就是 簡單設計 ( 程式 ) => 理論闡述 ( 書籍 ) => 開源實作 ( 工業軟硬體與流程 ), 整體的構想說明如下 : 1. 簡單設計 ( 程式 ): 採用 Verilog + C 設計 CPU 組譯器 編譯器 作業系統 等軟硬體, 遵循 KISS (Keep It Simple and Stupid) 原則, 不考慮 效能 與 商業競爭力 等問題, 甚至在實用性上進行了不少妥協, 一律採用 容易理解 為最高指導原則, 目的是清楚的展現整個 軟硬體系統 的架構 2. 理論闡述 ( 書籍 ): 但是 要瞭解像 處理器 系統軟體 編譯器 作業系統 這些領域, 只有程式是不夠的 因為程式通常不容易懂, 而且對於沒有背景知識的人而言, 往往難如天書 所以我們將撰寫一系列書籍, 用來說明上述簡單程式的設計原理, 然後開始進入 計算機結構 編譯器 作業系統 系統程式 的理論體系中, 導引出進一步的設計可能性與工業考量等議題 3. 開源實作 ( 工業 ): 一但有了前述的理論與實作基礎之後, 我們就會採用 開放原始碼 來進行案例研究 舉例而言 在 計算機結構 上我們會以 ARM 為實務核心 編譯器 領域則以 gcc, LLVM 為研究標的, 作業系統 上則會對 FreeRTOS Linux 等進行案例研究, 虛擬機 上則會以 QEMU V8 等開源案例為研究對象

9

10 圖 開放電腦計畫地圖 根據以上規劃, 本書乃為一系列書籍中的一本, 完整的書籍架構如下 : 開放電腦計畫書籍 簡易程式 工業實作 系統程式 as0, vm0, cc0, os0 gcc/llvm 計算機結構 mcu0, cpu0 ARM/OpenRISC 編譯器 c 0c, j0c g cc/llvm 作業系統 os0, XINU, MINIX FreeRTOS, Linux 這些書籍分別描述不同的面向, 其涵蓋範圍如下圖所示 :

11

12 圖 開放電腦計畫書籍圖 硬體 : 計算機結構 在硬體方面, 我們將自行設計兩款處理器, 一款是用來展示簡單 微處理器 設計原理的 16 位元微控制器 MCU0, 而另一款則是用來展示 高階處理器 設計原理的 32 位元處理器 CPU0 透過 MCU0, 我們希望展示一顆 最簡易微處理器 的設計方法, 我們將採用 流程式 與 區塊式 的方法分別實作一遍, 讓讀者可以分別從 硬體人 與 軟體人 的角度去體會處理器的設計方式 由於 流程式 的方法比較簡單, 因此我們會先用此法進行設計, 當讀者理解何謂 微處理器 之後, 在將同樣的功能改用 區塊式的方法 實作一遍, 這樣應該就能逐漸 由易至難 由淺入深 了 在 MCU0 當中, 我們採用 CPU 與記憶體 合一的設計方式, 這種方式比較像 系統單晶片 (SOC) 的設計方法, 其記憶體容量較小, 因此可以直接用 Verilog 陣列宣告放入 FPGA 當中使用, 不需考慮外部 DRAM 存取速度較慢的問題, 也不用考慮 記憶階層 的速度問題, 因此設計起來會相對容易許多 接著, 我們將再度設計一個 32 位元的處理器 -- CPU0 並透過 CPU0 來討論 當 CPU 速度比 DRAM 記憶體快上許多 的時候, 如何能透過快取 (cache) 與記憶體管理單元 (MMU) 達到 又快又大 的目的, 並且討論如何透過 流水線 架構 (Pipeline) 達到加速的目的, 這些都屬於 高階處理器 所

13 需要討論的問題 軟體 : 系統程式 有了 MCU0 與 CPU0 等硬體之後, 我們就可以建構運作於這些硬體之上的軟體了, 這些軟體包含 組譯器 虛擬機 編譯器 作業系統 等等 我們已經分別用 C 與 JavaSript 建構出簡易的 組譯器 虛擬機 編譯器 工具了, 讓我們先說明一下在 CPU0 上這些程式的使用方法, 以下示範是採用 node.js+javascript 實作的工具版本, 因此必須安裝 node.js 才能執行 組合語言 (Assembly Language) 接著 讓我們從組合語言的角度, 來看看 CPU0 處理器的設計, 以下是一個可以計算 的程式, 計算完成之後會透過呼叫軟體中斷 SWI 程序 ( 類似 DOS 時代的 INT 中斷 ), 在螢幕上印出下列訊息 =55 以下的檔案 sum.as0 正是完成這樣功能的一個 CPU0 組合語言程式 檔案 :sum.as0

14 LD R1, sum ; R1 = sum = 0 LD R2, i ; R2 = i = 1 LDI R3, 10 ; R3 = 10 FOR: CMP R2, R3 ; if (R2 > R3) JGT EXIT ; goto EXIT ADD R1, R1, R2 ; R1 = R1 + R2 (sum = sum + i) ADDI R2, R2, 1 ; R2 = R2 + 1 ( i = i + 1) JMP FOR ; goto FOR EXIT: ST R1, sum ; sum = R1 ST R2, i ; i = R2 LD R9, msgptr ; R9= pointer(msg) = &msg SWI 3 ; SWI 3 : 印出 R9 (=&msg) 中的字串 MOV R9, R1 ; R9 = R1 = sum SWI 4 ; SWI 4 : 印出 R9 (=R1=sum) 中的整數 RET ; return 返回上一層呼叫函數 i: RESW 1 ; int i sum: WORD 0 ; int sum=0 msg: BYTE " =", 0 ; char *msg = "sum="

15 msgptr: WORD msg ; char &msgptr = &msg 組譯器 (Assembler) 我們可以用以下指令呼叫 組譯器 AS0 對上述檔案進行組譯 : node as0 sum.as0 sum.ob0 上述的程式經過組譯之後, 會輸出組譯報表, 如下所示 sum.as0 的組譯報表 0000 LD R1,sum L F003C 0004 LD R2,i L F LDI R3,10 L A 000C FOR CMP R2,R3 A JGT EXIT J C 0014 ADD R1,R1,R2 A ADDI R2,R2,1 A 1B 1B C JMP FOR J 26 26FFFFEC

16 0020 EXIT ST R1,sum L F001C 0024 ST R2,i L F LD R9,msgptr L F C SWI 3 J 2A 2A MOV R9,R1 A SWI 2 J 2A 2A RET J 2C 2C C i RESW 1 D F sum WORD 0 D F msg BYTE " =",0 D F3 312B2E2E2E2B31303D00 004E msgptr WORD msg D F 最後 組譯器 AS0 會輸出機器碼到目的檔 sum.ob0 當中, 其內容如下所示 sum.as0 的機器碼 ( 以 16 進位顯示 ) 001F003C 002F A C B FFFFEC 011F001C 012F F0022 2A000003

17 A C B2E2E 2E2B3130 3D 虛擬機 (Virtual Machine) 如果我們用 虛擬機 VM0 去執行上述的目的檔 sum.ob0, 會看到程式的執行結果, 是在螢幕上列 印出 =55, 以下是我們的操作過程 =55 編譯器 (Compiler) 當然 一個完整的現代電腦應該包含比組譯器更高階的工具, 不只支援組合語言, 還要支援高階語言 因此 我們設計了一個稱為 J0 的高階語言, 語法有點像 JavaScript, 但卻是經過簡化的版本 然後 我們又設計了一個可以用來編譯 J0 語言的編譯器, 稱為 J0C (J0 Compiler), 可以用來將 J0 語言編譯成中間碼, 也可以直接將中間碼轉換為 CPU0 的組合語言 以下是一個 J0 語言的範例,

18 檔案 :sum.j0 s = sum(10); return s; function sum(n) { s = 0; i=1; while (i<=10) { s = s + i; i++; return s; 當我們使用 j0c 編譯器將上述程式編譯之後, 會輸出兩個檔案, 一個是 sum.ir, 是編譯器中間格式 (Intermediate Representation, 虛擬碼 pcode) 的輸出檔, 其內容如下 : D:\Dropbox\Public\web\oc\code>node j0c sum

19 sum L1 L2 arg 10 call T1 sum = s T1 return s function param n = s 0 = i 1 <= T2 i 10 if0 T2 L2 + T3 s i = s T3 ++ i goto L1 return s endf

20 另一個是將上述中間格式轉換成轉換成 CPU0 組合語言之後的結果, 如下所示 : sum L1 else1 POP n LDI R1 0 ST R1 s LDI R1 1 ST R1 i LD R1 i LDI R2 10 LDI R3 0 CMP R1 R2 JLE else1 LDI R3 1 ST R3 T1 LDI R1 T1

21 L2 CMP R1 0 JEQ L2 LD R1 s LD R2 i ADD R3 R1 R2 ST R3 T2 LDI R1 T2 ST R1 s LD R1 i ADDI R1 R1 1 ST R1 i JMP L1 LD R1 s RET LDI R1 10 PUSH R1 CALL sum

22 ST R1 T3 LDI R1 T3 ST R1 s s WORD 0 i WORD 0 T1 WORD 0 T2 WORD 0 T3 WORD 0 上述由 j0c 所編譯產生的組合語言, 感覺相對冗長, 是因為這個編譯器是最簡版本, 完全沒有做任 何優化動作, 甚至連暫存器都是每次重新載入的, 所以效率並不會很好 作業系統 (Operating System) 當然囉! 一個完整的電腦還必須要有作業系統, 不過如果是嵌入式系統的話, 沒有作業系統也沒關 係, 只要將全部的程式連結在一起, 就可以形成一台電腦了, 目前開放電腦計畫的 作業系統 還在研究開發當中, 希望很快就能提供大家一個最簡單的作業系統版本 目前我們已經寫了一個可以進行兩個行程切換 Task Switching 範例, 接著我們將參考 UNIXv6,

23 L4 等作業系統, 以建構更完整的簡易作業系統 當然 即使我們從 CPU 硬體一路設計到組譯器 虛擬機 編譯器 作業系統等, 未來仍然有更多領域等待我們去探索, 例如 網路模組 TCP/IP Ethernet 無線 RF 的硬體模組 繪圖卡 OpenGL... 等等, 希望我們能夠用最簡單的話語, 將這些電腦的原理說明清楚, 並用簡單的方式實作得更完整 參考文獻 陳鍾誠的網站 / 免費電子書 :Verilog 電路設計 系統程式陳鍾誠著, 旗標出版社. JavaScript (6) Node.js 命令列程式設計

24 CPU0 處理器 商用的處理器通常因為強調效能的原因, 其設計都會讓指令格式變得難懂且複雜 為了讓處理器變得更簡單, 更容易理解, 我們設計了 CPU0 處理器, 這個處理計的設計原則是 KISS, 也就是 Keep It Simple and Stupid CPU0 的設計不求速度, 只求清楚易懂, 因此在指令級與指令格式上都盡量簡單, 編碼都以 4 位元為單位, 因此也很容易可以用人腦將組合語言翻成機器碼 以下是一個 CPU0 的組合語言範例, 該程式所作的事情是計算 的結果, 最後應該會得到總和為 55 檔案 :sum.as0 LD R1, sum ; R1 = sum = 0 LD R2, i ; R2 = i = 1 LDI R3, 10 ; R3 = 10 FOR: CMP R2, R3 ; if (R2 > R3) JGT EXIT ; goto EXIT ADD R1, R1, R2 ; R1 = R1 + R2 (sum = sum + i)

25 ADDI R2, R2, 1 ; R2 = R2 + 1 ( i = i + 1) JMP FOR ; goto FOR EXIT: ST R1, sum ; sum = R1 ST R2, i ; i = R2 LD R9, msgptr ; R9= pointer(msg) = &msg SWI 3 ; SWI 3 : 印出 R9 (=&msg) 中的字串 MOV R9, R1 ; R9 = R1 = sum SWI 4 ; SWI 4 : 印出 R9 (=R1=sum) 中的整數 RET ; return 返回上一層呼叫函數 i: RESW 1 ; int i sum: WORD 0 ; int sum=0 msg: BYTE " =", 0 ; char *msg = "sum=" msgptr: WORD msg ; char &msgptr = &msg CPU0 指令集 CPU0 是一個簡易的 32 位元單匯流排處理器, 其架構如下圖所示, 包含 R0..R15, IR, MAR, MDR 等暫 存器, 其中 IR 是指令暫存器, R0 是一個永遠為常數 0 的唯讀暫存器,R15 是程式計數器 (Program

26 Counter : PC),R14 是連結暫存器 (Link Register : LR), R13 是堆疊指標暫存器 (Stack Pointer : SP), 而 R12 是狀態暫存器 (Status Word : SW) 圖 CPU0 的架構圖 CPU0 包含 載入儲存 運算指令 跳躍指令 堆疊指令 等四大類指令, 以下表格 是 CPU0 的指令編碼表, 記載了 CPU0 的指令集與每個指令的編碼

27 格式 指令 OP 說明 語法 語意 L LD 00 載入 word LD Ra, [Rb+Cx] Ra=[Rb+Cx] L ST 01 儲存 word ST Ra, [Rb+Cx] Ra=[Rb+Cx] L LDB 02 載入 byte LDB Ra, [Rb+Cx] Ra=(byte)[Rb+Cx] L STB 03 儲存 byte STB Ra, [Rb+Cx] Ra=(byte)[Rb+Cx] A LDR 04 LD 的暫存器版 LDR Ra, [Rb+Rc] Ra=[Rb+Rc] A STR 05 ST 的暫存器版 STR Ra, [Rb+Rc] Ra=[Rb+Rc] A LBR 06 LDB 的暫存器版 LBR Ra, [Rb+Rc] Ra=(byte)[Rb+Rc] A SBR 07 STB 的暫存器版 SBR Ra, [Rb+Rc] Ra=(byte)[Rb+Rc] L LDI 08 載入常數 LDI Ra, Cx Ra=Cx A CMP 10 比較 CMP Ra, Rb SW=Ra >=< Rb A MOV 12 移動 MOV Ra, Rb Ra=Rb

28 A ADD 13 加法 ADD Ra, Rb, Rc Ra=Rb+Rc A SUB 14 減法 SUB Ra, Rb, Rc Ra=Rb-Rc A MUL 15 乘法 MUL Ra, Rb, Rc Ra=Rb*Rc A DIV 16 除法 DIV Ra, Rb, Rc Ra=Rb/Rc A AND 18 邏輯 AND AND Ra, Rb, Rc Ra=Rb and Rc A OR 19 邏輯 OR OR Ra, Rb, Rc Ra=Rb or Rc A XOR 1A 邏輯 XOR XOR Ra, Rb, Rc Ra=Rb xor Rc A ADDI 1B 常數加法 ADDI Ra, Rb, Cx Ra=Rb + Cx A ROL 1C 向左旋轉 ROL Ra, Rb, Cx Ra=Rb rol Cx A ROR 1D 向右旋轉 ROR Ra, Rb, Cx Ra=Rb ror Cx A SHL 1E 向左移位 SHL Ra, Rb, Cx Ra=Rb << Cx A SHR 1F 向右移位 SHR Ra, Rb, Cx Ra=Rb >> Cx J JEQ 20 跳躍 ( 相等 ) JEQ Cx if SW(=) PC=PC+Cx

29 J JNE 21 跳躍 ( 不相等 ) JNE Cx if SW(!=) PC=PC+Cx J JLT 22 跳躍 (<) JLT Cx if SW(<) PC=PC+Cx J JGT 23 跳躍 (>) JGT Cx if SW(>) PC=PC+Cx J JLE 24 跳躍 (<=) JLE Cx if SW(<=) PC=PC+Cx J JGE 25 跳躍 (>=) JGE Cx if SW(>=) PC=PC+Cx J JMP 26 跳躍 ( 無條件 ) JMP Cx PC=PC+Cx J SWI 2A 軟體中斷 SWI Cx LR=PC; PC=Cx; INT=1 J CALL 2B 跳到副程式 CALL Cx LR=PC; PC=PC+Cx J RET 2C 返回 RET PC=LR J IRET 2D 中斷返回 IRET PC=LR; INT=0 A PUSH 30 推入 word PUSH Ra SP-=4; [SP]=Ra; A POP 31 彈出 word POP Ra Ra=[SP]; SP+=4;

30 A PUSHB 32 推入 byte PUSHB Ra SP--; [SP]=Ra; (byte) A POPB 33 彈出 byte POPB Ra Ra=[SP]; SP++; (byte) CPU0 指令格式 CPU0 所有指令長度均為 32 位元, 這些指令也可根據編碼方式分成三種不同的格式, 分別是 A 型 J 型與 L 型 大部分的運算指令屬於 A (Arithmatic) 型, 而載入儲存指令通常屬於 L (Load & Store) 型, 跳躍指令則通常屬於 J (Jump) 型, 這三種型態的指令格式如下圖所示 圖 CPU0 的指令格式

31 狀態暫存器 R12 狀態暫存器 (Status Word : SW) 是用來儲存 CPU 的狀態值, 這些狀態是許多旗標的組合 例如, 零旗標 (Zero, 簡寫為 Z) 代表比較的結果為 0, 負旗標 (Negative, 簡寫為 N) 代表比較的結果為負值, 另外常見的旗標還有進位旗標 (Carry, 簡寫為 C), 溢位旗標 (Overflow, 簡寫為 V) 等等 下圖顯示了 CPU0 的狀態暫存器格式, 最前面的四個位元 N Z C V 所代表的, 正是上述的幾個旗標值 圖 CPU0 中狀態暫存器 SW 的結構 條件旗標的 N Z 旗標值可以用來代表比較結果是大於 (>) 等於 (=) 還是小於 (<), 當執行 CMP Ra, Rb 動作後, 會有下列三種可能的情形 1. 若 Ra > Rb, 則 N=0, Z=0 2. 若 Ra < Rb, 則 N=1, Z=0 3. 若 Ra = Rb, 則 N=0, Z=1

32 如此, 用來進行條件跳躍的 JGT JGE JLT JLE JEQ JNE 指令, 就可以根據 SW 暫存器當中的 N Z 等旗標決定是否進行跳躍 SW 中還包含中斷控制旗標 I (Interrupt) 與 T (Trap), 用以控制中斷的啟動與禁止等行為, 假如將 I 旗標設定為 0, 則 CPU0 將禁止所有種類的中斷, 也就是對任何中斷都不會起反應 但如果只是將 T 旗標設定為 0, 則只會禁止軟體中斷指令 SWI (Software Interrupt), 不會禁止由硬體觸發的中斷 SW 中還儲存有 處理器模式 的欄位,M=0 時為 使用者模式 (user mode) 與 M=1 時為 特權模式 (super mode) 等, 這在作業系統的設計上經常被用來製作安全保護功能 在使用者模式當中, 任何設定狀態暫存器 R12 的動作都會被視為是非法的, 這是為了進行保護功能的緣故 但是在特權模式中, 允許進行任何動作, 包含設定中斷旗標與處理器模式等位元, 通常作業系統會使用特權模式 (M=1), 而一般程式只能處於使用者模式 (M=0) 位元組順序 CPU0 採用大者優先 (Big Endian) 的位元組順序 (Byte Ordering), 因此代表值越大的位元組會在記憶體的前面 ( 低位址處 ), 代表值小者會在高位址處 由於 CPU0 是 32 位元的電腦, 因此, 一個字組 (Word) 占用 4 個位元組 (Byte), 因此, 像 LD R1, [100] 這樣的指令, 其實是將記憶體 中的字組取出, 存入到暫存器 R1 當中 LDB 與 STB 等指令, 其中的 B 是指 Byte, 因此,LDB R1, [100] 會將記憶體 100 中的 byte 取出, 載入到 R1 當中 但是, 由於 R1 的大小是 32 bits, 相當於 4 個 byte, 此時,LDB 與 STB 指令到底是存

33 取四個 byte 當中的哪一個 byte 呢? 這個問題的答案是 byte 3, 也就是最後的一個 byte 中斷程序 CPU0 的中斷為不可重入式中斷, 其中斷分為軟體中斷 SWI (Trap) 與硬體中斷 HWI (Interrupt) 兩類 硬體中斷發生時, 中段代號 INT_ADDR 會從中段線路傳入, 此時執行下列動作 : 1. LR=PC; INT=1 2. PC=INT_ADDR 軟體中斷 SWI Cx 發生時, 會執行下列動作 : 1. LR=PC; INT=1 2. PC=Cx; 中斷最後可以使用 IRET 返回, 返回前會設定允許中斷狀態 1. PC=LR; INT=0 實作 :CPU0 的指令表 雖然 CPU0 處理器按理講應該直接以硬體實作, 但是我們恐怕不容易直接請 台積電 或 聯電

34 幫我們燒一顆, 因此在實作上我們使用了 FPGA + Verilog + Altera DE2-70 進行 CPU 設計 但是電腦光是有硬體的話, 仍然是不能使用的, 否則您可以試試在 PC 上不要安裝作業系統, 然後想辦法使用那台電腦, 您肯定是會望著電腦興嘆的 因此 就算 CPU 已經設計好了, 我們仍然需要 組譯器 編譯器 作業系統 等系統軟體 (System Software), 才能成為一台真正可以用的電腦 另外 如果我們能夠設計出 虛擬機, 那麼在這台電腦的硬體還沒有被生產出來之前, 我們也能將程式放到 虛擬機 上去執行, 因此我們將會在本書的後半部描述這些 系統軟體 的結構, 並且用 JavaScript 與 C 語言各自實作一組軟體系統 我們將在下兩章中詳細說明組譯器 AS0.js 與虛擬機 VM0.js 的實作方法, 並詳細的列出原始碼 現在 我們將先列出 虛擬機 AS0 與 組譯器 VM0 都會用到的共同部分, 也就是 處理器 CPU0.js 與 指令表 optable.js 兩個程式的原始碼, 並講解程式內容與執行結果 在 JavaScript 當中要設計出指令表 optable.js 非常的簡單, 因為 JavaScript 的物件本身就是個符號表, 因此我們只要用 this[op.name] = op 這行指令就能在 optable 這個建構函數當中, 將指令物件插入到表格內 檔案 :optable.js

35 var c = require("./ccc"); var Op = function(line) { var tokens = line.split(/\s+/); this.name = tokens[0]; this.id = parseint(tokens[1], 16); this.type = tokens[2]; var optable = function(oplist) { for (i in oplist) { var op = new Op(opList[i]); this[op.name] = op; optable.prototype.id = function(op) {

36 return this[op].id; optable.prototype.dump=function() { for (key in this) { var op = this[key]; if (typeof(op)!="function") c.log("%s %s %s", c.fill(' ', op.name, 8), c.hex(op.id, 2), op.type); module.exports = optable; 在上述程式碼中, 每個指令包含了 指令名稱 (name), 指令代碼 (id) 與指令型態 (type) 等三個欄位, 舉例而言, 當一個載入指令的字串定義為 "LD 00 L" 時, 就會被函數 Op = function(line) 拆解為 { name="ld", id=0x00, type="l" 這樣的物件, 然後新增到指令表當中 利用上述的 optable.js, 我們可以輕易的建構出 CPU0 處理器的指令表, 以下是 cpu0.js 程式的原始

37 碼, 該程式建構出了 CPU0 的完整指令表, 包含 LD, ST,..., PUSHB, POPB 等真實的指令 另外 以下表格當中還包含了 RESW, RESB, WORD, BYTE 等資料定義假指令, 其中 RESW 用來保留 n 個 Word,RESB 用來保留 n 個 BYTE, WORD 則用來定義有初始值的整數變數,BYTE 則用來定義有初始值的位元組變數, 像是 8 位元整數或字串等 檔案 :cpu0.js var optable = require("./optable"); var oplist = [ "LD 00 L", "ST 01 L", "LDB 02 L", "STB 03 L", "LDR 04 L", "STR 05 L", "LBR 06 L", "SBR 07 L", "LDI 08 L", "CMP 10 A", "MOV 1 2 A", "ADD 13 A", "SUB 14 A", "MUL 15 A", "DIV 16 A", "AND 18 A", "OR 19 A", "XOR 1A A", "ADDI 1B A", "ROL 1C A", "ROR 1D A", "SHL 1E A", "SHR 1F A", "JEQ 20 J", "JNE 21 J", "JLT 22 J", "JGT 23 J", "JLE 24 J", "JGE 2 5 J", "JMP 26 J", "SWI 2A J", "JSUB 2B J","RET 2C J", "PUSH 30 J", "POP 31 J", "PUSHB 32 J",

38 "POPB 33 J", "RESW F0 D", "RESB F1 D", "WORD F2 D", "BYTE F3 D"]; var cpu = { "optable" : new optable(oplist) ; cpu.optable.dump(); module.exports = cpu; 執行結果 : D:\Dropbox\Public\oc\code>node cpu0.js LD 00 L ST 01 L LDB 02 L STB 03 L LDR 04 L STR 05 L LBR 06 L SBR 07 L

39 LDI CMP MOV ADD SUB MUL DIV AND OR XOR ADDI ROL ROR SHL SHR JEQ JNE JLT 08 L 10 A 12 A 13 A 14 A 15 A 16 A 18 A 19 A 1A A 1B A 1C A 1D A 1E A 1F A 20 J 21 J 22 J

40 JGT JLE JGE JMP SWI JSUB RET PUSH POP PUSHB POPB RESW RESB WORD BYTE 23 J 24 J 25 J 26 J 2A J 2B J 2C J 30 J 31 J 32 J 33 J F0 D F1 D F2 D F3 D 細心的讀者可能會注意到, 我們在 optable.js 當中引入了 ccc.js 這個函式庫, 這個函式庫是 開放電 腦計畫 當中的常用函數集合, 其原始碼如下所示

41 var util = require("util"); var assert = require("assert"); var fs = require("fs"); var c = {; // 本模組的傳回物件 c.log = console.log; // 將 console.log 名稱縮短一點 c.format = util.format; // 字串格式化 c.assert = assert.ok; // assert 函數, 若不符合條件則程式會停止 c.bits = function(word, from, to) { return word << (31-to) >>> (31- to+from); // 取得 from 到 to 之間的位元 c.signbits = function(word, from, to) { return word << (31-to) >> ( 31-to+from); // 取得 from 到 to 之間的位元 c.nonull = function(o) { if (o == null) return ""; else return o; // 將 null 改為空字串傳回 c.space = " "; // 空白字串,dup() 函數中使用到的

42 c.dup = function(ch, n) { // 傳回 ch 重複 n 次的字串 ; 範例 :dup('x', 3) = 'xxx' assert.ok(n < c.space.length); return c.space.substr(0, n).replace(/ /g, ch); c.fill = function(ch, o, len) { // 將字串填滿 ch, 例如 :fill(' ', 35, 5) = '35 '; fill('0', 35, -5) = '00035'; var str = o.tostring(); if (len >= 0) return str+c.dup(ch, len-str.length); else return c.dup(ch, -len-str.length)+str; c.base = function(n, b, len) { // 將數字 n 轉換為以 b 為基底的字串 ; 例如 :base(31, 16, 5) = '0001F'; var str = n.tostring(b);

43 return c.dup('0', len-str.length)+str; c.hex = function(n, len) { // 將數字 n 轉換 16 進位 ; 例如 : hex(31, 5) = '0001F'; hex(-3, 5) = 'FFFFD' var str = (n < 0? (0xFFFFFFFF + n + 1) : n).tostring(16).toupperc ase(); if (n < 0) return c.fill('f', str, -len).substr(-len); else return c.fill('0', str, -len).substr(-len); c.str2hex = function(str) { // 將字串轉為 16 進位碼, 例如 :s tr2hex('hello!') = '48656C6C6F21' var hex=""; for (i=0; i<str.length; i++) { var code = str.charcodeat(i);

44 hex += c.hex(code, 2); return hex; c.error = function(msg, err) { c.log(msg); c.log("error : (%s):%s", err.name, err.message); c.log(err.stack); process.exit(1); c.test = function() { c.log("bits(0xf3a4, 4, 7)=%s", c.hex(c.bits(0xf3a4, 4, 7), 4)); c.log("dup('x', 3)=%s", c.dup('x', 3)); c.log("fill('0', 35, -5)=%s", c.fill('0', 35, -5)); c.log("base(100, 16, 5)=%s", c.base(100, 16, 5)); c.log("hex(-100)=%s", c.hex(-100, 6));

45 c.log("str2hex(hello!)=%s", c.str2hex("hello!")); c.test(); module.exports = c; 以上程式的單元測試 c.test() 執行結果如下 D:\Dropbox\Public\oc\code>node ccc bits(0xf3a4, 4, 7)=000A dup('x', 3)=xxx fill('0', 35, -5)=00035 base(100, 16, 5)=00064 hex(-100)=ffff9c str2hex(hello!)=48656c6c6f21

46 虛擬機 - vm0 在前幾章中, 我們介紹了 CPU0 處理器的指令集, 以及組譯器的實作方式, 文章網址如下 : 現在, 我們將接焦點轉移到虛擬機 VM0 的實作上, 說明一個最簡易的虛擬機是如何設計出來的 組譯範例 首先 讓讀者回顧一下, 在上一篇文章中, 我們設計了一個組譯器, 可以組譯像以下的組合語言程 式 組合語言 :sum.as0 LD R1, sum ; R1 = sum = 0 LD R2, i ; R2 = i = 1 LDI R3, 10 ; R3 = 10 FOR: CMP R2, R3 ; if (R2 > R3) JGT EXIT ; goto EXIT ADD R1, R1, R2 ; R1 = R1 + R2 (sum = sum + i) ADDI R2, R2, 1 ; R2 = R2 + 1 ( i = i + 1)

47 JMP FOR ; goto FOR EXIT: ST R1, sum ; sum = R1 ST R2, i ; i = R2 LD R9, msgptr ; R9= pointer(msg) = &msg SWI 3 ; SWI 3 : 印出 R9 (=&msg) 中的字串 MOV R9, R1 ; R9 = R1 = sum SWI 4 ; SWI 2 : 印出 R9 (=R1=sum) 中的整數 RET ; return 返回上一層呼叫函數 i: RESW 1 ; int i sum: WORD 0 ; int sum=0 msg: BYTE " =", 0 ; char *msg = "sum=" msgptr: WORD msg ; char &msgptr = &msg 我們可以用 AS0 組譯器對這樣的 CPU0 組合語言進行組譯, 以下是組譯過程與結果, 會輸出機器碼 到目的檔中 D:\Dropbox\Public\oc\code>node as0 sum.as0 sum.ob

48 =================SAVE OBJ FILE================ 00 : 001F003C 002F A : C B FFFFEC 20 : 011F001C 012F F001D 2A : A C : D3D 接著 我們就可以用虛擬機 VM0 來執行這個目的檔, 我們可以選擇用預設不傾印的方式, 得到以下的簡要執行結果 虛擬機執行過程 ( 不傾印 ) D:\oc\code>node vm0 sum.ob =55 也可以用加上 -d 參數的方式, 傾印每一個指令的執行過程, 如下所示 : 虛擬機執行過程 ( 詳細傾印 ) D:\oc\code>node vm0 sum.ob0 -d

49 00 : 001F003C 002F A : C B FFFFEC 20 : 011F001C 012F F0022 2A : A C : B2E2E 2E2B3130 3D : 0044 PC=0000 IR=001F003C SW= R[01]=0x =0 PC=0004 IR=002F0034 SW= R[02]=0x =0 PC=0008 IR= A SW= R[03]=0x A=10 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x =0 PC=0018 IR=1B SW= R[02]=0x =1 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x =1

50 PC=0018 IR=1B SW= R[02]=0x =2 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x =3 PC=0018 IR=1B SW= R[02]=0x =3 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x =6 PC=0018 IR=1B SW= R[02]=0x =4 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x A=10 PC=0018 IR=1B SW= R[02]=0x =5 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x =

51 PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x F=15 PC=0018 IR=1B SW= R[02]=0x =6 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x =21 PC=0018 IR=1B SW= R[02]=0x =7 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x C=28 PC=0018 IR=1B SW= R[02]=0x =8 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x =36 PC=0018 IR=1B SW= R[02]=0x =9

52 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x D=45 PC=0018 IR=1B SW= R[02]=0x A=10 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x =55 PC=0018 IR=1B SW= R[02]=0x B=11 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x =0 PC=0010 IR= C SW= R[00]=0x =0 m[0040]=55 PC=0020 IR=011F001C SW= R[01]=0x =55 m[003c]=11 PC=0024 IR=012F0014 SW= R[02]=0x B=11 PC=0028 IR=009F0022 SW= R[09]=0x =68

53 =PC=002C IR=2A SW= R[00]=0x =0 PC=0030 IR= SW= R[09]=0x =55 55PC=0034 IR=2A SW= R[00]=0x =0 PC=0038 IR=2C SW= R[00]=0x =0 如果您詳細追蹤上述過程, 就能更清楚的看出每個指令執行時, 所造成的暫存器變化, 舉例而言, 您可以看到程式在 PC=000C 到 PC=001C 之間循環了很多次, 最後一次的循環印出下列內容 PC=000C IR= SW= R[0C]=0x = PC=0010 IR= C SW= R[00]=0x =0 PC=0014 IR= SW= R[01]=0x =55 PC=0018 IR=1B SW= R[02]=0x B=11 PC=001C IR=26FFFFEC SW= R[0F]=0x C=12 PC=000C IR= SW= R[0C]=0x =0 PC=0010 IR= C SW= R[00]=0x =0 m[0040]=55 其中得到 R[01]=0x =55 的計算結果, 正是整個程式計算 =55 的結果

54 VM0 虛擬機設計 接著 我們要來看看虛擬機 VM0 是如何設計的, 但是在這之前, 先讓我們看看虛擬機當中一個重 要的資料結構, OpTable 指令表這個物件, 其程式碼如下 : 檔案 :optable.js var c = require("./ccc"); var Op = function(line) { var tokens = line.split(/\s+/); this.name = tokens[0]; this.id = parseint(tokens[1], 16); this.type = tokens[2]; var optable = function(oplist) { for (i in oplist) { var op = new Op(opList[i]);

55 this[op.name] = op; optable.prototype.id = function(op) { return this[op].id; optable.prototype.dump=function() { for (key in this) { var op = this[key]; if (typeof(op)!="function") c.log("%s %s %s", c.fill(' ', op.name, 8), c.hex(op.id, 2), op.type); module.exports = optable;

56 然後 我們利用上述的 OpTable 模組, 加入了 CPU0 的指令集之後, 建出了 CPU0 這個代表處理器 的模組, 程式碼如下 檔案 :cpu0.js var optable = require("./optable"); var oplist = [ "LD 00 L", "ST 01 L", "LDB 02 L", "STB 03 L", "LDR 04 L", "STR 05 L", "LBR 06 L", "SBR 07 L", "LDI 08 L", "CMP 10 A", "MOV 1 2 A", "ADD 13 A", "SUB 14 A", "MUL 15 A", "DIV 16 A", "AND 18 A", "OR 19 A", "XOR 1A A", "ADDI 1B A", "ROL 1C A", "ROR 1D A", "SHL 1E A", "SHR 1F A", "JEQ 20 J", "JNE 21 J", "JLT 22 J", "JGT 23 J", "JLE 24 J", "JGE 2 5 J", "JMP 26 J", "SWI 2A J", "JSUB 2B J","RET 2C J", "PUSH 30 J", "POP 31 J", "PUSHB 32 J", "POPB 33 J", "RESW F0 D", "RESB F1 D", "WORD F2 D", "BYTE F3 D"];

57 var cpu = { "optable" : new optable(oplist) ; if (process.argv[2] == "-d") cpu.optable.dump(); module.exports = cpu; 有了上述的兩個模組作為基礎, 我們就可以開始撰寫虛擬機 VM0 了, 以下是其原始程式碼 檔案 :vm0.js var c = require("./ccc"); var cpu1 = require("./cpu0"); var Memory = require("./memory"); var isdump = process.argv[3] == "-d"; var IR = 16, PC = 15, LR = 14, SP = 13, SW = 12;

58 var ID = function(op) { return cpu1.optable[op].id; var run = function(objfile) { R = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 13, -1, 0, 16]; m = new Memory(1); m.load(objfile); if (isdump) m.dump(); var stop = false; while (!stop) { // 如果尚未結束 var tpc = R[PC]; R[0] = 0; // R[0] 永遠為 0 R[IR] = m.geti(r[pc]); // 指令擷取,IR=[PC..PC+3] R[PC] += 4; // 擷取完將 PC 加 4, 指向下一個指令 var op = c.bits(r[ir], 24, 31); // 取得

59 op 欄位,IR[24..31] var ra = c.bits(r[ir], 20, 23); // 取得 ra 欄位,IR[20..23] var rb = c.bits(r[ir], 16, 19); // 取得 rb 欄位,IR[16..19] var rc = c.bits(r[ir], 12, 15); // 取得 rc 欄位,IR[12..15] var c24= c.signbits(r[ir], 0, 23); // 取得 24 位元的 cx var c16= c.signbits(r[ir], 0, 15); // 取得 16 位元的 cx var c5 = c.bits(r[ir], 0, 4); // 取得 16 位元的 cx var addr = R[rb]+c16; var raddr = R[rb]+R[rc]; // 取得 位址 [Rb+Rc] var N = c.bits(r[sw], 31, 31); var Z = c.bits(r[sw], 30, 30);

60 // c.log("ir=%s ra=%d rb=%d rc=%d c24=%s c16=%s addr=%s", c.hex (R[IR], 8), ra, rb, rc, c.hex(c24, 6), c.hex(c16, 4), c.hex(addr, 8) ) switch (op) { // 根據 op 執行動作 case ID("LD") : R[ra] = m.geti(addr); break; // 處理 LD 指令 case ID("ST") : // 處理 ST 指令 m.seti(addr, R[ra]); if (isdump) c.log("m[%s]=%s", c.hex(addr,4), m.geti(addr)) ; break; case ID("LDB"): R[ra] = m.getb(addr); break; // 處理 LDB 指令 case ID("STB"): m.setb(addr, R[ra]); break; // 處理 STB 指令 case ID("LDR"): R[ra] = m.geti(raddr); break; // 處

61 理 LDR 指令 case ID("STR"): m.seti(raddr, R[ra]); break; // 處理 STR 指令 case ID("LBR"): R[ra] = m.getb(raddr); break; // 處理 LBR 指令 case ID("SBR"): m.setb(raddr, R[ra]); break; // 處理 SBR 指令 case ID("LDI"): R[ra] = c16; break; // 處理 LDI 指令 case ID("CMP"): { // 處理 CMP 指令, 根據比較結果, 設定 N,Z 旗標 if (R[ra] > R[rb]) { // > : SW(N=0, Z=0) R[SW] &= 0x3FFFFFFF; // N=0, Z=0 else if (R[ra] < R[rb]) { // < : SW(N=1, Z=0,...) R[SW] = 0x ; // N=1;

62 R[SW] &= 0xBFFFFFFF; // Z=0; else { // = : SW(N=0, Z=1) R[SW] &= 0x7FFFFFFF; // N=0; R[SW] = 0x ; // Z=1; ra = 12; break; case ID("MOV"): R[ra] = R[rb]; break; 理 MOV 指令 case ID("ADD"): R[ra] = R[rb]+R[rc]; break; 理 ADD 指令 case ID("SUB"): R[ra] = R[rb]-R[rc]; break; 理 SUB 指令 case ID("MUL"): R[ra] = R[rb]*R[rc]; break; 理 MUL 指令 // 處 // 處 // 處 // 處

63 case ID("DIV"): R[ra] = R[rb]/R[rc]; break; // 處理 DIV 指令 case ID("AND"): R[ra] = R[rb]&R[rc]; break; // 處理 AND 指令 case ID("OR") : R[ra] = R[rb] R[rc]; break; // 處理 OR 指令 case ID("XOR"): R[ra] = R[rb]^R[rc]; break; // 處理 XOR 指令 case ID("SHL"): R[ra] = R[rb]<<c5; break; // 處理 SHL 指令 case ID("SHR"): R[ra] = R[rb]>>c5; break; // 處理 SHR 指令 case ID("ADDI"):R[ra] = R[rb] + c16; break; // 處理 ADDI 指令 case ID("JEQ"): if (Z==1) R[PC] += c24; break; // 處理 JEQ 指令 Z=1 case ID("JNE"): if (Z==0) R[PC] += c24; break; // 處理 JNE 指令 Z=0

64 case ID("JLT"): if (N==1&&Z==0) R[PC] += c24; break; // 處理 JLT 指令 NZ=10 case ID("JGT"): if (N==0&&Z==0) R[PC] += c24; break; // 處理 JGT 指令 NZ=00 case ID("JLE"): if ((N==1&&Z==0) (N==0&&Z==1)) R[PC]+=c24; break; // 處理 JLE 指令 NZ=10 or 01 case ID("JGE"): if ((N==0&&Z==0) (N==0&&Z==1)) R[PC]+=c24; break; // 處理 JGE 指令 NZ=00 or 01 case ID("JMP"): R[PC]+=c24; break; // 處理 JMP 指令 case ID("SWI"): // 處理 SWI 指令 switch (c24) { case 3: c.printf("%s", m.getstr(r[9])); break; case 4: c.printf("%d", R[9]); break; default: var emsg = c.format("swi cx=%d not found!", c24)

65 ; c.error(emsg, null); break; break; case ID("JSUB"):R[LR] = R[PC]; R[PC]+=c24; break; // 處理 JSUB 指令 case ID("RET"): if (R[LR]<0) stop=true; else R[PC]=LR; bre ak; // 處理 RET 指令 case ID("PUSH"):R[SP]-=4; R[ra]=m.geti(addr); m.seti(r[sp], R[ra]); break; // 處理 PUSH 指令 case ID("POP"): R[ra] = m.geti(r[sp]); R[SP]+=4; break; // 處理 POP 指令 case ID("PUSHB"):R[SP]--; R[ra]=m.getb(addr); m.setb(r[sp], R[ra]); break; // 處理 PUSH 指令 case ID("POPB"):R[ra] = m.getb(r[sp]); R[SP]++; break; // 處理 POPB 指令 default: c.error("op not found!", null);

66 // switch if (isdump) c.log("pc=%s IR=%s SW=%s R[%s]=0x%s=%d", // 印出 PC, IR, R[r a] 暫存器的值, 以利觀察 c.hex(tpc,4), c.hex(r[ir],8), c.hex(r[sw],8), c.hex(ra,2), c.hex(r[ra], 8), R[ra]); // while run(process.argv[2]); 從上面的 VM0 虛擬機當中, 您可以看到, 假如不考慮執行速度的問題, 那麼要撰寫一個虛擬機是非常容易的事情 我們只要去忠實的模擬每一個指令所應該做的動作, 就可以完成虛擬機的設計了 讓我們稍微解釋一下上述 VM0 虛擬機的程式原理, 請讀者將焦點先放在以下的程式片段中... m = new Memory(1);

67 m.load(objfile); var stop = false; while (!stop) { 尚未結束... R[IR] = m.geti(r[pc]); 擷取,IR=[PC..PC+3] R[PC] += 4; 完將 PC 加 4, 指向下一個指令 var op = c.bits(r[ir], 24, 31); op 欄位,IR[24..31] var ra = c.bits(r[ir], 20, 23); ra 欄位,IR[20..23] var rb = c.bits(r[ir], 16, 19); rb 欄位,IR[16..19] var rc = c.bits(r[ir], 12, 15); rc 欄位,IR[12..15] var c24= c.signbits(r[ir], 0, 23); // 如果 // 指令 // 擷取 // 取得 // 取得 // 取得 // 取得 // 取得

68 24 位元的 cx var c16= c.signbits(r[ir], 0, 15); // 取得 16 位元的 cx var c5 = c.bits(r[ir], 0, 4); // 取得 16 位元的 cx var addr = R[rb]+c16; var raddr = R[rb]+R[rc]; // 取得 位址 [Rb+Rc] var N = c.bits(r[sw], 31, 31); var Z = c.bits(r[sw], 30, 30); switch (op) { // 根據 op 執行動作 case ID("LD") : R[ra] = m.geti(addr); break; // 處 理 LD 指令... case ID("JMP"): R[PC]+=c24; break; // 處理 JMP 指令...

69 case ID("JSUB"):R[LR] = R[PC]; R[PC]+=c24; break; // 處理 JSUB 指令... case ID("RET"): if (R[LR]<0) stop=true; else R[PC]=LR; brea k; // 處理 RET 指令... 首先我們用 m = new Memory(1) 建立一個空的記憶體, 然後再用 m.load(objfile) 載入目的檔到記憶體中, 接著就開始進入 while (!stop) 起頭的指令解譯迴圈了, 然後接著用 R[IR] = m.geti(r[pc]) 這個指令取出程式計數暫存器 PC 所指到的記憶體內容 m[pc], 然後放到指令暫存器 IR 當中, 接著就可以取出指令暫存器 IR 當中的欄位, 像是指令碼 op 暫存器 ra, rb, rc 與常數部分 c24, c16, c5 等欄位 然後就能對每個指令所應做的動作進行模擬, 例如 LD 指令的功能是將記憶體位址 addr = R[rb]+c16 的內容取出, 放到編號 ra 的暫存器當中, 因此只要用 R[ra] = m.geti(addr) 這樣一個函數呼叫, 就可以完成模擬的動作了 當然 有些模擬動作很簡單, 可以用一兩個指令做完, 像是 LD, ST, JMP 等都是如此, 但有些動作就比較複雜, 像是 JSUB, RET, PUSH, POP 等就要好幾個指令, 最複雜的大概是 CMP 與 SWI 這兩個指令了,CMP 由於牽涉到比較動作且需要設定 N, Z 等旗標, 所以程式碼較長如下 :...

70 case ID("CMP"): { // 處理 CMP 指令, 根據比較結果, 設定 N,Z 旗標 if (R[ra] > R[rb]) { // > : SW(N=0, Z=0) R[SW] &= 0x3FFFFFFF; // N=0, Z=0 else if (R[ra] < R[rb]) { // < : SW(N=1, Z=0,...) R[SW] = 0x ; // N=1; R[SW] &= 0xBFFFFFFF; // Z=0; else { // = : SW(N=0, Z=1) R[SW] &= 0x7FFFFFFF; // N=0; R[SW] = 0x ; // Z=1; ra = 12; break;

71 ... 而 SWI 則是軟體中斷, 這個部分也可以不做任何事, 不過如果要支援某些中斷函數的話, 就可以在 這個指令中進行模擬, 目前 SWI 指令處理的原始碼如下 : SWI 指令 ; case ID("SWI"): // 處理 switch (c24) { case 3: c.printf("%s", m.getstr(r[9])); break; case 4: c.printf("%d", R[9]); break; default: var emsg = c.format("swi cx=%d not found!", c24) c.error(emsg, null); break; break;

72 目前我們支援兩個中斷處理呼叫, 也就是 SWI 3 與 SWI 4 其中的 SWI 4 會在螢幕上印出一個儲存在暫存器 R[9] 當中的整數, 而 SWI 3 會在螢幕上印出一個記憶體當中的字串, 這個字串的起始位址也是儲存在暫存器 R[9] 當中的 結語 透過 VM0, 筆者希望能夠讓讀者清楚的瞭解虛擬機的設計方式, 當然 VM0 是一個 跑得很慢 的虛擬機 如果要讓虛擬機跑得很快, 通常要搭配 立即編譯技術 (Just in Time Compiler, JIT), 像是 Java 虛擬機 JVM 就是利用 JIT 才能夠讓 Java 程式跑得夠快 另外 像是 VMWare VirtualBox 等, 則是在相同的 x86 架構下去執行的, 因此重點變成 如何有效的繞過作業系統的控管, 讓機器碼在 CPU 上執行 的問題了 在開放原始碼的領域,QEMU 是一個非常重要的虛擬機, 其做法可以參考下列 QEMU 原作者 bellard 的論文 : 摘要如下 :

73 The first step is to split each target CPU instruction into fewer simpler instructions called micro operations. Each micro operation is implemented by a small piece of C code. This small C source code is compiled by GCC to an object file. The micro operations are chosen so that their number is much smaller (typically a few hundreds) than all the combinations of instructions and operands of the target CPU. The translation from target CPU instructions to micro operations is done entirely with hand coded code. The source code is optimized for readability and compactness because the speed of this stage is less critical than in an interpreter. A compile time tool called dyngen uses the object file containing the micro operations as input to generate a dynamic code generator. This dynamic code generator is invoked at runtime to generate a complete host function which concatenates several micro operations. 筆者先前粗略的看了一下, 原本以為 QEMU 則是機器法反編譯為 C 語言基本運算後, 再度用 gcc 編譯為機器碼, 才能達到高速執行的目的, 但是仔細看又不是這樣, 想想還是不要自己亂解釋 好了, 不過有高手 J 兄來信說明如下, 原文附上 : QEMU 採取的技術為 portable JIT, 本質上是一種 template-based compilation, 事先透過 TCG 做 code generation, 使得 C-like template 得以在執行時期可對應到不同平台的 machine code, 而執行 時期沒有 gcc 的介入, 我想這點該澄清 像 bellard 這種高手寫的虛擬機, 果然是又快又好啊!

74 VM0 與 QEMU 相比, 速度上致少慢了幾十倍, 不過程式碼絕對是簡單很多就是了

75 組譯器 - as0 在前面幾章, 我們介紹了開放電腦計畫中的 處理器 -- 包含 CPU0 的結構 指令集與編碼方式 在本章中, 我們將為 CPU0 設計一個組譯器 AS0, 以便能更深入理解 CPU0 的結構, 並瞭解組譯器的設計原理 組譯範例 讓我們先用範例導向的方式, 先看看一個 CPU0 的組合語言程式, 如下所示 : 組合語言 :sum.as0 LD R1, sum ; R1 = sum = 0 LD R2, i ; R2 = i = 1 LDI R3, 10 ; R3 = 10 FOR: CMP R2, R3 ; if (R2 > R3) JGT EXIT ; goto EXIT ADD R1, R1, R2 ; R1 = R1 + R2 (sum = sum + i) ADDI R2, R2, 1 ; R2 = R2 + 1 ( i = i + 1) JMP FOR ; goto FOR

76 EXIT: ST R1, sum ; sum = R1 ST R2, i ; i = R2 LD R9, msgptr ; R9= pointer(msg) = &msg SWI 3 ; SWI 3 : print string &msg MOV R9, R1 ; R9 = R1 = sum SWI 2 ; SWI 2 : print number sum RET ; return to CALLER i: RESW 1 ; int i sum: WORD 0 ; int sum=0 msg: BYTE "sum=", 0 ; char *msg = "sum=" msgptr: WORD msg ; char &msgptr = &msg 上述程式是一個可以計算 之結果的程式, 最後會透過軟體中斷 (SWI, Software Interrupt) 的 方式, 印出訊息到螢幕畫面上, 以下是利用我們寫的組譯器 AS0 對上述程式進行組譯的過程 : D:\oc\code>node as0 sum.as0 sum.ob0 Assembler:asmFile=sum.as0 objfile=sum.ob0 ===============Assemble=============

77 [ ' LD R1, sum ; R1 = sum = 0', ' LD R2, i ; R2 = i = 1', ' LDI R3, 10 ; R3 = 10', 'FOR: CMP R2, R3 ; if (R2 > R3)', ' JGT EXIT ; goto EXIT', ' ADD R1, R1, R2 ; R1 = R1 + R2 (sum = sum + i)', ' ADDI R2, R2, 1 ; R2 = R2 + 1 ( i = i + 1)', ' JMP FOR ; goto FOR', 'EXIT: ST R1, sum ; sum = R1', ' ST R2, i ; i = R2', ' LD R9, msgptr ; R9= pointer(msg) = &msg', ' SWI 3 ; SWI 3 : 印出 R9 (=&msg) 中的字串 ', ' MOV R9, R1 ; R9 = R1 = sum', ' SWI 4 ; SWI 2 : 印出 R9 (=R1=sum) 中的整數 ', ' RET ; return 返回上一層呼叫函數 ', 'i: RESW 1 ; int i', 'sum: WORD 0 ; int sum=0',

78 'msg: BYTE " =", 0 ; char *msg = "sum="', 'msgptr: WORD msg ; char &msgptr = &msg' ] =================PASS1================ 0000 LD R1,sum L LD R2,i L LDI R3,10 L C FOR CMP R2,R3 A JGT EXIT J ADD R1,R1,R2 A ADDI R2,R2,1 A 1B 001C JMP FOR J EXIT ST R1,sum L ST R2,i L LD R9,msgptr L C SWI 3 J 2A 0030 MOV R9,R1 A SWI 4 J 2A 0038 RET J 2C

79 003C i RESW 1 D F sum WORD 0 D F msg BYTE " =",0 D F3 004E msgptr WORD msg D F2 ===============SYMBOL TABLE========= FOR 000C EXIT 0020 i 003C sum 0040 msg 0044 msgptr 004E =============PASS2============== 0000 LD R1,sum L F003C 0004 LD R2,i L F LDI R3,10 L A 000C FOR CMP R2,R3 A JGT EXIT J C 0014 ADD R1,R1,R2 A

80 0018 ADDI R2,R2,1 A 1B 1B C JMP FOR J 26 26FFFFEC 0020 EXIT ST R1,sum L F001C 0024 ST R2,i L F LD R9,msgptr L F C SWI 3 J 2A 2A MOV R9,R1 A SWI 4 J 2A 2A RET J 2C 2C C i RESW 1 D F sum WORD 0 D F msg BYTE " =",0 D F3 312B2E2E2E2B31303D00 004E msgptr WORD msg D F =================SAVE OBJ FILE================ 00 : 001F003C 002F A : C B FFFFEC 20 : 011F001C 012F F0022 2A000003

81 30 : A C : B2E2E 2E2B3130 3D : 0044 當您組譯完成之後, 就可以利用開放電腦計畫中的虛擬機 VM0 執行 AS0 所輸出的目的檔 sum.ob0, 其執行過程如下 : D:\oc\code>node vm0 sum.ob =55 AS0 組譯器設計 組譯器的設計, 通常採用兩階段的編碼方式, 第一階段 (PASS1) 先計算出每個指令的位址, 並記住所有標記符號的位址 然後在第二階段 (PASS2) 才真正將指令轉換為機器碼輸出, 在以下 AS0 組譯器的設計當中, 我們就採用了這種兩階段的處理方式 為了讓組譯器能夠容易修改與移植, 我們將一般組譯器都會有的基礎結構 ( 抽象的組譯器物件 ) 放在 as.js 這個程式模組當中, 然後將與 CPU0 有關的部分放在 as0.js 這個實作模組當中, 以下先列出 as.js 這個抽象物件模組 檔案 :as.js ( 抽象組譯器物件 )

82 var fs = require("fs"); // 引用檔案函式庫 var c = require("./ccc"); // 引用基本函式庫 ccc.js var Memory = require("./memory"); // 引用記憶體物件 memory.js var as = function(optable) { // 抽象組譯器物件 this.optable = optable; // 取得指令表 optable this.assemble = function(asmfile, objfile) { // 組譯器的主要函數 this.lines = []; this.codes = []; // 設定程式碼行 (lines), 指令陣列 (codes) this.symtable = {; // 建立空的符號表 (symtable) c.log("assembler:asmfile=%s objfile=%s", asmfile, objfile); // 輸入組合語言 輸出目的檔 c.log("===============assemble============="); var text = fs.readfilesync(asmfile, "utf8"); // 讀取檔案到 text 字串中 this.lines = text.split(/[\r\n]+/); // 將組合語言分割成一行一行

83 c.log(this.lines); // 印出組合語言以便觀察 this.pass1(); // 第一階段 : 計算位址 c.log("===============symbol TABLE========="); for (s in this.symtable) { // 印出符號表以便觀察 c.log("%s %s", c.fill(' ',s,8), c.hex(this.symtable[s].address, 4)); this.pass2(); // 第二階段 : 建構目的碼 this.saveobjfile(objfile); // 輸出目的檔 this.pass1 = function() { // 第一階段的組譯 var address = 0; // 程式計數器 PC 的起始位址為 0 c.log("=================pass1================"); for (var i in this.lines) { // 對於每一行 try { var code = this.parse(this.lines[i]); // 剖析並建立 code 物件 code.address = address; // 設定該行的位址

84 if (code.label.length!= 0) { // 如果有標記符號 this.symtable[code.label] = code; // 加入符號表中 this.codes.push(code); // 將剖析完成的指令放入陣列中 c.log("%s", code); // 印出指令物件 address += this.size(code); // 計算下一個指令位址 catch (err) { // 語法有錯, 印出錯誤的行號與內容 c.error(c.format("line %d : %s", i, this.lines[i]), err); this.pass2 = function(codes) { // 組譯器的第二階段 c.log("=============pass2=============="); for (var i in this.codes) { // 對每一個指令 try { this.translate(this.codes[i]); // 將組合語言指令翻譯成機器碼 c.log("%s", this.codes[i]); // 印出指令物件 ( 含組合語言與機器碼

85 ) catch (err) { // 語法有錯, 印出錯誤的行號與內容 c.error(c.format("line %d : %s", i, this.lines[i]), err); this.saveobjfile = function(objfile) { // 儲存目的檔 c.log("=================save OBJ FILE================"); var obj = ""; // obj 為目的檔的 16 進位字串, 初始化為空字串 for (var i in this.codes) // 對於每個指令 obj += this.codes[i].obj; // 都將目的碼加入 obj 字串中 var m = new Memory(1); // Memory 物件, 用來將 16 進位目的碼轉為 2 進位儲存 m.loadhex(obj); // 將 16 進位目的碼載入記憶體 m.dump(); // 輸出記憶體內容 m.save(objfile); // 將記憶體內容除存到目的檔 objfile 中

86 this.size = function(code) { // 計算指令所佔空間大小, 在 pass1() 當中會呼叫此函數 var len = 0, unitsize = 1; // len: 指令大小, unitsize: 每單位大小 (BYTE=1, WORD=4) switch (code.op.name) { // 根據運算碼 op case "RESW" : return 4 * parseint(code.args[0]); // 如果是 R ESW, 大小為 4* 保留量 ( 參數 0) case "RESB" : return 1 * parseint(code.args[0]); // 如果是 R ESB, 大小為 1* 保留量 ( 參數 0) case "WORD" : unitsize = 4; // 沒有 break, 繼續執行到 BYTE 部分的程式 ( 共用 ) case "BYTE" : // 如果是 BYTE, 大小是 1* 參數個數 for (i in code.args) { // 對於 BYTE 或 WORD 中的每個元素 if (code.args[i].match(/^\".*?\"$/)) // 如果是字串, 像 "He llo!" len += (code.args[i].length - 2) * unitsize; // 則大小為 unitsize* 字串長度

87 else // 否則大小就是 unitsize (BYTE=1, WORD=4) len += unitsize; return len; case "" : return 0; // 如果只是標記, 大小為 0 default : return 4; // 其他情形 ( 指令 ), 大小為 4 module.exports = as; // 匯出 抽象組譯器物件 as 請注意,as.js 模組缺少 parse(), translate() 等函數, 由於這兩個函數是與 CPU0 設計有關的部分, 因此定義在後續的 as0.js 當中註 : 雖然上述程式中的 size() 函數也可能會與 CPU 的設計有關, 但是對於 32 bit 的 CPU 而言, 可以通用, 因此我們將此函數放在上層的 as.js 當中, 如果要定義非 32 位元 CPU 或者重新定義組合語言的語法時, 可以覆寫掉這個 size() 函數 在上述程式中, 我們用到了一個 code 物件, 以下是該物件之定義模組 code.js 的原始碼 :

88 檔案 :code.js ( 指令物件 ) var c = require("./ccc"); // 引用基本函式庫 ccc.js var code = function(line, optable) { // 指令物件 code this.parser = function(str) { // 剖析暫存器參數 Ra, 例如 parse('r3 ') = 3 var rmatch = /R(\d+)/.exec(str); // 比對取出 Ra 中的數字 if (rmatch == null) // 如果比對失敗, 則傳回 NaN return NaN; return parseint(rmatch[1]); // 否則傳回暫存器代號 ( 數字 ) this.tostring = function() { // 輸出格式化後的指令 return c.format("%s %s %s %s %s %s %s", c.hex(this.address, 4), c.fill(' ',this.label,8), c.fill(' ',this.op.name, 8), c.fill(' ',this.args, 16), this.op.type, c.hex(this.op.id,2),

89 this.obj); var labcmd = /^((\w+):)?\s*([^;]*)/; // 指令的語法 var parts = labcmd.exec(line); // 分割出標記與命令 var tokens = parts[3].trim().split(/[,\t\r]+/); // 將命令分割成基本單元 var opname = tokens[0]; // 取出指令名稱 this.label = c.nonull(parts[2]); // 取出標記 (\w+) this.args = tokens.slice(1); // 取出參數部份 this.op = optable[opname]; // 取得指令表中的 OP 物件 this.obj = ""; // 清空目的碼 16 進位字串 obj module.exports = code; // 匯出指令物件 code 現在 我們以經完成組譯器抽象架構的設計了, 可以開始進入與 CPU0 有關的實作部分, 也就是

90 as0.js 的組譯器實作, 補完 as.js 當中所沒有的 parse(), translate() 等函數了, 以下是其原始程式碼 檔案 :as0.js ( 具體的 CPU0 組譯器 AS0) var c = require("./ccc"); // 引用基本函式庫 ccc.js var as = require("./as"); // 引用抽象組譯器物件 as.js var code = require("./code"); // 引用指令物件 code.js var cpu0 = require("./cpu0"); // 引用處理器物件 cpu0.js var as0 = new as(cpu0.optable); // 建立 as0 組譯器物件 as0.parse = function(line) { // 剖析組合語言指令, 建立 code 物件 return new code(line, this.optable); as0.translate = function(code) { // 指令的編碼函數 var ra=0, rb=0, rc=0, cx=0; var pc = code.address + 4; // 提取後 PC 為位址 +4 var args = code.args, parser = code.parser; // 取得 code 物件的函

91 數 var labelcode = null; // JMP label 中 label 所對應行的物件, 稱為 l abelcode if (code.op == undefined) { // 如果沒有指令碼 ( 只有標記 ), 則清空目的碼 code.obj = ""; return; switch (code.op.type) { // 根據指令型態 case 'J' : // 處理 J 型指令, 編出目的碼 OP Ra+cx switch (code.op.name) { case "RET": case "IRET" : // 如果式返回或中斷返回, 則只要輸出 op 碼 break; case "SWI" : // 如果是軟體中斷指令, 則只有 cx 參數有常數值 cx = parseint(args[0]); break; default : // 其他跳躍指令, 例如 JMP label, JLE label 等

92 labelcode = this.symtable[args[0]]; // 取得 label 符號位址 cx = labelcode.address - pc; // 計算 cx 欄位 break; code.obj = c.hex(code.op.id,2)+c.hex(cx, 6); // 編出目的碼 OP Ra+cx break; case 'L' : // 處理 L 型指令, 編出目的碼 OP Ra, Rb, cx ra = parser(args[0]); // 取得 Ra 欄位 switch (code.op.name) { case "LDI" : // 處理 LDI 指令 cx = parseint(args[1]); // 取得 cx 欄位 break; default : // 處理 LD, ST, LDB, STB 指令 if (args[1].match(/^[a-za-z]/)){ // 如果是 LD LABEL 這類情況 labelcode = this.symtable[args[1]]; // 取得標記的 code

93 物件 rb = 15; // R[15] is PC cx = labelcode.address - pc; // 計算標記與 PC 之間的差值 else { // 否則, 若是像 LD Ra, Rb+100 這樣的指令 rb = parser(args[2]); // 取得 rb 欄位 cx = parseint(args[3]); // 取得 cx 欄位 ( 例如 100) break; code.obj = c.hex(code.op.id, 2)+c.hex(ra, 1)+c.hex(rb, 1)+c.he x(cx, 4); // 編出目的碼 OP Ra, Rb, cx break; case 'A' : // 處理 A 型指令, 編出目的碼 OP Ra, Rb, Rc, cx ra = parser(args[0]); // 取得 Ra 欄位 switch (code.op.name) { case "LDR": case "LBR": case "STR": case "SBR": // 處理 L DR, LBR, STR, SBR 指令, 例如 LDR Ra, Rb+Rc

94 rb = parser(args[1]); // 取得 Rb 欄位 rc = parser(args[2]); // 取得 Rc 欄位 break; case "CMP": case "MOV" : // 處理 CMP 與 MOV 指令,CMP Ra, Rb ; MOV Ra, Rb rb = parser(args[1]); // 取得 Rb break; case "SHL": case "SHR": case "ADDI": // 處理 SHL, SHR, ADDI 指令, 例如 SHL Ra, Rb, Cx rb = parser(args[1]); // 取得 Rb 欄位 cx = parseint(args[2]); // 取得 cx 欄位 ( 例如 3) break; case "PUSH": case "POP": case "PUSHB": case "POPB" : // 處理 PUSH, POP, PUSHB, POPB break; // 例如 PUSH Ra, 只要處理 Ra 就好,A 型一進入就已經處理 Ra 了 default : // 其他情況, 像是 ADD, SUB, MUL, DIV, AND, OR, XO R 等, 例如 ADD Ra, Rb, Rc

95 rb = parser(args[1]); // 取得 Rb 欄位 rc = parser(args[2]); // 取得 Rc 欄位 break; code.obj = c.hex(code.op.id, 2)+c.hex(ra, 1)+c.hex(rb, 1)+c.he x(rc,1)+c.hex(cx, 3); // 編出目的碼 OP Ra, Rb, Rc, cx break; case 'D' : { // 我們將資料宣告 RESW, RESB, WORD, BYTE 也視為一種指令, 其形態為 D var unitsize = 1; // 預設的型態為 BYTE, 資料大小 = 1 switch (code.op.name) { case "RESW": case "RESB": // 如果是 RESW 或 RESB, 例如 a:re SB 2 code.obj = c.dup('0', this.size(code)*2); // 1 個 byte 的空間要用兩個 16 進位的 00 去填充 break; // 例如 :a RESB 2 會編為 '0000' case "WORD": // 如果是 WORD, 佔 4 個 byte

96 unitsize = 4; case "BYTE": { // 如果是 BYTE, 佔 1 個 byte code.obj = ""; // 一開始目的碼為空的 for (var i in args) { // 對於每個參數, 都要編為目的碼 if (args[i].match(/^\".*?\"$/)) { // 該參數為字串, 例如 : "Hello!" 轉為 68656C6C6F21 var str = args[i].substring(1, args[i].length-1); // 取得 "..." 中間的字串內容 code.obj += c.str2hex(str); // 將字串內容 ( 例如 Hello! ) 轉為 16 進位 ( 例如 68656C6C6F21) else if (args[i].match(/^\d+$/)) { // 該參數為常數, 例如 26 code.obj += c.hex(parseint(args[i]), unitsize*2); // 將常數轉為 16 進位目的碼 ( 例如 26 轉為 1A) else { // 該參數為標記, 將標記轉為記憶體位址, 例如 msgp tr: WORD msg 中的 msg 轉為位址 ( 例如 : ) labelcode = this.symtable[args[i]]; // 取得符號表內的物件

97 code.obj += c.hex(labelcode.address, unitsize*2); // 取得位址並轉為 16 進位, 塞入目的碼中 break; // case BYTE: // switch break; // case 'D' // 使用範例 node as0 sum.as0 sum.ob0 // 其中 argv[2] 為組合語言檔, argv[3] 為目的檔 as0.assemble(process.argv[2], process.argv[3]); 在 as0.js 組譯器中我們還匯入了 cpu0.js 這個模組, 雖然此模組已經於上一期當中介紹過了, 不過由於上一期有幾個指令型態設錯了 (LDR, STR, LBR, SBR 應該是 A 格式, 上一期當中誤植為 L 格

98 式 ), 因此我們再度列出 cpu0.js 的更正後內容如下 : var optable = require("./optable"); // 引用指令表 optable 物件 // 指令陣列 var oplist = [ "LD 00 L", "ST 01 L", "LDB 02 L", "STB 03 L", "LDR 04 A", "STR 05 A", "LBR 06 A", "SBR 07 A", "LDI 08 L", "CMP 10 A", "MOV 1 2 A", "ADD 13 A", "SUB 14 A", "MUL 15 A", "DIV 16 A", "AND 18 A", "OR 19 A", "XOR 1A A", "ADDI 1B A", "ROL 1C A", "ROR 1D A", "SHL 1E A", "SHR 1F A", "JEQ 20 J", "JNE 21 J", "JLT 22 J", "JGT 23 J", "JLE 24 J", "JGE 2 5 J", "JMP 26 J", "SWI 2A J", "JSUB 2B J","RET 2C J", "PUSH 30 J", "POP 31 J", "PUSHB 32 J", "POPB 33 J", "RESW F0 D", "RESB F1 D", "WORD F2 D", "BYTE F3 D"];

99 var cpu = { "optable" : new optable(oplist) ; // cpu0 處理器物件, 內含一個指令表 optable if (process.argv[3] == "-t") // 如果使用 node cpu0 -t 可以印出指令表 cpu.optable.dump(); module.exports = cpu; // 匯出 cpu0 模組 程式說明 在上述的 as.js 程式中, 第一階段 pass1() 的工作是將每個組合語言指令的位址編好, 並紀錄下所有符 號的位址, 這個過程顯示在組譯報表的 PASS1 部分, 您可以看到上述 as0 組譯器的輸出範例中, 每 個指令的位址都被計算出來了, 如下所示 : =================PASS1================ 0000 LD R1,sum L LD R2,i L LDI R3,10 L C FOR CMP R2,R3 A 10

100 0010 JGT EXIT J ADD R1,R1,R2 A ADDI R2,R2,1 A 1B 001C JMP FOR J EXIT ST R1,sum L ST R2,i L LD R9,msgptr L C SWI 3 J 2A 0030 MOV R9,R1 A SWI 4 J 2A 0038 RET J 2C 003C i RESW 1 D F sum WORD 0 D F msg BYTE " =",0 D F3 004E msgptr WORD msg D F2 而且在 PASS1 完成之後, 所有符號的位址都會被記錄在符號表當中, 如下所示 :

101 ===============SYMBOL TABLE========= FOR 000C EXIT 0020 i 003C sum 0040 msg 0044 msgptr 004E 接著在 PASS2 當中, 我們就可以利用這些符號表中的位址, 編制出每個指令中的符號的 定址方式 相對位址 等等, 如下表所示 : =============PASS2============== 0000 LD R1,sum L F003C 0004 LD R2,i L F LDI R3,10 L A 000C FOR CMP R2,R3 A JGT EXIT J C 0014 ADD R1,R1,R2 A

102 0018 ADDI R2,R2,1 A 1B 1B C JMP FOR J 26 26FFFFEC 0020 EXIT ST R1,sum L F001C 0024 ST R2,i L F LD R9,msgptr L F C SWI 3 J 2A 2A MOV R9,R1 A SWI 4 J 2A 2A RET J 2C 2C C i RESW 1 D F sum WORD 0 D F msg BYTE " =",0 D F3 312B2E2E2E2B31303D00 004E msgptr WORD msg D F 由於 CPU0 設計得很簡單, 因此對於一般的指令而言 ( 像是 ADD, MOV, RET 等 ), 編制出機器碼是很 容易的, 例如 RET 指令不包含任何參數, 因此其機器碼就是在指令碼 OP=2C 後面補 0, 直到填滿 32bit (8 個 16 進位數字 ) 為止, 而 ADD R1,R1,R2 的編碼也很容易, 就是將指令碼 OP=13 補上暫存器 代號 1, 1, 2 之後再補 0, 形成 的編碼

103 最難處理的是有標記的指令, 舉例而言, 像是 JGT EXIT 的機器碼 C 與 JMP FOR 的機器碼 26FFFFEC 是怎麼來的呢? 關於這點, 我們必須用較長的篇幅解釋一下 : 在上述 AS0 程式的設計當中, 我們一律用 相對於程式計數器 PC 的定址法 來進行標記的編碼 (cx = label.address-pc), 例如在 JGT EXIT 這個指令中, 由於標記 EXIT 的位址是 0020, 而 JGT EXIT 指令的位址為 0010, 因此兩者之差距為 0010, 但是由於 JGT EXIT 指令執行時其程式計數器 PC 已經進到下一個位址 (0014) 了 ( 在指令擷取階段完成後就會進到下一個位址 ), 所以 PC 與 FOR 標記之間的位址差距為 (cx = label.address-pc= = 000C) ( 請注意這是用 16 進位的減法 ), 因此整個 JGT EXIT 指令就被組譯為 JGT EXIT = JGT R15+cx = 23 F 000C ( 其中 R15 是 CPU0 的程式計數器 PC, 所以暫存器 Ra 部分編為 15 的十六進位值 F) 但是 有時候相對定址若是負值, 也就是標記在指令的前面, 像是 JMP FOR 的情況時, 最後 cx = label.address-pc 計算出來會是負值, 此時就必須採用 2 補數表示法, 例如 JMP FOR 的情況 (cx = label.address-pc = 000C-0020 = -0014) ( 請注意這是用 16 進位的減法 ), 採用 2 補數之後就會變成 FFFFEC, 因此 JMP FOR 被編為 26 F FFFEC 結語 現在 我們已經完成了組譯器 AS0 的設計, 並解析了整個組譯器的原始碼, 希望透過這種方式, 可 以讓讀者瞭解整個組譯器的設計過程 在後續的文章之中, 我們還會介紹開放電腦計畫中 虛擬

104 機 編譯器 的 JavaScript 原始碼, 以及實作 CPU0 處理器的 Verilog 原始碼 然後再進入作業系統 的設計部分, 希望透過這種方式, 可以讓讀者瞭解如何 自己動手設計一台電腦, 完成 開放 電腦計畫 的主要目標

105 編譯器 在前面的文章中, 我們首先介紹了整體架構, 接著設計出了 CPU0 的指令集, 然後寫出了 AS0 組譯器與 VM0 虛擬機 : 但是 直到目前為止, 我們都還沒有為開放電腦計畫打造出 高階語言, 因此本文將設計出一個名為 J0 的高階語言 ( 代表 JavaScript 的精簡版 ), 並採用 JavaScript 去實作, 然後在 node.js 平台中執行 有了 J0 語言與 J0C 編譯器之後, 我們就可以創建出以下的工具鏈 : J0 語言 ( j0c 編譯器 ) => IR0 中間碼 (ir2as 轉換器 ) => CPU0 組合語言 (AS0 組譯器 ) => CPU0 機器 碼 (VM0 虛擬機執行或 CPU0 FPGA 執行 ) 編譯器 : 高階語言轉中間碼 - j0c 在前面的文章中, 我們首先介紹了整體架構, 接著設計出了 CPU0 的指令集, 然後寫出了 AS0 組譯器與 VM0 虛擬機 : 但是 直到目前為止, 我們都還沒有為開放電腦計畫打造出 高階語言, 因此本文將設計出一個名為 J0 的高階語言 ( 代表 JavaScript 的精簡版 ), 並採用 JavaScript 去實作, 然後在 node.js 平台中執

106 行 有了 J0 語言與 J0C 編譯器之後, 我們就可以創建出以下的工具鏈 : J0 語言 ( j0c 編譯器 ) => IR0 中間碼 (ir2as 轉換器 ) => CPU0 組合語言 (AS0 組譯器 ) => CPU0 機器 碼 (VM0 虛擬機執行或 CPU0 FPGA 執行 ) JavaScript 簡化版 -- J0 語言以下是一個 J0 語言的程式範例, 支援了 function, while, if, for 等語句, 並且支援了 陣列與字典 等資料結構 檔案 :test.j0 s = sum(10); function sum(n) { s = 0; i=1; while (i<=10) { s = s + i;

107 i++; return s; m = max(3,5); function max(a, b) { if (a > b) return a; else return b; function total(a) { s = 0; for (i in a) { s = s + a[i];

108 return s; a = [ 1, 3, 7, 2, 6]; t = total(a); word = { e:"dog", c:" 狗 " ; 原始碼接著我們用 node.js + javascript 實作出 j0c 編譯器, 該編譯器可以將 J0 語言的程式, 編譯成一種平坦化的中間碼格式, 我們稱這種格式為 IR0, 也就是 Intermediate Representation 0 的意思, 以下是 j0c 編譯器的完整程式碼 檔案 :j0c.js // j0c 編譯器, 用法範例 : node j0c test.j0 var fs = require("fs"); var util = require("util"); var log = console.log; // 將 console.log 名稱縮短一點

109 var format = util.format; // 字串格式化 var tokens = []; var tokenidx = 0; var end = "$END"; var funcname = "main"; var funcstack = [ funcname ]; var irtext = ""; var symtable = {; symtable[funcname] = { type:"function", name:"main", pcodes:[] ; var scan=function(text) { var re = new RegExp(/(\/\*[\s\S]*?\*\/) (\/\/[^\r\n]) (".*?") (\d +(\.\d*)?) ([a-za-z]\w*) ([>=<!\+\-\*\/&% ]+) (\s+) (.)/gm); var types = [ "", "COMMENT", "COMMENT", "STRING", "INTEGER", "FLOA T", "ID", "OP2", "SPACE", "CH" ]; tokens = []; tokenidx = 0; var lines = 1, m;

110 while((m = re.exec(text))!== null) { var token = m[0], type; for (i=1; i<=9; i++) { if (m[i]!== undefined) type = types[i]; if (!token.match(/^[\s\r\n]/) && type!="comment") { tokens.push({ "token":token, "type":type, "lines":lines ); lines += token.split(/\n/).length-1; tokens.push({ "token": end, "type":end, "lines":lines ); return tokens; var error=function(expect) { var token = tokens[tokenidx];

111 log("error: line=%d token (%s) do not match expect (%s)!", token.l ines, token.token, expect); log(new Error().stack); process.exit(1); var skip=function(o) { if (isnext(o)) next(o); var next=function(o) { if (o==null isnext(o)) { return tokens[tokenidx++].token; error(o); var isnext=function(o) { if (tokenidx >= tokens.length) return false;

112 var token = tokens[tokenidx].token; if (o instanceof RegExp) { return token.match(o); else return (token == o); var nexttype=function(o) { if (o==null isnexttype(o)) { return tokens[tokenidx++].token; error(o); var isnexttype=function(pattern) { var type = tokens[tokenidx].type; return ((" "+pattern+" ").indexof(" "+type+" ")>=0);

113 var pcode=function(label, op, p, p1, p2) { symtable[funcname].pcodes.push({"label":label, "op":op, "p":p, "p1 ":p1, "p2":p2); var ircode = format("%s\t%s\t%s\t%s\t%s", label, op, p, p1, p2); log(ircode); irtext += ircode+"\n"; var tempidx = 1; var nexttemp=function() { var name="t"+tempidx++; symtable[name] = { type:"var", name:name ; return name; var labelidx = 1; var nextlabel=function() { return "L"+labelIdx++;

114 var elseidx = 1; var nextelse=function() { return "else"+elseidx++; var compile=function(text) { scan(text); PROG(); // PROG = STMTS var PROG=function() { STMTS(); // STMTS = STMT* var STMTS=function() { while (!isnext("") &&!isnext(end)) STMT();

115 // BLOCK = { STMTS var BLOCK=function() { next("{"); STMTS(); next(""); // STMT = FOR WHILE IF FUNCTION return EXP ; ASSIGN ; BL OCK var STMT=function() { if (isnext("for")) { FOR(); else if (isnext("while")) { WHILE(); else if (isnext("if")) { IF();

開放電腦計畫 -- 系統程式 2014 年 8 月出版 作者 : 陳鍾誠衍生自維基百科 ( 創作共用 : 姓名標示 相同方式分享授權 )

開放電腦計畫 -- 系統程式 2014 年 8 月出版 作者 : 陳鍾誠衍生自維基百科 ( 創作共用 : 姓名標示 相同方式分享授權 ) 開放電腦計畫 -- 系統程式 2014 年 8 月出版 作者 : 陳鍾誠衍生自維基百科 ( 創作共用 : 姓名標示 相同方式分享授權 ) 開放電腦計畫 -- 系統程式 前言序授權聲明開放電腦計畫硬體 : 計算機結構軟體 : 系統程式參考文獻 CPU0 處理器 CPU0 指令集實作 :CPU0 的指令表虛擬機 - vm0 組譯範例 VM0 虛擬機設計結語組譯器 - as0 組譯範例 AS0 組譯器設計程式說明結語編譯器編譯器

More information

教科書:系統程式 - 第 2 章、電腦的硬體結構

教科書:系統程式 - 第 2 章、電腦的硬體結構 第 2 章 電腦的硬體結構 作者 : 陳鍾誠 第 2 章 電腦的硬體結構 2.1 CPU0 處理器 2.2 CPU0 的指令集 2.3 CPU0 的運作原理 2.4 CPU0 的程式執行 2.5 實務案例 :IA32 處理器 2.1 CPU0 處理器 CPU0 是筆者所設計的一個簡易的 32 位元處理器, 主要用來說明系統程式的運作原理 CPU0 的設計主要是為了教學考量, 設計重點在於簡單 容易理解,

More information

CC213

CC213 : (Ken-Yi Lee), E-mail: feis.tw@gmail.com 9 [P.11] : Dev C++ [P.12] : http://c.feis.tw [P.13] [P.14] [P.15] [P.17] [P.23] Dev C++ [P.24] [P.27] [P.34] C / C++ [P.35] 10 C / C++ C C++ C C++ C++ C ( ) C++

More information

開放電腦計畫 -- 計算機硬體結構

開放電腦計畫 -- 計算機硬體結構 開 放 電 腦 計 畫 -- 計 算 機 硬 體 結 構 2014 年 7 月 出 版 作 者 : 陳 鍾 誠 ( 創 作 共 用 : 姓 名 標 示 相 同 方 式 分 享 授 權 ) 開 放 電 腦 計 畫 -- 計 算 機 硬 體 結 構 前 言 序 授 權 聲 明 開 放 電 腦 計 畫 簡 介 硬 體 : 計 算 機 結 構 軟 體 : 系 統 程 式 結 語 參 考 文 獻 電 腦 硬

More information

Microsoft PowerPoint - chap2.ppt

Microsoft PowerPoint - chap2.ppt 基本程式設計觀念 人 自然語言 ( 中文 英文...) 高階語言 (C C++ Java) 組合語言 (8051 或是 80x86) 機器語言 (8051 或是 80x86) 機器 林銘波編著 --- 全華科技圖書公司 2.1 計算機的階層式結構 應用程式 ( 或語言 ) 高階語言組合語言硬體 林銘波編著 --- 全華科技圖書公司 2.2 儲存程式計算機 資料輸入 中央處理器讀取 / 寫入控制 CPU

More information

第 15 章 程 式 編 写 語 言 15.1 程 式 編 写 語 言 的 角 色 程 式 編 寫 語 言 是 程 式 編 寫 員 與 電 腦 溝 通 的 界 面 語 法 是 一 組 規 則 讓 程 式 編 寫 員 將 字 詞 集 合 起 來 電 腦 是 處 理 位 元 和 字 節 的 機 器, 與

第 15 章 程 式 編 写 語 言 15.1 程 式 編 写 語 言 的 角 色 程 式 編 寫 語 言 是 程 式 編 寫 員 與 電 腦 溝 通 的 界 面 語 法 是 一 組 規 則 讓 程 式 編 寫 員 將 字 詞 集 合 起 來 電 腦 是 處 理 位 元 和 字 節 的 機 器, 與 程 式 編 写 語 言 在 完 成 這 章 後, 你 將 能 夠 了 解 程 式 編 写 語 言 的 功 能 了 解 高 階 語 言 和 低 階 語 言 之 間 的 分 別 知 道 翻 譯 程 式 的 意 義 和 能 夠 把 翻 譯 程 式 分 類 為 : 匯 編 程 式 編 譯 程 式 和 解 譯 程 式 認 識 不 同 翻 譯 程 式 的 優 點 和 缺 點 程 式 是 指 揮 電 腦 的 指

More information

,768 32,767 32K JMP Jnnn (386+) LOOP CALL [Label:] JMP short/near/far address L10: jmp jmp L20: L10 L20

,768 32,767 32K JMP Jnnn (386+) LOOP CALL [Label:] JMP short/near/far address L10: jmp jmp L20: L10 L20 (Jump) (Loop) (Conditional jump) CMP CALL AND SAR/SHR TEST JMP NOT SAL/SHL Jnnn* OR RCR/ROR LOOP XOR RCL/ROL RETn * nnn, JNE JL -128 127-32,768 32,767 32K JMP Jnnn (386+) LOOP CALL [Label:] JMP short/near/far

More information

投影片 1

投影片 1 資料庫管理程式 ( 補充教材 -Part2) 使用 ADO.NET 連結資料庫 ( 自行撰寫程式碼 以實現新增 刪除 修改等功能 ) Private Sub InsertButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles InsertButton.Click ' 宣告相關的 Connection

More information

ROP_bamboofox.key

ROP_bamboofox.key ROP Return Oriented Programming Lays @ BambooFox Who Am I Lays / L4ys / 累死 - l4ys.tw Reverse Engineering BambooFox / HITCON Outline Buffer Overflow ret2libc / ret2text Return Oriented Programming Payload

More information

CC213

CC213 : (Ken-Yi Lee), E-mail: feis.tw@gmail.com 49 [P.51] C/C++ [P.52] [P.53] [P.55] (int) [P.57] (float/double) [P.58] printf scanf [P.59] [P.61] ( / ) [P.62] (char) [P.65] : +-*/% [P.67] : = [P.68] : ,

More information

2/80 2

2/80 2 2/80 2 3/80 3 DSP2400 is a high performance Digital Signal Processor (DSP) designed and developed by author s laboratory. It is designed for multimedia and wireless application. To develop application

More information

教科書:系統程式 - 第 8 章、編譯器

教科書:系統程式 - 第 8 章、編譯器 第 8 章 編譯器 作者 : 陳鍾誠 旗標出版社 第 8 章 編譯器 8.1 簡介 8.2 詞彙掃描 8.3 語法剖析 8.4 語意分析 8.5 中間碼產生 8.6 組合語言產生 8.7 最佳化 8.8 實務案例 :gcc 編譯器 8.1 簡介 編譯器 將高階語言轉換成組合語言 ( 或機器碼 ) 的工具 sum = sum + i 編譯器 Compiler LD R1 sum LD R2 i ADD

More information

Fun Time (1) What happens in memory? 1 i n t i ; 2 s h o r t j ; 3 double k ; 4 char c = a ; 5 i = 3; j = 2; 6 k = i j ; H.-T. Lin (NTU CSIE) Referenc

Fun Time (1) What happens in memory? 1 i n t i ; 2 s h o r t j ; 3 double k ; 4 char c = a ; 5 i = 3; j = 2; 6 k = i j ; H.-T. Lin (NTU CSIE) Referenc References (Section 5.2) Hsuan-Tien Lin Deptartment of CSIE, NTU OOP Class, March 15-16, 2010 H.-T. Lin (NTU CSIE) References OOP 03/15-16/2010 0 / 22 Fun Time (1) What happens in memory? 1 i n t i ; 2

More information

0 0 = 1 0 = 0 1 = = 1 1 = 0 0 = 1

0 0 = 1 0 = 0 1 = = 1 1 = 0 0 = 1 0 0 = 1 0 = 0 1 = 0 1 1 = 1 1 = 0 0 = 1 : = {0, 1} : 3 (,, ) = + (,, ) = + + (, ) = + (,,, ) = ( + )( + ) + ( + )( + ) + = + = = + + = + = ( + ) + = + ( + ) () = () ( + ) = + + = ( + )( + ) + = = + 0

More information

1: public class MyOutputStream implements AutoCloseable { 3: public void close() throws IOException { 4: throw new IOException(); 5: } 6:

1: public class MyOutputStream implements AutoCloseable { 3: public void close() throws IOException { 4: throw new IOException(); 5: } 6: Chapter 15. Suppressed Exception CH14 Finally Block Java SE 7 try-with-resources JVM cleanup try-with-resources JVM cleanup cleanup Java SE 7 Throwable getsuppressed Throwable[] getsuppressed() Suppressed

More information

3.1 num = 3 ch = 'C' 2

3.1 num = 3 ch = 'C' 2 Java 1 3.1 num = 3 ch = 'C' 2 final 3.1 final : final final double PI=3.1415926; 3 3.2 4 int 3.2 (long int) (int) (short int) (byte) short sum; // sum 5 3.2 Java int long num=32967359818l; C:\java\app3_2.java:6:

More information

1 CPU

1 CPU 2000 Tel 82316285 82317634 Mail liuxd@buaa.edu.cn 1 CPU 2 CPU 7 72 A B 85 15 3 1/2 M301 2~17 : 3/4 1/2 323 IBM PC 1. 2. 3. 1. 2. 3. 1.1 Hardware Software 1.2 M3 M2 M1 1.2 M3 M1 M2 M2 M1 M1 M1 1.2 M3 M1

More information

untitled

untitled 8086/8088 CIP /. 2004.8 ISBN 7-03-014239-X.... TP313 CIP 2004 086019 16 100717 http://www.sciencep.com * 2004 8 2004 8 1 5 500 787 1092 1/16 16 1/2 391 000 1 2 ii 1 2 CAI CAI 3 To the teacher To the student

More information

学习MSP430单片机推荐参考书

学习MSP430单片机推荐参考书 MSP430 16 MSP430 C MSP430 C MSP430 FLASH 16 1 CPU 16 ALU 16 PC SP SR R4~R15 2 3 00-FFH 100-1FFH 4 5 1 2 51 24 27 6 1 2 3 4 5 6 4 12 SR SP SR CPU SR CPU C Z N GIE CPUOff CPU OscOff SCG0 SCG1 CPU EXIT SP

More information

ebook14-4

ebook14-4 4 TINY LL(1) First F o l l o w t o p - d o w n 3 3. 3 backtracking parser predictive parser recursive-descent parsing L L ( 1 ) LL(1) parsing L L ( 1 ) L L ( 1 ) 1 L 2 L 1 L L ( k ) k L L ( 1 ) F i r s

More information

untitled

untitled CPU!! 00-11-8 Liping zhang, Tsinghua 1 : ADD(r1, r, r) CMPLEC(r, 5, r0) MUL(r1, r, r) SUB(r1, r, r5) ADD r, ( ) r CMP. CMP r.. t t + 1 t + t + t + t + 5 t + 6 IF( ) ADD CMP MUL SUB RF NOP ADD CMP MUL SUB

More information

類型載入儲存運算指令跳躍指令 格式 指令 OP 說明 語法 語意 L LD 1 00 載入 word LD Ra, [Rb+Cx] Ra [Rb+ Cx] L ST 01 儲存 word ST Ra, [Rb+ Cx] Ra [ Rb+ Cx] L LDB 02 載入 byte LDB Ra, [R

類型載入儲存運算指令跳躍指令 格式 指令 OP 說明 語法 語意 L LD 1 00 載入 word LD Ra, [Rb+Cx] Ra [Rb+ Cx] L ST 01 儲存 word ST Ra, [Rb+ Cx] Ra [ Rb+ Cx] L LDB 02 載入 byte LDB Ra, [R 附錄 A CPU0 處理器 A.1 處理器 CPU0 是一個簡易的 32 位元處理器, 其架構如圖 A.1 所示, 包含 R0..R15, IR, MAR, MDR 等暫存器, 其中 IR 是指令暫存器,R0 是一個永遠為常數 0 的唯讀暫存器, R15 是程式計數器 (Program Counter : PC),R14 是連結暫存器 (Link Register : LR), R13 是堆疊指標暫存器

More information

四川省普通高等学校

四川省普通高等学校 四 川 省 普 通 高 等 学 校 计 算 机 应 用 知 识 和 能 力 等 级 考 试 考 试 大 纲 (2013 年 试 行 版 ) 四 川 省 教 育 厅 计 算 机 等 级 考 试 中 心 2013 年 1 月 目 录 一 级 考 试 大 纲 1 二 级 考 试 大 纲 6 程 序 设 计 公 共 基 础 知 识 6 BASIC 语 言 程 序 设 计 (Visual Basic) 9

More information

42 2141601026 2016 11 27 2 1.1............................................. 2 1.2....................................... 2 1.2.1......................................... 2 1.3.............................................

More information

, 7, Windows,,,, : ,,,, ;,, ( CIP) /,,. : ;, ( 21 ) ISBN : -. TP CIP ( 2005) 1

, 7, Windows,,,, : ,,,, ;,, ( CIP) /,,. : ;, ( 21 ) ISBN : -. TP CIP ( 2005) 1 21 , 7, Windows,,,, : 010-62782989 13501256678 13801310933,,,, ;,, ( CIP) /,,. : ;, 2005. 11 ( 21 ) ISBN 7-81082 - 634-4... - : -. TP316-44 CIP ( 2005) 123583 : : : : 100084 : 010-62776969 : 100044 : 010-51686414

More information

<4D F736F F D B0D3B77EC3FEA7DEC3C0C476C1C9A5BFA6A1B8D5C3442DB57BA6A1B35DAD702DBEC7ACEC2E646F6378>

<4D F736F F D B0D3B77EC3FEA7DEC3C0C476C1C9A5BFA6A1B8D5C3442DB57BA6A1B35DAD702DBEC7ACEC2E646F6378> 全國國高級中中等學校 105 學年度商商業類學學生技藝藝競賽 程式式設計 職職種 學學科 試試卷 崗位位編號 : 姓名 : 注意事項 : 請將答案案劃記於答案案卡, 未依依規定劃記者者不予計分分 試題說明 :( 選擇題每每題 4 分, 共 100 分 ) ( )1. 執行以下 Visual Basic 程式片段, 其結果為何?(A) 15 Dim i As Byte i = &HFC Console.WriteLine(Not

More information

Microsoft PowerPoint - chap5.ppt

Microsoft PowerPoint - chap5.ppt 邏輯運算指令的動作 0 1 0 1 0 0 1 1 OR 1 0 1 1 1 0 0 1 1 1 1 1 1 0 1 1 (a) OR 運算 0 1 0 1 0 0 1 1 XOR 1 0 1 1 1 0 0 1 1 1 1 0 1 0 1 0 (c) XOR 運算 希望設定為 1 的位元 罩網標的位元組 新標的位元組 不改變的位元 希望取補數的位元 罩網標的位元組 新標的位元組 不改變的位元 1

More information

運算子多載 Operator Overloading

運算子多載 Operator Overloading 多型 Polymorphism 講師 : 洪安 1 多型 編譯時期多型 ( 靜態多型 ) function overloading 如何正確呼叫同名的函數? 利用參數個數與型態 operator overloading 其實同 function overloading 執行時期多型 ( 或動態多型 ) 如何正確呼叫不同物件的相同名稱的成員函數 利用繼承與多型 2 子類別與父類別物件間的指定 (assignment)

More information

Python a p p l e b e a r c Fruit Animal a p p l e b e a r c 2-2

Python a p p l e b e a r c Fruit Animal a p p l e b e a r c 2-2 Chapter 02 變數與運算式 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.2 2.2.1 2.2.2 2.2.3 type 2.2.4 2.3 2.3.1 print 2.3.2 input 2.4 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 + 2.4.6 Python Python 2.1 2.1.1 a p p l e b e a r c 65438790

More information

C语言的应用.PDF

C语言的应用.PDF AVR C 9 1 AVR C IAR C, *.HEX, C,,! C, > 9.1 AVR C MCU,, AVR?! IAR AVR / IAR 32 ALU 1KBytes - 8MBytes (SPM ) 16 MBytes C C *var1, *var2; *var1++ = *--var2; AVR C 9 2 LD R16,-X ST Z+,R16 Auto (local

More information

instructions.PDF

instructions.PDF 94 SIMATIC (END) (END) Micro/WIN 32 (STOP) (STOP) CPU RUN STOP STOP CPU RUN STOP (WDR) (Watchdog Reset) (WDR) CPU WDR WDR ( ) I/O ( I/O ) SM (SM0 SM5 SM29 ) 25 0 ms 00 ms STOP 300ms 300ms WDR S7-200 CPU

More information

Microsoft PowerPoint - Ch2-1.ppt

Microsoft PowerPoint - Ch2-1.ppt 第 2 章組譯器 (Assembler) 基本組譯器功能 與機器相關之組譯程式功能 與機器無關之組譯程式功能 組譯器設計選項 2.1 基本組譯器功能 從輸入裝置 (F1) 讀入紀錄, 並將它們放到輸出裝置 (05),X : 表示索引定址. : 表示註解 組譯程式指引命令 START 指定程式名稱和起始位址 END 指示原始程式的結束處, 並指定程式中第一個可執行的指令 BYTE 定義字元或十六進位的常數,

More information

封面-12

封面-12 第十二章 701Client TECHNOLOGY CO.,LTD. 701Client 701Server 701Client "701Client", 12-1 :supervisor :supervisor : 1. : 00~99 100 2. : 00~63 ( 63 / / ) 3. : 18 9 4. : 18 9 5. 12-2 TECHNOLOGY CO.,LTD. 701Client

More information

目 录

目 录 1 Quick51...1 1.1 SmartSOPC Quick51...1 1.2 Quick51...1 1.3 Quick51...2 2 Keil C51 Quick51...4 2.1 Keil C51...4 2.2 Keil C51...4 2.3 1 Keil C51...4 2.4 Flash Magic...9 2.5 ISP...9 2.6...10 2.7 Keil C51...12

More information

The golden pins of the PCI card can be oxidized after months or years

The golden pins of the PCI card can be oxidized after months or years Q. 如何在 LabWindows/CVI 編譯 DAQ Card 程式? A: 請參考至下列步驟 : 步驟 1: 安裝驅動程式 1. 安裝 UniDAQ 驅動程式 UniDAQ 驅動程式下載位置 : CD:\NAPDOS\PCI\UniDAQ\DLL\Driver\ ftp://ftp.icpdas.com/pub/cd/iocard/pci/napdos/pci/unidaq/dll/driver/

More information

Autodesk Product Design Suite Standard 系統統需求 典型使用用者和工作流程 Autodesk Product Design Suite Standard 版本為為負責建立非凡凡產品的設計師師和工程師, 提供基本概念設計計和製圖工具, 以取得令人驚驚嘆

Autodesk Product Design Suite Standard 系統統需求 典型使用用者和工作流程 Autodesk Product Design Suite Standard 版本為為負責建立非凡凡產品的設計師師和工程師, 提供基本概念設計計和製圖工具, 以取得令人驚驚嘆 Autodesk Product Design Suite Standard 20122 系統統需求 典型使用用者和工作流程 Autodesk Product Design Suite Standard 版本為為負責建立非凡凡產品的設計師師和工程師, 提供基本概念設計計和製圖工具, 以取得令人驚驚嘆的產品設計計 Autodesk Product Design Suite Standard 版本中中包括以下軟體體產品

More information

(Load Project) (Save Project) (OffLine Mode) (Help) Intel Hex Motor

(Load Project) (Save Project) (OffLine Mode) (Help) Intel Hex Motor 1 4.1.1.1 (Load) 14 1.1 1 4.1.1.2 (Save) 14 1.1.1 1 4.1.2 (Buffer) 16 1.1.2 1 4.1.3 (Device) 16 1.1.3 1 4.1.3.1 (Select Device) 16 2 4.1.3.2 (Device Info) 16 2.1 2 4.1.3.3 (Adapter) 17 2.1.1 CD-ROM 2 4.1.4

More information

46 2011 11 467 數位遊戲式學習系統 7 2011 11 467 47 3 DBGameSys 48 2011 11 467 正規化資料模組 如何配置並儲存電子化資料 以 便減少資料被重覆儲存的程序 DBGameSys的主要功能模組包 學習者 審核評分模組 含 正規化資料模組 審核評分 模組 高分列表模組3大區塊 系統資料庫 在正規化資料模組的執行 高分列表模組 過程中 先要求學習者瀏覽遊戲

More information

Spyder Anaconda Spyder Python Spyder Python Spyder Spyder Spyder 開始 \ 所有程式 \ Anaconda3 (64-bit) \ Spyder Spyder IPython Python IPython Sp

Spyder Anaconda Spyder Python Spyder Python Spyder Spyder Spyder 開始 \ 所有程式 \ Anaconda3 (64-bit) \ Spyder Spyder IPython Python IPython Sp 01 1.6 Spyder Anaconda Spyder Python Spyder Python Spyder Spyder 1.6.1 Spyder 開始 \ 所有程式 \ Anaconda3 (64-bit) \ Spyder Spyder IPython Python IPython Spyder Python File

More information

Excel VBA Excel Visual Basic for Application

Excel VBA  Excel Visual Basic for Application Excel VBA Jun5,00 Sub 分頁 () Dim i As Integer Dim Cname As String Dim Code As Variant Set score=thisworkbook.sheets("sheet") Code=Array(" 專北一 "," 專北二 "," 專北三 "," 專桃園 "," 專桃竹 "," 專中苗 ", " 專台中 "," 專台南 ","

More information

Microsoft Word - ACI chapter00-1ed.docx

Microsoft Word - ACI chapter00-1ed.docx 前言 Excel Excel - v - 財務管理與投資分析 -Excel 建模活用範例集 5 相關 平衡 敏感 - vi - 前言 模擬 If-Then 規劃 ERP BI - vii - 財務管理與投資分析 -Excel 建模活用範例集 ERP + BI + ERP BI Excel 88 Excel 1. Excel Excel 2. Excel 3. Excel - viii - 前言 1.

More information

前言編輯小語授權聲明程式人介紹資訊政治人 :Stallman, Lessig, Swartz 與 Assange 程式人短訊資訊政治 : 台灣 鍵盤革命 的歷史與近況資訊政治 : 海盜黨簡介資訊政治 :g0v 政府零時差組織程式人頻道看影片瞭解 鍵盤革命 的 資訊政治學 程式人討論區網路與政治 : 網友們可以形成一個 虛擬國家 嗎? 程式人文集 Arduino 入門教學 (9) 在 2x16 LCD

More information

D C 93 2

D C 93 2 D9223468 3C 93 2 Java Java -- Java UML Java API UML MVC Eclipse API JavadocUML Omendo PSPPersonal Software Programming [6] 56 8 2587 56% Java 1 epaper(2005 ) Java C C (function) C (reusability) eat(chess1,

More information

<4D6963726F736F667420576F7264202D20C7B6C8EBCABDCFB5CDB3C9E8BCC6CAA6B0B8C0FDB5BCD1A75FD1F9D5C22E646F63>

<4D6963726F736F667420576F7264202D20C7B6C8EBCABDCFB5CDB3C9E8BCC6CAA6B0B8C0FDB5BCD1A75FD1F9D5C22E646F63> 因 为 路 过 你 的 路, 因 为 苦 过 你 的 苦, 所 以 快 乐 着 你 的 快 乐, 追 逐 着 你 的 追 逐 内 容 简 介 本 书 根 据 2005 年 下 半 年 实 施 的 全 国 计 算 机 技 术 与 软 件 专 业 技 术 资 格 ( 水 平 ) 考 试 嵌 入 式 系 统 设 计 师 级 考 试 大 纲 精 神, 在 深 入 研 究 历 年 计 算 机 技 术 与 软

More information

投影片 1

投影片 1 計算機程式及實習 期末報告 題目 : 六宿炒翻天 班級 : 奈米一乙姓名 : 陳洋翼學號 :4A514050 老師 : 謝慶存 程式說明 設計結帳系統, 選擇數量後, 在按下計算, 將會顯示總金額 若是老人或小孩, 將可享 8 折或 9 折的優惠 程式畫面 填選數量 在火腿蛋炒飯的數量選擇 1, 並按下計算, 可得總金額 50 元 程式畫面 打折 填選完後, 若客人是小孩或老人, 選擇欲打折項目,

More information

EK-STM32F

EK-STM32F STMEVKIT-STM32F10xx8 软 件 开 发 入 门 指 南 目 录 1 EWARM 安 装... 1 1.1 第 一 步 : 在 线 注 册... 1 1.2 第 二 步 : 下 载 软 件... 2 1.3 第 三 步 : 安 装 EWARM... 3 2 基 于 STMEVKIT-STM32F10xx8 的 示 例 代 码 运 行... 6 2.1 GPIO Demo... 6 2.2

More information

A Preliminary Implementation of Linux Kernel Virus and Process Hiding

A Preliminary Implementation of Linux Kernel Virus and Process Hiding 邵 俊 儒 翁 健 吉 妍 年 月 日 学 号 学 号 学 号 摘 要 结 合 课 堂 知 识 我 们 设 计 了 一 个 内 核 病 毒 该 病 毒 同 时 具 有 木 马 的 自 动 性 的 隐 蔽 性 和 蠕 虫 的 感 染 能 力 该 病 毒 获 得 权 限 后 会 自 动 将 自 身 加 入 内 核 模 块 中 劫 持 的 系 统 调 用 并 通 过 简 单 的 方 法 实 现 自 身 的

More information

Microsoft Word - 正文.doc

Microsoft Word - 正文.doc 1 2 1 2 3 4 5 6 7 8 9 10 3 1 150 2 150 1 1 1.1 1.1.1 1.2 1.2.1 1.2.2 1.2.3 1.3 1.3.1 1.3.2 1.4 1.4.1 CPU 1.4.2 I/O 1.4.3 I/O 1.5 1.5.1 CISC RISC 1.5.2 1.5.3 1.6 1.6.1 1.6.2 N 1.6.3 2 2.1 2.1.1 2.1.2 2.1.3

More information

软件测试(TA07)第一学期考试

软件测试(TA07)第一学期考试 一 判 断 题 ( 每 题 1 分, 正 确 的, 错 误 的,20 道 ) 1. 软 件 测 试 按 照 测 试 过 程 分 类 为 黑 盒 白 盒 测 试 ( ) 2. 在 设 计 测 试 用 例 时, 应 包 括 合 理 的 输 入 条 件 和 不 合 理 的 输 入 条 件 ( ) 3. 集 成 测 试 计 划 在 需 求 分 析 阶 段 末 提 交 ( ) 4. 单 元 测 试 属 于 动

More information

/ / (FC 3)...

/ / (FC 3)... Modbus/TCP 1.0 1999 3 29 Andy Swales Schneider aswales@modicon.com ... 2 1.... 3 2.... 3 2.1.. 3 2.2..4 2.3..4 2.4... 5 3.... 5 3.1 0... 5 3.2 1... 5 3.3 2... 6 3.4 / /... 7 4.... 7 5.... 8 5.1 0... 9

More information

<4D F736F F D D342DA57CA7DEA447B14D2DA475B57BBB50BADEB27AC3FEB14DA447B8D5C344>

<4D F736F F D D342DA57CA7DEA447B14D2DA475B57BBB50BADEB27AC3FEB14DA447B8D5C344> 1. 請 問 誰 提 出 積 體 電 路 (IC) 上 可 容 納 的 電 晶 體 數 目, 約 每 隔 24 個 月 (1975 年 更 改 為 18 個 月 ) 便 會 增 加 一 倍, 效 能 也 將 提 升 一 倍, 也 揭 示 了 資 訊 科 技 進 步 的 速 度? (A) 英 特 爾 (Intel) 公 司 創 始 人 戈 登. 摩 爾 (Gordon Moore) (B) 微 軟 (Microsoft)

More information

輕鬆學 Dreamweaver CS5 網頁設計..\Example\Ch0\ \.html..\example\ch0\ \mouse.txt..\example\ch0\ \ _Ok.html 學習重點 JavaScript 複製程式碼 mouse.txt Ctrl+C Ctrl+C 0-4

輕鬆學 Dreamweaver CS5 網頁設計..\Example\Ch0\ \.html..\example\ch0\ \mouse.txt..\example\ch0\ \ _Ok.html 學習重點 JavaScript 複製程式碼 mouse.txt Ctrl+C Ctrl+C 0-4 JAVA Extension 0..\Example\Ch0\ \ T.html..\Example\Ch0\ \ T.txt T.txt..\Example\Ch0\ \ T_Ok.html 提示 :. Marquee Marquee Font Color #FFFFFF BG Color #867bf Width 90 Height 50. T.txt Ctrl+C your scrolling

More information

第5章修改稿

第5章修改稿 (Programming Language), ok,, if then else,(), ()() 5.0 5.0.0, (Variable Declaration) var x : T x, T, x,,,, var x : T P = x, x' : T P P, () var x:t P,,, yz, var x : int x:=2. y := x+z = x, x' : int x' =2

More information

1 IT IT IT IT Virtual Machine, VM VM VM VM Operating Systems, OS IT

1 IT IT IT IT Virtual Machine, VM VM VM VM Operating Systems, OS IT 1 IT IT IT IT Virtual Machine, VM VM VM VM Operating Systems, OS IT Chapter 1 了解虛擬化技術種類 硬體 / 平台 / 伺服器虛擬化 VM VM VM CPU Hypervisor VMM Virtual Machine Manager VM Host OS VM VM Guest OS Host OS CPU VM Hyper-V

More information

untitled

untitled 1 Outline 數 料 數 數 列 亂數 練 數 數 數 來 數 數 來 數 料 利 料 來 數 A-Z a-z _ () 不 數 0-9 數 不 數 SCHOOL School school 數 讀 school_name schoolname 易 不 C# my name 7_eleven B&Q new C# (1) public protected private params override

More information

Microsoft PowerPoint - chap12.ppt

Microsoft PowerPoint - chap12.ppt 步並列資料轉移 CLK 位址與命令 資料 匯流排週期 (a) 單一時脈週期 匯流排週期 CLK 位址與命令 資料 匯流排週期 匯流排週期 (b) 多時脈週期 林銘波編著 --- 全華科技圖書公司 2. 閃脈控制方式 --- 來源裝置啟動 來源裝置 閃脈控制線 標的裝置 (a) 方塊圖 成立 閃脈控制線 (b) 時序圖 標的裝置將資料閘入資料暫存器中 林銘波編著 --- 全華科技圖書公司 2.2 閃脈控制方式

More information

雲端 Cloud Computing 技術指南 運算 應用 平台與架構 10/04/15 11:55:46 INFO 10/04/15 11:55:53 INFO 10/04/15 11:55:56 INFO 10/04/15 11:56:05 INFO 10/04/15 11:56:07 INFO

雲端 Cloud Computing 技術指南 運算 應用 平台與架構 10/04/15 11:55:46 INFO 10/04/15 11:55:53 INFO 10/04/15 11:55:56 INFO 10/04/15 11:56:05 INFO 10/04/15 11:56:07 INFO CHAPTER 使用 Hadoop 打造自己的雲 8 8.3 測試 Hadoop 雲端系統 4 Nodes Hadoop Map Reduce Hadoop WordCount 4 Nodes Hadoop Map/Reduce $HADOOP_HOME /home/ hadoop/hadoop-0.20.2 wordcount echo $ mkdir wordcount $ cd wordcount

More information

Microsoft PowerPoint - chap4.ppt

Microsoft PowerPoint - chap4.ppt 定址方式 定址方式 格式 有效位址 立即資料定址 #data8 暫存器定址 Rn (R0 ~ R7) 直接定址 addr8 addr8 絕對定址 addr11 addr11 長程 ( 絕對 ) 定址 addr16 addr16 ( 暫存器 ) 間接定址 @Ri (@R0 @R1) 或 @DPTR R0 R1 或 DPTR ( 暫存器 ) 相對定址 disp8 PC+ 符號擴展之 disp8 ( 基底

More information

C/C++语言 - C/C++数据

C/C++语言 - C/C++数据 C/C++ C/C++ Table of contents 1. 2. 3. 4. char 5. 1 C = 5 (F 32). 9 F C 2 1 // fal2cel. c: Convert Fah temperature to Cel temperature 2 # include < stdio.h> 3 int main ( void ) 4 { 5 float fah, cel ;

More information

程式人雜誌

程式人雜誌 程 式 人 雜 誌 2014 年 8 月 號 本 期 焦 點 :FPGA 可 程 式 化 電 路 程 式 人 雜 誌 前 言 編 輯 小 語 授 權 聲 明 本 期 焦 點 FPGA 簡 介 FPGA 的 設 計 流 程 與 開 發 工 具 -- 使 用 Icarus + Altera Quartus II + 北 瀚 FPGA 板 子 程 式 人 文 集 開 放 電 腦 計 畫 (13) -- 將

More information

Microsoft Word - ACL chapter02-5ed.docx

Microsoft Word - ACL chapter02-5ed.docx 第 2 章神奇的質數 2.1.1 什麼是質數 1 1 1 打下好基礎 - 程式設計必修的數學思維與邏輯訓練 1 1 0 10 2 3 5 7 4 6 8 9 10 4 10000 1229 1000 168 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131

More information

Microsoft Word - PHP7Ch01.docx

Microsoft Word - PHP7Ch01.docx PHP 01 1-6 PHP PHP HTML HTML PHP CSSJavaScript PHP PHP 1-6-1 PHP HTML PHP HTML 1. Notepad++ \ch01\hello.php 01: 02: 03: 04: 05: PHP 06:

More information

Ps22Pdf

Ps22Pdf ( ) ( 150 ) 25 15 20 40 ( 25, 1, 25 ), 1. A. B. C. D. 2. A. B. C. D. 3., J = 1 H = 1 ( A B, J', J, H ) A. A = B = 1, J' =0 B. A = B = J' =1 C. A = J' =1, B =0 D. B = J' = 1, A = 0 4. AB + AB A. AB B. AB

More information

資料結構之C語言重點複習

資料結構之C語言重點複習 鏈結串列自編教材 ( 一 ) 本教材 ( 一 ) 目標問題 : 每次以亂數產生一 [0,1000] 之整數值, 若該值 >100, 則以同方式繼續產生下一亂數值, 若該值

More information

Chapter 3 Camera Raw Step negative clarity +25 ] P / Step 4 0 ( 下一頁 ) Camera Raw Chapter 3 089

Chapter 3 Camera Raw Step negative clarity +25 ] P / Step 4 0 ( 下一頁 ) Camera Raw Chapter 3 089 Photoshop CC Camera Raw Photoshop Camera Raw Step 1 3 1 2 3 SCOTT KELBY Step 2 B Camera Raw 088 Chapter 3 Camera Raw Chapter 3 Camera Raw Step 3-4 -100 negative clarity +25 ] P / -75-50 Step 4 0 ( 下一頁

More information

untitled

untitled niosii H:\DB2005\project\niosDK\Example\NiosSmall QuartusII4.2 File -> New Project Wizard Diectory,Name,Top-Level Entity Add Files EDA Tools Setting Finish, OK H:\DB2005\project\niosDK\Example\NiosSmall

More information

PLC Simulative Control of an Elevator by PLC POWER SUPPLY ii iii ABSTRACT In the modern time, elevator is very popular and based. Most techniques of elevator are owned by foreigners. A simple introduction

More information

Microsoft PowerPoint - C15_LECTURE_NOTE_04.ppt

Microsoft PowerPoint - C15_LECTURE_NOTE_04.ppt MACHINE LANGUAGE CODING AND THE DEBUG SOFTWARE DEVELOPMENT PROGRAM OF THE PC MACHINE LANGUAGE CODING AND THE DEBUG SOFTWARE DEVELOPMENT PROGRAM OF THE PC 4.1 Converting Assembly Language Instructions to

More information

Microsoft PowerPoint - VB14.ppt

Microsoft PowerPoint - VB14.ppt VB 列表盒 LISTBOX 應用 資科系 林偉川 執行畫面 1 2 1 重要屬性 LISTBOX 物件 (VB6) 新增至 LISTBOX 物件中 ADDITEM 自 LISTBOX 物件中刪除選取物件 REMOVEITEM 自 LISTBOX 物件中取出選取物件 ListIndex 顯示 LISTBOX 物件中紀錄個數 Listcount 3 LISTBOX 物件 (VB.NET) 重要屬性 新增至

More information

Bus Hound 5

Bus Hound 5 Bus Hound 5.0 ( 1.0) 21IC 2007 7 BusHound perisoft PC hound Bus Hound 6.0 5.0 5.0 Bus Hound, IDE SCSI USB 1394 DVD Windows9X,WindowsMe,NT4.0,2000,2003,XP XP IRP Html ZIP SCSI sense USB Bus Hound 1 Bus

More information

Microsoft PowerPoint - C15_LECTURE_NOTE_04.ppt

Microsoft PowerPoint - C15_LECTURE_NOTE_04.ppt MACHINE LANGUAGE CODING AND THE DEBUG SOFTWARE DEVELOPMENT PROGRAM OF THE PC General instruction format for machine code 611 37100 微處理機原理與應用 Lecture 04-4 MACHINE LANGUAGE CODING AND THE DEBUG SOFTWARE

More information

Microsoft PowerPoint - Lecture7II.ppt

Microsoft PowerPoint - Lecture7II.ppt Lecture 8II SUDOKU PUZZLE SUDOKU New Play Check 軟體實作與計算實驗 1 4x4 Sudoku row column 3 2 } 4 } block 1 4 軟體實作與計算實驗 2 Sudoku Puzzle Numbers in the puzzle belong {1,2,3,4} Constraints Each column must contain

More information

Microsoft PowerPoint - C15_LECTURE_NOTE_05.ppt

Microsoft PowerPoint - C15_LECTURE_NOTE_05.ppt 8088/8086 MICROPROCESSOR PROGRAMMING INTEGER INSTRUCTIONS AND COMPUTATIONS 8088/8086 MICROPROCESSOR PROGRAMMING INTEGER INSTRUCTIONS AND COMPUTATIONS 5.1 Data-Transfer Instructions 5.2 Arithmetic Instructions

More information

Learning Java

Learning Java Java Introduction to Java Programming (Third Edition) Prentice-Hall,Inc. Y.Daniel Liang 2001 Java 2002.2 Java2 2001.10 Java2 Philip Heller & Simon Roberts 1999.4 Java2 2001.3 Java2 21 2002.4 Java UML 2002.10

More information

840 提示 Excel - Excel -- Excel (=) Excel ch0.xlsx H5 =D5+E5+F5+G5 (=) = - Excel 00

840 提示 Excel - Excel -- Excel (=) Excel ch0.xlsx H5 =D5+E5+F5+G5 (=) = - Excel 00 Excel - - Excel - -4-5 840 提示 Excel - Excel -- Excel (=) Excel ch0.xlsx H5 =D5+E5+F5+G5 (=) = - Excel 00 ( 0 ) 智慧標籤 相關說明提示 -5 -- Excel 4 5 6 7 8 + - * / % ^ = < >= & 9 0 (:) (,) ( ) Chapter - :,

More information

06721 main() lock pick proc() restart() [2][4] MINIX minix2.0 GDT, IDT irq table[] CPU CPU CPU CPU (IDTR) idt[] CPU _hwint00:! Interrupt

06721 main() lock pick proc() restart() [2][4] MINIX minix2.0 GDT, IDT irq table[] CPU CPU CPU CPU (IDTR) idt[] CPU _hwint00:! Interrupt MINIX ( 730000) ( 730000) MINIX MINIX2.0 MINIX : MINIX TP3 1 MINIX UNIX Tanenbaum UNIX MINIX LINUX MINIX MINIX MINIX1.0 UNIX V7 MINIX2.0[3] POSIX MINIX3 MINIX Gabriel A. Wainer 1994-1995 [5] 1998 I/O 2002

More information

C PICC C++ C++ C C #include<pic.h> C static volatile unsigned char 0x01; static volatile unsigned char 0x02; static volatile unsigned cha

C PICC C++ C++ C C #include<pic.h> C static volatile unsigned char 0x01; static volatile unsigned char 0x02; static volatile unsigned cha CYPOK CYPOK 1 UltraEdit Project-->Install Language Tool: Language Suite----->hi-tech picc Tool Name ---->PICC Compiler Executable ---->c:hi-picinpicc.exe ( Command-line Project-->New Project-->File Name--->myc

More information

27 :OPC 45 [4] (Automation Interface Standard), (Costom Interface Standard), OPC 2,,, VB Delphi OPC, OPC C++, OPC OPC OPC, [1] 1 OPC 1.1 OPC OPC(OLE f

27 :OPC 45 [4] (Automation Interface Standard), (Costom Interface Standard), OPC 2,,, VB Delphi OPC, OPC C++, OPC OPC OPC, [1] 1 OPC 1.1 OPC OPC(OLE f 27 1 Vol.27 No.1 CEMENTED CARBIDE 2010 2 Feb.2010!"!!!!"!!!!"!" doi:10.3969/j.issn.1003-7292.2010.01.011 OPC 1 1 2 1 (1., 412008; 2., 518052), OPC, WinCC VB,,, OPC ; ;VB ;WinCC Application of OPC Technology

More information

Microsoft Word - 01.DOC

Microsoft Word - 01.DOC 第 1 章 JavaScript 简 介 JavaScript 是 NetScape 公 司 为 Navigator 浏 览 器 开 发 的, 是 写 在 HTML 文 件 中 的 一 种 脚 本 语 言, 能 实 现 网 页 内 容 的 交 互 显 示 当 用 户 在 客 户 端 显 示 该 网 页 时, 浏 览 器 就 会 执 行 JavaScript 程 序, 用 户 通 过 交 互 式 的

More information

CH01.indd

CH01.indd 3D ios Android Windows 10 App Apple icloud Google Wi-Fi 4G 1 ( 3D ) 2 3 4 5 CPU / / 2 6 App UNIX OS X Windows Linux (ios Android Windows 8/8.1/10 BlackBerry OS) 7 ( ZigBee UWB) (IEEE 802.11/a/b/g/n/ad/ac

More information

運算子多載 Operator Overloading

運算子多載 Operator Overloading 函數樣板 (Function Template) 與 類別樣板 (Class Template) 講師 : 洪安 1 資料結構與 C++ 程式設計進階班 為何需要通用函數? (1/2) int abs(int x) { return (x>0)?x:-x; 取名困難不好記 float fabs(float x) { return (x>0)?x:-x; complex cabs(complex x)

More information

Microsoft Word - 100118002.htm

Microsoft Word - 100118002.htm 100 年 度 11800 電 腦 軟 體 應 用 乙 級 技 術 士 技 能 檢 定 學 科 測 試 試 題 本 試 卷 有 選 擇 題 80 題, 每 題 1.25 分, 皆 為 單 選 選 擇 題, 測 試 時 間 為 100 分 鐘, 請 在 答 案 卡 上 作 答, 答 錯 不 倒 扣 ; 未 作 答 者, 不 予 計 分 准 考 證 號 碼 : 姓 名 : 選 擇 題 : 1. (3)

More information

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.06.doc

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.06.doc 2 5 8 11 0 13 1. 13 2. 15 3. 18 1 23 1. 23 2. 26 3. 28 2 36 1. 36 2. 39 3. 42 4. 44 5. 49 6. 51 3 57 1. 57 2. 60 3. 64 4. 66 5. 70 6. 75 7. 83 8. 85 9. 88 10. 98 11. 103 12. 108 13. 112 4 115 1. 115 2.

More information

Java 程式設計初階 第 5 章:基本輸出入 & 流程控制

Java 程式設計初階 第 5 章:基本輸出入 & 流程控制 Java 程式設計 標準輸出入與流程控制 本章大綱 標準輸出入 (Standard I/O) 分支 (Branch) if ~ else switch ~ case 迴圈 (Loop) for while do ~ while 中斷指令 break continue 總整理 標準輸出 定義 : 將資料印到螢幕上 Java 標準輸出指令 System.out.println( 資料 ) 將資料印出後換行

More information

AL-M200 Series

AL-M200 Series NPD4754-00 TC ( ) Windows 7 1. [Start ( )] [Control Panel ()] [Network and Internet ( )] 2. [Network and Sharing Center ( )] 3. [Change adapter settings ( )] 4. 3 Windows XP 1. [Start ( )] [Control Panel

More information

Microsoft PowerPoint - C15_LECTURE_NOTE_05.ppt

Microsoft PowerPoint - C15_LECTURE_NOTE_05.ppt 8088/8086 MICROPROCSOR PROGRAMMING INTEGER INSTRUCTIONS AND COMPUTATIONS The MOVE The move (MOV) instruction is used to transfer a byte or a word of data from a source operand to a destination operand

More information

Fuzzy Highlight.ppt

Fuzzy Highlight.ppt Fuzzy Highlight high light Openfind O(kn) n k O(nm) m Knuth O(n) m Knuth Unix grep regular expression exact match Yahoo agrep fuzzy match Gais agrep Openfind gais exact match fuzzy match fuzzy match O(kn)

More information

1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File

1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File 51 C 51 51 C C C C C C * 2003-3-30 pnzwzw@163.com C C C C KEIL uvision2 MCS51 PLM C VC++ 51 KEIL51 KEIL51 KEIL51 KEIL 2K DEMO C KEIL KEIL51 P 1 1 1 1-1 - 1 Project New Project 1 2 Windows 1 3 N C test

More information

新版 明解C++入門編

新版 明解C++入門編 511!... 43, 85!=... 42 "... 118 " "... 337 " "... 8, 290 #... 71 #... 413 #define... 128, 236, 413 #endif... 412 #ifndef... 412 #if... 412 #include... 6, 337 #undef... 413 %... 23, 27 %=... 97 &... 243,

More information

全国计算机技术与软件专业技术资格(水平)考试

全国计算机技术与软件专业技术资格(水平)考试 全 国 计 算 机 技 术 与 软 件 专 业 技 术 资 格 ( 水 平 ) 考 试 2008 年 上 半 年 程 序 员 下 午 试 卷 ( 考 试 时 间 14:00~16:30 共 150 分 钟 ) 试 题 一 ( 共 15 分 ) 阅 读 以 下 说 明 和 流 程 图, 填 补 流 程 图 中 的 空 缺 (1)~(9), 将 解 答 填 入 答 题 纸 的 对 应 栏 内 [ 说 明

More information

09 F9 128 peer to peer, P2P file transfer protocol bittorrent 10 P2P P2P GNU/ Linux P2P CC 單機版的智慧財產權 vs. 人權戰爭 1980 DVD content

09 F9 128 peer to peer, P2P file transfer protocol bittorrent 10 P2P P2P GNU/ Linux P2P CC 單機版的智慧財產權 vs. 人權戰爭 1980 DVD content 當智慧財產 侵犯人權? 智慧財產與人權 Kickstarter The Matrix The Matrix Avatar Eywa 12 2013 4 484 09 F9 128 peer to peer, P2P file transfer protocol bittorrent 10 P2P P2P GNU/ Linux P2P CC 單機版的智慧財產權 vs. 人權戰爭 1980 DVD content

More information

第5章:汇编语言程序设计

第5章:汇编语言程序设计 第 5 章 : 汇编语言程序设计 程 汇编语言指令格式 系统伪指令 存储器选择方式 常用子程序 1 汇编语言程序设计 PIC 指令系统 语言系统 指 CPU 编 器语言 器语言 器语言 设计 用 语言 设计 语言 汇编语言 2 汇编语言指令格式 汇编语言指令格式 ( 指令 ) label opcode operand comment 指令 用 存 指令 指令语 3 汇编语言指令格式 1 指令 用 指令

More information

桌上型個人電腦採購規格說明表

桌上型個人電腦採購規格說明表 第三組顯示卡規範書 1. Nvidia 繪圖晶片 1-1. 1-1-1. 繪圖晶片 :NVIDIA GeForce 8400 系列 ( 含 ) 以上 ( 請註明採用商品之廠牌及型號, 並於型錄標示對 NVIDIA 應到主要規格之項次 ) GeForce 1-1-2. 繪圖介面 : 支援 PCI Express 介面 16X( 含 ) 以上高速繪圖晶片 8400 低階顯 1-1-3. 提供 256MB

More information

桌上型個人電腦採購規格說明表

桌上型個人電腦採購規格說明表 第三組顯示卡規範書 1. Nvidia 繪圖晶片 1-1. 1-1-1. 繪圖晶片 :NVIDIA GeForce 6200 系列 ( 含 ) 以上 ( 請註明採用商品之廠牌及型號, 並於型錄標示對應低階顯示卡到主要規格之項次 ) ( 備註 : 對應 1-1-2. 繪圖介面 : 支援 AGP 介面 8X( 含 ) 以上高速繪圖晶片項次為第 1 1-1-3. 提供 128MB 64 位元 DDR SDRAM(

More information

科学计算的语言-FORTRAN95

科学计算的语言-FORTRAN95 科 学 计 算 的 语 言 -FORTRAN95 目 录 第 一 篇 闲 话 第 1 章 目 的 是 计 算 第 2 章 FORTRAN95 如 何 描 述 计 算 第 3 章 FORTRAN 的 编 译 系 统 第 二 篇 计 算 的 叙 述 第 4 章 FORTRAN95 语 言 的 形 貌 第 5 章 准 备 数 据 第 6 章 构 造 数 据 第 7 章 声 明 数 据 第 8 章 构 造

More information

Microsoft PowerPoint - os_4.ppt

Microsoft PowerPoint - os_4.ppt 行 程 資 科 系 林 偉 川 行 程 概 念 行 程 與 程 式 主 要 的 不 同 點 : 程 式 是 被 放 在 外 部 的 儲 存 裝 置 如 磁 碟 上, 而 行 程 則 被 放 在 記 憶 體 中 程 式 在 儲 存 裝 置 中 是 靜 態 的, 而 行 程 在 記 憶 體 中 是 動 態 的, 它 會 隨 著 一 些 事 件 的 發 生 而 產 生 相 對 的 改 變 行 程, 就 是

More information

1 4 1.1 4 1.2..4 2..4 2.1..4 3.4 3.1 Java.5 3.1.1..5 3.1.2 5 3.1.3 6 4.6 4.1 6 4.2.6 5 7 5.1..8 5.1.1 8 5.1.2..8 5.1.3..8 5.1.4..9 5.2..9 6.10 6.1.10

1 4 1.1 4 1.2..4 2..4 2.1..4 3.4 3.1 Java.5 3.1.1..5 3.1.2 5 3.1.3 6 4.6 4.1 6 4.2.6 5 7 5.1..8 5.1.1 8 5.1.2..8 5.1.3..8 5.1.4..9 5.2..9 6.10 6.1.10 Java V1.0.1 2007 4 10 1 4 1.1 4 1.2..4 2..4 2.1..4 3.4 3.1 Java.5 3.1.1..5 3.1.2 5 3.1.3 6 4.6 4.1 6 4.2.6 5 7 5.1..8 5.1.1 8 5.1.2..8 5.1.3..8 5.1.4..9 5.2..9 6.10 6.1.10 6.2.10 6.3..10 6.4 11 7.12 7.1

More information

ICD ICD ICD ICD ICD

ICD ICD ICD ICD ICD MPLAB ICD2 MPLAB ICD2 PIC MPLAB-IDE V6.0 ICD2 usb PC RS232 MPLAB IDE PC PC 2.0 5.5V LED EEDATA MPLAB ICD2 Microchip MPLAB-IDE v6.0 Windows 95/98 Windows NT Windows 2000 www.elc-mcu.com 1 ICD2...4 1.1 ICD2...4

More information

PowerPoint 簡報

PowerPoint 簡報 微算機原理與實驗 (UEE 2301/1071 ) Chap 5. MCS-51 Addressing Modes 宋開泰 Office:EE709 Phone:5731865( 校內分機 :31865) E-mail:ktsong@mail.nctu.edu.tw URL:http://isci.cn.nctu.edu.tw 1 Addressing Modes Addressing mode is

More information