每日一 Bug,
其实作天就有发现 get_imm()
运算结果怪怪的,
如果会 Sign-Extension,怎麽 get_imm(24, 20)
结果竟然是 31,
如果不会 Sign-Estension,前面的 get_imm(31, 20)
怎麽会回传负数?
大家可以先猜猜问题出在哪,下面再为大家解答!
先给一点提示:读文件,治百病
这次修改的范围刚好会碰到在 Register File 生灰尘的 Program Counter,
就顺便让它动起来吧!
另外特别感谢 Ruinland Maskman 的发文:RISC-V core上porting Linux
在研究这个系统的过程中,发现了另外一个 RISC-V Emulator exactstep,
各方面实作很完整,指令解码方式跟 RISC-V-TLM 也完全不一样,
对设计新的 Instruction Decoder 很有帮助。
指令格式如下:
|31 12|11 7|6 0|
+-------------------------------------------+
| imm | rd | opcode |
+-------------------------------------------+
采用 20 bit Asymmetric 的设计,
搭配 I-type 指令就可以指定任何想要的数值。
rd = imm << 12;
|31 12|11 7|6 0|
+-------------------------------------------+
| imm | rd | opcode |
+-------------------------------------------+
imm 设定为 0 可以取得 Program Counter,
规格书上有提到其实 JALR 也一样可以有一样的效果,
但是会影响 Pipeline 和 Branch Predictor 系统的运作流程。
目前没有使用这道指令的经验,
看起来跟 Boot Loader 准备好 MMU 设定之後跳过去指定位置执行有关,
有看过的夥伴欢迎帮忙补充。
rd = current_pc + (imm << 12);
|31 12|11 7|6 0|
+-------------------------------------------+
| imm | rd | opcode |
+-------------------------------------------+
github 页面 Tag: ITDay14
写 Tag 写这麽多天,刚刚才发现根本忘记推上 github...
首先先来解决那个奇怪的 Bug:
根据 SystemC 2.3.1 文件所述,
sc_int<32> 只有在 Assign 之後才会执行 extend_sign()
,
//sc_int_base.h
sc_int_base& operator <<= ( int_type v )
{ m_val <<= v; extend_sign(); return *this; }
照上面的描述可以知道,
单纯的 << Operator 是不会进行 sign extension 的,
需要 Assign 才行,
改成下面这样就没问题了:
//instructionDecoder.cpp
int32_t INSTRUCTION_DECODER::get_imm(uint32_t end, uint32_t start)
{
auto value = sc_dt::sc_int<32>(instruction_value);
value <<= (31-end);
value >>= (31 - end + start);
return value;
}
这次刚好用到 Program Counter 相关的功能,
就顺便做完它。
看起来是个小小的功能,做起来其实很有趣,
参考了相对成熟的 RISC-V-TLM 和 exactstep,
前者是在执行後回传 PC 是否需要 +4,後者是直接在每道指令执行时决定,
一个会在每个 Ececute Function 开不必要的介面,
另一个会多写很多不必要的程序码增加修改时错误的机率。
最後决定自己换一个方法:
EXECUTOR
中增加一个暂存的 new_pc ,
在执行指令前设定为 current_pc + 4,
在由执行中的指令依照需求覆盖,并在最後写入。
...
//executor.h
uint32_t new_pc; //write back to register when execute finished
...
//executor.cpp
void EXECUTOR::execute()
{
new_pc = register_file->get_pc() + 4;
...
register_file->set_pc(new_pc);
}
指令的部分相对单纯
//instructionDecoderInterface.h
...
LUI_OP = 0b0110111,
AUIPC_OP = 0b0010111,
...
//executor.cpp
...
case INSTRUCTION_DECODER_INTERFACE::LUI_OP:
LUI_E();
break;
case INSTRUCTION_DECODER_INTERFACE::AUIPC_OP:
AUIPC_E();
break;
...
void EXECUTOR::LUI_E()
{
auto rd = instruction_decoder->get_rd();
auto value = (instruction_decoder->get_imm(31, 12) << 12);
register_file->set_value_integer(rd, value);
...
}
void EXECUTOR::AUIPC_E()
{
auto rd = instruction_decoder->get_rd();
auto value = register_file->get_pc() + (instruction_decoder->get_imm(31, 12) << 12);
register_file->set_value_integer(rd, value);
...
}
...
<<: 不要为了 Unit Test 而写 Unit Test
>>: Day13-旧网站重写成Vue_4_TAB页签式选单
堆叠跟柱列在程序中算是很基本的资料结构~ 它们的储存特性一个是LIFO~ 另一个则是FIFO~ 学习...
LabelTagHelper的使用 对应於HTML tag的封装,用於给予对应的显示名称。 当中的f...
现在我们来学习函式的进阶,全域变数跟区域变数的差别和使用方法。区域变数的差别和使用方法。 ...
Basics of Color Light and Spectra(光和光谱) 可见光(visibl...
今天要介绍的是(小鼓滚奏)……………..YOLO! YOLO(you only live once)...