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 又要赶快睡觉准备上班,
打从心底尊敬所有铁人赛完赛的人。
<<: Chapter5 - 当一个勤劳的园丁,来修剪我们美丽的树(II)Canvas素材 修图、压缩、效能优化
>>: 【领域展开 19 式】初次使用 Elementor 编辑页面
多执行绪(multithreading) 所以我们的多执行绪在程序是怎麽运作呢? 一般情况: 假设 ...
ㄟ,拍谢,这篇又变成 windows 了。 我平常还是用 windows 系统,因为 windows...
MDU3603 QFN8 MOS 采用先进的 MOSFET 技术,提供低导通电阻。 这种场效应管适用...
我们用到的 API endpoint 只有一个,就是用来取得港铁机场快綫、东涌綫、屯马綫及将军澳綫最...
在上一篇我们完成面的旋转,却发现旋转途中若点击放开,面会停留在旋转途中,今天我们就要来解决这个问题。...