# 2017q3 Homework3 (simulator)
contributed by <`ZixinYang`>
## 研究 [full-stack-hello](https://github.com/sysprog21/full-stack-hello) 程式碼
### README
本作業目的: 用小型的指令集及組譯/編譯器實現 Hello World 程式
### Makefile
* `$make`: 編譯所有檔案
* `$make check`: 執行 tests 目錄下的所有 .s 檔
* `$make test`: 執行 tests/runner.py
### 組譯器使用
```
$ ./as_exec -h
Usage: as_exec [-w] [-x] [-o <out_file>] <in_file>
-w Assemble <in_file> and write to an ELF file, see -o below
-o if -w is specifed, <out_file> is used to store the object code
-x Load <in_file> and execute it
<in_file> the file name to be used by commands above
```
* 不加參數: 組譯和執行
* -w: 組譯並輸出 ELF 格式目的檔 `tests/hello.o`
* -o: 指定目的檔儲存的位置
* -x: 載入目的檔並執行
* 實行看看並用 objdump 顯示所有標頭檔資訊
```
$ ./as_exec -o tests/hello.o -w tests/hello.s
$ ./as_exec -x tests/hello.o
Hello World
$ objdump -x tests/hello.o
tests/hello.o: file format elf64-little
tests/hello.o
architecture: UNKNOWN!, flags 0x00000102:
EXEC_P, D_PAGED
start address 0x0000000000000000
Program Header:
0x464c457f off 0x0000000000000000 vaddr 0x0000000100000002 paddr 0x0000000000000000 align 2**54
filesz 0x0000000000000000 memsz 0x0000000000000000 flags -w- 10100
INTERP off 0x0000000000000001 vaddr 0x00000000000000e8 paddr 0x0000000000000000 align 2**5
filesz 0x0000000000000000 memsz 0x0000000000000018 flags ---
0x20 off 0x0000000000000001 vaddr 0x0000000000000100 paddr 0x0000000000000000 align 2**5
filesz 0x0000000000000000 memsz 0x000000000000001c flags ---
Sections:
Idx Name Size VMA LMA File off Algn
SYMBOL TABLE:
no symbols
```
|file|Implementation|
|:--------:|:-------:|
|driver.c|主程式,判斷 argv 呼叫對應的 function|
|as|組譯器, 呼叫 elf 裡函式, 將組語轉換成機器碼, 產生目的檔 (.o)|
|elf|內含組譯所需函式|
|opcode|指令集的實作|
|vm|虛擬機器實作|
### as
* functions:
```
ASSEMBLE_AND_EVAL // 組譯並執行
ASSEMBLE_AND_ELF // 組譯並輸出成 ELF 目的檔
LOAD_ELF_AND_EVAL // 載入之前輸出好的目的檔並執行
```
### opcode
* functions
```
driver.c 呼叫 hook_opcodes
hook_opcodes // 呼叫 vm_hook_opcode_handler, 傳入 opcode 及對應的函式
vm_hook_opcode_handler // 紀錄 opcode 及對應的函式
```
### vm
* variables
```
size_t pc; // 指向目前執行的指令的位置
size_t sp; // 指向目前 stack 最後的位置
size_t from; // 指向最後一個 branch/return 之前的位置
size_t to; // 指向最後一個 branch/return 之後的位置
vm_inst insts[INSTS_MAX_SIZE]; /* 紀錄 instruction*/
vm_value cpool[CPOOL_MAX_SIZE]; /* 儲存常數 */
vm_value temps[TEMPS_MAX_SIZE]; /* 暫存器 */
vm_opcode_impl impl[OPCODE_IMPL_MAX_SIZE]; /* 紀錄指令集 */
vm_regs r;
int insts_count;
int cpool_count;
int temps_count;
```
* functions
```
driver.c 呼叫 vm_run 開始進入虛擬機器的程式碼
VM_CALL_HANDLER // env 已 hook 的 opcode handler 在這裡實現
// 實現 compute goto, 將 pc 指向特定位置 (符合情況才跳)
VM_JLT, VM_JLE(), VM_JZ(), VM_JGE(), VM_JGT, VM_JNZ(), VM_CALL(), VM_RET()
```
### gen_opcode.py
讀取 `opcode.def`, 將各個 operation 的資訊存在 class `OPCODE` , 並輸出 `opcode.h`, 這樣的作法方便擴增及修改指令集, 只需要更改 `opcode.def`, 就可以再自動產生新的 `opcode.h`
## Fibonacci 數列
* 指令集功能
opcode: 指令編號 / has_op1: 第一個輸入 / has_op2: 第二個輸入 / has_result: 輸出
```
name, opcode, has_op1, has_op2, has_result
halt, 0, 0, 0, 0 // 停止
add, 1, 1, 1, 1 // 加法
sub, 2, 1, 1, 1 // 減法
mul, 11, 1, 1, 1 // 乘法
div, 12, 1, 1, 1 // 除法
mod, 13, 1, 1, 1 // 取餘數
and, 16, 1, 1, 1
or, 17, 1, 1, 1
not, 18, 1, 1, 0
xor, 19, 1, 1, 1
lsl, 20, 1, 1, 1 // 左移
lsr, 21, 1, 1, 1 // 右移
asr, 22, 1, 1, 1 // 右移 (signed)
print, 3, 1, 0, 0
jlt, 4, 1, 1, 0 // if < jump
jle, 5, 1, 1, 0 // if <= jump
jz, 6, 1, 1, 0 // if ==0 jump
jge, 7, 1, 1, 0 // if >= jump
jgt, 8, 1, 1, 0 // if > jump
jnz, 9, 1, 1, 0 // if !=0 jump
jmp, 10, 1, 0, 0
call, 14, 1, 0, 0
ret, 15, 0, 0, 0
```
### Iterative
**c programming**
```clike=
int fib(int n)
{
if (n == 0) return 0;
int prevPrev = 0;
int prev = 1;
while (n > 0)
{
n--;
result = prev + prevPrev;
prevPrev = prev;
prev = result;
}
return result;
}
```
**full-stack-hello ISA**
```
; if input = 0, print 0
xor #0 $0 #1
jz #1 #13
sub #0 $1 #0
; initialization
or $0 $0 #1
or $0 $1 #2
; iteration
sub #0 $1 #0
add #1 #2 #3
or #2 $0 #1
or #3 $0 #2
jz #0 #11
jgt #0 #5
; print result
print #3
halt
; print 0
print $0
halt
```
`note:` j- 指令 op2 記錄的是指令在 instruction cache 上的第幾個位置, 進而 goto 正確的指令執行。
### Recursive
**c programming**
```clike=
int fib(int n)
{
if (n == 0) return 0;
if (n == 1) return 1;
return fib(n - 1) + fib(n - 2);
}
```
**full-stack-hello ISA**
## 作業要求
* 閱讀 [現代處理器設計](http://hackfoldr.org/cpu) 教材和觀看裡頭所有錄影,記錄你的心得和疑惑
* 研究給定的 [full-stack-hello](https://github.com/sysprog21/full-stack-hello),學習其中 ISA 和模擬器實作,並在 GitHub 上 fork [full-stack-hello](https://github.com/sysprog21/full-stack-hello)
* 對照研讀 [你所不知道的 C 語言:編譯器和最佳化原理篇](https://hackmd.io/s/Hy72937Me) 教材和觀看直播錄影,以得知編譯器運作原理
* 閱讀 [你所不知道的C語言:遞迴呼叫篇](https://hackmd.io/s/rJ8BOjGGl) 和觀看對應講座錄影,用 [full-stack-hello](https://github.com/sysprog21/full-stack-hello) 的指令實作 Fibonacci 數列
* 需要包含 recursive 和 non-recursive 實作,分別置於檔案 `tests/fib-recursive.s` 和 `tests/fib-iterative.s`
* 修改 `vm.c` (和對應的原始程式碼),允許執行時期由使用者 (和 `Makefile`) 帶入參數,如 `--input`,這數值應該透過暫存器作為上述 Fibonacci 數列程式的 `Fib(N)`
* 研究現有 [full-stack-hello](https://github.com/sysprog21/full-stack-hello) 的自動測試程式,整合上述兩種 Fibonacci 程式實作,並且比較效能 (需要包含 vm 內部的 cycle count)
* 除了 recursive 和 iterative 版本,應該一併考慮以下 Fibonacci 數列的實作方式,並善用 GNU plot 製圖和解讀
* Tail recursion
* Q-Matrix
* Fast doubling
* 過程中可修改 [full-stack-hello](https://github.com/sysprog21/full-stack-hello) 模擬器的程式碼,加入追蹤 / 除錯用途的指令 (instruction),也應該探討模擬器的運作機制並說明自己修改的方式
* 注意 Fib(63) 之後的數值會超過 2^32^ 可表達的範圍,需要設計有效的數值表示機制來處理 (如用兩個 32-bit 暫存器保存 2^64^ 數值)
* 觀察 [Add label support](https://github.com/jserv/full-stack-hello/pull/30) 的實作方式,試著在[full-stack-hello](https://github.com/sysprog21/full-stack-hello) 給定的組譯器中新增 label 的支援
* 相關的背景知識錄影共有 ==18 小時== (當然不可能看了就懂,請預留思考和提問討論的時間),務必及早開始
* 將你的觀察、上述要求的解說,以及各式效能改善過程,善用 gnuplot 製圖,紀錄於「[作業區](https://hackmd.io/s/BJR9BTlRW)」
## 參考資料
* [clang-format](https://clang.llvm.org/docs/ClangFormat.html)