Skip to content
Snippets Groups Projects
Commit 2f7596b8 authored by Geo Ster's avatar Geo Ster
Browse files

Handle branch delay slots

* MIPS has an architectural feature, where instead of flushing the
pipeline when executing a branch instruction, it goes ahead and executes
the instruction following the branch as well. Flushing the pipeline
is costly and is the cause of those complex branch predictors on
modern CPUs that try to guess when a branch will be taken.

* To properly emulate this behaviour we must act how the pipeline acts. We
will always have 2 instructions loaded the current one and the next one. This way
we can load the instruction after the branch even though the pc changes.
parent 0e09c3a1
No related branches found
No related tags found
No related merge requests found
...@@ -63,6 +63,7 @@ public: ...@@ -63,6 +63,7 @@ public:
/* Opcodes */ /* Opcodes */
void op_cop0(); void op_mfc0(); void op_sw(); void op_cop0(); void op_mfc0(); void op_sw();
void op_special(); void op_sll(); void op_slti(); void op_special(); void op_sll(); void op_slti();
void op_bne();
protected: protected:
ComponentManager* manager; ComponentManager* manager;
...@@ -70,9 +71,9 @@ protected: ...@@ -70,9 +71,9 @@ protected:
/* Registers. */ /* Registers. */
Register gpr[32]; Register gpr[32];
uint32_t pc; uint32_t pc;
uint64_t hi0, hi1, lo0, lo1; /* Used to store multiplication and division results */ uint64_t hi0, hi1, lo0, lo1;
uint32_t sa; /* Specifies the shift amount used by the funnel shift instruction */ uint32_t sa;
Instruction instr; Instruction instr, next_instr;
/* Coprocessors */ /* Coprocessors */
COP0 cop0; COP0 cop0;
......
...@@ -21,25 +21,31 @@ void EmotionEngine::reset_state() ...@@ -21,25 +21,31 @@ void EmotionEngine::reset_state()
{ {
/* Reset PC. */ /* Reset PC. */
pc = 0xbfc00000; pc = 0xbfc00000;
/* Reset instruction holders */
instr.value = 0;
next_instr.value = 0;
} }
void EmotionEngine::fetch_instruction() void EmotionEngine::fetch_instruction()
{ {
instr.value = manager->read_memory<uint32_t>(pc); /* Handle branch delay slots by prefetching the next one */
instr.value = next_instr.value;
next_instr = manager->read_memory<uint32_t>(pc);
pc += 4;
std::cout << "PC: " << std::hex << pc << " Instruction: " << instr.value << '\n'; std::cout << "PC: " << std::hex << pc << " Instruction: " << instr.value << '\n';
switch(instr.opcode) switch(instr.opcode)
{ {
case COP0_OPCODE: op_cop0(); break; case COP0_OPCODE: op_cop0(); break;
case SPECIAL_OPCODE: op_special(); break; case SPECIAL_OPCODE: op_special(); break;
case 0b101011: op_sw(); break; case 0b101011: op_sw(); break;
case 0b001010: op_slti(); break; case 0b001010: op_slti(); break;
case 0b000101: op_bne(); break;
default: default:
std::cout << "Unimplemented opcode: " << std::bitset<6>(instr.opcode) << '\n'; std::cout << "Unimplemented opcode: " << std::bitset<6>(instr.opcode) << '\n';
std::abort(); std::abort();
} }
pc += 4;
} }
void EmotionEngine::op_cop0() void EmotionEngine::op_cop0()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment