From 53c75d278a958e40b9c0b0ca3b04cfb11f356827 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Sun, 3 Feb 2019 10:33:05 +0100 Subject: Implement instructions MULT, MULTU, DIV, DIVU. Signed-off-by: Pavel Pisa --- qtmips_machine/alu.cpp | 21 ++++++++++++++++ qtmips_machine/alu.h | 4 +++ qtmips_machine/core.cpp | 36 ++++++++++++++++++++------- qtmips_machine/instruction.cpp | 20 +++++++-------- qtmips_machine/tests/testcore.cpp | 51 ++++++++++++++++++++++++++++++++++++++- qtmips_machine/tests/tests.pro | 7 ++++++ 6 files changed, 119 insertions(+), 20 deletions(-) diff --git a/qtmips_machine/alu.cpp b/qtmips_machine/alu.cpp index 176a9a5..bb3a745 100644 --- a/qtmips_machine/alu.cpp +++ b/qtmips_machine/alu.cpp @@ -5,6 +5,9 @@ using namespace machine; std::uint32_t machine::alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa, Registers *regs) { + std::int64_t s64_val; + std::uint64_t u64_val; + switch(operation) { case ALU_OP_SLL: return t << sa; @@ -42,6 +45,24 @@ std::uint32_t machine::alu_operate(enum AluOp operation, std::uint32_t s, std::u case ALU_OP_MTLO: regs->write_hi_lo(false, s); return 0x0; + case ALU_OP_MULT: + s64_val = (std::int64_t)(std::int32_t)s * (std::int32_t)t; + regs->write_hi_lo(false, (std::uint32_t)(s64_val & 0xffffffff)); + regs->write_hi_lo(true, (std::uint32_t)(s64_val >> 32)); + return 0x0; + case ALU_OP_MULTU: + u64_val = (std::uint64_t)s * t; + regs->write_hi_lo(false, (std::uint32_t)(u64_val & 0xffffffff)); + regs->write_hi_lo(true, (std::uint32_t)(u64_val >> 32)); + return 0x0; + case ALU_OP_DIV: + regs->write_hi_lo(false, (std::uint32_t)((std::int32_t)s / (std::int32_t)t)); + regs->write_hi_lo(true, (std::uint32_t)((std::int32_t)s % (std::int32_t)t)); + return 0x0; + case ALU_OP_DIVU: + regs->write_hi_lo(false, s / t); + regs->write_hi_lo(true, s % t); + return 0x0; case ALU_OP_ADD: /* s(31) ^ ~t(31) ... same signs on input */ /* (s + t)(31) ^ s(31) ... different sign on output */ diff --git a/qtmips_machine/alu.h b/qtmips_machine/alu.h index f0ce6c2..7846244 100644 --- a/qtmips_machine/alu.h +++ b/qtmips_machine/alu.h @@ -23,6 +23,10 @@ enum AluOp : std::uint8_t { ALU_OP_MTHI, ALU_OP_MFLO, ALU_OP_MTLO, + ALU_OP_MULT = 24, + ALU_OP_MULTU = 25, + ALU_OP_DIV = 26, + ALU_OP_DIVU = 27, ALU_OP_ADD = 32, ALU_OP_ADDU, ALU_OP_SUB, diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp index 255840a..7793305 100644 --- a/qtmips_machine/core.cpp +++ b/qtmips_machine/core.cpp @@ -93,7 +93,7 @@ static const struct DecodeMap dmap[] = { NOPE, // 60 NOPE, // 61 NOPE, // 62 - NOPE // 63 + NOPE // 63 }; Core::Core(Registers *regs, MemoryAccess *mem_program, MemoryAccess *mem_data) { @@ -138,14 +138,36 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) { std::uint32_t val_rs = regs->read_gp(dt.inst.rs()); std::uint32_t val_rt = regs->read_gp(dt.inst.rt()); std::uint32_t immediate_val; + bool regwrite = dec.flags & DM_REGWRITE; bool regd = dec.flags & DM_REGD; bool regd31 = dec.flags & DM_PC_TO_R31; // requires rs for beq, bne, blez, bgtz, jr nad jalr bool bjr_req_rs = dec.flags & DM_BJR_REQ_RS; - if (dt.inst.opcode() == 0 && ((dt.inst.funct() == ALU_OP_JR) || - (dt.inst.funct() == ALU_OP_JALR))) { - bjr_req_rs = true; + if (dt.inst.opcode() == 0) { + switch (dt.inst.funct()) { + case ALU_OP_MTHI: + FALLTROUGH + case ALU_OP_MTLO: + FALLTROUGH + case ALU_OP_MULT: + FALLTROUGH + case ALU_OP_MULTU: + FALLTROUGH + case ALU_OP_DIV: + FALLTROUGH + case ALU_OP_DIVU: + regwrite = false; + break; + case ALU_OP_JR: + regwrite = false; + bjr_req_rs = true; + break; + case ALU_OP_JALR: + val_rt = dt.inst_addr + 8; + bjr_req_rs = true; + break; + } } // requires rt for beq, bne bool bjr_req_rt = dec.flags & DM_BJR_REQ_RT; @@ -174,10 +196,6 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) { val_rs = dt.inst_addr + 8; } - if ((dt.inst.opcode() == 0 && dt.inst.funct() == ALU_OP_JALR)) { - val_rt = dt.inst_addr + 8; - } - rwrite = regd31 ? 31: regd ? dt.inst.rd() : dt.inst.rt(); return { @@ -187,7 +205,7 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) { .alusrc = dec.flags & DM_ALUSRC, .regd = regd, .regd31 = regd31, - .regwrite = dec.flags & DM_REGWRITE, + .regwrite = regwrite, .bjr_req_rs = bjr_req_rs, .bjr_req_rt = bjr_req_rt, .forward_m_d_rs = false, diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp index d87619b..7feebd3 100644 --- a/qtmips_machine/instruction.cpp +++ b/qtmips_machine/instruction.cpp @@ -111,7 +111,7 @@ static const struct AluInstructionMap alu_instruction_map[] = { AIM_UNKNOWN, AIM_UNKNOWN, AIM_UNKNOWN, - {"MFHU"}, + {"MFHI"}, {"MTHI"}, {"MFLO"}, {"MTLO"}, @@ -119,15 +119,15 @@ static const struct AluInstructionMap alu_instruction_map[] = { AIM_UNKNOWN, AIM_UNKNOWN, AIM_UNKNOWN, - AIM_UNKNOWN, - AIM_UNKNOWN, - AIM_UNKNOWN, - AIM_UNKNOWN, - AIM_UNKNOWN, - AIM_UNKNOWN, - AIM_UNKNOWN, - AIM_UNKNOWN, - {"ADD"}, + {"MULT"}, // 24 + {"MULTU"}, // 25 + {"DIV"}, // 26 + {"DIVU"}, // 27 + AIM_UNKNOWN, // 28 + AIM_UNKNOWN, // 29 + AIM_UNKNOWN, // 30 + AIM_UNKNOWN, // 31 + {"ADD"}, // 32 {"ADDU"}, {"SUB"}, {"SUBU"}, diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp index ea29577..8b5e17e 100644 --- a/qtmips_machine/tests/testcore.cpp +++ b/qtmips_machine/tests/testcore.cpp @@ -471,7 +471,7 @@ static void core_alu_forward_data() { } - // Test forwarding of ALU operands + // Test forwarding in JR and JALR { QVector code{ // start: = 0x80020000 @@ -523,6 +523,55 @@ static void core_alu_forward_data() { regs_res.pc_abs_jmp(0x80020060); QTest::newRow("j_jal_jalr") << code << regs_init << regs_res; } + + // Test multiplication and division + { + QVector code{ + // start: + 0x3c021234, // lui v0,0x1234 + 0x34425678, // ori v0,v0,0x5678 + 0x3c03abcd, // lui v1,0xabcd + 0x3463ef01, // ori v1,v1,0xef01 + 0x00430018, // mult v0,v1 + 0x00008012, // mflo s0 + 0x00008810, // mfhi s1 + 0x00430019, // multu v0,v1 + 0x00009012, // mflo s2 + 0x00009810, // mfhi s3 + 0x0062001a, // div zero,v1,v0 + 0x0000a012, // mflo s4 + 0x0000a810, // mfhi s5 + 0x0062001b, // divu zero,v1,v0 + 0x0000b012, // mflo s6 + 0x0000b810, // mfhi s7 + // loop: + 0x1000ffff, // b 80020070 + 0x00000000, // nop + }; + Registers regs_init; + regs_init.pc_abs_jmp(0x80020000); + Registers regs_res(regs_init); + std::uint32_t val_a = 0x12345678; + std::uint32_t val_b = 0xabcdef01; + std::uint64_t val_u64; + std::int64_t val_s64; + regs_res.write_gp(2, val_a); + regs_res.write_gp(3, val_b); + val_s64 = (std::int64_t)(std::int32_t)val_a * (std::int32_t)val_b; + regs_res.write_gp(16, (std::uint32_t)(val_s64 & 0xffffffff)); + regs_res.write_gp(17, (std::uint32_t)(val_s64 >> 32)); + val_u64 = (std::uint64_t)val_a * val_b; + regs_res.write_gp(18, (std::uint32_t)(val_u64 & 0xffffffff)); + regs_res.write_gp(19, (std::uint32_t)(val_u64 >> 32)); + regs_res.write_gp(20, (std::uint32_t)((std::int32_t)val_b / (std::int32_t)val_a)); + regs_res.write_gp(21, (std::uint32_t)((std::int32_t)val_b % (std::int32_t)val_a)); + regs_res.write_gp(22, val_b / val_a); + regs_res.write_gp(23, val_b % val_a); + regs_res.write_hi_lo(false, regs_res.read_gp(22)); + regs_res.write_hi_lo(true, regs_res.read_gp(23)); + regs_res.pc_abs_jmp(regs_init.read_pc() + 4 * code.length()); + QTest::newRow("mul-div") << code << regs_init << regs_res; + } } void MachineTests::singlecore_alu_forward_data() { diff --git a/qtmips_machine/tests/tests.pro b/qtmips_machine/tests/tests.pro index 751bf8a..63792b0 100644 --- a/qtmips_machine/tests/tests.pro +++ b/qtmips_machine/tests/tests.pro @@ -9,6 +9,13 @@ CONFIG += c++11 TEMPLATE = app LIBS += -L$$OUT_PWD/../ -lqtmips_machine + +DOLAR=$ + +unix: LIBS += \ + -Wl,-rpath,\'$${DOLAR}$${DOLAR}ORIGIN/../lib\' \ + --enable-new-dtags \ + INCLUDEPATH += $$PWD/.. DEPENDPATH += $$PWD/.. QMAKE_CXXFLAGS += -std=c++0x -- cgit v1.2.3