aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qtmips_machine/core.cpp79
-rw-r--r--qtmips_machine/core.h7
-rw-r--r--qtmips_machine/instruction.cpp22
-rw-r--r--qtmips_machine/instruction.h2
-rw-r--r--qtmips_machine/machinedefs.h7
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)
};