From e9ffa56110da05a6938ad690872cdac6d48fd586 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Tue, 5 Feb 2019 12:46:08 +0100 Subject: Reorganize PC handling and implement full REGIMM decode. Signed-off-by: Pavel Pisa --- qtmips_machine/alu.cpp | 4 +-- qtmips_machine/core.cpp | 69 +++++++++++++++++---------------------- qtmips_machine/core.h | 6 ++++ qtmips_machine/instruction.cpp | 74 +++++++++++++++++++++++++++++++++++------- qtmips_machine/instruction.h | 4 +++ qtmips_machine/machinedefs.h | 4 +-- 6 files changed, 106 insertions(+), 55 deletions(-) (limited to 'qtmips_machine') 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) }; -- cgit v1.2.3