CPU 運作過程中很容易遇到需要等待的情況,
例如 Cache Miss、Data Dependency等等。
為了隱藏等待造成的延遲,
現代 CPU 可能會亂序執行,Memory 也有 Read/Write Buffer 等結構,
導致 CPU 或 I/O Device 之間觀測到的執行順序可能跟預期的不一樣。
如果在多處理器執行的時候,
會因為觀測到的指令順序不同,導致行為和預期的不符。
FENCE 就是用來確保其它 Hart (Hardware Thread) 和 I/O Device 看到的指令執行順序,
任何一個 FENCE 後的特定類型指令(successor),
都不會比在 FENCE 前的特定類型指令(predecessor)早發生。
指令格式如下:
|31 20|19 15|14 12|11 7|6 0|
+-------------------------------------------+
| imm | rs1 | funct3 | rd | opcode |
+-------------------------------------------+
rs1 和 rd 都留給未來擴充更精確的 FENCE 指令用,
如果是標準的執行環境,rs1 和 rd 都應該要是 0
|31 28|27|26|25|24|23|22|21|20|19 15|14 12|11 7|6 0|
+----------------------------------------------------------------+
| 0000 |PI|PO|PR|PW|SI|SO|SR|SW| 0 | 000 | 0 | 0001111 |
+----------------------------------------------------------------+
針對 LOAD 和 STORE 各自做出限制的 FENCE 指令,
但是 LOAD 和 STORE 之間並沒有限制,
相較於標準的 FENCE 放寬了 R-W 之間的順序。
|31 28|27|26|25|24|23|22|21|20|19 15|14 12|11 7|6 0|
+----------------------------------------------------------------+
| 1000 |0 |0 |1 |1 |0 |0 |1 |1 | 0 | 000 | 0 | 0001111 |
+----------------------------------------------------------------+
github 頁面 Tag: ITDay20
今天是快樂的一天,
這次實作的模擬器很單純,不會有亂序的問題。
就做一個空殼出來,然後修修 Bug 吧!
Binary Operation 的部分真的很容易犯錯,
今天又修了一個 Range Overlaping 的問題,
除了避免自己手寫,並盡量整理成可以重複使用的函式、
以及多寫測試確認之外,還要再想想有沒有更好的工作流程。
這次也為 FENCE 新增一個 get_imm_fence_fm
。
//instructionDecoder.cpp
int32_t INSTRUCTION_DECODER::get_imm_b()
{
auto value = sc_dt::sc_int<32>();
value(12, 12) = instruction_value(31, 31);
value(11, 11) = instruction_value(7, 7);
value(10, 5) = instruction_value(30, 25);
value(4, 1) = instruction_value(11, 8);
value <<= 19;
value >>= 19;
return value;
}
uint32_t INSTRUCTION_DECODER::get_imm_fence_fm()
{
return instruction_value.range(31, 28);
}
在寫 BRANCH 測試的 Binary Code 才發現有個大問題:
有兩個 switch statement 的 break
被漏掉了。
為了減少維護程式過程中出錯的可能性,
習慣只要碰到同樣的問題 3 次,就要想辦法解決它。
這兩次出錯的原因都是 Dispatch 的流程太不好閱讀了,
決定把牠們拆出來到小的 Dispatcher。
//executor.cpp
void EXECUTOR::execute()
{
new_pc = register_file->get_pc() + 4;
cmmand_dispatch();
register_file->set_pc(new_pc);
}
void EXECUTOR::cmmand_dispatch()
{
switch (instruction_decoder->get_opcode()) {
case INSTRUCTION_DECODER_INTERFACE::IMM_OP:
imm_dispatch();
break;
case INSTRUCTION_DECODER_INTERFACE::LUI_OP:
LUI_E();
break;
case INSTRUCTION_DECODER_INTERFACE::AUIPC_OP:
AUIPC_E();
break;
case INSTRUCTION_DECODER_INTERFACE::LOAD_OP:
load_dispatch();
break;
case INSTRUCTION_DECODER_INTERFACE::STORE_OP:
store_dispatch();
break;
case INSTRUCTION_DECODER_INTERFACE::JAL_OP:
JAL_E();
break;
case INSTRUCTION_DECODER_INTERFACE::JALR_OP:
jalr_dispatch();
break;
case INSTRUCTION_DECODER_INTERFACE::BRANCH_OP:
branch_dispatch();
break;
case INSTRUCTION_DECODER_INTERFACE::MISC_MEM_OP:
fence_dispatch();
break;
default:
std::cout << "INVALID: Opcode :" << instruction_decoder->get_opcode() << std::endl;
break;
}
}
...
找到一個躲很久沒被發現的 hello_thread
小朋友,
幫他取一個符合身分地位的好名子。
//cpu.h
...
void cpu_thread(void);
...
//cpu.cpp
...
void CPU::cpu_thread(void)
...
快要變成狐猴了,
最近累到下班回家不睡一兩個小時沒辦法寫 Code,
半夜寫完 Code 又要趕快睡覺準備上班,
打從心底尊敬所有鐵人賽完賽的人。