aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2019-02-03 10:33:05 +0100
committerPavel Pisa <pisa@cmp.felk.cvut.cz>2019-02-03 10:33:05 +0100
commit53c75d278a958e40b9c0b0ca3b04cfb11f356827 (patch)
tree87472f3d8df4b6fbb44fe7b2afd7bf0c89c55035
parent12536c28a74e3b1fd6f5d1213311c809f9ddf824 (diff)
downloadqtmips-53c75d278a958e40b9c0b0ca3b04cfb11f356827.tar.gz
qtmips-53c75d278a958e40b9c0b0ca3b04cfb11f356827.tar.bz2
qtmips-53c75d278a958e40b9c0b0ca3b04cfb11f356827.zip
Implement instructions MULT, MULTU, DIV, DIVU.
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
-rw-r--r--qtmips_machine/alu.cpp21
-rw-r--r--qtmips_machine/alu.h4
-rw-r--r--qtmips_machine/core.cpp36
-rw-r--r--qtmips_machine/instruction.cpp20
-rw-r--r--qtmips_machine/tests/testcore.cpp51
-rw-r--r--qtmips_machine/tests/tests.pro7
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<uint32_t> 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<uint32_t> 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 <loop>
+ 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