diff options
-rw-r--r-- | qtmips_machine/core.cpp | 79 | ||||
-rw-r--r-- | qtmips_machine/core.h | 7 | ||||
-rw-r--r-- | qtmips_machine/instruction.cpp | 22 | ||||
-rw-r--r-- | qtmips_machine/instruction.h | 2 | ||||
-rw-r--r-- | qtmips_machine/machinedefs.h | 7 |
5 files changed, 101 insertions, 16 deletions
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp index fb3db5c..8bf3977 100644 --- a/qtmips_machine/core.cpp +++ b/qtmips_machine/core.cpp @@ -67,6 +67,7 @@ struct Core::dtFetch Core::fetch() { return { .inst = inst, .inst_addr = inst_addr, + .excause = EXCAUSE_NONE, }; } @@ -76,6 +77,7 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) { enum InstructionFlags flags; enum AluOp alu_op; enum AccessControl mem_ctl; + enum ExceptionCause excause = dt.excause; dt.inst.flags_alu_op_mem_ctl(flags, alu_op, mem_ctl); @@ -101,6 +103,10 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) { else immediate_val = sign_extend(dt.inst.immediate()); + if ((flags & IMF_EXCEPTION) && (excause == EXCAUSE_NONE)) { + excause = dt.inst.encoded_exception(); + } + emit decode_instruction_value(dt.inst.data()); emit decode_reg1_value(val_rs); emit decode_reg2_value(val_rt); @@ -148,6 +154,8 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) { .rwrite = rwrite, .ff_rs = FORWARD_NONE, .ff_rt = FORWARD_NONE, + .inst_addr = dt.inst_addr, + .excause = excause, }; } @@ -189,37 +197,50 @@ struct Core::dtExecute Core::execute(const struct dtDecode &dt) { .val_rt = dt.val_rt, .rwrite = dt.rwrite, .alu_val = alu_val, + .inst_addr = dt.inst_addr, + .excause = dt.excause, }; } struct Core::dtMemory Core::memory(const struct dtExecute &dt) { emit instruction_memory(dt.inst); std::uint32_t towrite_val = dt.alu_val; + bool memread = dt.memread; + bool memwrite = dt.memwrite; + bool regwrite = dt.regwrite; - if (dt.memctl == AC_CACHE_OP) - mem_data->sync(); - else if (dt.memwrite) - mem_data->write_ctl(dt.memctl, dt.alu_val, dt.val_rt); - else if (dt.memread) - towrite_val = mem_data->read_ctl(dt.memctl, dt.alu_val); + if (dt.excause != EXCAUSE_NONE) { + memread = false; + memwrite = false; + regwrite = false; + } else { + if (dt.memctl == AC_CACHE_OP) + mem_data->sync(); + else if (memwrite) + mem_data->write_ctl(dt.memctl, dt.alu_val, dt.val_rt); + else if (memread) + towrite_val = mem_data->read_ctl(dt.memctl, dt.alu_val); + } emit memory_alu_value(dt.alu_val); emit memory_rt_value(dt.val_rt); - emit memory_mem_value(dt.memread ? towrite_val : 0); - emit memory_regw_value(dt.regwrite); + emit memory_mem_value(memread ? towrite_val : 0); + emit memory_regw_value(regwrite); emit memory_memtoreg_value(dt.memread); emit memory_memread_value(dt.memread); - emit memory_memwrite_value(dt.memwrite); + emit memory_memwrite_value(memwrite); emit memory_regw_num_value(dt.rwrite); - if (dt.inst.is_break()) + if (dt.excause == EXCAUSE_BREAK) emit memory_break_reached(); return { .inst = dt.inst, - .regwrite = dt.regwrite, + .regwrite = regwrite, .rwrite = dt.rwrite, .towrite_val = towrite_val, + .inst_addr = dt.inst_addr, + .excause = dt.excause, }; } @@ -275,6 +296,7 @@ void Core::handle_pc(const struct dtDecode &dt) { void Core::dtFetchInit(struct dtFetch &dt) { dt.inst = Instruction(0x00); + dt.excause = EXCAUSE_NONE; } void Core::dtDecodeInit(struct dtDecode &dt) { @@ -296,6 +318,8 @@ void Core::dtDecodeInit(struct dtDecode &dt) { dt.immediate_val = 0; dt.ff_rs = FORWARD_NONE; dt.ff_rt = FORWARD_NONE; + dt.inst_addr = 0; + dt.excause = EXCAUSE_NONE; } void Core::dtExecuteInit(struct dtExecute &dt) { @@ -307,6 +331,8 @@ void Core::dtExecuteInit(struct dtExecute &dt) { dt.val_rt = 0; dt.rwrite = 0; dt.alu_val = 0; + dt.inst_addr = 0; + dt.excause = EXCAUSE_NONE; } void Core::dtMemoryInit(struct dtMemory &dt) { @@ -314,6 +340,8 @@ void Core::dtMemoryInit(struct dtMemory &dt) { dt.regwrite = false; dt.rwrite = false; dt.towrite_val = 0; + dt.inst_addr = 0; + dt.excause = EXCAUSE_NONE; } CoreSingle::CoreSingle(Registers *regs, MemoryAccess *mem_program, MemoryAccess *mem_data, bool jmp_delay_slot) : \ @@ -335,7 +363,16 @@ void CoreSingle::do_step() { struct dtDecode d = decode(f); struct dtExecute e = execute(d); struct dtMemory m = memory(e); + + if (m.excause != EXCAUSE_NONE) { + regs->pc_abs_jmp(m.inst_addr + 4); + if (jmp_delay_decode != nullptr) + dtDecodeInit(*jmp_delay_decode); + return; + } + writeback(m); + if (jmp_delay_decode != nullptr) { handle_pc(*jmp_delay_decode); *jmp_delay_decode = d; // Copy current decode @@ -355,14 +392,30 @@ CorePipelined::CorePipelined(Registers *regs, MemoryAccess *mem_program, MemoryA } void CorePipelined::do_step() { + bool stall = false; + bool excpt_in_progress = false; + // Process stages writeback(dt_m); dt_m = memory(dt_e); dt_e = execute(dt_d); dt_d = decode(dt_f); - // TODO signals - bool stall = false; + // Resolve exceptions + excpt_in_progress = dt_m.excause != EXCAUSE_NONE; + if (excpt_in_progress) + dtExecuteInit(dt_e); + excpt_in_progress = excpt_in_progress || dt_e.excause != EXCAUSE_NONE; + if (excpt_in_progress) + dtDecodeInit(dt_d); + excpt_in_progress = excpt_in_progress || dt_e.excause != EXCAUSE_NONE; + if (excpt_in_progress) { + dtFetchInit(dt_f); + if (dt_m.excause != EXCAUSE_NONE) { + regs->pc_abs_jmp(dt_m.inst_addr + 4); + } + return; + } dt_d.ff_rs = FORWARD_NONE; dt_d.ff_rt = FORWARD_NONE; diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h index ac0ee81..d5ce4fb 100644 --- a/qtmips_machine/core.h +++ b/qtmips_machine/core.h @@ -125,6 +125,7 @@ protected: struct dtFetch { Instruction inst; // Loaded instruction uint32_t inst_addr; // Address of instruction + enum ExceptionCause excause; }; struct dtDecode { Instruction inst; @@ -152,6 +153,8 @@ protected: std::uint8_t rwrite; // Writeback register (multiplexed between rt and rd according to regd) ForwardFrom ff_rs; ForwardFrom ff_rt; + uint32_t inst_addr; // Address of instruction + enum ExceptionCause excause; }; struct dtExecute { Instruction inst; @@ -162,12 +165,16 @@ protected: std::uint32_t val_rt; std::uint8_t rwrite; // Writeback register (multiplexed between rt and rd according to regd) std::uint32_t alu_val; // Result of ALU execution + uint32_t inst_addr; // Address of instruction + enum ExceptionCause excause; }; struct dtMemory { Instruction inst; bool regwrite; std::uint8_t rwrite; std::uint32_t towrite_val; + uint32_t inst_addr; // Address of instruction + enum ExceptionCause excause; }; struct dtFetch fetch(); diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp index ed9064b..9eae5f3 100644 --- a/qtmips_machine/instruction.cpp +++ b/qtmips_machine/instruction.cpp @@ -106,9 +106,10 @@ static const struct InstructionMap alu_instruction_map[] = { .flags = FLAGS_ALU_T_R_STD}, {"MOVN", IT_R, ALU_OP_MOVN, NOMEM, nullptr, .flags = FLAGS_ALU_T_R_STD}, - IM_UNKNOWN, + {"SYSCALL",IT_R, ALU_OP_SYSCALL, NOMEM, nullptr, + .flags = IMF_SUPPORTED | IMF_EXCEPTION}, {"BREAK", IT_R, ALU_OP_BREAK, NOMEM, nullptr, - .flags = IMF_SUPPORTED}, + .flags = IMF_SUPPORTED | IMF_EXCEPTION}, IM_UNKNOWN, IM_UNKNOWN, {"MFHI", IT_R, ALU_OP_MFHI, NOMEM, nullptr, @@ -426,8 +427,23 @@ void Instruction::flags_alu_op_mem_ctl(enum InstructionFlags &flags, mem_ctl = im.mem_ctl; } +enum ExceptionCause Instruction::encoded_exception() const { + const struct InstructionMap &im = InstructionMapFind(dt); + if (!(im.flags & IMF_EXCEPTION)) + return EXCAUSE_NONE; + switch (im.alu) { + case ALU_OP_BREAK: + return EXCAUSE_BREAK; + case ALU_OP_SYSCALL: + return EXCAUSE_SYSCALL; + default: + return EXCAUSE_NONE; + } +} + bool Instruction::is_break() const { - return opcode() == 0 && funct() == ALU_OP_BREAK; + const struct InstructionMap &im = InstructionMapFind(dt); + return im.alu == ALU_OP_BREAK; } bool Instruction::operator==(const Instruction &c) const { diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h index a8779f5..b26d9ac 100644 --- a/qtmips_machine/instruction.h +++ b/qtmips_machine/instruction.h @@ -67,6 +67,7 @@ enum InstructionFlags { IMF_JUMP = 1L<<19, IMF_BJ_NOT = 1L<<20, IMF_BGTZ_BLEZ = 1L<<21, + IMF_EXCEPTION = 1L<<22, }; class Instruction { @@ -98,6 +99,7 @@ public: enum InstructionFlags flags() const; enum AluOp alu_op() const; enum AccessControl mem_ctl() const; + enum ExceptionCause encoded_exception() const; void flags_alu_op_mem_ctl(enum InstructionFlags &flags, enum AluOp &alu_op, enum AccessControl &mem_ctl) const; diff --git a/qtmips_machine/machinedefs.h b/qtmips_machine/machinedefs.h index 2e419a8..f4a4a81 100644 --- a/qtmips_machine/machinedefs.h +++ b/qtmips_machine/machinedefs.h @@ -50,6 +50,12 @@ enum AccessControl { AC_CACHE_OP, }; +enum ExceptionCause { + EXCAUSE_NONE, + EXCAUSE_BREAK, + EXCAUSE_SYSCALL, +}; + enum AluOp : std::uint8_t { ALU_OP_SLL = 0, ALU_OP_SRL = 2, @@ -82,6 +88,7 @@ enum AluOp : std::uint8_t { ALU_OP_SLTU, ALU_OP_LUI = 64, // We don't care about exact index for this one ALU_OP_PASS_T, // Pass t argument without change for JAL + ALU_OP_SYSCALL, ALU_OP_UNKNOWN, ALU_OP_LAST // First impossible operation (just to be sure that we don't overflow) }; |