diff --git a/include/cpu/cpu.hh b/include/cpu/cpu.hh index 2f176c4..07df5ca 100644 --- a/include/cpu/cpu.hh +++ b/include/cpu/cpu.hh @@ -64,8 +64,28 @@ class Cpu { Psr abt; Psr irq; Psr und; - } spsr_banked; // banked saved program status registers + } spsr_banked = {}; // banked saved program status registers - bool is_flushed; + // raw instructions in the pipeline + std::array opcodes = {}; + + inline void advance_pc_arm() { pc += arm::INSTRUCTION_SIZE; }; + inline void advance_pc_thumb() { pc += thumb::INSTRUCTION_SIZE; } + + bool is_flushed = false; + inline void flush_pipeline() { + is_flushed = true; + if (cpsr.state() == State::Arm) { + opcodes[0] = bus->read_word(pc); + advance_pc_arm(); + opcodes[1] = bus->read_word(pc); + advance_pc_arm(); + } else { + opcodes[0] = bus->read_halfword(pc); + advance_pc_thumb(); + opcodes[1] = bus->read_halfword(pc); + advance_pc_thumb(); + } + }; }; } diff --git a/include/cpu/psr.hh b/include/cpu/psr.hh index 40999b5..43ad962 100644 --- a/include/cpu/psr.hh +++ b/include/cpu/psr.hh @@ -71,7 +71,7 @@ stringify(Condition cond) { class Psr { public: - // clear the reserved bits i.e, [8:27] + Psr() = default; Psr(uint32_t raw); uint32_t raw() const; diff --git a/src/cpu/cpu.cc b/src/cpu/cpu.cc index c62a309..e68f51d 100644 --- a/src/cpu/cpu.cc +++ b/src/cpu/cpu.cc @@ -3,31 +3,18 @@ #include "cpu/thumb/instruction.hh" #include "util/bits.hh" #include "util/log.hh" -#include -#include namespace matar { Cpu::Cpu(std::shared_ptr bus) noexcept - : bus(bus) - , gpr({ 0 }) - , cpsr(0) - , spsr(0) - , gpr_banked({ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }) - , spsr_banked({ 0, 0, 0, 0, 0 }) - , is_flushed(false) { + : bus(bus) { cpsr.set_mode(Mode::Supervisor); cpsr.set_irq_disabled(true); cpsr.set_fiq_disabled(true); cpsr.set_state(State::Arm); - uint32_t a = 4444; - dbg(this->bus->read_word(0x2000000)); - this->bus->write_word(0x2000000, a); - dbg(this->bus->read_word(0x2000000)); glogger.info("CPU successfully initialised"); // PC always points to two instructions ahead - // PC - 2 is the instruction being executed - pc += 2 * arm::INSTRUCTION_SIZE; + flush_pipeline(); } /* change modes */ @@ -141,41 +128,45 @@ Cpu::step() { if (cpsr.state() == State::Arm) { // word align rst_bit(pc, 1); - // Current instruction is two instructions behind PC - uint32_t cur_pc = pc - 2 * arm::INSTRUCTION_SIZE; - arm::Instruction instruction(bus->read_word(cur_pc)); + + uint32_t next_opcode = bus->read_word(pc); + arm::Instruction instruction(opcodes[0]); + + opcodes[0] = opcodes[1]; + opcodes[1] = next_opcode; #ifdef DISASSEMBLER - glogger.info("0x{:08X} : {}", cur_pc, instruction.disassemble()); + glogger.info("0x{:08X} : {}", + pc - 2 * arm::INSTRUCTION_SIZE, + instruction.disassemble()); #endif instruction.exec(*this); - } else { - uint32_t cur_pc = pc - 2 * thumb::INSTRUCTION_SIZE; - thumb::Instruction instruction(bus->read_halfword(cur_pc)); - -#ifdef DISASSEMBLER - glogger.info("0x{:08X} : {}", cur_pc, instruction.disassemble()); -#endif - - instruction.exec(*this); - } - - // advance PC - { - size_t size = cpsr.state() == State::Arm ? arm::INSTRUCTION_SIZE - : thumb::INSTRUCTION_SIZE; if (is_flushed) { - // if flushed, do not increment the PC, instead set it to two - // instructions ahead to account for flushed "fetch" and "decode" - // instructions - pc += 2 * size; + flush_pipeline(); is_flushed = false; - } else { - // if not flushed continue like normal - pc += size; - } + } else + advance_pc_arm(); + } else { + uint32_t next_opcode = bus->read_halfword(pc); + thumb::Instruction instruction(opcodes[0]); + + opcodes[0] = opcodes[1]; + opcodes[1] = next_opcode; + +#ifdef DISASSEMBLER + glogger.info("0x{:08X} : {}", + pc - 2 * thumb::INSTRUCTION_SIZE, + instruction.disassemble()); +#endif + + instruction.exec(*this); + if (is_flushed) { + flush_pipeline(); + is_flushed = false; + } else + advance_pc_thumb(); } } }