aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine/alu.cpp
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 /qtmips_machine/alu.cpp
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>
Diffstat (limited to 'qtmips_machine/alu.cpp')
-rw-r--r--qtmips_machine/alu.cpp21
1 files changed, 21 insertions, 0 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 */