aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qtmips_machine/alu.cpp4
-rw-r--r--qtmips_machine/core.cpp69
-rw-r--r--qtmips_machine/core.h6
-rw-r--r--qtmips_machine/instruction.cpp74
-rw-r--r--qtmips_machine/instruction.h4
-rw-r--r--qtmips_machine/machinedefs.h4
6 files changed, 106 insertions, 55 deletions
diff --git a/qtmips_machine/alu.cpp b/qtmips_machine/alu.cpp
index 83e73bb..fa9b7d2 100644
--- a/qtmips_machine/alu.cpp
+++ b/qtmips_machine/alu.cpp
@@ -134,8 +134,8 @@ std::uint32_t machine::alu_operate(enum AluOp operation, std::uint32_t s, std::u
return (s < t) ? 1 : 0;
case ALU_OP_LUI:
return t << 16;
- case ALU_OP_PASS_S: // Pass s argument without change for JAL
- return s;
+ case ALU_OP_PASS_T: // Pass s argument without change for JAL
+ return t;
default:
throw QTMIPS_EXCEPTION(UnsupportedAluOperation, "Unknown ALU operation", QString::number(operation, 16));
}
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp
index 7e529ae..3118d01 100644
--- a/qtmips_machine/core.cpp
+++ b/qtmips_machine/core.cpp
@@ -117,7 +117,7 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) {
emit decode_regd31_value(regd31);
if (regd31) {
- val_rs = dt.inst_addr + 8;
+ val_rt = dt.inst_addr + 8;
}
rwrite = regd31 ? 31: regd ? dt.inst.rd() : dt.inst.rt();
@@ -134,6 +134,10 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) {
.alu_req_rt = flags & IMF_ALU_REQ_RT,
.bjr_req_rs = bjr_req_rs,
.bjr_req_rt = bjr_req_rt,
+ .branch = flags & IMF_BRANCH,
+ .jump = flags & IMF_JUMP,
+ .bj_not = flags & IMF_BJ_NOT,
+ .bgt_blez = flags & IMF_BGTZ_BLEZ,
.forward_m_d_rs = false,
.forward_m_d_rt = false,
.aluop = alu_op,
@@ -229,53 +233,38 @@ void Core::writeback(const struct dtMemory &dt) {
}
void Core::handle_pc(const struct dtDecode &dt) {
+ bool branch;
emit instruction_program_counter(dt.inst);
- bool branch = false;
- bool link = false;
- // TODO implement link
-
- switch (dt.inst.opcode()) {
- case 0: // JR (JALR)
- if (dt.inst.funct() == ALU_OP_JR || dt.inst.funct() == ALU_OP_JALR) {
+ if (dt.jump) {
+ if (!dt.bjr_req_rs) {
+ regs->pc_abs_jmp_28(dt.inst.address() << 2);
+ emit fetch_jump_value(true);
+ emit fetch_jump_reg_value(false);
+ } else {
regs->pc_abs_jmp(dt.val_rs);
- emit fetch_branch_value(true);
- return;
+ emit fetch_jump_value(false);
+ emit fetch_jump_reg_value(true);
}
- break;
- case 1: // REGIMM instruction
- //switch (dt.inst.rt() & 0xF) { // Should be used when linking is supported
- switch (dt.inst.rt()) {
- case 0: // BLTZ(AL)
+ emit fetch_branch_value(false);
+ return;
+ }
+
+ if (dt.branch) {
+ if (dt.bjr_req_rt) {
+ branch = dt.val_rs == dt.val_rt;
+ } else if (!dt.bgt_blez) {
branch = (std::int32_t)dt.val_rs < 0;
- break;
- case 1: // BGEZ(AL)
- branch = (std::int32_t)dt.val_rs >= 0;
- break;
- default:
- throw QTMIPS_EXCEPTION(UnsupportedInstruction, "REGIMM instruction with unknown rt code", QString::number(dt.inst.rt(), 16));
+ } else {
+ branch = (std::int32_t)dt.val_rs <= 0;
}
- link = dt.inst.rs() & 0x10;
- break;
- case 2: // J
- case 3: // JAL
- regs->pc_abs_jmp_28(dt.inst.address() << 2);
- emit fetch_branch_value(true);
- return;
- case 4: // BEQ
- branch = dt.val_rs == dt.val_rt;
- break;
- case 5: // BNE
- branch = dt.val_rs != dt.val_rt;
- break;
- case 6: // BLEZ
- branch = (std::int32_t)dt.val_rs <= 0;
- break;
- case 7: // BGTZ
- branch = (std::int32_t)dt.val_rs > 0;
- break;
+
+ if (dt.bj_not)
+ branch = !branch;
}
+ emit fetch_jump_value(false);
+ emit fetch_jump_reg_value(false);
emit fetch_branch_value(branch);
if (branch)
diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h
index 6f9509f..ac0ee81 100644
--- a/qtmips_machine/core.h
+++ b/qtmips_machine/core.h
@@ -70,6 +70,8 @@ signals:
void instruction_writeback(const machine::Instruction &inst);
void instruction_program_counter(const machine::Instruction &inst);
+ void fetch_jump_reg_value(std::uint32_t);
+ void fetch_jump_value(std::uint32_t);
void fetch_branch_value(std::uint32_t);
void decode_instruction_value(std::uint32_t);
void decode_reg1_value(std::uint32_t);
@@ -136,6 +138,10 @@ protected:
bool alu_req_rt; // requires rt value for ALU or SW
bool bjr_req_rs; // requires rs for beq, bne, blez, bgtz, jr nad jalr
bool bjr_req_rt; // requires rt for beq, bne
+ bool branch; // branch instruction
+ bool jump; // jump
+ bool bj_not; // negate branch condition
+ bool bgt_blez; // BGTZ/BLEZ instead of BGEZ/BLTZ
bool forward_m_d_rs; // forwarding required for beq, bne, blez, bgtz, jr nad jalr
bool forward_m_d_rt; // forwarding required for beq, bne
enum AluOp aluop; // Decoded ALU operation
diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp
index e5e8be9..a0570fd 100644
--- a/qtmips_machine/instruction.cpp
+++ b/qtmips_machine/instruction.cpp
@@ -58,6 +58,8 @@ using namespace machine;
#define FLAGS_ALU_T_R_SD (FLAGS_ALU_T_R_D | IMF_ALU_REQ_RS)
#define FLAGS_ALU_T_R_ST (IMF_SUPPORTED | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT)
+#define FLAGS_J_B_PC_TO_R31 (IMF_SUPPORTED | IMF_PC_TO_R31 | IMF_REGWRITE)
+
#define NOALU .alu = ALU_OP_SLL
#define NOMEM .mem_ctl = AC_NONE
@@ -97,9 +99,9 @@ static const struct InstructionMap alu_instruction_map[] = {
{"SRAV", IT_R, ALU_OP_SRAV, NOMEM, nullptr,
.flags = FLAGS_ALU_T_R_STD_SHV},
{"JR", IT_R, ALU_OP_JR, NOMEM, nullptr,
- .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS},
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_JUMP},
{"JALR", IT_R, ALU_OP_JALR, NOMEM, nullptr,
- .flags = IMF_SUPPORTED | IMF_REGD | IMF_REGWRITE | IMF_BJR_REQ_RS | IMF_PC8_TO_RT},
+ .flags = IMF_SUPPORTED | IMF_REGD | IMF_REGWRITE | IMF_BJR_REQ_RS | IMF_PC8_TO_RT | IMF_JUMP},
{"MOVZ", IT_R, ALU_OP_MOVZ, NOMEM, nullptr,
.flags = FLAGS_ALU_T_R_STD},
{"MOVN", IT_R, ALU_OP_MOVN, NOMEM, nullptr,
@@ -157,26 +159,76 @@ static const struct InstructionMap alu_instruction_map[] = {
.flags = FLAGS_ALU_T_R_STD},
};
+static const struct InstructionMap regimm_instruction_map[] = {
+ {"BLTZ", IT_I, NOALU, NOMEM, nullptr, // BLTZ
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BRANCH},
+ {"BGEZ", IT_I, NOALU, NOMEM, nullptr, // BGEZ
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BRANCH | IMF_BJ_NOT},
+ {"BLTZL", IT_I, NOALU, NOMEM, nullptr, // BLTZL
+ .flags = IMF_BJR_REQ_RS},
+ {"BGEZL", IT_I, NOALU, NOMEM, nullptr, // BGEZL
+ .flags = IMF_BJR_REQ_RS | IMF_BJ_NOT},
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ {"TGEI", IT_I, NOALU, NOMEM, nullptr, // TGEI
+ .flags = IMF_BJR_REQ_RS},
+ {"TGEIU", IT_I, NOALU, NOMEM, nullptr, // TGEIU
+ .flags = IMF_BJR_REQ_RS},
+ {"TLTI", IT_I, NOALU, NOMEM, nullptr, // TLTI
+ .flags = IMF_BJR_REQ_RS},
+ {"TLTIU", IT_I, NOALU, NOMEM, nullptr, // TLTIU
+ .flags = IMF_BJR_REQ_RS},
+ {"TEQI", IT_I, NOALU, NOMEM, nullptr, // TEQI
+ .flags = IMF_BJR_REQ_RS},
+ IM_UNKNOWN,
+ {"TNEI", IT_I, NOALU, NOMEM, nullptr, // TNEI
+ .flags = IMF_BJR_REQ_RS},
+ IM_UNKNOWN,
+ {"BLTZAL", IT_I, NOALU, NOMEM, nullptr, // BLTZAL
+ .flags = FLAGS_J_B_PC_TO_R31 | IMF_BJR_REQ_RS | IMF_BRANCH},
+ {"BGEZAL", IT_I, NOALU, NOMEM, nullptr, // BGEZAL
+ .flags = FLAGS_J_B_PC_TO_R31 | IMF_BJR_REQ_RS | IMF_BRANCH | IMF_BJ_NOT},
+ {"BLTZALL", IT_I, NOALU, NOMEM, nullptr, // BLTZALL
+ .flags = IMF_BJR_REQ_RS},
+ {"BGEZALL", IT_I, NOALU, NOMEM, nullptr, // BGEZALL
+ .flags = IMF_BJR_REQ_RS | IMF_BJ_NOT},
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ {"SYNCI", IT_I, NOALU, NOMEM, nullptr, // SYNCI
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS},
+};
+
const std::int32_t instruction_map_opcode_field = IMF_SUB_ENCODE(6, 26);
// This table is indexed by opcode
static const struct InstructionMap instruction_map[] = {
{"ALU", IT_R, NOALU, NOMEM, alu_instruction_map, // Alu operations
.flags = IMF_SUB_ENCODE(6, 0)},
- {"REGIMM", IT_I, NOALU, NOMEM, nullptr, // REGIMM (BLTZ, BGEZ)
- .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS},
+ {"REGIMM", IT_I, NOALU, NOMEM, regimm_instruction_map, // REGIMM (BLTZ, BGEZ)
+ .flags = IMF_SUB_ENCODE(5, 16)},
{"J", IT_J, NOALU, NOMEM, nullptr, // J
- .flags = IMF_SUPPORTED},
- {"JAL", IT_J, ALU_OP_PASS_S, NOMEM, nullptr, // JAL
- .flags = IMF_SUPPORTED | IMF_PC_TO_R31 | IMF_REGWRITE},
+ .flags = IMF_SUPPORTED | IMF_JUMP},
+ {"JAL", IT_J, ALU_OP_PASS_T, NOMEM, nullptr, // JAL
+ .flags = FLAGS_J_B_PC_TO_R31 | IMF_JUMP},
{"BEQ", IT_I, NOALU, NOMEM, nullptr, // BEQ
- .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BJR_REQ_RT},
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BJR_REQ_RT | IMF_BRANCH},
{"BNE", IT_I, NOALU, NOMEM, nullptr, // BNE
- .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BJR_REQ_RT},
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BJR_REQ_RT | IMF_BRANCH | IMF_BJ_NOT},
{"BLEZ", IT_I, NOALU, NOMEM, nullptr, // BLEZ
- .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS},
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BRANCH | IMF_BGTZ_BLEZ},
{"BGTZ", IT_I, NOALU, NOMEM, nullptr, // BGTZ
- .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS},
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BRANCH | IMF_BGTZ_BLEZ | IMF_BJ_NOT},
{"ADDI", IT_I, ALU_OP_ADD, NOMEM, nullptr, // ADDI
.flags = FLAGS_ALU_I},
{"ADDIU", IT_I, ALU_OP_ADDU, NOMEM, nullptr, // ADDIU
diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h
index 8396bc7..a8779f5 100644
--- a/qtmips_machine/instruction.h
+++ b/qtmips_machine/instruction.h
@@ -63,6 +63,10 @@ enum InstructionFlags {
IMF_READ_HILO = 1L<<15,
IMF_WRITE_HILO = 1L<<16,
IMF_PC8_TO_RT = 1L<<17,
+ IMF_BRANCH = 1L<<18,
+ IMF_JUMP = 1L<<19,
+ IMF_BJ_NOT = 1L<<20,
+ IMF_BGTZ_BLEZ = 1L<<21,
};
class Instruction {
diff --git a/qtmips_machine/machinedefs.h b/qtmips_machine/machinedefs.h
index 0629f3e..2e419a8 100644
--- a/qtmips_machine/machinedefs.h
+++ b/qtmips_machine/machinedefs.h
@@ -81,8 +81,8 @@ enum AluOp : std::uint8_t {
ALU_OP_SLT = 42,
ALU_OP_SLTU,
ALU_OP_LUI = 64, // We don't care about exact index for this one
- ALU_OP_PASS_S, // Pass s argument without change for JAL
- ALU_OP_UNKNOWN, // Pass s argument without change for JAL
+ ALU_OP_PASS_T, // Pass t argument without change for JAL
+ ALU_OP_UNKNOWN,
ALU_OP_LAST // First impossible operation (just to be sure that we don't overflow)
};