RISC-V: R-type 位移指令

今天一样是简单的 SLL、SRL、SRA 指令实作,
再一样为了 Code Stream Logger 做准备,
另外再加码一个 run 过这份程序的人一定会发现的 Bug 吧。

R-type

指令格式如下:

|31     25|24   20|19   15|14    12|11   7|6       0|
+---------------------------------------------------+
|  func7  |  rs2  |  rs1  | funct3 |  rd  | opcode  |
+---------------------------------------------------+

SLL

rd = rs1 << rs2

|31         25|24   20|19   15|14    12|11   7|6       0|
+-------------------------------------------------------+
|   0000000   |  rs2  |  rs1  |  001   |  rd  | 0110011 |
+-------------------------------------------------------+

SRL

rd = (uint_32)rs1 >> rs2

|31         25|24   20|19   15|14    12|11   7|6       0|
+-------------------------------------------------------+
|   0000000   |  rs2  |  rs1  |  101   |  rd  | 0110011 |
+-------------------------------------------------------+

SRA

rd = rs1 >> rs2

|31         25|24   20|19   15|14    12|11   7|6       0|
+-------------------------------------------------------+
|   0100000   |  rs2  |  rs1  |  101   |  rd  | 0110011 |
+-------------------------------------------------------+

实际程序

github 页面 Tag: ITDay25

这次的 Bug 是几天前做 Exception 留下来的,
当时把 Cpu 的 this 放进 shared_ptr ,
又因为 Cpu 在 main 结束的时候会解构,
会有解构两次造成 crash 的情况,
但是当时想到两个解法,其中一个是用 Raw Pointer ,
另外一个是在 Cpu 内放一个 shared_ptr,
都不是很漂亮,这个 Bug 又不影响运作过程就没立刻动手。

虽然另外指定一个什麽事都不做的 Deleter 也没比 Raw Pointer 好到哪去,
但是不用改使用介面的情况下,是最好的选择了,
至少这样做在写 Executer 的 Unit Test 可以直接用 shared_ptr。

//cpu.cpp
...
	executor->set_cpu(std::shared_ptr<CPU_INTERFACE>(this, [](CPU *p){}));
...

这次正式的把 Decoder 从 Executor 移到 Instruction Decoder 了,
把程序复制贴上再取代真的有够无聊,
之後找找看有没有 vim 的功能可以加速这个过程。

改到心很累, Function Name 的部分就之後再改吧,
到时候 Refactor 预计 99% 都会删掉改写。

//executor.cpp
...
void EXECUTOR::command_dispatch()
{
	switch (instruction_decoder->get_instruction()) {
		case INSTRUCTION_DECODER_INTERFACE::ADDI_INSTRUCTION_ENUM:
			ADDI_E();
			break;
		case INSTRUCTION_DECODER_INTERFACE::ANDI_INSTRUCTION_ENUM:
			ANDI_E();
			break;
...
//instructionDecoder.cpp
...
INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::get_instruction()
{
	return cmmand_dispatch();
}

INSTRUCTION_DECODER_INTERFACE::Instruction INSTRUCTION_DECODER::cmmand_dispatch()
{
	switch (get_opcode()) {
		case INSTRUCTION_DECODER_INTERFACE::IMM_OP:
			return imm_dispatch();

		case INSTRUCTION_DECODER_INTERFACE::LUI_OP:
			return LUI_INSTRUCTION_ENUM;
...

指令实作的地方把 instruction_name_map 里的注解取消了,
其他部分大家都很熟就不多说,照着贴:

//instructionDecoderInterface.h
...
		SLL_FN3 = 0b001,
		SRL_FN3 = 0b101,
		SRA_FN3 = 0b101,
...
		SLL_FN7 = 0b0000000,
		SRL_FN7 = 0b0000000,
		SRA_FN7 = 0b0100000,
...
//executor.cpp
...
		case INSTRUCTION_DECODER_INTERFACE::SLL_FN3:
			SLL_E();
			//do not check FN7 for readibility, refactor in future
			break;
		case INSTRUCTION_DECODER_INTERFACE::SRL_FN3:
			switch (instruction_decoder->get_func7()) {
				case INSTRUCTION_DECODER_INTERFACE::SRL_FN7:
					SRL_E();
					break;
				case INSTRUCTION_DECODER_INTERFACE::SRA_FN7:
					SRA_E();
					break;
				default:
					std::cout << "INVALID: Func7 in REG_OP :" << instruction_decoder->get_func3() << std::endl;
					break;
			}
			break;
...
void EXECUTOR::SLL_E()
{
	auto rd = instruction_decoder->get_rd();
	auto rs1 = instruction_decoder->get_rs1();
	auto rs2 = instruction_decoder->get_rs2();

	auto value = register_file->get_value_integer(rs1) << register_file->get_value_integer(rs2);
	register_file->set_value_integer(rd, value);
}

void EXECUTOR::SRL_E()
{
	auto rd = instruction_decoder->get_rd();
	auto rs1 = instruction_decoder->get_rs1();
	auto rs2 = instruction_decoder->get_rs2();

	auto value = (uint32_t)register_file->get_value_integer(rs1) >> register_file->get_value_integer(rs2);
	register_file->set_value_integer(rd, value);
}

void EXECUTOR::SRA_E()
{
	auto rd = instruction_decoder->get_rd();
	auto rs1 = instruction_decoder->get_rs1();
	auto rs2 = instruction_decoder->get_rs2();

	auto value = register_file->get_value_integer(rs1) >> register_file->get_value_integer(rs2);
	register_file->set_value_integer(rd, value);
}

...

<<:  #24 No-code 之旅 — 在 Next.js 专案中实作 API

>>:  [Python] 来自己建立一个Neural Network吧

[Day 17]独自一人的全端攻略(後端篇)

挑战目标: MockNative Camp 今天来自定义Spring ExceptionHandle...

Day 11 Chatbot integration- 看图学英文

Chatbot integration- 看图学英文 大致上的概念是要利用 Line 把图片传给 c...

Day 09 pipenv

Pipenv 是什麽呢? 想像一下,当你现在是个专业的工程师,身上背着十几个不同类型的专案(好啦,有...

VPC(二)

VPC使用 昨天提到了关於VPC是什麽?以及如何简单的建立VPC XPN等的内容,那今天就来说说关於...

Alteryx使用案例║Mercedes-Benz 因疫情产线停摆无法交车怎麽办?

这近一个月的疫情高峰,相信你手头上会有很多突发的任务要处理 就像是这位 Mercedes-Benz ...